1 /*
2 * Copyright (C) 2009-2018 Free Software Foundation, Inc.
3 *
4 * Author: Daiki Ueno, Ander Juaristi
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 <https://www.gnu.org/licenses/>
20 *
21 */
22
23 #include "gnutls_int.h"
24 #include "errors.h"
25 #include <datum.h>
26 #include <algorithms.h>
27 #include <handshake.h>
28 #include <num.h>
29 #include <constate.h>
30 #include <session_pack.h>
31 #include <random.h>
32 #include <ext/session_ticket.h>
33 #include <mbuffers.h>
34 #include <hello_ext.h>
35 #include <constate.h>
36 #include <dtls.h>
37 #include "stek.h"
38 #include "db.h"
39
40 static int session_ticket_recv_params(gnutls_session_t session,
41 const uint8_t * data,
42 size_t data_size);
43 static int session_ticket_send_params(gnutls_session_t session,
44 gnutls_buffer_st * extdata);
45 static int session_ticket_unpack(gnutls_buffer_st * ps,
46 gnutls_ext_priv_data_t * _priv);
47 static int session_ticket_pack(gnutls_ext_priv_data_t _priv,
48 gnutls_buffer_st * ps);
49 static void session_ticket_deinit_data(gnutls_ext_priv_data_t priv);
50
51 const hello_ext_entry_st ext_mod_session_ticket = {
52 .name = "Session Ticket",
53 .tls_id = 35,
54 .gid = GNUTLS_EXTENSION_SESSION_TICKET,
55 .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
56 GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
57 /* This extension must be parsed on session resumption as well; see
58 * https://gitlab.com/gnutls/gnutls/issues/841 */
59 .client_parse_point = GNUTLS_EXT_MANDATORY,
60 /* on server side we want this parsed after normal handshake resumption
61 * actions are complete */
62 .server_parse_point = GNUTLS_EXT_TLS,
63 .recv_func = session_ticket_recv_params,
64 .send_func = session_ticket_send_params,
65 .pack_func = session_ticket_pack,
66 .unpack_func = session_ticket_unpack,
67 .deinit_func = session_ticket_deinit_data,
68 .cannot_be_overriden = 1
69 };
70
71 typedef struct {
72 uint8_t *session_ticket;
73 int session_ticket_len;
74 } session_ticket_ext_st;
75
76 static void
deinit_ticket(struct ticket_st * ticket)77 deinit_ticket(struct ticket_st *ticket)
78 {
79 free(ticket->encrypted_state);
80 }
81
82 static int
unpack_ticket(const gnutls_datum_t * ticket_data,struct ticket_st * ticket)83 unpack_ticket(const gnutls_datum_t *ticket_data, struct ticket_st *ticket)
84 {
85 const uint8_t * data = ticket_data->data;
86 size_t data_size = ticket_data->size;
87 const uint8_t *encrypted_state;
88
89 /* Format:
90 * Key name
91 * IV
92 * data length
93 * encrypted data
94 * MAC
95 */
96 DECR_LEN(data_size, TICKET_KEY_NAME_SIZE);
97 memcpy(ticket->key_name, data, TICKET_KEY_NAME_SIZE);
98 data += TICKET_KEY_NAME_SIZE;
99
100 DECR_LEN(data_size, TICKET_IV_SIZE);
101 memcpy(ticket->IV, data, TICKET_IV_SIZE);
102 data += TICKET_IV_SIZE;
103
104 DECR_LEN(data_size, 2);
105 ticket->encrypted_state_len = _gnutls_read_uint16(data);
106 data += 2;
107
108 encrypted_state = data;
109
110 DECR_LEN(data_size, ticket->encrypted_state_len);
111 data += ticket->encrypted_state_len;
112
113 DECR_LEN(data_size, TICKET_MAC_SIZE);
114 memcpy(ticket->mac, data, TICKET_MAC_SIZE);
115
116 ticket->encrypted_state =
117 gnutls_malloc(ticket->encrypted_state_len);
118 if (!ticket->encrypted_state) {
119 gnutls_assert();
120 return GNUTLS_E_MEMORY_ERROR;
121 }
122 memcpy(ticket->encrypted_state, encrypted_state,
123 ticket->encrypted_state_len);
124
125 return 0;
126 }
127
128 static void
pack_ticket(const struct ticket_st * ticket,gnutls_datum_t * ticket_data)129 pack_ticket(const struct ticket_st *ticket, gnutls_datum_t *ticket_data)
130 {
131 uint8_t *p;
132
133 p = ticket_data->data;
134
135 memcpy(p, ticket->key_name, TICKET_KEY_NAME_SIZE);
136 p += TICKET_KEY_NAME_SIZE;
137
138 memcpy(p, ticket->IV, TICKET_IV_SIZE);
139 p += TICKET_IV_SIZE;
140
141 _gnutls_write_uint16(ticket->encrypted_state_len, p);
142 p += 2;
143
144 /* We use memmove instead of memcpy here because
145 * ticket->encrypted_state is allocated from
146 * ticket_data->data, and thus both memory areas may overlap.
147 */
148 memmove(p, ticket->encrypted_state, ticket->encrypted_state_len);
149 p += ticket->encrypted_state_len;
150
151 memcpy(p, ticket->mac, TICKET_MAC_SIZE);
152 }
153
154 static
digest_ticket(const gnutls_datum_t * key,struct ticket_st * ticket,uint8_t * digest)155 int digest_ticket(const gnutls_datum_t * key, struct ticket_st *ticket,
156 uint8_t * digest)
157 {
158 mac_hd_st digest_hd;
159 uint16_t length16;
160 int ret;
161
162 ret = _gnutls_mac_init(&digest_hd, mac_to_entry(TICKET_MAC_ALGO),
163 key->data, key->size);
164 if (ret < 0) {
165 gnutls_assert();
166 return ret;
167 }
168
169 _gnutls_mac(&digest_hd, ticket->key_name, TICKET_KEY_NAME_SIZE);
170 _gnutls_mac(&digest_hd, ticket->IV, TICKET_IV_SIZE);
171 length16 = _gnutls_conv_uint16(ticket->encrypted_state_len);
172 _gnutls_mac(&digest_hd, &length16, 2);
173 _gnutls_mac(&digest_hd, ticket->encrypted_state,
174 ticket->encrypted_state_len);
175 _gnutls_mac_deinit(&digest_hd, digest);
176
177 return 0;
178 }
179
180 int
_gnutls_decrypt_session_ticket(gnutls_session_t session,const gnutls_datum_t * ticket_data,gnutls_datum_t * state)181 _gnutls_decrypt_session_ticket(gnutls_session_t session,
182 const gnutls_datum_t *ticket_data,
183 gnutls_datum_t *state)
184 {
185 cipher_hd_st cipher_hd;
186 gnutls_datum_t IV;
187 gnutls_datum_t stek_key_name, stek_cipher_key, stek_mac_key;
188 uint8_t cmac[TICKET_MAC_SIZE];
189 struct ticket_st ticket;
190 int ret;
191
192 /* callers must have that checked */
193 assert(!(session->internals.flags & GNUTLS_NO_TICKETS));
194
195 /* Retrieve ticket decryption keys */
196 if (_gnutls_get_session_ticket_decryption_key(session,
197 ticket_data,
198 &stek_key_name,
199 &stek_mac_key,
200 &stek_cipher_key) < 0)
201 return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
202
203 ret = unpack_ticket(ticket_data, &ticket);
204 if (ret < 0)
205 return ret;
206
207 /* If the key name of the ticket does not match the one that is currently active,
208 issue a new ticket. */
209 if (memcmp
210 (ticket.key_name, stek_key_name.data,
211 stek_key_name.size)) {
212 ret = GNUTLS_E_DECRYPTION_FAILED;
213 goto cleanup;
214 }
215
216 /* Check the integrity of ticket */
217 ret = digest_ticket(&stek_mac_key, &ticket, cmac);
218 if (ret < 0) {
219 gnutls_assert();
220 goto cleanup;
221 }
222
223 if (memcmp(ticket.mac, cmac, TICKET_MAC_SIZE)) {
224 ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
225 goto cleanup;
226 }
227
228 if (ticket.encrypted_state_len % TICKET_BLOCK_SIZE != 0) {
229 ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
230 goto cleanup;
231 }
232
233 /* Decrypt encrypted_state */
234 IV.data = ticket.IV;
235 IV.size = TICKET_IV_SIZE;
236 ret =
237 _gnutls_cipher_init(&cipher_hd,
238 cipher_to_entry(TICKET_CIPHER),
239 &stek_cipher_key, &IV, 0);
240 if (ret < 0) {
241 gnutls_assert();
242 goto cleanup;
243 }
244
245 ret = _gnutls_cipher_decrypt(&cipher_hd, ticket.encrypted_state,
246 ticket.encrypted_state_len);
247 if (ret < 0) {
248 gnutls_assert();
249 goto cleanup2;
250 }
251
252 state->data = ticket.encrypted_state;
253 state->size = ticket.encrypted_state_len;
254
255 ticket.encrypted_state = NULL;
256
257 ret = 0;
258
259 cleanup2:
260 _gnutls_cipher_deinit(&cipher_hd);
261
262 cleanup:
263 deinit_ticket(&ticket);
264
265 return ret;
266
267 }
268
269 int
_gnutls_encrypt_session_ticket(gnutls_session_t session,const gnutls_datum_t * state,gnutls_datum_t * ticket_data)270 _gnutls_encrypt_session_ticket(gnutls_session_t session,
271 const gnutls_datum_t *state,
272 gnutls_datum_t *ticket_data)
273 {
274 cipher_hd_st cipher_hd;
275 gnutls_datum_t IV;
276 gnutls_datum_t encrypted_state = {NULL,0};
277 uint8_t iv[TICKET_IV_SIZE];
278 gnutls_datum_t stek_cipher_key, stek_mac_key, stek_key_name;
279 struct ticket_st ticket;
280 int ret;
281
282 encrypted_state.size = ((state->size + TICKET_BLOCK_SIZE - 1) / TICKET_BLOCK_SIZE) * TICKET_BLOCK_SIZE;
283 ticket_data->size = TICKET_KEY_NAME_SIZE + TICKET_IV_SIZE + 2 +
284 encrypted_state.size + TICKET_MAC_SIZE;
285 ticket_data->data = gnutls_calloc(1, ticket_data->size);
286 if (!ticket_data->data) {
287 gnutls_assert();
288 ret = GNUTLS_E_MEMORY_ERROR;
289 goto cleanup;
290 }
291 encrypted_state.data = ticket_data->data + TICKET_KEY_NAME_SIZE + TICKET_IV_SIZE + 2;
292 memcpy(encrypted_state.data, state->data, state->size);
293
294 /* Retrieve ticket encryption keys */
295 if (_gnutls_get_session_ticket_encryption_key(session,
296 &stek_key_name,
297 &stek_mac_key,
298 &stek_cipher_key) < 0) {
299 ret = GNUTLS_E_ENCRYPTION_FAILED;
300 goto cleanup;
301 }
302
303 /* Encrypt state */
304 IV.data = iv;
305 IV.size = TICKET_IV_SIZE;
306
307 ret = gnutls_rnd(GNUTLS_RND_NONCE, iv, TICKET_IV_SIZE);
308 if (ret < 0) {
309 gnutls_assert();
310 goto cleanup;
311 }
312
313 ret =
314 _gnutls_cipher_init(&cipher_hd,
315 cipher_to_entry(TICKET_CIPHER),
316 &stek_cipher_key, &IV, 1);
317 if (ret < 0) {
318 gnutls_assert();
319 goto cleanup;
320 }
321
322 ret = _gnutls_cipher_encrypt(&cipher_hd, encrypted_state.data,
323 encrypted_state.size);
324 if (ret < 0) {
325 gnutls_assert();
326 goto cleanup2;
327 }
328
329
330 /* Fill the ticket structure to compute MAC. */
331 memcpy(ticket.key_name, stek_key_name.data, stek_key_name.size);
332 memcpy(ticket.IV, IV.data, IV.size);
333 ticket.encrypted_state_len = encrypted_state.size;
334 ticket.encrypted_state = encrypted_state.data;
335
336 ret = digest_ticket(&stek_mac_key, &ticket, ticket.mac);
337 if (ret < 0) {
338 gnutls_assert();
339 goto cleanup2;
340 }
341
342 encrypted_state.data = NULL;
343
344 pack_ticket(&ticket, ticket_data);
345
346 ret = 0;
347
348 cleanup2:
349 _gnutls_cipher_deinit(&cipher_hd);
350
351 cleanup:
352 _gnutls_free_datum(&encrypted_state);
353
354 return ret;
355 }
356
357 static int
unpack_session(gnutls_session_t session,const gnutls_datum_t * state)358 unpack_session(gnutls_session_t session, const gnutls_datum_t *state)
359 {
360 int ret;
361
362 if (unlikely(!state))
363 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
364
365 ret = _gnutls_session_unpack(session, state);
366 if (ret < 0)
367 return gnutls_assert_val(ret);
368
369 ret = _gnutls_check_resumed_params(session);
370 if (ret < 0)
371 return gnutls_assert_val(ret);
372
373 session->internals.resumed = RESUME_TRUE;
374 return 0;
375 }
376
377 static int
session_ticket_recv_params(gnutls_session_t session,const uint8_t * data,size_t data_size)378 session_ticket_recv_params(gnutls_session_t session,
379 const uint8_t * data, size_t data_size)
380 {
381 gnutls_datum_t ticket_data;
382 gnutls_datum_t state;
383 int ret;
384
385 if (session->internals.flags & GNUTLS_NO_TICKETS)
386 return 0;
387
388 if (session->security_parameters.entity == GNUTLS_SERVER) {
389 /* The client requested a new session ticket. */
390 if (data_size == 0) {
391 session->internals.session_ticket_renew = 1;
392 return 0;
393 }
394
395 ticket_data.data = (void *)data;
396 ticket_data.size = data_size;
397 if ((ret = _gnutls_decrypt_session_ticket(session, &ticket_data, &state)) == 0) {
398 ret = unpack_session(session, &state);
399
400 _gnutls_free_datum(&state);
401 }
402
403 if (ret < 0) {
404 session->internals.session_ticket_renew = 1;
405 return 0;
406 }
407 } else { /* Client */
408
409 if (data_size == 0) {
410 session->internals.session_ticket_renew = 1;
411 return 0;
412 }
413 }
414
415 return 0;
416 }
417
418 /* returns a positive number if we send the extension data, (0) if we
419 do not want to send it, and a negative number on failure.
420 */
421 static int
session_ticket_send_params(gnutls_session_t session,gnutls_buffer_st * extdata)422 session_ticket_send_params(gnutls_session_t session,
423 gnutls_buffer_st * extdata)
424 {
425 session_ticket_ext_st *priv = NULL;
426 gnutls_ext_priv_data_t epriv;
427 int ret;
428
429 if (session->internals.flags & GNUTLS_NO_TICKETS)
430 return 0;
431
432 if (session->security_parameters.entity == GNUTLS_SERVER) {
433 if (session->internals.session_ticket_renew) {
434 return GNUTLS_E_INT_RET_0;
435 }
436 } else {
437 ret =
438 _gnutls_hello_ext_get_resumed_priv(session,
439 GNUTLS_EXTENSION_SESSION_TICKET,
440 &epriv);
441 if (ret >= 0)
442 priv = epriv;
443
444 /* no previous data. Just advertise it */
445 if (ret < 0)
446 return GNUTLS_E_INT_RET_0;
447
448 /* previous data had session tickets disabled. Don't advertise. Ignore. */
449 if (session->internals.flags & GNUTLS_NO_TICKETS)
450 return 0;
451
452 if (priv->session_ticket_len > 0) {
453 ret =
454 _gnutls_buffer_append_data(extdata,
455 priv->
456 session_ticket,
457 priv->
458 session_ticket_len);
459 if (ret < 0)
460 return gnutls_assert_val(ret);
461
462 return priv->session_ticket_len;
463 }
464 }
465 return 0;
466 }
467
468
session_ticket_deinit_data(gnutls_ext_priv_data_t epriv)469 static void session_ticket_deinit_data(gnutls_ext_priv_data_t epriv)
470 {
471 session_ticket_ext_st *priv = epriv;
472
473 gnutls_free(priv->session_ticket);
474 gnutls_free(priv);
475 }
476
477 static int
session_ticket_pack(gnutls_ext_priv_data_t epriv,gnutls_buffer_st * ps)478 session_ticket_pack(gnutls_ext_priv_data_t epriv, gnutls_buffer_st * ps)
479 {
480 session_ticket_ext_st *priv = epriv;
481 int ret;
482
483 BUFFER_APPEND_PFX4(ps, priv->session_ticket,
484 priv->session_ticket_len);
485
486 return 0;
487 }
488
489 static int
session_ticket_unpack(gnutls_buffer_st * ps,gnutls_ext_priv_data_t * _priv)490 session_ticket_unpack(gnutls_buffer_st * ps, gnutls_ext_priv_data_t * _priv)
491 {
492 session_ticket_ext_st *priv = NULL;
493 int ret;
494 gnutls_ext_priv_data_t epriv;
495 gnutls_datum_t ticket;
496
497 priv = gnutls_calloc(1, sizeof(*priv));
498 if (priv == NULL) {
499 gnutls_assert();
500 return GNUTLS_E_MEMORY_ERROR;
501 }
502
503 BUFFER_POP_DATUM(ps, &ticket);
504 priv->session_ticket = ticket.data;
505 priv->session_ticket_len = ticket.size;
506
507 epriv = priv;
508 *_priv = epriv;
509
510 return 0;
511
512 error:
513 gnutls_free(priv);
514 return ret;
515 }
516
517
518
519 /**
520 * gnutls_session_ticket_key_generate:
521 * @key: is a pointer to a #gnutls_datum_t which will contain a newly
522 * created key.
523 *
524 * Generate a random key to encrypt security parameters within
525 * SessionTicket.
526 *
527 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
528 * error code.
529 *
530 * Since: 2.10.0
531 **/
gnutls_session_ticket_key_generate(gnutls_datum_t * key)532 int gnutls_session_ticket_key_generate(gnutls_datum_t * key)
533 {
534 if (_gnutls_fips_mode_enabled()) {
535 int ret;
536 /* in FIPS140-2 mode gnutls_key_generate imposes
537 * some limits on allowed key size, thus it is not
538 * used. These limits do not affect this function as
539 * it does not generate a "key" but rather key material
540 * that includes nonces and other stuff. */
541 key->data = gnutls_malloc(TICKET_MASTER_KEY_SIZE);
542 if (key->data == NULL)
543 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
544
545 key->size = TICKET_MASTER_KEY_SIZE;
546 ret = gnutls_rnd(GNUTLS_RND_RANDOM, key->data, key->size);
547 if (ret < 0) {
548 gnutls_free(key->data);
549 return ret;
550 }
551 return 0;
552 } else {
553 return gnutls_key_generate(key, TICKET_MASTER_KEY_SIZE);
554 }
555 }
556
557 /**
558 * gnutls_session_ticket_enable_client:
559 * @session: is a #gnutls_session_t type.
560 *
561 * Request that the client should attempt session resumption using
562 * SessionTicket. This call is typically unnecessary as session
563 * tickets are enabled by default.
564 *
565 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
566 * error code.
567 *
568 * Since: 2.10.0
569 **/
gnutls_session_ticket_enable_client(gnutls_session_t session)570 int gnutls_session_ticket_enable_client(gnutls_session_t session)
571 {
572 if (!session) {
573 gnutls_assert();
574 return GNUTLS_E_INVALID_REQUEST;
575 }
576
577 session->internals.flags &= ~GNUTLS_NO_TICKETS;
578
579 return 0;
580 }
581
582 /**
583 * gnutls_session_ticket_enable_server:
584 * @session: is a #gnutls_session_t type.
585 * @key: key to encrypt session parameters.
586 *
587 * Request that the server should attempt session resumption using
588 * session tickets, i.e., by delegating storage to the client.
589 * @key must be initialized using gnutls_session_ticket_key_generate().
590 * To avoid leaking that key, use gnutls_memset() prior to
591 * releasing it.
592 *
593 * The default ticket expiration time can be overridden using
594 * gnutls_db_set_cache_expiration().
595 *
596 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
597 * error code.
598 *
599 * Since: 2.10.0
600 **/
601 int
gnutls_session_ticket_enable_server(gnutls_session_t session,const gnutls_datum_t * key)602 gnutls_session_ticket_enable_server(gnutls_session_t session,
603 const gnutls_datum_t * key)
604 {
605 int ret;
606
607 if (!session || !key || key->size != TICKET_MASTER_KEY_SIZE || !key->data) {
608 gnutls_assert();
609 return GNUTLS_E_INVALID_REQUEST;
610 }
611
612 ret = _gnutls_initialize_session_ticket_key_rotation(session, key);
613 if (ret < 0)
614 return gnutls_assert_val(ret);
615
616 session->internals.flags &= ~GNUTLS_NO_TICKETS;
617
618 return 0;
619 }
620
621 /*
622 * Return zero if session tickets haven't been enabled.
623 */
_gnutls_send_new_session_ticket(gnutls_session_t session,int again)624 int _gnutls_send_new_session_ticket(gnutls_session_t session, int again)
625 {
626 mbuffer_st *bufel = NULL;
627 uint8_t *data = NULL, *p;
628 int data_size = 0;
629 int ret;
630 gnutls_datum_t state = { NULL, 0 };
631 uint16_t epoch_saved = session->security_parameters.epoch_write;
632 gnutls_datum_t ticket_data;
633
634 if (again == 0) {
635 if (session->internals.flags & GNUTLS_NO_TICKETS)
636 return 0;
637 if (!session->internals.session_ticket_renew)
638 return 0;
639
640 _gnutls_handshake_log
641 ("HSK[%p]: sending session ticket\n", session);
642
643 /* XXX: Temporarily set write algorithms to be used.
644 _gnutls_write_connection_state_init() does this job, but it also
645 triggers encryption, while NewSessionTicket should not be
646 encrypted in the record layer. */
647 ret =
648 _gnutls_epoch_set_keys(session,
649 session->security_parameters.
650 epoch_next, 0);
651 if (ret < 0) {
652 gnutls_assert();
653 return ret;
654 }
655
656 /* Under TLS1.2 with session tickets, the session ID is used for different
657 * purposes than the TLS1.0 session ID. Ensure that there is an internally
658 * set value which the server will see on the original and resumed sessions */
659 if (session->internals.resumed != RESUME_TRUE) {
660 ret = _gnutls_generate_session_id(session->security_parameters.
661 session_id,
662 &session->security_parameters.
663 session_id_size);
664 if (ret < 0) {
665 gnutls_assert();
666 return ret;
667 }
668 }
669
670 session->security_parameters.epoch_write =
671 session->security_parameters.epoch_next;
672
673 /* Pack security parameters. */
674 ret = _gnutls_session_pack(session, &state);
675 if (ret < 0) {
676 gnutls_assert();
677 return ret;
678 }
679
680 /* Generate an encrypted ticket */
681 ret = _gnutls_encrypt_session_ticket(session, &state, &ticket_data);
682 session->security_parameters.epoch_write = epoch_saved;
683 _gnutls_free_datum(&state);
684 if (ret < 0) {
685 gnutls_assert();
686 return ret;
687 }
688
689 bufel =
690 _gnutls_handshake_alloc(session,
691 4 + 2 + ticket_data.size);
692 if (!bufel) {
693 gnutls_assert();
694 _gnutls_free_datum(&ticket_data);
695 return GNUTLS_E_MEMORY_ERROR;
696 }
697
698 data = _mbuffer_get_udata_ptr(bufel);
699 p = data;
700
701 _gnutls_write_uint32(session->internals.expire_time, p);
702 p += 4;
703
704 _gnutls_write_uint16(ticket_data.size, p);
705 p += 2;
706
707 memcpy(p, ticket_data.data, ticket_data.size);
708 p += ticket_data.size;
709
710 _gnutls_free_datum(&ticket_data);
711
712 data_size = p - data;
713
714 session->internals.hsk_flags |= HSK_TLS12_TICKET_SENT;
715 }
716 return _gnutls_send_handshake(session, data_size ? bufel : NULL,
717 GNUTLS_HANDSHAKE_NEW_SESSION_TICKET);
718 }
719
720 /*
721 * Return zero if session tickets haven't been enabled.
722 */
_gnutls_recv_new_session_ticket(gnutls_session_t session)723 int _gnutls_recv_new_session_ticket(gnutls_session_t session)
724 {
725 uint8_t *p;
726 int data_size;
727 gnutls_buffer_st buf;
728 uint16_t ticket_len;
729 int ret;
730 session_ticket_ext_st *priv = NULL;
731 gnutls_ext_priv_data_t epriv;
732
733 if (session->internals.flags & GNUTLS_NO_TICKETS)
734 return 0;
735 if (!session->internals.session_ticket_renew)
736 return 0;
737
738 /* This is the last flight and peer cannot be sure
739 * we have received it unless we notify him. So we
740 * wait for a message and retransmit if needed. */
741 if (IS_DTLS(session) && !_dtls_is_async(session)) {
742 unsigned have;
743 mbuffer_st *bufel = NULL;
744
745 have = gnutls_record_check_pending(session) +
746 record_check_unprocessed(session);
747
748 if (have != 0) {
749 bufel = _mbuffer_head_get_first(&session->internals.record_buffer, NULL);
750 }
751
752 if (have == 0 || (bufel && bufel->type != GNUTLS_HANDSHAKE)) {
753 ret = _dtls_wait_and_retransmit(session);
754 if (ret < 0)
755 return gnutls_assert_val(ret);
756 }
757 }
758
759 ret = _gnutls_recv_handshake(session,
760 GNUTLS_HANDSHAKE_NEW_SESSION_TICKET,
761 0, &buf);
762 if (ret < 0)
763 return gnutls_assert_val_fatal(ret);
764
765 p = buf.data;
766 data_size = buf.length;
767
768 DECR_LENGTH_COM(data_size, 4, ret =
769 GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
770 goto error);
771 /* skip over lifetime hint */
772 p += 4;
773
774 DECR_LENGTH_COM(data_size, 2, ret =
775 GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
776 goto error);
777 ticket_len = _gnutls_read_uint16(p);
778 p += 2;
779
780 DECR_LENGTH_COM(data_size, ticket_len, ret =
781 GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
782 goto error);
783
784 priv = gnutls_calloc(1, sizeof(*priv));
785 if (!priv) {
786 gnutls_assert();
787 ret = GNUTLS_E_MEMORY_ERROR;
788 goto error;
789 }
790 if (ticket_len > 0) {
791 priv->session_ticket =
792 gnutls_realloc_fast(priv->session_ticket, ticket_len);
793 if (!priv->session_ticket) {
794 gnutls_free(priv);
795 gnutls_assert();
796 ret = GNUTLS_E_MEMORY_ERROR;
797 goto error;
798 }
799 memcpy(priv->session_ticket, p, ticket_len);
800 }
801 priv->session_ticket_len = ticket_len;
802 epriv = priv;
803
804 /* Discard the current session ID. (RFC5077 3.4) */
805 ret =
806 _gnutls_generate_session_id(session->security_parameters.
807 session_id,
808 &session->security_parameters.
809 session_id_size);
810 if (ret < 0) {
811 gnutls_assert();
812 session_ticket_deinit_data(epriv);
813 ret = GNUTLS_E_INTERNAL_ERROR;
814 goto error;
815 }
816 ret = 0;
817
818 _gnutls_handshake_log
819 ("HSK[%p]: received session ticket\n", session);
820 session->internals.hsk_flags |= HSK_TICKET_RECEIVED;
821
822 _gnutls_hello_ext_set_priv(session,
823 GNUTLS_EXTENSION_SESSION_TICKET,
824 epriv);
825
826 error:
827 _gnutls_buffer_clear(&buf);
828
829 return ret;
830 }
831