]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Source/mbedtls/library/ssl_ticket.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Source / mbedtls / library / ssl_ticket.c
1 /*\r
2  *  TLS server tickets callbacks implementation\r
3  *\r
4  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved\r
5  *  SPDX-License-Identifier: Apache-2.0\r
6  *\r
7  *  Licensed under the Apache License, Version 2.0 (the "License"); you may\r
8  *  not use this file except in compliance with the License.\r
9  *  You may obtain a copy of the License at\r
10  *\r
11  *  http://www.apache.org/licenses/LICENSE-2.0\r
12  *\r
13  *  Unless required by applicable law or agreed to in writing, software\r
14  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\r
15  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  *  See the License for the specific language governing permissions and\r
17  *  limitations under the License.\r
18  *\r
19  *  This file is part of mbed TLS (https://tls.mbed.org)\r
20  */\r
21 \r
22 #if !defined(MBEDTLS_CONFIG_FILE)\r
23 #include "mbedtls/config.h"\r
24 #else\r
25 #include MBEDTLS_CONFIG_FILE\r
26 #endif\r
27 \r
28 #if defined(MBEDTLS_SSL_TICKET_C)\r
29 \r
30 #if defined(MBEDTLS_PLATFORM_C)\r
31 #include "mbedtls/platform.h"\r
32 #else\r
33 #include <stdlib.h>\r
34 #define mbedtls_calloc    calloc\r
35 #define mbedtls_free      free\r
36 #endif\r
37 \r
38 #include "mbedtls/ssl_ticket.h"\r
39 #include "mbedtls/platform_util.h"\r
40 \r
41 #include <string.h>\r
42 \r
43 /*\r
44  * Initialze context\r
45  */\r
46 void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx )\r
47 {\r
48     memset( ctx, 0, sizeof( mbedtls_ssl_ticket_context ) );\r
49 \r
50 #if defined(MBEDTLS_THREADING_C)\r
51     mbedtls_mutex_init( &ctx->mutex );\r
52 #endif\r
53 }\r
54 \r
55 #define MAX_KEY_BYTES 32    /* 256 bits */\r
56 \r
57 #define TICKET_KEY_NAME_BYTES    4\r
58 #define TICKET_IV_BYTES         12\r
59 #define TICKET_CRYPT_LEN_BYTES   2\r
60 #define TICKET_AUTH_TAG_BYTES   16\r
61 \r
62 #define TICKET_MIN_LEN ( TICKET_KEY_NAME_BYTES  +        \\r
63                          TICKET_IV_BYTES        +        \\r
64                          TICKET_CRYPT_LEN_BYTES +        \\r
65                          TICKET_AUTH_TAG_BYTES )\r
66 #define TICKET_ADD_DATA_LEN ( TICKET_KEY_NAME_BYTES  +        \\r
67                               TICKET_IV_BYTES        +        \\r
68                               TICKET_CRYPT_LEN_BYTES )\r
69 \r
70 /*\r
71  * Generate/update a key\r
72  */\r
73 static int ssl_ticket_gen_key( mbedtls_ssl_ticket_context *ctx,\r
74                                unsigned char index )\r
75 {\r
76     int ret;\r
77     unsigned char buf[MAX_KEY_BYTES];\r
78     mbedtls_ssl_ticket_key *key = ctx->keys + index;\r
79 \r
80 #if defined(MBEDTLS_HAVE_TIME)\r
81     key->generation_time = (uint32_t) mbedtls_time( NULL );\r
82 #endif\r
83 \r
84     if( ( ret = ctx->f_rng( ctx->p_rng, key->name, sizeof( key->name ) ) ) != 0 )\r
85         return( ret );\r
86 \r
87     if( ( ret = ctx->f_rng( ctx->p_rng, buf, sizeof( buf ) ) ) != 0 )\r
88         return( ret );\r
89 \r
90     /* With GCM and CCM, same context can encrypt & decrypt */\r
91     ret = mbedtls_cipher_setkey( &key->ctx, buf,\r
92                                  mbedtls_cipher_get_key_bitlen( &key->ctx ),\r
93                                  MBEDTLS_ENCRYPT );\r
94 \r
95     mbedtls_platform_zeroize( buf, sizeof( buf ) );\r
96 \r
97     return( ret );\r
98 }\r
99 \r
100 /*\r
101  * Rotate/generate keys if necessary\r
102  */\r
103 static int ssl_ticket_update_keys( mbedtls_ssl_ticket_context *ctx )\r
104 {\r
105 #if !defined(MBEDTLS_HAVE_TIME)\r
106     ((void) ctx);\r
107 #else\r
108     if( ctx->ticket_lifetime != 0 )\r
109     {\r
110         uint32_t current_time = (uint32_t) mbedtls_time( NULL );\r
111         uint32_t key_time = ctx->keys[ctx->active].generation_time;\r
112 \r
113         if( current_time >= key_time &&\r
114             current_time - key_time < ctx->ticket_lifetime )\r
115         {\r
116             return( 0 );\r
117         }\r
118 \r
119         ctx->active = 1 - ctx->active;\r
120 \r
121         return( ssl_ticket_gen_key( ctx, ctx->active ) );\r
122     }\r
123     else\r
124 #endif /* MBEDTLS_HAVE_TIME */\r
125         return( 0 );\r
126 }\r
127 \r
128 /*\r
129  * Setup context for actual use\r
130  */\r
131 int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx,\r
132     int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,\r
133     mbedtls_cipher_type_t cipher,\r
134     uint32_t lifetime )\r
135 {\r
136     int ret;\r
137     const mbedtls_cipher_info_t *cipher_info;\r
138 \r
139     ctx->f_rng = f_rng;\r
140     ctx->p_rng = p_rng;\r
141 \r
142     ctx->ticket_lifetime = lifetime;\r
143 \r
144     cipher_info = mbedtls_cipher_info_from_type( cipher);\r
145     if( cipher_info == NULL )\r
146         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );\r
147 \r
148     if( cipher_info->mode != MBEDTLS_MODE_GCM &&\r
149         cipher_info->mode != MBEDTLS_MODE_CCM )\r
150     {\r
151         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );\r
152     }\r
153 \r
154     if( cipher_info->key_bitlen > 8 * MAX_KEY_BYTES )\r
155         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );\r
156 \r
157 #if defined(MBEDTLS_USE_PSA_CRYPTO)\r
158     ret = mbedtls_cipher_setup_psa( &ctx->keys[0].ctx,\r
159                                     cipher_info, TICKET_AUTH_TAG_BYTES );\r
160     if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )\r
161         return( ret );\r
162     /* We don't yet expect to support all ciphers through PSA,\r
163      * so allow fallback to ordinary mbedtls_cipher_setup(). */\r
164     if( ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )\r
165 #endif /* MBEDTLS_USE_PSA_CRYPTO */\r
166     if( ( ret = mbedtls_cipher_setup( &ctx->keys[0].ctx, cipher_info ) ) != 0 )\r
167         return( ret );\r
168 \r
169 #if defined(MBEDTLS_USE_PSA_CRYPTO)\r
170     ret = mbedtls_cipher_setup_psa( &ctx->keys[1].ctx,\r
171                                     cipher_info, TICKET_AUTH_TAG_BYTES );\r
172     if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )\r
173         return( ret );\r
174     if( ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )\r
175 #endif /* MBEDTLS_USE_PSA_CRYPTO */\r
176     if( ( ret = mbedtls_cipher_setup( &ctx->keys[1].ctx, cipher_info ) ) != 0 )\r
177         return( ret );\r
178 \r
179     if( ( ret = ssl_ticket_gen_key( ctx, 0 ) ) != 0 ||\r
180         ( ret = ssl_ticket_gen_key( ctx, 1 ) ) != 0 )\r
181     {\r
182         return( ret );\r
183     }\r
184 \r
185     return( 0 );\r
186 }\r
187 \r
188 /*\r
189  * Serialize a session in the following format:\r
190  *\r
191  * - If MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is enabled:\r
192  *    0       .   n-1   session structure, n = sizeof(mbedtls_ssl_session)\r
193  *    n       .   n+2   peer_cert length = m (0 if no certificate)\r
194  *    n+3     .   n+2+m peer cert ASN.1\r
195  *\r
196  * - If MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is disabled:\r
197  *    0       .   n-1   session structure, n = sizeof(mbedtls_ssl_session)\r
198  *    n       .   n     length of peer certificate digest = k (0 if no digest)\r
199  *    n+1     .   n+k   peer certificate digest (digest type encoded in session)\r
200  */\r
201 static int ssl_save_session( const mbedtls_ssl_session *session,\r
202                              unsigned char *buf, size_t buf_len,\r
203                              size_t *olen )\r
204 {\r
205     unsigned char *p = buf;\r
206     size_t left = buf_len;\r
207 #if defined(MBEDTLS_X509_CRT_PARSE_C)\r
208 #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)\r
209     size_t cert_len;\r
210 #else\r
211     size_t cert_digest_len;\r
212 #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */\r
213 #endif /* MBEDTLS_X509_CRT_PARSE_C */\r
214 \r
215     if( left < sizeof( mbedtls_ssl_session ) )\r
216         return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );\r
217 \r
218     /* This also copies the values of pointer fields in the\r
219      * session to be serialized, but they'll be ignored when\r
220      * loading the session through ssl_load_session(). */\r
221     memcpy( p, session, sizeof( mbedtls_ssl_session ) );\r
222     p += sizeof( mbedtls_ssl_session );\r
223     left -= sizeof( mbedtls_ssl_session );\r
224 \r
225 #if defined(MBEDTLS_X509_CRT_PARSE_C)\r
226 #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)\r
227     if( session->peer_cert == NULL )\r
228         cert_len = 0;\r
229     else\r
230         cert_len = session->peer_cert->raw.len;\r
231 \r
232     if( left < 3 + cert_len )\r
233         return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );\r
234 \r
235     *p++ = (unsigned char)( ( cert_len >> 16 ) & 0xFF );\r
236     *p++ = (unsigned char)( ( cert_len >>  8 ) & 0xFF );\r
237     *p++ = (unsigned char)( ( cert_len       ) & 0xFF );\r
238     left -= 3;\r
239 \r
240     if( session->peer_cert != NULL )\r
241         memcpy( p, session->peer_cert->raw.p, cert_len );\r
242 \r
243     p += cert_len;\r
244     left -= cert_len;\r
245 #else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */\r
246     if( session->peer_cert_digest != NULL )\r
247         cert_digest_len = 0;\r
248     else\r
249         cert_digest_len = session->peer_cert_digest_len;\r
250 \r
251     if( left < 1 + cert_digest_len )\r
252         return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );\r
253 \r
254     *p++ = (unsigned char) cert_digest_len;\r
255     left--;\r
256 \r
257     if( session->peer_cert_digest != NULL )\r
258         memcpy( p, session->peer_cert_digest, cert_digest_len );\r
259 \r
260     p    += cert_digest_len;\r
261     left -= cert_digest_len;\r
262 #endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */\r
263 #endif /* MBEDTLS_X509_CRT_PARSE_C */\r
264 \r
265     *olen = p - buf;\r
266 \r
267     return( 0 );\r
268 }\r
269 \r
270 /*\r
271  * Unserialise session, see ssl_save_session()\r
272  */\r
273 static int ssl_load_session( mbedtls_ssl_session *session,\r
274                              const unsigned char *buf, size_t len )\r
275 {\r
276     const unsigned char *p = buf;\r
277     const unsigned char * const end = buf + len;\r
278 #if defined(MBEDTLS_X509_CRT_PARSE_C)\r
279 #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)\r
280     size_t cert_len;\r
281 #else\r
282     size_t cert_digest_len;\r
283 #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */\r
284 #endif /* MBEDTLS_X509_CRT_PARSE_C */\r
285 \r
286     if( sizeof( mbedtls_ssl_session ) > (size_t)( end - p ) )\r
287         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );\r
288 \r
289     memcpy( session, p, sizeof( mbedtls_ssl_session ) );\r
290     p += sizeof( mbedtls_ssl_session );\r
291 \r
292     /* Non-NULL pointer fields of `session` are meaningless\r
293      * and potentially harmful. Zeroize them for safety. */\r
294 #if defined(MBEDTLS_X509_CRT_PARSE_C)\r
295 #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)\r
296     session->peer_cert = NULL;\r
297 #else\r
298     session->peer_cert_digest = NULL;\r
299 #endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */\r
300 #endif /* MBEDTLS_X509_CRT_PARSE_C */\r
301 #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)\r
302     session->ticket = NULL;\r
303 #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */\r
304 \r
305 #if defined(MBEDTLS_X509_CRT_PARSE_C)\r
306 #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)\r
307     /* Deserialize CRT from the end of the ticket. */\r
308     if( 3 > (size_t)( end - p ) )\r
309         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );\r
310 \r
311     cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2];\r
312     p += 3;\r
313 \r
314     if( cert_len != 0 )\r
315     {\r
316         int ret;\r
317 \r
318         if( cert_len > (size_t)( end - p ) )\r
319             return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );\r
320 \r
321         session->peer_cert = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) );\r
322 \r
323         if( session->peer_cert == NULL )\r
324             return( MBEDTLS_ERR_SSL_ALLOC_FAILED );\r
325 \r
326         mbedtls_x509_crt_init( session->peer_cert );\r
327 \r
328         if( ( ret = mbedtls_x509_crt_parse_der( session->peer_cert,\r
329                                                 p, cert_len ) ) != 0 )\r
330         {\r
331             mbedtls_x509_crt_free( session->peer_cert );\r
332             mbedtls_free( session->peer_cert );\r
333             session->peer_cert = NULL;\r
334             return( ret );\r
335         }\r
336 \r
337         p += cert_len;\r
338     }\r
339 #else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */\r
340     /* Deserialize CRT digest from the end of the ticket. */\r
341     if( 1 > (size_t)( end - p ) )\r
342         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );\r
343 \r
344     cert_digest_len = (size_t) p[0];\r
345     p++;\r
346 \r
347     if( cert_digest_len != 0 )\r
348     {\r
349         if( cert_digest_len > (size_t)( end - p ) ||\r
350             cert_digest_len != session->peer_cert_digest_len )\r
351         {\r
352             return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );\r
353         }\r
354 \r
355         session->peer_cert_digest = mbedtls_calloc( 1, cert_digest_len );\r
356         if( session->peer_cert_digest == NULL )\r
357             return( MBEDTLS_ERR_SSL_ALLOC_FAILED );\r
358 \r
359         memcpy( session->peer_cert_digest, p, cert_digest_len );\r
360         p += cert_digest_len;\r
361     }\r
362 #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */\r
363 #endif /* MBEDTLS_X509_CRT_PARSE_C */\r
364 \r
365     if( p != end )\r
366         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );\r
367 \r
368     return( 0 );\r
369 }\r
370 \r
371 /*\r
372  * Create session ticket, with the following structure:\r
373  *\r
374  *    struct {\r
375  *        opaque key_name[4];\r
376  *        opaque iv[12];\r
377  *        opaque encrypted_state<0..2^16-1>;\r
378  *        opaque tag[16];\r
379  *    } ticket;\r
380  *\r
381  * The key_name, iv, and length of encrypted_state are the additional\r
382  * authenticated data.\r
383  */\r
384 \r
385 int mbedtls_ssl_ticket_write( void *p_ticket,\r
386                               const mbedtls_ssl_session *session,\r
387                               unsigned char *start,\r
388                               const unsigned char *end,\r
389                               size_t *tlen,\r
390                               uint32_t *ticket_lifetime )\r
391 {\r
392     int ret;\r
393     mbedtls_ssl_ticket_context *ctx = p_ticket;\r
394     mbedtls_ssl_ticket_key *key;\r
395     unsigned char *key_name = start;\r
396     unsigned char *iv = start + TICKET_KEY_NAME_BYTES;\r
397     unsigned char *state_len_bytes = iv + TICKET_IV_BYTES;\r
398     unsigned char *state = state_len_bytes + TICKET_CRYPT_LEN_BYTES;\r
399     unsigned char *tag;\r
400     size_t clear_len, ciph_len;\r
401 \r
402     *tlen = 0;\r
403 \r
404     if( ctx == NULL || ctx->f_rng == NULL )\r
405         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );\r
406 \r
407     /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag,\r
408      * in addition to session itself, that will be checked when writing it. */\r
409     if( end - start < TICKET_MIN_LEN )\r
410         return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );\r
411 \r
412 #if defined(MBEDTLS_THREADING_C)\r
413     if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )\r
414         return( ret );\r
415 #endif\r
416 \r
417     if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 )\r
418         goto cleanup;\r
419 \r
420     key = &ctx->keys[ctx->active];\r
421 \r
422     *ticket_lifetime = ctx->ticket_lifetime;\r
423 \r
424     memcpy( key_name, key->name, TICKET_KEY_NAME_BYTES );\r
425 \r
426     if( ( ret = ctx->f_rng( ctx->p_rng, iv, TICKET_IV_BYTES ) ) != 0 )\r
427         goto cleanup;\r
428 \r
429     /* Dump session state */\r
430     if( ( ret = ssl_save_session( session,\r
431                                   state, end - state, &clear_len ) ) != 0 ||\r
432         (unsigned long) clear_len > 65535 )\r
433     {\r
434          goto cleanup;\r
435     }\r
436     state_len_bytes[0] = ( clear_len >> 8 ) & 0xff;\r
437     state_len_bytes[1] = ( clear_len      ) & 0xff;\r
438 \r
439     /* Encrypt and authenticate */\r
440     tag = state + clear_len;\r
441     if( ( ret = mbedtls_cipher_auth_encrypt( &key->ctx,\r
442                     iv, TICKET_IV_BYTES,\r
443                     /* Additional data: key name, IV and length */\r
444                     key_name, TICKET_ADD_DATA_LEN,\r
445                     state, clear_len, state, &ciph_len,\r
446                     tag, TICKET_AUTH_TAG_BYTES ) ) != 0 )\r
447     {\r
448         goto cleanup;\r
449     }\r
450     if( ciph_len != clear_len )\r
451     {\r
452         ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;\r
453         goto cleanup;\r
454     }\r
455 \r
456     *tlen = TICKET_MIN_LEN + ciph_len;\r
457 \r
458 cleanup:\r
459 #if defined(MBEDTLS_THREADING_C)\r
460     if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )\r
461         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );\r
462 #endif\r
463 \r
464     return( ret );\r
465 }\r
466 \r
467 /*\r
468  * Select key based on name\r
469  */\r
470 static mbedtls_ssl_ticket_key *ssl_ticket_select_key(\r
471         mbedtls_ssl_ticket_context *ctx,\r
472         const unsigned char name[4] )\r
473 {\r
474     unsigned char i;\r
475 \r
476     for( i = 0; i < sizeof( ctx->keys ) / sizeof( *ctx->keys ); i++ )\r
477         if( memcmp( name, ctx->keys[i].name, 4 ) == 0 )\r
478             return( &ctx->keys[i] );\r
479 \r
480     return( NULL );\r
481 }\r
482 \r
483 /*\r
484  * Load session ticket (see mbedtls_ssl_ticket_write for structure)\r
485  */\r
486 int mbedtls_ssl_ticket_parse( void *p_ticket,\r
487                               mbedtls_ssl_session *session,\r
488                               unsigned char *buf,\r
489                               size_t len )\r
490 {\r
491     int ret;\r
492     mbedtls_ssl_ticket_context *ctx = p_ticket;\r
493     mbedtls_ssl_ticket_key *key;\r
494     unsigned char *key_name = buf;\r
495     unsigned char *iv = buf + TICKET_KEY_NAME_BYTES;\r
496     unsigned char *enc_len_p = iv + TICKET_IV_BYTES;\r
497     unsigned char *ticket = enc_len_p + TICKET_CRYPT_LEN_BYTES;\r
498     unsigned char *tag;\r
499     size_t enc_len, clear_len;\r
500 \r
501     if( ctx == NULL || ctx->f_rng == NULL )\r
502         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );\r
503 \r
504     if( len < TICKET_MIN_LEN )\r
505         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );\r
506 \r
507 #if defined(MBEDTLS_THREADING_C)\r
508     if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )\r
509         return( ret );\r
510 #endif\r
511 \r
512     if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 )\r
513         goto cleanup;\r
514 \r
515     enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1];\r
516     tag = ticket + enc_len;\r
517 \r
518     if( len != TICKET_MIN_LEN + enc_len )\r
519     {\r
520         ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;\r
521         goto cleanup;\r
522     }\r
523 \r
524     /* Select key */\r
525     if( ( key = ssl_ticket_select_key( ctx, key_name ) ) == NULL )\r
526     {\r
527         /* We can't know for sure but this is a likely option unless we're\r
528          * under attack - this is only informative anyway */\r
529         ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;\r
530         goto cleanup;\r
531     }\r
532 \r
533     /* Decrypt and authenticate */\r
534     if( ( ret = mbedtls_cipher_auth_decrypt( &key->ctx,\r
535                     iv, TICKET_IV_BYTES,\r
536                     /* Additional data: key name, IV and length */\r
537                     key_name, TICKET_ADD_DATA_LEN,\r
538                     ticket, enc_len,\r
539                     ticket, &clear_len,\r
540                     tag, TICKET_AUTH_TAG_BYTES ) ) != 0 )\r
541     {\r
542         if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED )\r
543             ret = MBEDTLS_ERR_SSL_INVALID_MAC;\r
544 \r
545         goto cleanup;\r
546     }\r
547     if( clear_len != enc_len )\r
548     {\r
549         ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;\r
550         goto cleanup;\r
551     }\r
552 \r
553     /* Actually load session */\r
554     if( ( ret = ssl_load_session( session, ticket, clear_len ) ) != 0 )\r
555         goto cleanup;\r
556 \r
557 #if defined(MBEDTLS_HAVE_TIME)\r
558     {\r
559         /* Check for expiration */\r
560         mbedtls_time_t current_time = mbedtls_time( NULL );\r
561 \r
562         if( current_time < session->start ||\r
563             (uint32_t)( current_time - session->start ) > ctx->ticket_lifetime )\r
564         {\r
565             ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;\r
566             goto cleanup;\r
567         }\r
568     }\r
569 #endif\r
570 \r
571 cleanup:\r
572 #if defined(MBEDTLS_THREADING_C)\r
573     if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )\r
574         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );\r
575 #endif\r
576 \r
577     return( ret );\r
578 }\r
579 \r
580 /*\r
581  * Free context\r
582  */\r
583 void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx )\r
584 {\r
585     mbedtls_cipher_free( &ctx->keys[0].ctx );\r
586     mbedtls_cipher_free( &ctx->keys[1].ctx );\r
587 \r
588 #if defined(MBEDTLS_THREADING_C)\r
589     mbedtls_mutex_free( &ctx->mutex );\r
590 #endif\r
591 \r
592     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) );\r
593 }\r
594 \r
595 #endif /* MBEDTLS_SSL_TICKET_C */\r