Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbedtls by
ssl_ticket.c
00001 /* 00002 * TLS server tickets callbacks implementation 00003 * 00004 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 00005 * SPDX-License-Identifier: Apache-2.0 00006 * 00007 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00008 * not use this file except in compliance with the License. 00009 * You may obtain a copy of the License at 00010 * 00011 * http://www.apache.org/licenses/LICENSE-2.0 00012 * 00013 * Unless required by applicable law or agreed to in writing, software 00014 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00015 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00016 * See the License for the specific language governing permissions and 00017 * limitations under the License. 00018 * 00019 * This file is part of mbed TLS (https://tls.mbed.org) 00020 */ 00021 00022 #if !defined(MBEDTLS_CONFIG_FILE) 00023 #include "mbedtls/config.h" 00024 #else 00025 #include MBEDTLS_CONFIG_FILE 00026 #endif 00027 00028 #if defined(MBEDTLS_SSL_TICKET_C) 00029 00030 #include "mbedtls/ssl_ticket.h" 00031 00032 #if defined(MBEDTLS_PLATFORM_C) 00033 #include "mbedtls/platform.h" 00034 #else 00035 #include <stdlib.h> 00036 #define mbedtls_calloc calloc 00037 #define mbedtls_free free 00038 #endif 00039 00040 #include <string.h> 00041 00042 /* Implementation that should never be optimized out by the compiler */ 00043 static void mbedtls_zeroize( void *v, size_t n ) { 00044 volatile unsigned char *p = v; while( n-- ) *p++ = 0; 00045 } 00046 00047 /* 00048 * Initialze context 00049 */ 00050 void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx ) 00051 { 00052 memset( ctx, 0, sizeof( mbedtls_ssl_ticket_context ) ); 00053 00054 #if defined(MBEDTLS_THREADING_C) 00055 mbedtls_mutex_init( &ctx->mutex ); 00056 #endif 00057 } 00058 00059 #define MAX_KEY_BYTES 32 /* 256 bits */ 00060 00061 /* 00062 * Generate/update a key 00063 */ 00064 static int ssl_ticket_gen_key( mbedtls_ssl_ticket_context *ctx, 00065 unsigned char index ) 00066 { 00067 int ret; 00068 unsigned char buf[MAX_KEY_BYTES]; 00069 mbedtls_ssl_ticket_key *key = ctx->keys + index; 00070 00071 #if defined(MBEDTLS_HAVE_TIME) 00072 key->generation_time = (uint32_t) time( NULL ); 00073 #endif 00074 00075 if( ( ret = ctx->f_rng( ctx->p_rng , key->name , sizeof( key->name ) ) ) != 0 ) 00076 return( ret ); 00077 00078 if( ( ret = ctx->f_rng( ctx->p_rng , buf, sizeof( buf ) ) ) != 0 ) 00079 return( ret ); 00080 00081 /* With GCM and CCM, same context can encrypt & decrypt */ 00082 ret = mbedtls_cipher_setkey( &key->ctx , buf, 00083 mbedtls_cipher_get_key_bitlen( &key->ctx ), 00084 MBEDTLS_ENCRYPT ); 00085 00086 mbedtls_zeroize( buf, sizeof( buf ) ); 00087 00088 return( ret ); 00089 } 00090 00091 /* 00092 * Rotate/generate keys if necessary 00093 */ 00094 static int ssl_ticket_update_keys( mbedtls_ssl_ticket_context *ctx ) 00095 { 00096 #if !defined(MBEDTLS_HAVE_TIME) 00097 ((void) ctx); 00098 #else 00099 if( ctx->ticket_lifetime != 0 ) 00100 { 00101 uint32_t current_time = (uint32_t) time( NULL ); 00102 uint32_t key_time = ctx->keys [ctx->active ].generation_time ; 00103 00104 if( current_time > key_time && 00105 current_time - key_time < ctx->ticket_lifetime ) 00106 { 00107 return( 0 ); 00108 } 00109 00110 ctx->active = 1 - ctx->active ; 00111 00112 return( ssl_ticket_gen_key( ctx, ctx->active ) ); 00113 } 00114 else 00115 #endif /* MBEDTLS_HAVE_TIME */ 00116 return( 0 ); 00117 } 00118 00119 /* 00120 * Setup context for actual use 00121 */ 00122 int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx, 00123 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, 00124 mbedtls_cipher_type_t cipher, 00125 uint32_t lifetime ) 00126 { 00127 int ret; 00128 const mbedtls_cipher_info_t *cipher_info; 00129 00130 ctx->f_rng = f_rng; 00131 ctx->p_rng = p_rng; 00132 00133 ctx->ticket_lifetime = lifetime; 00134 00135 cipher_info = mbedtls_cipher_info_from_type( cipher); 00136 if( cipher_info == NULL ) 00137 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 00138 00139 if( cipher_info->mode != MBEDTLS_MODE_GCM && 00140 cipher_info->mode != MBEDTLS_MODE_CCM ) 00141 { 00142 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 00143 } 00144 00145 if( cipher_info->key_bitlen > 8 * MAX_KEY_BYTES ) 00146 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 00147 00148 if( ( ret = mbedtls_cipher_setup( &ctx->keys [0].ctx , cipher_info ) ) != 0 || 00149 ( ret = mbedtls_cipher_setup( &ctx->keys [1].ctx , cipher_info ) ) != 0 ) 00150 { 00151 return( ret ); 00152 } 00153 00154 if( ( ret = ssl_ticket_gen_key( ctx, 0 ) ) != 0 || 00155 ( ret = ssl_ticket_gen_key( ctx, 1 ) ) != 0 ) 00156 { 00157 return( ret ); 00158 } 00159 00160 return( 0 ); 00161 } 00162 00163 /* 00164 * Serialize a session in the following format: 00165 * 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session) 00166 * n . n+2 peer_cert length = m (0 if no certificate) 00167 * n+3 . n+2+m peer cert ASN.1 00168 */ 00169 static int ssl_save_session( const mbedtls_ssl_session *session, 00170 unsigned char *buf, size_t buf_len, 00171 size_t *olen ) 00172 { 00173 unsigned char *p = buf; 00174 size_t left = buf_len; 00175 #if defined(MBEDTLS_X509_CRT_PARSE_C) 00176 size_t cert_len; 00177 #endif /* MBEDTLS_X509_CRT_PARSE_C */ 00178 00179 if( left < sizeof( mbedtls_ssl_session ) ) 00180 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); 00181 00182 memcpy( p, session, sizeof( mbedtls_ssl_session ) ); 00183 p += sizeof( mbedtls_ssl_session ); 00184 left -= sizeof( mbedtls_ssl_session ); 00185 00186 #if defined(MBEDTLS_X509_CRT_PARSE_C) 00187 if( session->peer_cert == NULL ) 00188 cert_len = 0; 00189 else 00190 cert_len = session->peer_cert->raw.len; 00191 00192 if( left < 3 + cert_len ) 00193 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); 00194 00195 *p++ = (unsigned char)( cert_len >> 16 & 0xFF ); 00196 *p++ = (unsigned char)( cert_len >> 8 & 0xFF ); 00197 *p++ = (unsigned char)( cert_len & 0xFF ); 00198 00199 if( session->peer_cert != NULL ) 00200 memcpy( p, session->peer_cert->raw.p, cert_len ); 00201 00202 p += cert_len; 00203 #endif /* MBEDTLS_X509_CRT_PARSE_C */ 00204 00205 *olen = p - buf; 00206 00207 return( 0 ); 00208 } 00209 00210 /* 00211 * Unserialise session, see ssl_save_session() 00212 */ 00213 static int ssl_load_session( mbedtls_ssl_session *session, 00214 const unsigned char *buf, size_t len ) 00215 { 00216 const unsigned char *p = buf; 00217 const unsigned char * const end = buf + len; 00218 #if defined(MBEDTLS_X509_CRT_PARSE_C) 00219 size_t cert_len; 00220 #endif /* MBEDTLS_X509_CRT_PARSE_C */ 00221 00222 if( p + sizeof( mbedtls_ssl_session ) > end ) 00223 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 00224 00225 memcpy( session, p, sizeof( mbedtls_ssl_session ) ); 00226 p += sizeof( mbedtls_ssl_session ); 00227 00228 #if defined(MBEDTLS_X509_CRT_PARSE_C) 00229 if( p + 3 > end ) 00230 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 00231 00232 cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2]; 00233 p += 3; 00234 00235 if( cert_len == 0 ) 00236 { 00237 session->peer_cert = NULL; 00238 } 00239 else 00240 { 00241 int ret; 00242 00243 if( p + cert_len > end ) 00244 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 00245 00246 session->peer_cert = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); 00247 00248 if( session->peer_cert == NULL ) 00249 return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); 00250 00251 mbedtls_x509_crt_init( session->peer_cert ); 00252 00253 if( ( ret = mbedtls_x509_crt_parse_der( session->peer_cert, 00254 p, cert_len ) ) != 0 ) 00255 { 00256 mbedtls_x509_crt_free( session->peer_cert ); 00257 mbedtls_free( session->peer_cert ); 00258 session->peer_cert = NULL; 00259 return( ret ); 00260 } 00261 00262 p += cert_len; 00263 } 00264 #endif /* MBEDTLS_X509_CRT_PARSE_C */ 00265 00266 if( p != end ) 00267 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 00268 00269 return( 0 ); 00270 } 00271 00272 /* 00273 * Create session ticket, with the following structure: 00274 * 00275 * struct { 00276 * opaque key_name[4]; 00277 * opaque iv[12]; 00278 * opaque encrypted_state<0..2^16-1>; 00279 * opaque tag[16]; 00280 * } ticket; 00281 * 00282 * The key_name, iv, and length of encrypted_state are the additional 00283 * authenticated data. 00284 */ 00285 int mbedtls_ssl_ticket_write( void *p_ticket, 00286 const mbedtls_ssl_session *session, 00287 unsigned char *start, 00288 const unsigned char *end, 00289 size_t *tlen, 00290 uint32_t *ticket_lifetime ) 00291 { 00292 int ret; 00293 mbedtls_ssl_ticket_context *ctx = p_ticket; 00294 mbedtls_ssl_ticket_key *key; 00295 unsigned char *key_name = start; 00296 unsigned char *iv = start + 4; 00297 unsigned char *state_len_bytes = iv + 12; 00298 unsigned char *state = state_len_bytes + 2; 00299 unsigned char *tag; 00300 size_t clear_len, ciph_len; 00301 00302 *tlen = 0; 00303 00304 if( ctx == NULL || ctx->f_rng == NULL ) 00305 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 00306 00307 /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag, 00308 * in addition to session itself, that will be checked when writing it. */ 00309 if( end - start < 4 + 12 + 2 + 16 ) 00310 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); 00311 00312 #if defined(MBEDTLS_THREADING_C) 00313 if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) 00314 return( ret ); 00315 #endif 00316 00317 if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 ) 00318 goto cleanup; 00319 00320 key = &ctx->keys [ctx->active ]; 00321 00322 *ticket_lifetime = ctx->ticket_lifetime ; 00323 00324 memcpy( key_name, key->name , 4 ); 00325 00326 if( ( ret = ctx->f_rng( ctx->p_rng , iv, 12 ) ) != 0 ) 00327 goto cleanup; 00328 00329 /* Dump session state */ 00330 if( ( ret = ssl_save_session( session, 00331 state, end - state, &clear_len ) ) != 0 || 00332 (unsigned long) clear_len > 65535 ) 00333 { 00334 goto cleanup; 00335 } 00336 state_len_bytes[0] = ( clear_len >> 8 ) & 0xff; 00337 state_len_bytes[1] = ( clear_len ) & 0xff; 00338 00339 /* Encrypt and authenticate */ 00340 tag = state + clear_len; 00341 if( ( ret = mbedtls_cipher_auth_encrypt( &key->ctx , 00342 iv, 12, key_name, 4 + 12 + 2, 00343 state, clear_len, state, &ciph_len, tag, 16 ) ) != 0 ) 00344 { 00345 goto cleanup; 00346 } 00347 if( ciph_len != clear_len ) 00348 { 00349 ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; 00350 goto cleanup; 00351 } 00352 00353 *tlen = 4 + 12 + 2 + 16 + ciph_len; 00354 00355 cleanup: 00356 #if defined(MBEDTLS_THREADING_C) 00357 if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) 00358 return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); 00359 #endif 00360 00361 return( ret ); 00362 } 00363 00364 /* 00365 * Select key based on name 00366 */ 00367 static mbedtls_ssl_ticket_key *ssl_ticket_select_key( 00368 mbedtls_ssl_ticket_context *ctx, 00369 const unsigned char name[4] ) 00370 { 00371 unsigned char i; 00372 00373 for( i = 0; i < sizeof( ctx->keys ) / sizeof( *ctx->keys ); i++ ) 00374 if( memcmp( name, ctx->keys [i].name , 4 ) == 0 ) 00375 return( &ctx->keys [i] ); 00376 00377 return( NULL ); 00378 } 00379 00380 /* 00381 * Load session ticket (see mbedtls_ssl_ticket_write for structure) 00382 */ 00383 int mbedtls_ssl_ticket_parse( void *p_ticket, 00384 mbedtls_ssl_session *session, 00385 unsigned char *buf, 00386 size_t len ) 00387 { 00388 int ret; 00389 mbedtls_ssl_ticket_context *ctx = p_ticket; 00390 mbedtls_ssl_ticket_key *key; 00391 unsigned char *key_name = buf; 00392 unsigned char *iv = buf + 4; 00393 unsigned char *enc_len_p = iv + 12; 00394 unsigned char *ticket = enc_len_p + 2; 00395 unsigned char *tag; 00396 size_t enc_len, clear_len; 00397 00398 if( ctx == NULL || ctx->f_rng == NULL ) 00399 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 00400 00401 /* See mbedtls_ssl_ticket_write() */ 00402 if( len < 4 + 12 + 2 + 16 ) 00403 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 00404 00405 #if defined(MBEDTLS_THREADING_C) 00406 if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) 00407 return( ret ); 00408 #endif 00409 00410 if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 ) 00411 goto cleanup; 00412 00413 enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1]; 00414 tag = ticket + enc_len; 00415 00416 if( len != 4 + 12 + 2 + enc_len + 16 ) 00417 { 00418 ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA; 00419 goto cleanup; 00420 } 00421 00422 /* Select key */ 00423 if( ( key = ssl_ticket_select_key( ctx, key_name ) ) == NULL ) 00424 { 00425 /* We can't know for sure but this is a likely option unless we're 00426 * under attack - this is only informative anyway */ 00427 ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; 00428 goto cleanup; 00429 } 00430 00431 /* Decrypt and authenticate */ 00432 if( ( ret = mbedtls_cipher_auth_decrypt( &key->ctx , iv, 12, 00433 key_name, 4 + 12 + 2, ticket, enc_len, 00434 ticket, &clear_len, tag, 16 ) ) != 0 ) 00435 { 00436 if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED ) 00437 ret = MBEDTLS_ERR_SSL_INVALID_MAC; 00438 00439 goto cleanup; 00440 } 00441 if( clear_len != enc_len ) 00442 { 00443 ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; 00444 goto cleanup; 00445 } 00446 00447 /* Actually load session */ 00448 if( ( ret = ssl_load_session( session, ticket, clear_len ) ) != 0 ) 00449 goto cleanup; 00450 00451 #if defined(MBEDTLS_HAVE_TIME) 00452 { 00453 /* Check for expiration */ 00454 time_t current_time = time( NULL ); 00455 00456 if( current_time < session->start || 00457 (uint32_t)( current_time - session->start ) > ctx->ticket_lifetime ) 00458 { 00459 ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; 00460 goto cleanup; 00461 } 00462 } 00463 #endif 00464 00465 cleanup: 00466 #if defined(MBEDTLS_THREADING_C) 00467 if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) 00468 return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); 00469 #endif 00470 00471 return( ret ); 00472 } 00473 00474 /* 00475 * Free context 00476 */ 00477 void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx ) 00478 { 00479 mbedtls_cipher_free( &ctx->keys [0].ctx ); 00480 mbedtls_cipher_free( &ctx->keys [1].ctx ); 00481 00482 #if defined(MBEDTLS_THREADING_C) 00483 mbedtls_mutex_free( &ctx->mutex ); 00484 #endif 00485 00486 mbedtls_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) ); 00487 } 00488 00489 #endif /* MBEDTLS_SSL_TICKET_C */
Generated on Tue Jul 12 2022 12:52:48 by
