removed unused constants
[gnutls:gnutls.git] / lib / gnutls_constate.c
1 /*
2  * Copyright (C) 2001-2012 Free Software Foundation, Inc.
3  *
4  * Author: Nikos Mavrogiannopoulos
5  *
6  * This file is part of GnuTLS.
7  *
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 2.1 of
11  * the License, or (at your option) any later version.
12  *
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.
17  *
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/>
20  *
21  */
22
23 /* Functions that are supposed to run after the handshake procedure is
24  * finished. These functions activate the established security parameters.
25  */
26
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>
37
38 static int
39 _gnutls_set_kx(gnutls_session_t session, gnutls_kx_algorithm_t algo);
40
41 static const char keyexp[] = "key expansion";
42 static const int keyexp_length = sizeof(keyexp) - 1;
43
44 /* This function is to be called after handshake, when master_secret,
45  *  client_random and server_random have been initialized. 
46  * This function creates the keys and stores them into pending session.
47  * (session->cipher_specs)
48  */
49 static int
50 _gnutls_set_keys(gnutls_session_t session, record_parameters_st * params,
51                  int hash_size, int IV_size, int key_size)
52 {
53         /* FIXME: This function is too long
54          */
55         uint8_t rnd[2 * GNUTLS_RANDOM_SIZE];
56         uint8_t rrnd[2 * GNUTLS_RANDOM_SIZE];
57         int pos, ret;
58         int block_size;
59         char buf[65];
60         /* avoid using malloc */
61         uint8_t key_block[2 * MAX_HASH_SIZE + 2 * MAX_CIPHER_KEY_SIZE +
62                           2 * MAX_CIPHER_BLOCK_SIZE];
63         record_state_st *client_write, *server_write;
64
65         if (session->security_parameters.entity == GNUTLS_CLIENT) {
66                 client_write = &params->write;
67                 server_write = &params->read;
68         } else {
69                 client_write = &params->read;
70                 server_write = &params->write;
71         }
72
73         block_size = 2 * hash_size + 2 * key_size;
74         block_size += 2 * IV_size;
75
76         memcpy(rnd, session->security_parameters.server_random,
77                GNUTLS_RANDOM_SIZE);
78         memcpy(&rnd[GNUTLS_RANDOM_SIZE],
79                session->security_parameters.client_random,
80                GNUTLS_RANDOM_SIZE);
81
82         memcpy(rrnd, session->security_parameters.client_random,
83                GNUTLS_RANDOM_SIZE);
84         memcpy(&rrnd[GNUTLS_RANDOM_SIZE],
85                session->security_parameters.server_random,
86                GNUTLS_RANDOM_SIZE);
87
88         if (get_num_version(session) == GNUTLS_SSL3) {  /* SSL 3 */
89                 ret =
90                     _gnutls_ssl3_generate_random
91                     (session->security_parameters.master_secret,
92                      GNUTLS_MASTER_SIZE, rnd, 2 * GNUTLS_RANDOM_SIZE,
93                      block_size, key_block);
94         } else {                /* TLS 1.0 */
95                 ret =
96                     _gnutls_PRF(session,
97                                 session->security_parameters.master_secret,
98                                 GNUTLS_MASTER_SIZE, keyexp, keyexp_length,
99                                 rnd, 2 * GNUTLS_RANDOM_SIZE, block_size,
100                                 key_block);
101         }
102
103         if (ret < 0)
104                 return gnutls_assert_val(ret);
105
106         _gnutls_hard_log("INT: KEY BLOCK[%d]: %s\n", block_size,
107                          _gnutls_bin2hex(key_block, block_size, buf,
108                                          sizeof(buf), NULL));
109
110         pos = 0;
111         if (hash_size > 0) {
112
113                 if (_gnutls_set_datum
114                     (&client_write->mac_secret, &key_block[pos],
115                      hash_size) < 0)
116                         return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
117
118                 pos += hash_size;
119
120                 if (_gnutls_set_datum
121                     (&server_write->mac_secret, &key_block[pos],
122                      hash_size) < 0)
123                         return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
124
125                 pos += hash_size;
126         }
127
128         if (key_size > 0) {
129                 uint8_t *client_write_key, *server_write_key;
130                 int client_write_key_size, server_write_key_size;
131
132                 client_write_key = &key_block[pos];
133                 client_write_key_size = key_size;
134
135                 pos += key_size;
136
137                 server_write_key = &key_block[pos];
138                 server_write_key_size = key_size;
139
140                 pos += key_size;
141
142                 if (_gnutls_set_datum
143                     (&client_write->key, client_write_key,
144                      client_write_key_size) < 0)
145                         return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
146
147                 _gnutls_hard_log("INT: CLIENT WRITE KEY [%d]: %s\n",
148                                  client_write_key_size,
149                                  _gnutls_bin2hex(client_write_key,
150                                                  client_write_key_size,
151                                                  buf, sizeof(buf), NULL));
152
153                 if (_gnutls_set_datum
154                     (&server_write->key, server_write_key,
155                      server_write_key_size) < 0)
156                         return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
157
158                 _gnutls_hard_log("INT: SERVER WRITE KEY [%d]: %s\n",
159                                  server_write_key_size,
160                                  _gnutls_bin2hex(server_write_key,
161                                                  server_write_key_size,
162                                                  buf, sizeof(buf), NULL));
163
164         }
165
166         /* IV generation in export and non export ciphers.
167          */
168         if (IV_size > 0) {
169                 if (_gnutls_set_datum
170                     (&client_write->IV, &key_block[pos], IV_size) < 0)
171                         return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
172
173                 pos += IV_size;
174
175                 if (_gnutls_set_datum
176                     (&server_write->IV, &key_block[pos], IV_size) < 0)
177                         return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
178
179         }
180
181         return 0;
182 }
183
184 static int
185 _gnutls_init_record_state(record_parameters_st * params,
186                           const version_entry_st * ver, int read,
187                           record_state_st * state)
188 {
189         int ret;
190         gnutls_datum_t *iv = NULL;
191
192         if (!_gnutls_version_has_explicit_iv(ver)) {
193                 if (_gnutls_cipher_type(params->cipher) == CIPHER_BLOCK)
194                         iv = &state->IV;
195         }
196
197         ret = _gnutls_auth_cipher_init(&state->cipher_state,
198                                        params->cipher, &state->key, iv,
199                                        params->mac, &state->mac_secret,
200                                        params->etm,
201                                        (ver->id == GNUTLS_SSL3) ? 1 : 0,
202                                        1 - read /*1==encrypt */ );
203         if (ret < 0 && params->cipher->id != GNUTLS_CIPHER_NULL)
204                 return gnutls_assert_val(ret);
205
206         ret =
207             _gnutls_comp_init(&state->compression_state,
208                               params->compression_algorithm,
209                               read /*1==decompress */ );
210
211         if (ret < 0)
212                 return gnutls_assert_val(ret);
213
214         return 0;
215 }
216
217 int
218 _gnutls_epoch_set_cipher_suite(gnutls_session_t session,
219                                int epoch_rel, const uint8_t suite[2])
220 {
221         const cipher_entry_st *cipher_algo;
222         const mac_entry_st *mac_algo;
223         record_parameters_st *params;
224         int ret;
225
226         ret = _gnutls_epoch_get(session, epoch_rel, &params);
227         if (ret < 0)
228                 return gnutls_assert_val(ret);
229
230         if (params->initialized
231             || params->cipher != NULL || params->mac != NULL)
232                 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
233
234         cipher_algo = _gnutls_cipher_suite_get_cipher_algo(suite);
235         mac_algo = _gnutls_cipher_suite_get_mac_algo(suite);
236
237         if (_gnutls_cipher_is_ok(cipher_algo) == 0
238             || _gnutls_mac_is_ok(mac_algo) == 0)
239                 return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
240
241         if (_gnutls_cipher_priority(session, cipher_algo->id) < 0)
242                 return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
243
244         if (_gnutls_mac_priority(session, mac_algo->id) < 0)
245                 return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
246
247         params->cipher = cipher_algo;
248         params->mac = mac_algo;
249
250         return 0;
251 }
252
253 int
254 _gnutls_epoch_set_compression(gnutls_session_t session,
255                               int epoch_rel,
256                               gnutls_compression_method_t comp_algo)
257 {
258         record_parameters_st *params;
259         int ret;
260
261         ret = _gnutls_epoch_get(session, epoch_rel, &params);
262         if (ret < 0)
263                 return gnutls_assert_val(ret);
264
265         if (params->initialized
266             || params->compression_algorithm != GNUTLS_COMP_UNKNOWN)
267                 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
268
269         if (_gnutls_compression_is_ok(comp_algo) != 0)
270                 return
271                     gnutls_assert_val
272                     (GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM);
273
274         params->compression_algorithm = comp_algo;
275
276         return 0;
277 }
278
279 void
280 _gnutls_epoch_set_null_algos(gnutls_session_t session,
281                              record_parameters_st * params)
282 {
283         /* This is only called on startup. We are extra paranoid about this
284            because it may cause unencrypted application data to go out on
285            the wire. */
286         if (params->initialized || params->epoch != 0) {
287                 gnutls_assert();
288                 return;
289         }
290
291         params->cipher = cipher_to_entry(GNUTLS_CIPHER_NULL);
292         params->mac = mac_to_entry(GNUTLS_MAC_NULL);
293         params->compression_algorithm = GNUTLS_COMP_NULL;
294         params->initialized = 1;
295 }
296
297 int _gnutls_epoch_set_keys(gnutls_session_t session, uint16_t epoch)
298 {
299         int hash_size;
300         int IV_size;
301         int key_size;
302         gnutls_compression_method_t comp_algo;
303         record_parameters_st *params;
304         int ret;
305         const version_entry_st *ver = get_version(session);
306
307         if (unlikely(ver == NULL))
308                 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
309
310         ret = _gnutls_epoch_get(session, epoch, &params);
311         if (ret < 0)
312                 return gnutls_assert_val(ret);
313
314         if (params->initialized)
315                 return 0;
316
317         _gnutls_record_log
318             ("REC[%p]: Initializing epoch #%u\n", session, params->epoch);
319
320         comp_algo = params->compression_algorithm;
321
322         if (_gnutls_cipher_is_ok(params->cipher) == 0
323             || _gnutls_mac_is_ok(params->mac) == 0)
324                 return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
325
326         if (_gnutls_cipher_priority(session, params->cipher->id) < 0)
327                 return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
328
329         if (_gnutls_mac_priority(session, params->mac->id) < 0)
330                 return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
331
332         if (_gnutls_compression_is_ok(comp_algo) != 0)
333                 return
334                     gnutls_assert_val
335                     (GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM);
336
337         if (!_gnutls_version_has_explicit_iv(ver) &&
338             _gnutls_cipher_type(params->cipher) == CIPHER_BLOCK) {
339                 IV_size = _gnutls_cipher_get_iv_size(params->cipher);
340         } else {
341                 IV_size = _gnutls_cipher_get_implicit_iv_size(params->cipher);
342         }
343
344         key_size = _gnutls_cipher_get_key_size(params->cipher);
345         hash_size = _gnutls_mac_get_key_size(params->mac);
346         params->etm = session->security_parameters.etm;
347
348         ret = _gnutls_set_keys
349             (session, params, hash_size, IV_size, key_size);
350         if (ret < 0)
351                 return gnutls_assert_val(ret);
352
353         ret = _gnutls_init_record_state(params, ver, 1, &params->read);
354         if (ret < 0)
355                 return gnutls_assert_val(ret);
356
357         ret = _gnutls_init_record_state(params, ver, 0, &params->write);
358         if (ret < 0)
359                 return gnutls_assert_val(ret);
360
361         params->record_sw_size = 0;
362
363         _gnutls_record_log("REC[%p]: Epoch #%u ready\n", session,
364                            params->epoch);
365
366         params->initialized = 1;
367         return 0;
368 }
369
370
371 #define CPY_COMMON dst->entity = src->entity; \
372         dst->kx_algorithm = src->kx_algorithm; \
373         memcpy( dst->cipher_suite, src->cipher_suite, 2); \
374         memcpy( dst->master_secret, src->master_secret, GNUTLS_MASTER_SIZE); \
375         memcpy( dst->client_random, src->client_random, GNUTLS_RANDOM_SIZE); \
376         memcpy( dst->server_random, src->server_random, GNUTLS_RANDOM_SIZE); \
377         memcpy( dst->session_id, src->session_id, GNUTLS_MAX_SESSION_ID_SIZE); \
378         dst->session_id_size = src->session_id_size; \
379         dst->cert_type = src->cert_type; \
380         dst->compression_method = src->compression_method; \
381         dst->timestamp = src->timestamp; \
382         dst->ext_master_secret = src->ext_master_secret; \
383         dst->etm = src->etm; \
384         dst->max_record_recv_size = src->max_record_recv_size; \
385         dst->max_record_send_size = src->max_record_send_size
386
387 static void _gnutls_set_resumed_parameters(gnutls_session_t session)
388 {
389         security_parameters_st *src =
390             &session->internals.resumed_security_parameters;
391         security_parameters_st *dst = &session->security_parameters;
392
393         CPY_COMMON;
394         dst->pversion = src->pversion;
395 }
396
397 /* Sets the current connection session to conform with the
398  * Security parameters(pending session), and initializes encryption.
399  * Actually it initializes and starts encryption ( so it needs
400  * secrets and random numbers to have been negotiated)
401  * This is to be called after sending the Change Cipher Spec packet.
402  */
403 int _gnutls_connection_state_init(gnutls_session_t session)
404 {
405         int ret;
406
407 /* Setup the master secret 
408  */
409         if ((ret = _gnutls_generate_master(session, 0)) < 0)
410                 return gnutls_assert_val(ret);
411
412         return 0;
413 }
414
415 int _gnutls_epoch_get_compression(gnutls_session_t session, int epoch)
416 {
417         record_parameters_st *params;
418         int ret;
419
420         ret = _gnutls_epoch_get(session, epoch, &params);
421         if (ret < 0)
422                 return GNUTLS_COMP_UNKNOWN;
423
424         return params->compression_algorithm;
425 }
426
427 /* Initializes the read connection session
428  * (read encrypted data)
429  */
430 int _gnutls_read_connection_state_init(gnutls_session_t session)
431 {
432         const uint16_t epoch_next =
433             session->security_parameters.epoch_next;
434         int ret;
435
436         /* Update internals from CipherSuite selected.
437          * If we are resuming just copy the connection session
438          */
439         if (session->internals.resumed == RESUME_FALSE) {
440                 ret = _gnutls_set_kx(session,
441                                      _gnutls_cipher_suite_get_kx_algo
442                                      (session->security_parameters.
443                                       cipher_suite));
444                 if (ret < 0)
445                         return ret;
446         } else if (session->security_parameters.entity == GNUTLS_CLIENT)
447                 _gnutls_set_resumed_parameters(session);
448
449         ret = _gnutls_epoch_set_keys(session, epoch_next);
450         if (ret < 0)
451                 return ret;
452
453         _gnutls_handshake_log("HSK[%p]: Cipher Suite: %s\n",
454                               session,
455                               _gnutls_cipher_suite_get_name
456                               (session->security_parameters.cipher_suite));
457
458         session->security_parameters.epoch_read = epoch_next;
459
460         return 0;
461 }
462
463
464
465 /* Initializes the write connection session
466  * (write encrypted data)
467  */
468 int _gnutls_write_connection_state_init(gnutls_session_t session)
469 {
470         const uint16_t epoch_next =
471             session->security_parameters.epoch_next;
472         int ret;
473
474 /* Update internals from CipherSuite selected.
475  * If we are resuming just copy the connection session
476  */
477         if (session->internals.resumed == RESUME_FALSE) {
478                 ret = _gnutls_set_kx(session,
479                                      _gnutls_cipher_suite_get_kx_algo
480                                      (session->security_parameters.
481                                       cipher_suite));
482                 if (ret < 0)
483                         return ret;
484         } else if (session->security_parameters.entity == GNUTLS_SERVER)
485                 _gnutls_set_resumed_parameters(session);
486
487         ret = _gnutls_epoch_set_keys(session, epoch_next);
488         if (ret < 0)
489                 return gnutls_assert_val(ret);
490
491         _gnutls_handshake_log("HSK[%p]: Cipher Suite: %s\n", session,
492                               _gnutls_cipher_suite_get_name
493                               (session->security_parameters.cipher_suite));
494
495         _gnutls_handshake_log
496             ("HSK[%p]: Initializing internal [write] cipher sessions\n",
497              session);
498
499         session->security_parameters.epoch_write = epoch_next;
500
501         return 0;
502 }
503
504 /* Sets the specified kx algorithm into pending session
505  */
506 static int
507 _gnutls_set_kx(gnutls_session_t session, gnutls_kx_algorithm_t algo)
508 {
509
510         if (_gnutls_kx_is_ok(algo) == 0) {
511                 session->security_parameters.kx_algorithm = algo;
512         } else
513                 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
514
515         if (_gnutls_kx_priority(session, algo) < 0)
516                 return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
517
518         return 0;
519 }
520
521 static inline int
522 epoch_resolve(gnutls_session_t session,
523               unsigned int epoch_rel, uint16_t * epoch_out)
524 {
525         switch (epoch_rel) {
526         case EPOCH_READ_CURRENT:
527                 *epoch_out = session->security_parameters.epoch_read;
528                 return 0;
529
530         case EPOCH_WRITE_CURRENT:
531                 *epoch_out = session->security_parameters.epoch_write;
532                 return 0;
533
534         case EPOCH_NEXT:
535                 *epoch_out = session->security_parameters.epoch_next;
536                 return 0;
537
538         default:
539                 if (epoch_rel > 0xffffu)
540                         return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
541
542                 *epoch_out = epoch_rel;
543                 return 0;
544         }
545 }
546
547 static inline record_parameters_st **epoch_get_slot(gnutls_session_t
548                                                     session,
549                                                     uint16_t epoch)
550 {
551         uint16_t epoch_index =
552             epoch - session->security_parameters.epoch_min;
553
554         if (epoch_index >= MAX_EPOCH_INDEX) {
555                 _gnutls_handshake_log
556                     ("Epoch %d out of range (idx: %d, max: %d)\n",
557                      (int) epoch, (int) epoch_index, MAX_EPOCH_INDEX);
558                 gnutls_assert();
559                 return NULL;
560         }
561         /* The slot may still be empty (NULL) */
562         return &session->record_parameters[epoch_index];
563 }
564
565 int
566 _gnutls_epoch_get(gnutls_session_t session, unsigned int epoch_rel,
567                   record_parameters_st ** params_out)
568 {
569         uint16_t epoch;
570         record_parameters_st **params;
571         int ret;
572
573         ret = epoch_resolve(session, epoch_rel, &epoch);
574         if (ret < 0)
575                 return gnutls_assert_val(ret);
576
577         params = epoch_get_slot(session, epoch);
578         if (params == NULL || *params == NULL)
579                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
580
581         *params_out = *params;
582
583         return 0;
584 }
585
586 int
587 _gnutls_epoch_alloc(gnutls_session_t session, uint16_t epoch,
588                     record_parameters_st ** out)
589 {
590         record_parameters_st **slot;
591
592         _gnutls_record_log("REC[%p]: Allocating epoch #%u\n", session,
593                            epoch);
594
595         slot = epoch_get_slot(session, epoch);
596
597         /* If slot out of range or not empty. */
598         if (slot == NULL)
599                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
600
601         if (*slot != NULL)
602                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
603
604         *slot = gnutls_calloc(1, sizeof(record_parameters_st));
605         if (*slot == NULL)
606                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
607
608         (*slot)->epoch = epoch;
609         (*slot)->cipher = NULL;
610         (*slot)->mac = NULL;
611         (*slot)->compression_algorithm = GNUTLS_COMP_UNKNOWN;
612
613         if (IS_DTLS(session))
614                 _gnutls_write_uint16(epoch,
615                                      UINT64DATA((*slot)->write.
616                                                 sequence_number));
617
618         if (out != NULL)
619                 *out = *slot;
620
621         return 0;
622 }
623
624 static inline int
625 epoch_is_active(gnutls_session_t session, record_parameters_st * params)
626 {
627         const security_parameters_st *sp = &session->security_parameters;
628
629         if (params->epoch == sp->epoch_read)
630                 return 1;
631
632         if (params->epoch == sp->epoch_write)
633                 return 1;
634
635         if (params->epoch == sp->epoch_next)
636                 return 1;
637
638         return 0;
639 }
640
641 static inline int
642 epoch_alive(gnutls_session_t session, record_parameters_st * params)
643 {
644         if (params->usage_cnt > 0)
645                 return 1;
646
647         return epoch_is_active(session, params);
648 }
649
650 void _gnutls_epoch_gc(gnutls_session_t session)
651 {
652         int i, j;
653         unsigned int min_index = 0;
654
655         _gnutls_record_log("REC[%p]: Start of epoch cleanup\n", session);
656
657         /* Free all dead cipher state */
658         for (i = 0; i < MAX_EPOCH_INDEX; i++) {
659                 if (session->record_parameters[i] != NULL) {
660                         if (!epoch_is_active
661                             (session, session->record_parameters[i])
662                             && session->record_parameters[i]->usage_cnt)
663                                 _gnutls_record_log
664                                     ("REC[%p]: Note inactive epoch %d has %d users\n",
665                                      session,
666                                      session->record_parameters[i]->epoch,
667                                      session->record_parameters[i]->
668                                      usage_cnt);
669                         if (!epoch_alive
670                             (session, session->record_parameters[i])) {
671                                 _gnutls_epoch_free(session,
672                                                    session->
673                                                    record_parameters[i]);
674                                 session->record_parameters[i] = NULL;
675                         }
676                 }
677         }
678
679         /* Look for contiguous NULLs at the start of the array */
680         for (i = 0;
681              i < MAX_EPOCH_INDEX && session->record_parameters[i] == NULL;
682              i++);
683         min_index = i;
684
685         /* Pick up the slack in the epoch window. */
686         for (i = 0, j = min_index; j < MAX_EPOCH_INDEX; i++, j++)
687                 session->record_parameters[i] =
688                     session->record_parameters[j];
689
690         /* Set the new epoch_min */
691         if (session->record_parameters[0] != NULL)
692                 session->security_parameters.epoch_min =
693                     session->record_parameters[0]->epoch;
694
695         _gnutls_record_log("REC[%p]: End of epoch cleanup\n", session);
696 }
697
698 static inline void free_record_state(record_state_st * state, int d)
699 {
700         _gnutls_free_datum(&state->mac_secret);
701         _gnutls_free_datum(&state->IV);
702         _gnutls_free_datum(&state->key);
703
704         _gnutls_auth_cipher_deinit(&state->cipher_state);
705
706         if (state->compression_state.handle != NULL)
707                 _gnutls_comp_deinit(&state->compression_state, d);
708 }
709
710 void
711 _gnutls_epoch_free(gnutls_session_t session, record_parameters_st * params)
712 {
713         _gnutls_record_log("REC[%p]: Epoch #%u freed\n", session,
714                            params->epoch);
715
716         free_record_state(&params->read, 1);
717         free_record_state(&params->write, 0);
718
719         gnutls_free(params);
720 }