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