Corrected functionality of gnutls_record_get_direction(). Reported by Philip Allison.
[gnutls.git] / lib / gnutls_constate.c
bloba3f2b028de8eb0e30f6f44d8c384ef5d003a87e5
1 /*
2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2010 Free
3 * Software Foundation, Inc.
5 * Author: Nikos Mavrogiannopoulos
7 * This file is part of GnuTLS.
9 * The GnuTLS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22 * USA
26 /* Functions that are supposed to run after the handshake procedure is
27 * finished. These functions activate the established security parameters.
30 #include <gnutls_int.h>
31 #include <gnutls_constate.h>
32 #include <gnutls_errors.h>
33 #include <gnutls_kx.h>
34 #include <gnutls_algorithms.h>
35 #include <gnutls_num.h>
36 #include <gnutls_datum.h>
37 #include <gnutls_state.h>
38 #include <gnutls_extensions.h>
39 #include <gnutls_buffers.h>
41 static const char keyexp[] = "key expansion";
42 static const int keyexp_length = sizeof (keyexp) - 1;
44 static const char ivblock[] = "IV block";
45 static const int ivblock_length = sizeof (ivblock) - 1;
47 static const char cliwrite[] = "client write key";
48 static const int cliwrite_length = sizeof (cliwrite) - 1;
50 static const char servwrite[] = "server write key";
51 static const int servwrite_length = sizeof (servwrite) - 1;
53 #define EXPORT_FINAL_KEY_SIZE 16
55 /* This function is to be called after handshake, when master_secret,
56 * client_random and server_random have been initialized.
57 * This function creates the keys and stores them into pending session.
58 * (session->cipher_specs)
60 static int
61 _gnutls_set_keys (gnutls_session_t session, record_parameters_st * params,
62 int hash_size, int IV_size, int key_size, int export_flag)
64 /* FIXME: This function is too long
66 opaque rnd[2 * GNUTLS_RANDOM_SIZE];
67 opaque rrnd[2 * GNUTLS_RANDOM_SIZE];
68 int pos, ret;
69 int block_size;
70 char buf[65];
71 /* avoid using malloc */
72 opaque key_block[2 * MAX_HASH_SIZE + 2 * MAX_CIPHER_KEY_SIZE +
73 2 * MAX_CIPHER_BLOCK_SIZE];
74 record_state_st *client_write, *server_write;
76 client_write =
77 session->security_parameters.entity ==
78 GNUTLS_CLIENT ? &params->write : &params->read;
79 server_write =
80 session->security_parameters.entity ==
81 GNUTLS_SERVER ? &params->write : &params->read;
83 block_size = 2 * hash_size + 2 * key_size;
84 if (export_flag == 0)
85 block_size += 2 * IV_size;
87 memcpy (rnd, session->security_parameters.server_random,
88 GNUTLS_RANDOM_SIZE);
89 memcpy (&rnd[GNUTLS_RANDOM_SIZE],
90 session->security_parameters.client_random, GNUTLS_RANDOM_SIZE);
92 memcpy (rrnd, session->security_parameters.client_random,
93 GNUTLS_RANDOM_SIZE);
94 memcpy (&rrnd[GNUTLS_RANDOM_SIZE],
95 session->security_parameters.server_random, GNUTLS_RANDOM_SIZE);
97 if (session->security_parameters.version == GNUTLS_SSL3)
98 { /* SSL 3 */
99 ret =
100 _gnutls_ssl3_generate_random
101 (session->security_parameters.master_secret, GNUTLS_MASTER_SIZE, rnd,
102 2 * GNUTLS_RANDOM_SIZE, block_size, key_block);
104 else
105 { /* TLS 1.0 */
106 ret =
107 _gnutls_PRF (session, session->security_parameters.master_secret,
108 GNUTLS_MASTER_SIZE, keyexp, keyexp_length,
109 rnd, 2 * GNUTLS_RANDOM_SIZE, block_size, key_block);
112 if (ret < 0)
113 return gnutls_assert_val (ret);
115 _gnutls_hard_log ("INT: KEY BLOCK[%d]: %s\n", block_size,
116 _gnutls_bin2hex (key_block, block_size, buf,
117 sizeof (buf), NULL));
119 pos = 0;
120 if (hash_size > 0)
123 if (_gnutls_sset_datum
124 (&client_write->mac_secret, &key_block[pos], hash_size) < 0)
125 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
127 pos += hash_size;
129 if (_gnutls_sset_datum
130 (&server_write->mac_secret, &key_block[pos], hash_size) < 0)
131 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
133 pos += hash_size;
136 if (key_size > 0)
138 opaque key1[EXPORT_FINAL_KEY_SIZE];
139 opaque key2[EXPORT_FINAL_KEY_SIZE];
140 opaque *client_write_key, *server_write_key;
141 int client_write_key_size, server_write_key_size;
143 if (export_flag == 0)
145 client_write_key = &key_block[pos];
146 client_write_key_size = key_size;
148 pos += key_size;
150 server_write_key = &key_block[pos];
151 server_write_key_size = key_size;
153 pos += key_size;
156 else
157 { /* export */
158 client_write_key = key1;
159 server_write_key = key2;
161 /* generate the final keys */
163 if (session->security_parameters.version == GNUTLS_SSL3)
164 { /* SSL 3 */
165 ret =
166 _gnutls_ssl3_hash_md5 (&key_block[pos],
167 key_size, rrnd,
168 2 * GNUTLS_RANDOM_SIZE,
169 EXPORT_FINAL_KEY_SIZE,
170 client_write_key);
173 else
174 { /* TLS 1.0 */
175 ret =
176 _gnutls_PRF (session, &key_block[pos], key_size,
177 cliwrite, cliwrite_length,
178 rrnd,
179 2 * GNUTLS_RANDOM_SIZE,
180 EXPORT_FINAL_KEY_SIZE, client_write_key);
183 if (ret < 0)
184 return gnutls_assert_val (ret);
186 client_write_key_size = EXPORT_FINAL_KEY_SIZE;
187 pos += key_size;
189 if (session->security_parameters.version == GNUTLS_SSL3)
190 { /* SSL 3 */
191 ret =
192 _gnutls_ssl3_hash_md5 (&key_block[pos], key_size,
193 rnd, 2 * GNUTLS_RANDOM_SIZE,
194 EXPORT_FINAL_KEY_SIZE,
195 server_write_key);
197 else
198 { /* TLS 1.0 */
199 ret =
200 _gnutls_PRF (session, &key_block[pos], key_size,
201 servwrite, servwrite_length,
202 rrnd, 2 * GNUTLS_RANDOM_SIZE,
203 EXPORT_FINAL_KEY_SIZE, server_write_key);
206 if (ret < 0)
207 return gnutls_assert_val (ret);
209 server_write_key_size = EXPORT_FINAL_KEY_SIZE;
210 pos += key_size;
213 if (_gnutls_sset_datum
214 (&client_write->key, client_write_key, client_write_key_size) < 0)
215 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
217 _gnutls_hard_log ("INT: CLIENT WRITE KEY [%d]: %s\n",
218 client_write_key_size,
219 _gnutls_bin2hex (client_write_key,
220 client_write_key_size, buf,
221 sizeof (buf), NULL));
223 if (_gnutls_sset_datum
224 (&server_write->key, server_write_key, server_write_key_size) < 0)
225 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
227 _gnutls_hard_log ("INT: SERVER WRITE KEY [%d]: %s\n",
228 server_write_key_size,
229 _gnutls_bin2hex (server_write_key,
230 server_write_key_size, buf,
231 sizeof (buf), NULL));
236 /* IV generation in export and non export ciphers.
238 if (IV_size > 0 && export_flag == 0)
240 if (_gnutls_sset_datum
241 (&client_write->IV, &key_block[pos], IV_size) < 0)
242 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
244 pos += IV_size;
246 if (_gnutls_sset_datum
247 (&server_write->IV, &key_block[pos], IV_size) < 0)
248 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
250 pos += IV_size;
253 else if (IV_size > 0 && export_flag != 0)
255 opaque iv_block[MAX_CIPHER_BLOCK_SIZE * 2];
257 if (session->security_parameters.version == GNUTLS_SSL3)
258 { /* SSL 3 */
259 ret = _gnutls_ssl3_hash_md5 ("", 0,
260 rrnd, GNUTLS_RANDOM_SIZE * 2,
261 IV_size, iv_block);
263 if (ret < 0)
264 return gnutls_assert_val (ret);
267 ret = _gnutls_ssl3_hash_md5 ("", 0, rnd,
268 GNUTLS_RANDOM_SIZE * 2,
269 IV_size, &iv_block[IV_size]);
272 else
273 { /* TLS 1.0 */
274 ret = _gnutls_PRF (session, "", 0,
275 ivblock, ivblock_length, rrnd,
276 2 * GNUTLS_RANDOM_SIZE, IV_size * 2, iv_block);
279 if (ret < 0)
280 return gnutls_assert_val (ret);
282 if (_gnutls_sset_datum (&client_write->IV, iv_block, IV_size) < 0)
283 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
285 if (_gnutls_sset_datum
286 (&server_write->IV, &iv_block[IV_size], IV_size) < 0)
287 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
290 return 0;
293 static int
294 _gnutls_init_record_state (record_parameters_st * params, int read,
295 record_state_st * state)
297 int ret;
299 ret = _gnutls_cipher_init (&state->cipher_state,
300 params->cipher_algorithm,
301 &state->key, &state->IV);
302 if (ret < 0 && params->cipher_algorithm != GNUTLS_CIPHER_NULL)
303 return gnutls_assert_val (ret);
305 state->compression_state =
306 _gnutls_comp_init (params->compression_algorithm, read);
308 if (state->compression_state == GNUTLS_COMP_FAILED)
309 return gnutls_assert_val (GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM);
311 return 0;
315 _gnutls_epoch_set_cipher_suite (gnutls_session_t session,
316 int epoch_rel, cipher_suite_st * suite)
318 gnutls_cipher_algorithm_t cipher_algo;
319 gnutls_mac_algorithm_t mac_algo;
320 record_parameters_st *params;
321 int ret;
323 ret = _gnutls_epoch_get (session, epoch_rel, &params);
324 if (ret < 0)
325 return gnutls_assert_val (ret);
327 if (params->initialized
328 || params->cipher_algorithm != GNUTLS_CIPHER_UNKNOWN
329 || params->mac_algorithm != GNUTLS_MAC_UNKNOWN)
330 return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
332 cipher_algo = _gnutls_cipher_suite_get_cipher_algo (suite);
333 mac_algo = _gnutls_cipher_suite_get_mac_algo (suite);
335 if (_gnutls_cipher_is_ok (cipher_algo) != 0
336 || _gnutls_mac_is_ok (mac_algo) != 0)
337 return gnutls_assert_val (GNUTLS_E_UNWANTED_ALGORITHM);
339 params->cipher_algorithm = cipher_algo;
340 params->mac_algorithm = mac_algo;
342 return 0;
346 _gnutls_epoch_set_compression (gnutls_session_t session,
347 int epoch_rel,
348 gnutls_compression_method_t comp_algo)
350 record_parameters_st *params;
351 int ret;
353 ret = _gnutls_epoch_get (session, epoch_rel, &params);
354 if (ret < 0)
355 return gnutls_assert_val (ret);
357 if (params->initialized
358 || params->compression_algorithm != GNUTLS_COMP_UNKNOWN)
359 return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
361 if (_gnutls_compression_is_ok (comp_algo) != 0)
362 return gnutls_assert_val (GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM);
364 params->compression_algorithm = comp_algo;
366 return 0;
369 void
370 _gnutls_epoch_set_null_algos (gnutls_session_t session,
371 record_parameters_st * params)
373 /* This is only called on startup. We are extra paranoid about this
374 because it may cause unencrypted application data to go out on
375 the wire. */
376 if (params->initialized || params->epoch != 0)
378 gnutls_assert ();
379 return;
382 params->cipher_algorithm = GNUTLS_CIPHER_NULL;
383 params->mac_algorithm = GNUTLS_MAC_NULL;
384 params->compression_algorithm = GNUTLS_COMP_NULL;
385 params->initialized = 1;
389 _gnutls_epoch_set_keys (gnutls_session_t session, uint16_t epoch)
391 int hash_size;
392 int IV_size;
393 int key_size, export_flag;
394 gnutls_cipher_algorithm_t cipher_algo;
395 gnutls_mac_algorithm_t mac_algo;
396 gnutls_compression_method_t comp_algo;
397 record_parameters_st *params;
398 int ret;
400 ret = _gnutls_epoch_get (session, epoch, &params);
401 if (ret < 0)
402 return gnutls_assert_val (ret);
404 if (params->initialized)
405 return 0;
407 _gnutls_record_log
408 ("REC[%p]: Initializing epoch #%u\n", session, params->epoch);
410 cipher_algo = params->cipher_algorithm;
411 mac_algo = params->mac_algorithm;
412 comp_algo = params->compression_algorithm;
414 if (_gnutls_cipher_is_ok (cipher_algo) != 0
415 || _gnutls_mac_is_ok (mac_algo) != 0)
416 return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
418 if (_gnutls_compression_is_ok (comp_algo) != 0)
419 return gnutls_assert_val (GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM);
421 IV_size = _gnutls_cipher_get_iv_size (cipher_algo);
422 key_size = gnutls_cipher_get_key_size (cipher_algo);
423 export_flag = _gnutls_cipher_get_export_flag (cipher_algo);
424 hash_size = _gnutls_hash_get_algo_len (mac_algo);
426 ret = _gnutls_set_keys
427 (session, params, hash_size, IV_size, key_size, export_flag);
428 if (ret < 0)
429 return gnutls_assert_val (ret);
431 ret = _gnutls_init_record_state (params, 1, &params->read);
432 if (ret < 0)
433 return gnutls_assert_val (ret);
435 ret = _gnutls_init_record_state (params, 0, &params->write);
436 if (ret < 0)
437 return gnutls_assert_val (ret);
439 _gnutls_record_log ("REC[%p]: Epoch #%u ready\n", session, params->epoch);
441 params->initialized = 1;
442 return 0;
446 #define CPY_COMMON dst->entity = src->entity; \
447 dst->kx_algorithm = src->kx_algorithm; \
448 memcpy( &dst->current_cipher_suite, &src->current_cipher_suite, sizeof(cipher_suite_st)); \
449 memcpy( dst->master_secret, src->master_secret, GNUTLS_MASTER_SIZE); \
450 memcpy( dst->client_random, src->client_random, GNUTLS_RANDOM_SIZE); \
451 memcpy( dst->server_random, src->server_random, GNUTLS_RANDOM_SIZE); \
452 memcpy( dst->session_id, src->session_id, TLS_MAX_SESSION_ID_SIZE); \
453 dst->session_id_size = src->session_id_size; \
454 dst->cert_type = src->cert_type; \
455 dst->timestamp = src->timestamp; \
456 dst->max_record_recv_size = src->max_record_recv_size; \
457 dst->max_record_send_size = src->max_record_send_size; \
458 dst->version = src->version
460 static void
461 _gnutls_set_resumed_parameters (gnutls_session_t session)
463 security_parameters_st *src =
464 &session->internals.resumed_security_parameters;
465 security_parameters_st *dst = &session->security_parameters;
467 CPY_COMMON;
470 /* Sets the current connection session to conform with the
471 * Security parameters(pending session), and initializes encryption.
472 * Actually it initializes and starts encryption ( so it needs
473 * secrets and random numbers to have been negotiated)
474 * This is to be called after sending the Change Cipher Spec packet.
477 _gnutls_connection_state_init (gnutls_session_t session)
479 int ret;
481 /* Setup the master secret
483 if ((ret = _gnutls_generate_master (session, 0)) < 0)
484 return gnutls_assert_val (ret);
486 return 0;
491 static int
492 _gnutls_check_algos (gnutls_session_t session,
493 cipher_suite_st * suite,
494 gnutls_compression_method_t comp_algo)
496 gnutls_cipher_algorithm_t cipher_algo;
497 gnutls_mac_algorithm_t mac_algo;
499 cipher_algo = _gnutls_cipher_suite_get_cipher_algo (suite);
500 mac_algo = _gnutls_cipher_suite_get_mac_algo (suite);
502 if (_gnutls_cipher_is_ok (cipher_algo) != 0)
503 return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
505 if (_gnutls_cipher_priority (session, cipher_algo) < 0)
506 return gnutls_assert_val (GNUTLS_E_UNWANTED_ALGORITHM);
509 if (_gnutls_mac_is_ok (mac_algo) != 0)
510 return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
512 if (_gnutls_mac_priority (session, mac_algo) < 0)
513 return gnutls_assert_val (GNUTLS_E_UNWANTED_ALGORITHM);
516 if (_gnutls_compression_is_ok (comp_algo) != 0)
517 return gnutls_assert_val (GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM);
519 return 0;
522 /* Initializes the read connection session
523 * (read encrypted data)
526 _gnutls_read_connection_state_init (gnutls_session_t session)
528 const uint16_t epoch_next = session->security_parameters.epoch_next;
529 int ret;
531 /* Update internals from CipherSuite selected.
532 * If we are resuming just copy the connection session
534 if (session->internals.resumed == RESUME_FALSE)
536 ret = _gnutls_check_algos (session,
537 &session->
538 security_parameters.current_cipher_suite,
539 session->internals.compression_method);
540 if (ret < 0)
541 return ret;
543 ret = _gnutls_set_kx (session,
544 _gnutls_cipher_suite_get_kx_algo
545 (&session->
546 security_parameters.current_cipher_suite));
547 if (ret < 0)
548 return ret;
550 else if (session->security_parameters.entity == GNUTLS_CLIENT)
551 _gnutls_set_resumed_parameters (session);
553 ret = _gnutls_epoch_set_keys (session, epoch_next);
554 if (ret < 0)
555 return ret;
557 _gnutls_handshake_log ("HSK[%p]: Cipher Suite: %s\n",
558 session,
559 _gnutls_cipher_suite_get_name
560 (&session->
561 security_parameters.current_cipher_suite));
563 session->security_parameters.epoch_read = epoch_next;
564 _gnutls_epoch_gc (session);
566 return 0;
571 /* Initializes the write connection session
572 * (write encrypted data)
575 _gnutls_write_connection_state_init (gnutls_session_t session)
577 const uint16_t epoch_next = session->security_parameters.epoch_next;
578 int ret;
580 /* Update internals from CipherSuite selected.
581 * If we are resuming just copy the connection session
583 if (session->internals.resumed == RESUME_FALSE)
585 ret = _gnutls_check_algos (session,
586 &session->
587 security_parameters.current_cipher_suite,
588 session->internals.compression_method);
589 if (ret < 0)
590 return ret;
592 ret = _gnutls_set_kx (session,
593 _gnutls_cipher_suite_get_kx_algo
594 (&session->
595 security_parameters.current_cipher_suite));
596 if (ret < 0)
597 return ret;
599 else if (session->security_parameters.entity == GNUTLS_SERVER)
600 _gnutls_set_resumed_parameters (session);
602 ret = _gnutls_epoch_set_keys (session, epoch_next);
603 if (ret < 0)
604 return gnutls_assert_val (ret);
606 _gnutls_handshake_log ("HSK[%p]: Cipher Suite: %s\n", session,
607 _gnutls_cipher_suite_get_name
608 (&session->
609 security_parameters.current_cipher_suite));
611 _gnutls_handshake_log
612 ("HSK[%p]: Initializing internal [write] cipher sessions\n", session);
614 session->security_parameters.epoch_write = epoch_next;
615 _gnutls_epoch_gc (session);
617 return 0;
620 /* Sets the specified kx algorithm into pending session
623 _gnutls_set_kx (gnutls_session_t session, gnutls_kx_algorithm_t algo)
626 if (_gnutls_kx_is_ok (algo) == 0)
628 session->security_parameters.kx_algorithm = algo;
630 else
631 return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
633 if (_gnutls_kx_priority (session, algo) < 0)
634 return gnutls_assert_val (GNUTLS_E_UNWANTED_ALGORITHM);
636 return 0;
639 static inline int
640 epoch_resolve (gnutls_session_t session,
641 unsigned int epoch_rel, uint16_t * epoch_out)
643 switch (epoch_rel)
645 case EPOCH_READ_CURRENT:
646 *epoch_out = session->security_parameters.epoch_read;
647 return 0;
649 case EPOCH_WRITE_CURRENT:
650 *epoch_out = session->security_parameters.epoch_write;
651 return 0;
653 case EPOCH_NEXT:
654 *epoch_out = session->security_parameters.epoch_next;
655 return 0;
657 default:
658 if (epoch_rel > 0xffffu)
659 return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
661 *epoch_out = epoch_rel;
662 return 0;
666 static inline record_parameters_st **
667 epoch_get_slot (gnutls_session_t session, uint16_t epoch)
669 uint16_t epoch_index = epoch - session->security_parameters.epoch_min;
671 if (epoch_index >= MAX_EPOCH_INDEX)
673 gnutls_assert ();
674 return NULL;
677 /* The slot may still be empty (NULL) */
678 return &session->record_parameters[epoch_index];
682 _gnutls_epoch_get (gnutls_session_t session, unsigned int epoch_rel,
683 record_parameters_st ** params_out)
685 uint16_t epoch;
686 record_parameters_st **params;
687 int ret;
689 ret = epoch_resolve (session, epoch_rel, &epoch);
690 if (ret < 0)
691 return gnutls_assert_val (ret);
693 params = epoch_get_slot (session, epoch);
694 if (params == NULL || *params == NULL)
695 return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
697 *params_out = *params;
699 return 0;
703 _gnutls_epoch_alloc (gnutls_session_t session, uint16_t epoch,
704 record_parameters_st ** out)
706 record_parameters_st **slot;
708 _gnutls_record_log ("REC[%p]: Allocating epoch #%u\n", session, epoch);
710 slot = epoch_get_slot (session, epoch);
712 /* If slot out of range or not empty. */
713 if (slot == NULL)
714 return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
716 if (*slot != NULL)
717 return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
719 *slot = gnutls_calloc (1, sizeof (record_parameters_st));
720 if (*slot == NULL)
721 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
723 (*slot)->epoch = epoch;
724 (*slot)->cipher_algorithm = GNUTLS_CIPHER_UNKNOWN;
725 (*slot)->mac_algorithm = GNUTLS_MAC_UNKNOWN;
726 (*slot)->compression_algorithm = GNUTLS_COMP_UNKNOWN;
728 if (out != NULL)
729 *out = *slot;
731 return 0;
734 static inline int
735 epoch_alive (gnutls_session_t session, record_parameters_st * params)
737 const security_parameters_st *sp = &session->security_parameters;
739 /* DTLS will, in addition, need to check the epoch timeout value. */
740 return (params->epoch == sp->epoch_read
741 || params->epoch == sp->epoch_write
742 || params->epoch == sp->epoch_next);
745 void
746 _gnutls_epoch_gc (gnutls_session_t session)
748 int i, j;
749 unsigned int min_index = 0;
751 _gnutls_record_log ("REC[%p]: Start of epoch cleanup\n", session);
753 /* Free all dead cipher state */
754 for (i = 0; i < MAX_EPOCH_INDEX; i++)
755 if (session->record_parameters[i] != NULL
756 && !epoch_alive (session, session->record_parameters[i]))
758 _gnutls_epoch_free (session, session->record_parameters[i]);
759 session->record_parameters[i] = NULL;
762 /* Look for contiguous NULLs at the start of the array */
763 for (i = 0; i < MAX_EPOCH_INDEX && session->record_parameters[i] == NULL;
764 i++);
765 min_index = i;
767 /* Pick up the slack in the epoch window. */
768 for (i = 0, j = min_index; j < MAX_EPOCH_INDEX; i++, j++)
769 session->record_parameters[i] = session->record_parameters[j];
771 /* Set the new epoch_min */
772 if (session->record_parameters[0] != NULL)
773 session->security_parameters.epoch_min =
774 session->record_parameters[0]->epoch;
776 _gnutls_record_log ("REC[%p]: End of epoch cleanup\n", session);
779 static inline void
780 free_record_state (record_state_st * state, int read)
782 _gnutls_free_datum (&state->mac_secret);
783 _gnutls_free_datum (&state->IV);
784 _gnutls_free_datum (&state->key);
786 _gnutls_cipher_deinit (&state->cipher_state);
788 if (state->compression_state != NULL)
789 _gnutls_comp_deinit (state->compression_state, read);
792 void
793 _gnutls_epoch_free (gnutls_session_t session, record_parameters_st * params)
795 _gnutls_record_log ("REC[%p]: Epoch #%u freed\n", session, params->epoch);
797 free_record_state (&params->read, 1);
798 free_record_state (&params->write, 0);
800 gnutls_free (params);