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