2 * TLS server tickets callbacks implementation
4 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
5 * SPDX-License-Identifier: GPL-2.0
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 * This file is part of mbed TLS (https://tls.mbed.org)
24 #if !defined(MBEDTLS_CONFIG_FILE)
25 #include "mbedtls/config.h"
27 #include MBEDTLS_CONFIG_FILE
30 #if defined(MBEDTLS_SSL_TICKET_C)
32 #if defined(MBEDTLS_PLATFORM_C)
33 #include "mbedtls/platform.h"
36 #define mbedtls_calloc calloc
37 #define mbedtls_free free
40 #include "mbedtls/ssl_ticket.h"
44 /* Implementation that should never be optimized out by the compiler */
45 static void mbedtls_zeroize( void *v
, size_t n
) {
46 volatile unsigned char *p
= v
; while( n
-- ) *p
++ = 0;
52 void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context
*ctx
)
54 memset( ctx
, 0, sizeof( mbedtls_ssl_ticket_context
) );
56 #if defined(MBEDTLS_THREADING_C)
57 mbedtls_mutex_init( &ctx
->mutex
);
61 #define MAX_KEY_BYTES 32 /* 256 bits */
64 * Generate/update a key
66 static int ssl_ticket_gen_key( mbedtls_ssl_ticket_context
*ctx
,
70 unsigned char buf
[MAX_KEY_BYTES
];
71 mbedtls_ssl_ticket_key
*key
= ctx
->keys
+ index
;
73 #if defined(MBEDTLS_HAVE_TIME)
74 key
->generation_time
= (uint32_t) mbedtls_time( NULL
);
77 if( ( ret
= ctx
->f_rng( ctx
->p_rng
, key
->name
, sizeof( key
->name
) ) ) != 0 )
80 if( ( ret
= ctx
->f_rng( ctx
->p_rng
, buf
, sizeof( buf
) ) ) != 0 )
83 /* With GCM and CCM, same context can encrypt & decrypt */
84 ret
= mbedtls_cipher_setkey( &key
->ctx
, buf
,
85 mbedtls_cipher_get_key_bitlen( &key
->ctx
),
88 mbedtls_zeroize( buf
, sizeof( buf
) );
94 * Rotate/generate keys if necessary
96 static int ssl_ticket_update_keys( mbedtls_ssl_ticket_context
*ctx
)
98 #if !defined(MBEDTLS_HAVE_TIME)
101 if( ctx
->ticket_lifetime
!= 0 )
103 uint32_t current_time
= (uint32_t) mbedtls_time( NULL
);
104 uint32_t key_time
= ctx
->keys
[ctx
->active
].generation_time
;
106 if( current_time
> key_time
&&
107 current_time
- key_time
< ctx
->ticket_lifetime
)
112 ctx
->active
= 1 - ctx
->active
;
114 return( ssl_ticket_gen_key( ctx
, ctx
->active
) );
117 #endif /* MBEDTLS_HAVE_TIME */
122 * Setup context for actual use
124 int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context
*ctx
,
125 int (*f_rng
)(void *, unsigned char *, size_t), void *p_rng
,
126 mbedtls_cipher_type_t cipher
,
130 const mbedtls_cipher_info_t
*cipher_info
;
135 ctx
->ticket_lifetime
= lifetime
;
137 cipher_info
= mbedtls_cipher_info_from_type( cipher
);
138 if( cipher_info
== NULL
)
139 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
141 if( cipher_info
->mode
!= MBEDTLS_MODE_GCM
&&
142 cipher_info
->mode
!= MBEDTLS_MODE_CCM
)
144 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
147 if( cipher_info
->key_bitlen
> 8 * MAX_KEY_BYTES
)
148 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
150 if( ( ret
= mbedtls_cipher_setup( &ctx
->keys
[0].ctx
, cipher_info
) ) != 0 ||
151 ( ret
= mbedtls_cipher_setup( &ctx
->keys
[1].ctx
, cipher_info
) ) != 0 )
156 if( ( ret
= ssl_ticket_gen_key( ctx
, 0 ) ) != 0 ||
157 ( ret
= ssl_ticket_gen_key( ctx
, 1 ) ) != 0 )
166 * Serialize a session in the following format:
167 * 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session)
168 * n . n+2 peer_cert length = m (0 if no certificate)
169 * n+3 . n+2+m peer cert ASN.1
171 static int ssl_save_session( const mbedtls_ssl_session
*session
,
172 unsigned char *buf
, size_t buf_len
,
175 unsigned char *p
= buf
;
176 size_t left
= buf_len
;
177 #if defined(MBEDTLS_X509_CRT_PARSE_C)
179 #endif /* MBEDTLS_X509_CRT_PARSE_C */
181 if( left
< sizeof( mbedtls_ssl_session
) )
182 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL
);
184 memcpy( p
, session
, sizeof( mbedtls_ssl_session
) );
185 p
+= sizeof( mbedtls_ssl_session
);
186 left
-= sizeof( mbedtls_ssl_session
);
188 #if defined(MBEDTLS_X509_CRT_PARSE_C)
189 if( session
->peer_cert
== NULL
)
192 cert_len
= session
->peer_cert
->raw
.len
;
194 if( left
< 3 + cert_len
)
195 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL
);
197 *p
++ = (unsigned char)( cert_len
>> 16 & 0xFF );
198 *p
++ = (unsigned char)( cert_len
>> 8 & 0xFF );
199 *p
++ = (unsigned char)( cert_len
& 0xFF );
201 if( session
->peer_cert
!= NULL
)
202 memcpy( p
, session
->peer_cert
->raw
.p
, cert_len
);
205 #endif /* MBEDTLS_X509_CRT_PARSE_C */
213 * Unserialise session, see ssl_save_session()
215 static int ssl_load_session( mbedtls_ssl_session
*session
,
216 const unsigned char *buf
, size_t len
)
218 const unsigned char *p
= buf
;
219 const unsigned char * const end
= buf
+ len
;
220 #if defined(MBEDTLS_X509_CRT_PARSE_C)
222 #endif /* MBEDTLS_X509_CRT_PARSE_C */
224 if( p
+ sizeof( mbedtls_ssl_session
) > end
)
225 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
227 memcpy( session
, p
, sizeof( mbedtls_ssl_session
) );
228 p
+= sizeof( mbedtls_ssl_session
);
230 #if defined(MBEDTLS_X509_CRT_PARSE_C)
232 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
234 cert_len
= ( p
[0] << 16 ) | ( p
[1] << 8 ) | p
[2];
239 session
->peer_cert
= NULL
;
245 if( p
+ cert_len
> end
)
246 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
248 session
->peer_cert
= mbedtls_calloc( 1, sizeof( mbedtls_x509_crt
) );
250 if( session
->peer_cert
== NULL
)
251 return( MBEDTLS_ERR_SSL_ALLOC_FAILED
);
253 mbedtls_x509_crt_init( session
->peer_cert
);
255 if( ( ret
= mbedtls_x509_crt_parse_der( session
->peer_cert
,
256 p
, cert_len
) ) != 0 )
258 mbedtls_x509_crt_free( session
->peer_cert
);
259 mbedtls_free( session
->peer_cert
);
260 session
->peer_cert
= NULL
;
266 #endif /* MBEDTLS_X509_CRT_PARSE_C */
269 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
275 * Create session ticket, with the following structure:
278 * opaque key_name[4];
280 * opaque encrypted_state<0..2^16-1>;
284 * The key_name, iv, and length of encrypted_state are the additional
285 * authenticated data.
287 int mbedtls_ssl_ticket_write( void *p_ticket
,
288 const mbedtls_ssl_session
*session
,
289 unsigned char *start
,
290 const unsigned char *end
,
292 uint32_t *ticket_lifetime
)
295 mbedtls_ssl_ticket_context
*ctx
= p_ticket
;
296 mbedtls_ssl_ticket_key
*key
;
297 unsigned char *key_name
= start
;
298 unsigned char *iv
= start
+ 4;
299 unsigned char *state_len_bytes
= iv
+ 12;
300 unsigned char *state
= state_len_bytes
+ 2;
302 size_t clear_len
, ciph_len
;
306 if( ctx
== NULL
|| ctx
->f_rng
== NULL
)
307 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
309 /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag,
310 * in addition to session itself, that will be checked when writing it. */
311 if( end
- start
< 4 + 12 + 2 + 16 )
312 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL
);
314 #if defined(MBEDTLS_THREADING_C)
315 if( ( ret
= mbedtls_mutex_lock( &ctx
->mutex
) ) != 0 )
319 if( ( ret
= ssl_ticket_update_keys( ctx
) ) != 0 )
322 key
= &ctx
->keys
[ctx
->active
];
324 *ticket_lifetime
= ctx
->ticket_lifetime
;
326 memcpy( key_name
, key
->name
, 4 );
328 if( ( ret
= ctx
->f_rng( ctx
->p_rng
, iv
, 12 ) ) != 0 )
331 /* Dump session state */
332 if( ( ret
= ssl_save_session( session
,
333 state
, end
- state
, &clear_len
) ) != 0 ||
334 (unsigned long) clear_len
> 65535 )
338 state_len_bytes
[0] = ( clear_len
>> 8 ) & 0xff;
339 state_len_bytes
[1] = ( clear_len
) & 0xff;
341 /* Encrypt and authenticate */
342 tag
= state
+ clear_len
;
343 if( ( ret
= mbedtls_cipher_auth_encrypt( &key
->ctx
,
344 iv
, 12, key_name
, 4 + 12 + 2,
345 state
, clear_len
, state
, &ciph_len
, tag
, 16 ) ) != 0 )
349 if( ciph_len
!= clear_len
)
351 ret
= MBEDTLS_ERR_SSL_INTERNAL_ERROR
;
355 *tlen
= 4 + 12 + 2 + 16 + ciph_len
;
358 #if defined(MBEDTLS_THREADING_C)
359 if( mbedtls_mutex_unlock( &ctx
->mutex
) != 0 )
360 return( MBEDTLS_ERR_THREADING_MUTEX_ERROR
);
367 * Select key based on name
369 static mbedtls_ssl_ticket_key
*ssl_ticket_select_key(
370 mbedtls_ssl_ticket_context
*ctx
,
371 const unsigned char name
[4] )
375 for( i
= 0; i
< sizeof( ctx
->keys
) / sizeof( *ctx
->keys
); i
++ )
376 if( memcmp( name
, ctx
->keys
[i
].name
, 4 ) == 0 )
377 return( &ctx
->keys
[i
] );
383 * Load session ticket (see mbedtls_ssl_ticket_write for structure)
385 int mbedtls_ssl_ticket_parse( void *p_ticket
,
386 mbedtls_ssl_session
*session
,
391 mbedtls_ssl_ticket_context
*ctx
= p_ticket
;
392 mbedtls_ssl_ticket_key
*key
;
393 unsigned char *key_name
= buf
;
394 unsigned char *iv
= buf
+ 4;
395 unsigned char *enc_len_p
= iv
+ 12;
396 unsigned char *ticket
= enc_len_p
+ 2;
398 size_t enc_len
, clear_len
;
400 if( ctx
== NULL
|| ctx
->f_rng
== NULL
)
401 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
403 /* See mbedtls_ssl_ticket_write() */
404 if( len
< 4 + 12 + 2 + 16 )
405 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
407 #if defined(MBEDTLS_THREADING_C)
408 if( ( ret
= mbedtls_mutex_lock( &ctx
->mutex
) ) != 0 )
412 if( ( ret
= ssl_ticket_update_keys( ctx
) ) != 0 )
415 enc_len
= ( enc_len_p
[0] << 8 ) | enc_len_p
[1];
416 tag
= ticket
+ enc_len
;
418 if( len
!= 4 + 12 + 2 + enc_len
+ 16 )
420 ret
= MBEDTLS_ERR_SSL_BAD_INPUT_DATA
;
425 if( ( key
= ssl_ticket_select_key( ctx
, key_name
) ) == NULL
)
427 /* We can't know for sure but this is a likely option unless we're
428 * under attack - this is only informative anyway */
429 ret
= MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED
;
433 /* Decrypt and authenticate */
434 if( ( ret
= mbedtls_cipher_auth_decrypt( &key
->ctx
, iv
, 12,
435 key_name
, 4 + 12 + 2, ticket
, enc_len
,
436 ticket
, &clear_len
, tag
, 16 ) ) != 0 )
438 if( ret
== MBEDTLS_ERR_CIPHER_AUTH_FAILED
)
439 ret
= MBEDTLS_ERR_SSL_INVALID_MAC
;
443 if( clear_len
!= enc_len
)
445 ret
= MBEDTLS_ERR_SSL_INTERNAL_ERROR
;
449 /* Actually load session */
450 if( ( ret
= ssl_load_session( session
, ticket
, clear_len
) ) != 0 )
453 #if defined(MBEDTLS_HAVE_TIME)
455 /* Check for expiration */
456 mbedtls_time_t current_time
= mbedtls_time( NULL
);
458 if( current_time
< session
->start
||
459 (uint32_t)( current_time
- session
->start
) > ctx
->ticket_lifetime
)
461 ret
= MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED
;
468 #if defined(MBEDTLS_THREADING_C)
469 if( mbedtls_mutex_unlock( &ctx
->mutex
) != 0 )
470 return( MBEDTLS_ERR_THREADING_MUTEX_ERROR
);
479 void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context
*ctx
)
481 mbedtls_cipher_free( &ctx
->keys
[0].ctx
);
482 mbedtls_cipher_free( &ctx
->keys
[1].ctx
);
484 #if defined(MBEDTLS_THREADING_C)
485 mbedtls_mutex_free( &ctx
->mutex
);
488 mbedtls_zeroize( ctx
, sizeof( mbedtls_ssl_ticket_context
) );
491 #endif /* MBEDTLS_SSL_TICKET_C */