Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
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 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) mbedtls_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) mbedtls_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 mbedtls_time_t current_time = mbedtls_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 Sun Jul 17 2022 08:25:31 by 1.7.2