2 * TLS server tickets callbacks implementation
4 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
5 * SPDX-License-Identifier: Apache-2.0
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 * This file is part of mbed TLS (https://tls.mbed.org)
22 #if !defined(MBEDTLS_CONFIG_FILE)
23 #include "mbedtls/config.h"
25 #include MBEDTLS_CONFIG_FILE
28 #if defined(MBEDTLS_SSL_TICKET_C)
30 #include "mbedtls/ssl_ticket.h"
32 #if defined(MBEDTLS_PLATFORM_C)
33 #include "mbedtls/platform.h"
36 #define mbedtls_calloc calloc
37 #define mbedtls_free free
42 /* Implementation that should never be optimized out by the compiler */
43 static void mbedtls_zeroize( void *v
, size_t n
) {
44 volatile unsigned char *p
= v
; while( n
-- ) *p
++ = 0;
50 void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context
*ctx
)
52 memset( ctx
, 0, sizeof( mbedtls_ssl_ticket_context
) );
54 #if defined(MBEDTLS_THREADING_C)
55 mbedtls_mutex_init( &ctx
->mutex
);
59 #define MAX_KEY_BYTES 32 /* 256 bits */
62 * Generate/update a key
64 static int ssl_ticket_gen_key( mbedtls_ssl_ticket_context
*ctx
,
68 unsigned char buf
[MAX_KEY_BYTES
];
69 mbedtls_ssl_ticket_key
*key
= ctx
->keys
+ index
;
71 #if defined(MBEDTLS_HAVE_TIME)
72 key
->generation_time
= (uint32_t) time( NULL
);
75 if( ( ret
= ctx
->f_rng( ctx
->p_rng
, key
->name
, sizeof( key
->name
) ) ) != 0 )
78 if( ( ret
= ctx
->f_rng( ctx
->p_rng
, buf
, sizeof( buf
) ) ) != 0 )
81 /* With GCM and CCM, same context can encrypt & decrypt */
82 ret
= mbedtls_cipher_setkey( &key
->ctx
, buf
,
83 mbedtls_cipher_get_key_bitlen( &key
->ctx
),
86 mbedtls_zeroize( buf
, sizeof( buf
) );
92 * Rotate/generate keys if necessary
94 static int ssl_ticket_update_keys( mbedtls_ssl_ticket_context
*ctx
)
96 #if !defined(MBEDTLS_HAVE_TIME)
99 if( ctx
->ticket_lifetime
!= 0 )
101 uint32_t current_time
= (uint32_t) time( NULL
);
102 uint32_t key_time
= ctx
->keys
[ctx
->active
].generation_time
;
104 if( current_time
> key_time
&&
105 current_time
- key_time
< ctx
->ticket_lifetime
)
110 ctx
->active
= 1 - ctx
->active
;
112 return( ssl_ticket_gen_key( ctx
, ctx
->active
) );
115 #endif /* MBEDTLS_HAVE_TIME */
120 * Setup context for actual use
122 int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context
*ctx
,
123 int (*f_rng
)(void *, unsigned char *, size_t), void *p_rng
,
124 mbedtls_cipher_type_t cipher
,
128 const mbedtls_cipher_info_t
*cipher_info
;
133 ctx
->ticket_lifetime
= lifetime
;
135 cipher_info
= mbedtls_cipher_info_from_type( cipher
);
136 if( cipher_info
== NULL
)
137 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
139 if( cipher_info
->mode
!= MBEDTLS_MODE_GCM
&&
140 cipher_info
->mode
!= MBEDTLS_MODE_CCM
)
142 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
145 if( cipher_info
->key_bitlen
> 8 * MAX_KEY_BYTES
)
146 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
148 if( ( ret
= mbedtls_cipher_setup( &ctx
->keys
[0].ctx
, cipher_info
) ) != 0 ||
149 ( ret
= mbedtls_cipher_setup( &ctx
->keys
[1].ctx
, cipher_info
) ) != 0 )
154 if( ( ret
= ssl_ticket_gen_key( ctx
, 0 ) ) != 0 ||
155 ( ret
= ssl_ticket_gen_key( ctx
, 1 ) ) != 0 )
164 * Serialize a session in the following format:
165 * 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session)
166 * n . n+2 peer_cert length = m (0 if no certificate)
167 * n+3 . n+2+m peer cert ASN.1
169 static int ssl_save_session( const mbedtls_ssl_session
*session
,
170 unsigned char *buf
, size_t buf_len
,
173 unsigned char *p
= buf
;
174 size_t left
= buf_len
;
175 #if defined(MBEDTLS_X509_CRT_PARSE_C)
177 #endif /* MBEDTLS_X509_CRT_PARSE_C */
179 if( left
< sizeof( mbedtls_ssl_session
) )
180 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL
);
182 memcpy( p
, session
, sizeof( mbedtls_ssl_session
) );
183 p
+= sizeof( mbedtls_ssl_session
);
184 left
-= sizeof( mbedtls_ssl_session
);
186 #if defined(MBEDTLS_X509_CRT_PARSE_C)
187 if( session
->peer_cert
== NULL
)
190 cert_len
= session
->peer_cert
->raw
.len
;
192 if( left
< 3 + cert_len
)
193 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL
);
195 *p
++ = (unsigned char)( cert_len
>> 16 & 0xFF );
196 *p
++ = (unsigned char)( cert_len
>> 8 & 0xFF );
197 *p
++ = (unsigned char)( cert_len
& 0xFF );
199 if( session
->peer_cert
!= NULL
)
200 memcpy( p
, session
->peer_cert
->raw
.p
, cert_len
);
203 #endif /* MBEDTLS_X509_CRT_PARSE_C */
211 * Unserialise session, see ssl_save_session()
213 static int ssl_load_session( mbedtls_ssl_session
*session
,
214 const unsigned char *buf
, size_t len
)
216 const unsigned char *p
= buf
;
217 const unsigned char * const end
= buf
+ len
;
218 #if defined(MBEDTLS_X509_CRT_PARSE_C)
220 #endif /* MBEDTLS_X509_CRT_PARSE_C */
222 if( p
+ sizeof( mbedtls_ssl_session
) > end
)
223 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
225 memcpy( session
, p
, sizeof( mbedtls_ssl_session
) );
226 p
+= sizeof( mbedtls_ssl_session
);
228 #if defined(MBEDTLS_X509_CRT_PARSE_C)
230 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
232 cert_len
= ( p
[0] << 16 ) | ( p
[1] << 8 ) | p
[2];
237 session
->peer_cert
= NULL
;
243 if( p
+ cert_len
> end
)
244 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
246 session
->peer_cert
= mbedtls_calloc( 1, sizeof( mbedtls_x509_crt
) );
248 if( session
->peer_cert
== NULL
)
249 return( MBEDTLS_ERR_SSL_ALLOC_FAILED
);
251 mbedtls_x509_crt_init( session
->peer_cert
);
253 if( ( ret
= mbedtls_x509_crt_parse_der( session
->peer_cert
,
254 p
, cert_len
) ) != 0 )
256 mbedtls_x509_crt_free( session
->peer_cert
);
257 mbedtls_free( session
->peer_cert
);
258 session
->peer_cert
= NULL
;
264 #endif /* MBEDTLS_X509_CRT_PARSE_C */
267 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
273 * Create session ticket, with the following structure:
276 * opaque key_name[4];
278 * opaque encrypted_state<0..2^16-1>;
282 * The key_name, iv, and length of encrypted_state are the additional
283 * authenticated data.
285 int mbedtls_ssl_ticket_write( void *p_ticket
,
286 const mbedtls_ssl_session
*session
,
287 unsigned char *start
,
288 const unsigned char *end
,
290 uint32_t *ticket_lifetime
)
293 mbedtls_ssl_ticket_context
*ctx
= p_ticket
;
294 mbedtls_ssl_ticket_key
*key
;
295 unsigned char *key_name
= start
;
296 unsigned char *iv
= start
+ 4;
297 unsigned char *state_len_bytes
= iv
+ 12;
298 unsigned char *state
= state_len_bytes
+ 2;
300 size_t clear_len
, ciph_len
;
304 if( ctx
== NULL
|| ctx
->f_rng
== NULL
)
305 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
307 /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag,
308 * in addition to session itself, that will be checked when writing it. */
309 if( end
- start
< 4 + 12 + 2 + 16 )
310 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL
);
312 #if defined(MBEDTLS_THREADING_C)
313 if( ( ret
= mbedtls_mutex_lock( &ctx
->mutex
) ) != 0 )
317 if( ( ret
= ssl_ticket_update_keys( ctx
) ) != 0 )
320 key
= &ctx
->keys
[ctx
->active
];
322 *ticket_lifetime
= ctx
->ticket_lifetime
;
324 memcpy( key_name
, key
->name
, 4 );
326 if( ( ret
= ctx
->f_rng( ctx
->p_rng
, iv
, 12 ) ) != 0 )
329 /* Dump session state */
330 if( ( ret
= ssl_save_session( session
,
331 state
, end
- state
, &clear_len
) ) != 0 ||
332 (unsigned long) clear_len
> 65535 )
336 state_len_bytes
[0] = ( clear_len
>> 8 ) & 0xff;
337 state_len_bytes
[1] = ( clear_len
) & 0xff;
339 /* Encrypt and authenticate */
340 tag
= state
+ clear_len
;
341 if( ( ret
= mbedtls_cipher_auth_encrypt( &key
->ctx
,
342 iv
, 12, key_name
, 4 + 12 + 2,
343 state
, clear_len
, state
, &ciph_len
, tag
, 16 ) ) != 0 )
347 if( ciph_len
!= clear_len
)
349 ret
= MBEDTLS_ERR_SSL_INTERNAL_ERROR
;
353 *tlen
= 4 + 12 + 2 + 16 + ciph_len
;
356 #if defined(MBEDTLS_THREADING_C)
357 if( mbedtls_mutex_unlock( &ctx
->mutex
) != 0 )
358 return( MBEDTLS_ERR_THREADING_MUTEX_ERROR
);
365 * Select key based on name
367 static mbedtls_ssl_ticket_key
*ssl_ticket_select_key(
368 mbedtls_ssl_ticket_context
*ctx
,
369 const unsigned char name
[4] )
373 for( i
= 0; i
< sizeof( ctx
->keys
) / sizeof( *ctx
->keys
); i
++ )
374 if( memcmp( name
, ctx
->keys
[i
].name
, 4 ) == 0 )
375 return( &ctx
->keys
[i
] );
381 * Load session ticket (see mbedtls_ssl_ticket_write for structure)
383 int mbedtls_ssl_ticket_parse( void *p_ticket
,
384 mbedtls_ssl_session
*session
,
389 mbedtls_ssl_ticket_context
*ctx
= p_ticket
;
390 mbedtls_ssl_ticket_key
*key
;
391 unsigned char *key_name
= buf
;
392 unsigned char *iv
= buf
+ 4;
393 unsigned char *enc_len_p
= iv
+ 12;
394 unsigned char *ticket
= enc_len_p
+ 2;
396 size_t enc_len
, clear_len
;
398 if( ctx
== NULL
|| ctx
->f_rng
== NULL
)
399 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
401 /* See mbedtls_ssl_ticket_write() */
402 if( len
< 4 + 12 + 2 + 16 )
403 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA
);
405 #if defined(MBEDTLS_THREADING_C)
406 if( ( ret
= mbedtls_mutex_lock( &ctx
->mutex
) ) != 0 )
410 if( ( ret
= ssl_ticket_update_keys( ctx
) ) != 0 )
413 enc_len
= ( enc_len_p
[0] << 8 ) | enc_len_p
[1];
414 tag
= ticket
+ enc_len
;
416 if( len
!= 4 + 12 + 2 + enc_len
+ 16 )
418 ret
= MBEDTLS_ERR_SSL_BAD_INPUT_DATA
;
423 if( ( key
= ssl_ticket_select_key( ctx
, key_name
) ) == NULL
)
425 /* We can't know for sure but this is a likely option unless we're
426 * under attack - this is only informative anyway */
427 ret
= MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED
;
431 /* Decrypt and authenticate */
432 if( ( ret
= mbedtls_cipher_auth_decrypt( &key
->ctx
, iv
, 12,
433 key_name
, 4 + 12 + 2, ticket
, enc_len
,
434 ticket
, &clear_len
, tag
, 16 ) ) != 0 )
436 if( ret
== MBEDTLS_ERR_CIPHER_AUTH_FAILED
)
437 ret
= MBEDTLS_ERR_SSL_INVALID_MAC
;
441 if( clear_len
!= enc_len
)
443 ret
= MBEDTLS_ERR_SSL_INTERNAL_ERROR
;
447 /* Actually load session */
448 if( ( ret
= ssl_load_session( session
, ticket
, clear_len
) ) != 0 )
451 #if defined(MBEDTLS_HAVE_TIME)
453 /* Check for expiration */
454 time_t current_time
= time( NULL
);
456 if( current_time
< session
->start
||
457 (uint32_t)( current_time
- session
->start
) > ctx
->ticket_lifetime
)
459 ret
= MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED
;
466 #if defined(MBEDTLS_THREADING_C)
467 if( mbedtls_mutex_unlock( &ctx
->mutex
) != 0 )
468 return( MBEDTLS_ERR_THREADING_MUTEX_ERROR
);
477 void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context
*ctx
)
479 mbedtls_cipher_free( &ctx
->keys
[0].ctx
);
480 mbedtls_cipher_free( &ctx
->keys
[1].ctx
);
482 #if defined(MBEDTLS_THREADING_C)
483 mbedtls_mutex_free( &ctx
->mutex
);
486 mbedtls_zeroize( ctx
, sizeof( mbedtls_ssl_ticket_context
) );
489 #endif /* MBEDTLS_SSL_TICKET_C */