added new functions
[gnutls.git] / lib / gnutls_constate.c
blob942675267c89dc55f24317754dc8c12577862160
1 /*
2 * Copyright (C) 2001-2012 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
8 * The GnuTLS is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 /* Functions that are supposed to run after the handshake procedure is
24 * finished. These functions activate the established security parameters.
27 #include <gnutls_int.h>
28 #include <gnutls_constate.h>
29 #include <gnutls_errors.h>
30 #include <gnutls_kx.h>
31 #include <algorithms.h>
32 #include <gnutls_num.h>
33 #include <gnutls_datum.h>
34 #include <gnutls_state.h>
35 #include <gnutls_extensions.h>
36 #include <gnutls_buffers.h>
38 static const char keyexp[] = "key expansion";
39 static const int keyexp_length = sizeof (keyexp) - 1;
41 static const char ivblock[] = "IV block";
42 static const int ivblock_length = sizeof (ivblock) - 1;
44 static const char cliwrite[] = "client write key";
45 static const int cliwrite_length = sizeof (cliwrite) - 1;
47 static const char servwrite[] = "server write key";
48 static const int servwrite_length = sizeof (servwrite) - 1;
50 #define EXPORT_FINAL_KEY_SIZE 16
52 /* This function is to be called after handshake, when master_secret,
53 * client_random and server_random have been initialized.
54 * This function creates the keys and stores them into pending session.
55 * (session->cipher_specs)
57 static int
58 _gnutls_set_keys (gnutls_session_t session, record_parameters_st * params,
59 int hash_size, int IV_size, int key_size, int export_flag)
61 /* FIXME: This function is too long
63 uint8_t rnd[2 * GNUTLS_RANDOM_SIZE];
64 uint8_t rrnd[2 * GNUTLS_RANDOM_SIZE];
65 int pos, ret;
66 int block_size;
67 char buf[65];
68 /* avoid using malloc */
69 uint8_t key_block[2 * MAX_HASH_SIZE + 2 * MAX_CIPHER_KEY_SIZE +
70 2 * MAX_CIPHER_BLOCK_SIZE];
71 record_state_st *client_write, *server_write;
73 if (session->security_parameters.entity == GNUTLS_CLIENT)
75 client_write = &params->write;
76 server_write = &params->read;
78 else
80 client_write = &params->read;
81 server_write = &params->write;
84 block_size = 2 * hash_size + 2 * key_size;
85 if (export_flag == 0)
86 block_size += 2 * IV_size;
88 memcpy (rnd, session->security_parameters.server_random,
89 GNUTLS_RANDOM_SIZE);
90 memcpy (&rnd[GNUTLS_RANDOM_SIZE],
91 session->security_parameters.client_random, GNUTLS_RANDOM_SIZE);
93 memcpy (rrnd, session->security_parameters.client_random,
94 GNUTLS_RANDOM_SIZE);
95 memcpy (&rrnd[GNUTLS_RANDOM_SIZE],
96 session->security_parameters.server_random, GNUTLS_RANDOM_SIZE);
98 if (session->security_parameters.version == GNUTLS_SSL3)
99 { /* SSL 3 */
100 ret =
101 _gnutls_ssl3_generate_random
102 (session->security_parameters.master_secret, GNUTLS_MASTER_SIZE, rnd,
103 2 * GNUTLS_RANDOM_SIZE, block_size, key_block);
105 else
106 { /* TLS 1.0 */
107 ret =
108 _gnutls_PRF (session, session->security_parameters.master_secret,
109 GNUTLS_MASTER_SIZE, keyexp, keyexp_length,
110 rnd, 2 * GNUTLS_RANDOM_SIZE, block_size, key_block);
113 if (ret < 0)
114 return gnutls_assert_val (ret);
116 _gnutls_hard_log ("INT: KEY BLOCK[%d]: %s\n", block_size,
117 _gnutls_bin2hex (key_block, block_size, buf,
118 sizeof (buf), NULL));
120 pos = 0;
121 if (hash_size > 0)
124 if (_gnutls_set_datum
125 (&client_write->mac_secret, &key_block[pos], hash_size) < 0)
126 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
128 pos += hash_size;
130 if (_gnutls_set_datum
131 (&server_write->mac_secret, &key_block[pos], hash_size) < 0)
132 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
134 pos += hash_size;
137 if (key_size > 0)
139 uint8_t key1[EXPORT_FINAL_KEY_SIZE];
140 uint8_t key2[EXPORT_FINAL_KEY_SIZE];
141 uint8_t *client_write_key, *server_write_key;
142 int client_write_key_size, server_write_key_size;
144 if (export_flag == 0)
146 client_write_key = &key_block[pos];
147 client_write_key_size = key_size;
149 pos += key_size;
151 server_write_key = &key_block[pos];
152 server_write_key_size = key_size;
154 pos += key_size;
157 else
158 { /* export */
159 client_write_key = key1;
160 server_write_key = key2;
162 /* generate the final keys */
164 if (session->security_parameters.version == GNUTLS_SSL3)
165 { /* SSL 3 */
166 ret =
167 _gnutls_ssl3_hash_md5 (&key_block[pos],
168 key_size, rrnd,
169 2 * GNUTLS_RANDOM_SIZE,
170 EXPORT_FINAL_KEY_SIZE,
171 client_write_key);
174 else
175 { /* TLS 1.0 */
176 ret =
177 _gnutls_PRF (session, &key_block[pos], key_size,
178 cliwrite, cliwrite_length,
179 rrnd,
180 2 * GNUTLS_RANDOM_SIZE,
181 EXPORT_FINAL_KEY_SIZE, client_write_key);
184 if (ret < 0)
185 return gnutls_assert_val (ret);
187 client_write_key_size = EXPORT_FINAL_KEY_SIZE;
188 pos += key_size;
190 if (session->security_parameters.version == GNUTLS_SSL3)
191 { /* SSL 3 */
192 ret =
193 _gnutls_ssl3_hash_md5 (&key_block[pos], key_size,
194 rnd, 2 * GNUTLS_RANDOM_SIZE,
195 EXPORT_FINAL_KEY_SIZE,
196 server_write_key);
198 else
199 { /* TLS 1.0 */
200 ret =
201 _gnutls_PRF (session, &key_block[pos], key_size,
202 servwrite, servwrite_length,
203 rrnd, 2 * GNUTLS_RANDOM_SIZE,
204 EXPORT_FINAL_KEY_SIZE, server_write_key);
207 if (ret < 0)
208 return gnutls_assert_val (ret);
210 server_write_key_size = EXPORT_FINAL_KEY_SIZE;
211 pos += key_size;
214 if (_gnutls_set_datum
215 (&client_write->key, client_write_key, client_write_key_size) < 0)
216 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
218 _gnutls_hard_log ("INT: CLIENT WRITE KEY [%d]: %s\n",
219 client_write_key_size,
220 _gnutls_bin2hex (client_write_key,
221 client_write_key_size, buf,
222 sizeof (buf), NULL));
224 if (_gnutls_set_datum
225 (&server_write->key, server_write_key, server_write_key_size) < 0)
226 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
228 _gnutls_hard_log ("INT: SERVER WRITE KEY [%d]: %s\n",
229 server_write_key_size,
230 _gnutls_bin2hex (server_write_key,
231 server_write_key_size, buf,
232 sizeof (buf), NULL));
237 /* IV generation in export and non export ciphers.
239 if (IV_size > 0 && export_flag == 0)
241 if (_gnutls_set_datum
242 (&client_write->IV, &key_block[pos], IV_size) < 0)
243 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
245 pos += IV_size;
247 if (_gnutls_set_datum
248 (&server_write->IV, &key_block[pos], IV_size) < 0)
249 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
252 else if (IV_size > 0 && export_flag != 0)
254 uint8_t iv_block[MAX_CIPHER_BLOCK_SIZE * 2];
256 if (session->security_parameters.version == GNUTLS_SSL3)
257 { /* SSL 3 */
258 ret = _gnutls_ssl3_hash_md5 ("", 0,
259 rrnd, GNUTLS_RANDOM_SIZE * 2,
260 IV_size, iv_block);
262 if (ret < 0)
263 return gnutls_assert_val (ret);
266 ret = _gnutls_ssl3_hash_md5 ("", 0, rnd,
267 GNUTLS_RANDOM_SIZE * 2,
268 IV_size, &iv_block[IV_size]);
271 else
272 { /* TLS 1.0 */
273 ret = _gnutls_PRF (session, (uint8_t*)"", 0,
274 ivblock, ivblock_length, rrnd,
275 2 * GNUTLS_RANDOM_SIZE, IV_size * 2, iv_block);
278 if (ret < 0)
279 return gnutls_assert_val (ret);
281 if (_gnutls_set_datum (&client_write->IV, iv_block, IV_size) < 0)
282 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
284 if (_gnutls_set_datum
285 (&server_write->IV, &iv_block[IV_size], IV_size) < 0)
286 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
289 return 0;
292 static int
293 _gnutls_init_record_state (record_parameters_st * params, gnutls_protocol_t ver, int read,
294 record_state_st * state)
296 int ret;
297 gnutls_datum_t * iv = NULL;
299 if (!_gnutls_version_has_explicit_iv(ver))
301 iv = &state->IV;
304 ret = _gnutls_auth_cipher_init (&state->cipher_state,
305 params->cipher_algorithm, &state->key, iv,
306 params->mac_algorithm, &state->mac_secret, (ver==GNUTLS_SSL3)?1:0, 1-read/*1==encrypt*/);
307 if (ret < 0 && params->cipher_algorithm != GNUTLS_CIPHER_NULL)
308 return gnutls_assert_val (ret);
310 ret =
311 _gnutls_comp_init (&state->compression_state, params->compression_algorithm, read/*1==decompress*/);
313 if (ret < 0)
314 return gnutls_assert_val (ret);
316 return 0;
320 _gnutls_epoch_set_cipher_suite (gnutls_session_t session,
321 int epoch_rel, const uint8_t suite[2])
323 gnutls_cipher_algorithm_t cipher_algo;
324 gnutls_mac_algorithm_t mac_algo;
325 record_parameters_st *params;
326 int ret;
328 ret = _gnutls_epoch_get (session, epoch_rel, &params);
329 if (ret < 0)
330 return gnutls_assert_val (ret);
332 if (params->initialized
333 || params->cipher_algorithm != GNUTLS_CIPHER_UNKNOWN
334 || params->mac_algorithm != GNUTLS_MAC_UNKNOWN)
335 return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
337 cipher_algo = _gnutls_cipher_suite_get_cipher_algo (suite);
338 mac_algo = _gnutls_cipher_suite_get_mac_algo (suite);
340 if (_gnutls_cipher_is_ok (cipher_algo) != 0
341 || _gnutls_mac_is_ok (mac_algo) != 0)
342 return gnutls_assert_val (GNUTLS_E_UNWANTED_ALGORITHM);
344 params->cipher_algorithm = cipher_algo;
345 params->mac_algorithm = mac_algo;
347 return 0;
351 _gnutls_epoch_set_compression (gnutls_session_t session,
352 int epoch_rel,
353 gnutls_compression_method_t comp_algo)
355 record_parameters_st *params;
356 int ret;
358 ret = _gnutls_epoch_get (session, epoch_rel, &params);
359 if (ret < 0)
360 return gnutls_assert_val (ret);
362 if (params->initialized
363 || params->compression_algorithm != GNUTLS_COMP_UNKNOWN)
364 return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
366 if (_gnutls_compression_is_ok (comp_algo) != 0)
367 return gnutls_assert_val (GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM);
369 params->compression_algorithm = comp_algo;
371 return 0;
374 void
375 _gnutls_epoch_set_null_algos (gnutls_session_t session,
376 record_parameters_st * params)
378 /* This is only called on startup. We are extra paranoid about this
379 because it may cause unencrypted application data to go out on
380 the wire. */
381 if (params->initialized || params->epoch != 0)
383 gnutls_assert ();
384 return;
387 params->cipher_algorithm = GNUTLS_CIPHER_NULL;
388 params->mac_algorithm = GNUTLS_MAC_NULL;
389 params->compression_algorithm = GNUTLS_COMP_NULL;
390 params->initialized = 1;
394 _gnutls_epoch_set_keys (gnutls_session_t session, uint16_t epoch)
396 int hash_size;
397 int IV_size;
398 int key_size, export_flag;
399 gnutls_cipher_algorithm_t cipher_algo;
400 gnutls_mac_algorithm_t mac_algo;
401 gnutls_compression_method_t comp_algo;
402 record_parameters_st *params;
403 int ret;
404 gnutls_protocol_t ver = gnutls_protocol_get_version (session);
406 ret = _gnutls_epoch_get (session, epoch, &params);
407 if (ret < 0)
408 return gnutls_assert_val (ret);
410 if (params->initialized)
411 return 0;
413 _gnutls_record_log
414 ("REC[%p]: Initializing epoch #%u\n", session, params->epoch);
416 cipher_algo = params->cipher_algorithm;
417 mac_algo = params->mac_algorithm;
418 comp_algo = params->compression_algorithm;
420 if (_gnutls_cipher_is_ok (cipher_algo) != 0
421 || _gnutls_mac_is_ok (mac_algo) != 0)
422 return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
424 if (_gnutls_compression_is_ok (comp_algo) != 0)
425 return gnutls_assert_val (GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM);
427 IV_size = _gnutls_cipher_get_iv_size (cipher_algo);
428 key_size = gnutls_cipher_get_key_size (cipher_algo);
429 export_flag = _gnutls_cipher_get_export_flag (cipher_algo);
430 hash_size = _gnutls_hmac_get_algo_len (mac_algo);
432 ret = _gnutls_set_keys
433 (session, params, hash_size, IV_size, key_size, export_flag);
434 if (ret < 0)
435 return gnutls_assert_val (ret);
437 ret = _gnutls_init_record_state (params, ver, 1, &params->read);
438 if (ret < 0)
439 return gnutls_assert_val (ret);
441 ret = _gnutls_init_record_state (params, ver, 0, &params->write);
442 if (ret < 0)
443 return gnutls_assert_val (ret);
445 params->record_sw_size = 0;
447 _gnutls_record_log ("REC[%p]: Epoch #%u ready\n", session, params->epoch);
449 params->initialized = 1;
450 return 0;
454 #define CPY_COMMON dst->entity = src->entity; \
455 dst->kx_algorithm = src->kx_algorithm; \
456 memcpy( dst->cipher_suite, src->cipher_suite, 2); \
457 memcpy( dst->master_secret, src->master_secret, GNUTLS_MASTER_SIZE); \
458 memcpy( dst->client_random, src->client_random, GNUTLS_RANDOM_SIZE); \
459 memcpy( dst->server_random, src->server_random, GNUTLS_RANDOM_SIZE); \
460 memcpy( dst->session_id, src->session_id, TLS_MAX_SESSION_ID_SIZE); \
461 dst->session_id_size = src->session_id_size; \
462 dst->cert_type = src->cert_type; \
463 dst->compression_method = src->compression_method; \
464 dst->timestamp = src->timestamp; \
465 dst->max_record_recv_size = src->max_record_recv_size; \
466 dst->max_record_send_size = src->max_record_send_size; \
467 dst->version = src->version;
469 static void
470 _gnutls_set_resumed_parameters (gnutls_session_t session)
472 security_parameters_st *src =
473 &session->internals.resumed_security_parameters;
474 security_parameters_st *dst = &session->security_parameters;
476 CPY_COMMON;
479 /* Sets the current connection session to conform with the
480 * Security parameters(pending session), and initializes encryption.
481 * Actually it initializes and starts encryption ( so it needs
482 * secrets and random numbers to have been negotiated)
483 * This is to be called after sending the Change Cipher Spec packet.
486 _gnutls_connection_state_init (gnutls_session_t session)
488 int ret;
490 /* Setup the master secret
492 if ((ret = _gnutls_generate_master (session, 0)) < 0)
493 return gnutls_assert_val (ret);
495 return 0;
500 static int
501 _gnutls_check_algos (gnutls_session_t session,
502 const uint8_t suite[2],
503 gnutls_compression_method_t comp_algo)
505 gnutls_cipher_algorithm_t cipher_algo;
506 gnutls_mac_algorithm_t mac_algo;
508 cipher_algo = _gnutls_cipher_suite_get_cipher_algo (suite);
509 mac_algo = _gnutls_cipher_suite_get_mac_algo (suite);
511 if (_gnutls_cipher_is_ok (cipher_algo) != 0)
512 return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
514 if (_gnutls_cipher_priority (session, cipher_algo) < 0)
515 return gnutls_assert_val (GNUTLS_E_UNWANTED_ALGORITHM);
518 if (_gnutls_mac_is_ok (mac_algo) != 0)
519 return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
521 if (_gnutls_mac_priority (session, mac_algo) < 0)
522 return gnutls_assert_val (GNUTLS_E_UNWANTED_ALGORITHM);
525 if (_gnutls_compression_is_ok (comp_algo) != 0)
526 return gnutls_assert_val (GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM);
528 return 0;
531 int _gnutls_epoch_get_compression(gnutls_session_t session, int epoch)
533 record_parameters_st *params;
534 int ret;
536 ret = _gnutls_epoch_get (session, epoch, &params);
537 if (ret < 0)
538 return GNUTLS_COMP_UNKNOWN;
540 return params->compression_algorithm;
543 /* Initializes the read connection session
544 * (read encrypted data)
547 _gnutls_read_connection_state_init (gnutls_session_t session)
549 const uint16_t epoch_next = session->security_parameters.epoch_next;
550 int ret;
552 /* Update internals from CipherSuite selected.
553 * If we are resuming just copy the connection session
555 if (session->internals.resumed == RESUME_FALSE)
558 ret = _gnutls_check_algos (session,
559 session->
560 security_parameters.cipher_suite,
561 _gnutls_epoch_get_compression(session, epoch_next));
562 if (ret < 0)
563 return ret;
565 ret = _gnutls_set_kx (session,
566 _gnutls_cipher_suite_get_kx_algo
567 (session->
568 security_parameters.cipher_suite));
569 if (ret < 0)
570 return ret;
572 else if (session->security_parameters.entity == GNUTLS_CLIENT)
573 _gnutls_set_resumed_parameters (session);
575 ret = _gnutls_epoch_set_keys (session, epoch_next);
576 if (ret < 0)
577 return ret;
579 _gnutls_handshake_log ("HSK[%p]: Cipher Suite: %s\n",
580 session,
581 _gnutls_cipher_suite_get_name
582 (session->
583 security_parameters.cipher_suite));
585 session->security_parameters.epoch_read = epoch_next;
587 return 0;
592 /* Initializes the write connection session
593 * (write encrypted data)
596 _gnutls_write_connection_state_init (gnutls_session_t session)
598 const uint16_t epoch_next = session->security_parameters.epoch_next;
599 int ret;
601 /* Update internals from CipherSuite selected.
602 * If we are resuming just copy the connection session
604 if (session->internals.resumed == RESUME_FALSE)
606 ret = _gnutls_check_algos (session,
607 session->
608 security_parameters.cipher_suite,
609 _gnutls_epoch_get_compression(session, epoch_next));
610 if (ret < 0)
611 return ret;
613 ret = _gnutls_set_kx (session,
614 _gnutls_cipher_suite_get_kx_algo
615 (session->
616 security_parameters.cipher_suite));
617 if (ret < 0)
618 return ret;
620 else if (session->security_parameters.entity == GNUTLS_SERVER)
621 _gnutls_set_resumed_parameters (session);
623 ret = _gnutls_epoch_set_keys (session, epoch_next);
624 if (ret < 0)
625 return gnutls_assert_val (ret);
627 _gnutls_handshake_log ("HSK[%p]: Cipher Suite: %s\n", session,
628 _gnutls_cipher_suite_get_name
629 (session->
630 security_parameters.cipher_suite));
632 _gnutls_handshake_log
633 ("HSK[%p]: Initializing internal [write] cipher sessions\n", session);
635 session->security_parameters.epoch_write = epoch_next;
637 return 0;
640 /* Sets the specified kx algorithm into pending session
643 _gnutls_set_kx (gnutls_session_t session, gnutls_kx_algorithm_t algo)
646 if (_gnutls_kx_is_ok (algo) == 0)
648 session->security_parameters.kx_algorithm = algo;
650 else
651 return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
653 if (_gnutls_kx_priority (session, algo) < 0)
654 return gnutls_assert_val (GNUTLS_E_UNWANTED_ALGORITHM);
656 return 0;
659 static inline int
660 epoch_resolve (gnutls_session_t session,
661 unsigned int epoch_rel, uint16_t * epoch_out)
663 switch (epoch_rel)
665 case EPOCH_READ_CURRENT:
666 *epoch_out = session->security_parameters.epoch_read;
667 return 0;
669 case EPOCH_WRITE_CURRENT:
670 *epoch_out = session->security_parameters.epoch_write;
671 return 0;
673 case EPOCH_NEXT:
674 *epoch_out = session->security_parameters.epoch_next;
675 return 0;
677 default:
678 if (epoch_rel > 0xffffu)
679 return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
681 *epoch_out = epoch_rel;
682 return 0;
686 static inline record_parameters_st **
687 epoch_get_slot (gnutls_session_t session, uint16_t epoch)
689 uint16_t epoch_index = epoch - session->security_parameters.epoch_min;
691 if (epoch_index >= MAX_EPOCH_INDEX)
693 _gnutls_handshake_log("Epoch %d out of range (idx: %d, max: %d)\n", (int)epoch, (int)epoch_index, MAX_EPOCH_INDEX);
694 gnutls_assert ();
695 return NULL;
697 /* The slot may still be empty (NULL) */
698 return &session->record_parameters[epoch_index];
702 _gnutls_epoch_get (gnutls_session_t session, unsigned int epoch_rel,
703 record_parameters_st ** params_out)
705 uint16_t epoch;
706 record_parameters_st **params;
707 int ret;
709 ret = epoch_resolve (session, epoch_rel, &epoch);
710 if (ret < 0)
711 return gnutls_assert_val (ret);
713 params = epoch_get_slot (session, epoch);
714 if (params == NULL || *params == NULL)
715 return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
717 *params_out = *params;
719 return 0;
723 _gnutls_epoch_alloc (gnutls_session_t session, uint16_t epoch,
724 record_parameters_st ** out)
726 record_parameters_st **slot;
728 _gnutls_record_log ("REC[%p]: Allocating epoch #%u\n", session, epoch);
730 slot = epoch_get_slot (session, epoch);
732 /* If slot out of range or not empty. */
733 if (slot == NULL)
734 return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
736 if (*slot != NULL)
737 return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
739 *slot = gnutls_calloc (1, sizeof (record_parameters_st));
740 if (*slot == NULL)
741 return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
743 (*slot)->epoch = epoch;
744 (*slot)->cipher_algorithm = GNUTLS_CIPHER_UNKNOWN;
745 (*slot)->mac_algorithm = GNUTLS_MAC_UNKNOWN;
746 (*slot)->compression_algorithm = GNUTLS_COMP_UNKNOWN;
748 if (IS_DTLS (session))
749 _gnutls_write_uint16 (epoch, UINT64DATA((*slot)->write.sequence_number));
751 if (out != NULL)
752 *out = *slot;
754 return 0;
757 static inline int
758 epoch_is_active(gnutls_session_t session, record_parameters_st * params)
760 const security_parameters_st *sp = &session->security_parameters;
762 if (params->epoch == sp->epoch_read)
763 return 1;
765 if (params->epoch == sp->epoch_write)
766 return 1;
768 if (params->epoch == sp->epoch_next)
769 return 1;
771 return 0;
774 static inline int
775 epoch_alive (gnutls_session_t session, record_parameters_st * params)
777 if (params->usage_cnt > 0)
778 return 1;
780 return epoch_is_active(session, params);
783 void
784 _gnutls_epoch_gc (gnutls_session_t session)
786 int i, j;
787 unsigned int min_index = 0;
789 _gnutls_record_log ("REC[%p]: Start of epoch cleanup\n", session);
791 /* Free all dead cipher state */
792 for (i = 0; i < MAX_EPOCH_INDEX; i++)
794 if (session->record_parameters[i] != NULL)
796 if (!epoch_is_active(session, session->record_parameters[i]) && session->record_parameters[i]->usage_cnt)
797 _gnutls_record_log ("REC[%p]: Note inactive epoch %d has %d users\n", session, session->record_parameters[i]->epoch, session->record_parameters[i]->usage_cnt);
798 if (!epoch_alive (session, session->record_parameters[i]))
800 _gnutls_epoch_free (session, session->record_parameters[i]);
801 session->record_parameters[i] = NULL;
806 /* Look for contiguous NULLs at the start of the array */
807 for (i = 0; i < MAX_EPOCH_INDEX && session->record_parameters[i] == NULL;
808 i++);
809 min_index = i;
811 /* Pick up the slack in the epoch window. */
812 for (i = 0, j = min_index; j < MAX_EPOCH_INDEX; i++, j++)
813 session->record_parameters[i] = session->record_parameters[j];
815 /* Set the new epoch_min */
816 if (session->record_parameters[0] != NULL)
817 session->security_parameters.epoch_min =
818 session->record_parameters[0]->epoch;
820 _gnutls_record_log ("REC[%p]: End of epoch cleanup\n", session);
823 static inline void
824 free_record_state (record_state_st * state, int d)
826 _gnutls_free_datum (&state->mac_secret);
827 _gnutls_free_datum (&state->IV);
828 _gnutls_free_datum (&state->key);
830 _gnutls_auth_cipher_deinit (&state->cipher_state);
832 if (state->compression_state.handle != NULL)
833 _gnutls_comp_deinit (&state->compression_state, d);
836 void
837 _gnutls_epoch_free (gnutls_session_t session, record_parameters_st * params)
839 _gnutls_record_log ("REC[%p]: Epoch #%u freed\n", session, params->epoch);
841 free_record_state (&params->read, 1);
842 free_record_state (&params->write, 0);
844 gnutls_free (params);