1 // SPDX-License-Identifier: Apache-2.0 2 /* 3 * TLS server tickets callbacks implementation 4 * 5 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 6 * 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 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 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. 18 * 19 * This file is part of mbed TLS (https://tls.mbed.org) 20 */ 21 22 #if !defined(MBEDTLS_CONFIG_FILE) 23 #include "mbedtls/config.h" 24 #else 25 #include MBEDTLS_CONFIG_FILE 26 #endif 27 28 #if defined(MBEDTLS_SSL_TICKET_C) 29 30 #if defined(MBEDTLS_PLATFORM_C) 31 #include "mbedtls/platform.h" 32 #else 33 #include <stdlib.h> 34 #define mbedtls_calloc calloc 35 #define mbedtls_free free 36 #endif 37 38 #include "mbedtls/ssl_ticket.h" 39 #include "mbedtls/platform_util.h" 40 41 #include <string.h> 42 43 /* 44 * Initialze context 45 */ 46 void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx ) 47 { 48 memset( ctx, 0, sizeof( mbedtls_ssl_ticket_context ) ); 49 50 #if defined(MBEDTLS_THREADING_C) 51 mbedtls_mutex_init( &ctx->mutex ); 52 #endif 53 } 54 55 #define MAX_KEY_BYTES 32 /* 256 bits */ 56 57 /* 58 * Generate/update a key 59 */ 60 static int ssl_ticket_gen_key( mbedtls_ssl_ticket_context *ctx, 61 unsigned char index ) 62 { 63 int ret; 64 unsigned char buf[MAX_KEY_BYTES]; 65 mbedtls_ssl_ticket_key *key = ctx->keys + index; 66 67 #if defined(MBEDTLS_HAVE_TIME) 68 key->generation_time = (uint32_t) mbedtls_time( NULL ); 69 #endif 70 71 if( ( ret = ctx->f_rng( ctx->p_rng, key->name, sizeof( key->name ) ) ) != 0 ) 72 return( ret ); 73 74 if( ( ret = ctx->f_rng( ctx->p_rng, buf, sizeof( buf ) ) ) != 0 ) 75 return( ret ); 76 77 /* With GCM and CCM, same context can encrypt & decrypt */ 78 ret = mbedtls_cipher_setkey( &key->ctx, buf, 79 mbedtls_cipher_get_key_bitlen( &key->ctx ), 80 MBEDTLS_ENCRYPT ); 81 82 mbedtls_platform_zeroize( buf, sizeof( buf ) ); 83 84 return( ret ); 85 } 86 87 /* 88 * Rotate/generate keys if necessary 89 */ 90 static int ssl_ticket_update_keys( mbedtls_ssl_ticket_context *ctx ) 91 { 92 #if !defined(MBEDTLS_HAVE_TIME) 93 ((void) ctx); 94 #else 95 if( ctx->ticket_lifetime != 0 ) 96 { 97 uint32_t current_time = (uint32_t) mbedtls_time( NULL ); 98 uint32_t key_time = ctx->keys[ctx->active].generation_time; 99 100 if( current_time >= key_time && 101 current_time - key_time < ctx->ticket_lifetime ) 102 { 103 return( 0 ); 104 } 105 106 ctx->active = 1 - ctx->active; 107 108 return( ssl_ticket_gen_key( ctx, ctx->active ) ); 109 } 110 else 111 #endif /* MBEDTLS_HAVE_TIME */ 112 return( 0 ); 113 } 114 115 /* 116 * Setup context for actual use 117 */ 118 int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx, 119 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, 120 mbedtls_cipher_type_t cipher, 121 uint32_t lifetime ) 122 { 123 int ret; 124 const mbedtls_cipher_info_t *cipher_info; 125 126 ctx->f_rng = f_rng; 127 ctx->p_rng = p_rng; 128 129 ctx->ticket_lifetime = lifetime; 130 131 cipher_info = mbedtls_cipher_info_from_type( cipher); 132 if( cipher_info == NULL ) 133 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 134 135 if( cipher_info->mode != MBEDTLS_MODE_GCM && 136 cipher_info->mode != MBEDTLS_MODE_CCM ) 137 { 138 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 139 } 140 141 if( cipher_info->key_bitlen > 8 * MAX_KEY_BYTES ) 142 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 143 144 if( ( ret = mbedtls_cipher_setup( &ctx->keys[0].ctx, cipher_info ) ) != 0 || 145 ( ret = mbedtls_cipher_setup( &ctx->keys[1].ctx, cipher_info ) ) != 0 ) 146 { 147 return( ret ); 148 } 149 150 if( ( ret = ssl_ticket_gen_key( ctx, 0 ) ) != 0 || 151 ( ret = ssl_ticket_gen_key( ctx, 1 ) ) != 0 ) 152 { 153 return( ret ); 154 } 155 156 return( 0 ); 157 } 158 159 /* 160 * Serialize a session in the following format: 161 * 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session) 162 * n . n+2 peer_cert length = m (0 if no certificate) 163 * n+3 . n+2+m peer cert ASN.1 164 */ 165 static int ssl_save_session( const mbedtls_ssl_session *session, 166 unsigned char *buf, size_t buf_len, 167 size_t *olen ) 168 { 169 unsigned char *p = buf; 170 size_t left = buf_len; 171 #if defined(MBEDTLS_X509_CRT_PARSE_C) 172 size_t cert_len; 173 #endif /* MBEDTLS_X509_CRT_PARSE_C */ 174 175 if( left < sizeof( mbedtls_ssl_session ) ) 176 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); 177 178 memcpy( p, session, sizeof( mbedtls_ssl_session ) ); 179 p += sizeof( mbedtls_ssl_session ); 180 left -= sizeof( mbedtls_ssl_session ); 181 182 #if defined(MBEDTLS_X509_CRT_PARSE_C) 183 if( session->peer_cert == NULL ) 184 cert_len = 0; 185 else 186 cert_len = session->peer_cert->raw.len; 187 188 if( left < 3 + cert_len ) 189 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); 190 191 *p++ = (unsigned char)( ( cert_len >> 16 ) & 0xFF ); 192 *p++ = (unsigned char)( ( cert_len >> 8 ) & 0xFF ); 193 *p++ = (unsigned char)( ( cert_len ) & 0xFF ); 194 195 if( session->peer_cert != NULL ) 196 memcpy( p, session->peer_cert->raw.p, cert_len ); 197 198 p += cert_len; 199 #endif /* MBEDTLS_X509_CRT_PARSE_C */ 200 201 *olen = p - buf; 202 203 return( 0 ); 204 } 205 206 /* 207 * Unserialise session, see ssl_save_session() 208 */ 209 static int ssl_load_session( mbedtls_ssl_session *session, 210 const unsigned char *buf, size_t len ) 211 { 212 const unsigned char *p = buf; 213 const unsigned char * const end = buf + len; 214 #if defined(MBEDTLS_X509_CRT_PARSE_C) 215 size_t cert_len; 216 #endif /* MBEDTLS_X509_CRT_PARSE_C */ 217 218 if( sizeof( mbedtls_ssl_session ) > (size_t)( end - p ) ) 219 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 220 221 memcpy( session, p, sizeof( mbedtls_ssl_session ) ); 222 p += sizeof( mbedtls_ssl_session ); 223 224 #if defined(MBEDTLS_X509_CRT_PARSE_C) 225 if( 3 > (size_t)( end - p ) ) 226 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 227 228 cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2]; 229 p += 3; 230 231 if( cert_len == 0 ) 232 { 233 session->peer_cert = NULL; 234 } 235 else 236 { 237 int ret; 238 239 if( cert_len > (size_t)( end - p ) ) 240 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 241 242 session->peer_cert = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); 243 244 if( session->peer_cert == NULL ) 245 return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); 246 247 mbedtls_x509_crt_init( session->peer_cert ); 248 249 if( ( ret = mbedtls_x509_crt_parse_der( session->peer_cert, 250 p, cert_len ) ) != 0 ) 251 { 252 mbedtls_x509_crt_free( session->peer_cert ); 253 mbedtls_free( session->peer_cert ); 254 session->peer_cert = NULL; 255 return( ret ); 256 } 257 258 p += cert_len; 259 } 260 #endif /* MBEDTLS_X509_CRT_PARSE_C */ 261 262 if( p != end ) 263 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 264 265 return( 0 ); 266 } 267 268 /* 269 * Create session ticket, with the following structure: 270 * 271 * struct { 272 * opaque key_name[4]; 273 * opaque iv[12]; 274 * opaque encrypted_state<0..2^16-1>; 275 * opaque tag[16]; 276 * } ticket; 277 * 278 * The key_name, iv, and length of encrypted_state are the additional 279 * authenticated data. 280 */ 281 int mbedtls_ssl_ticket_write( void *p_ticket, 282 const mbedtls_ssl_session *session, 283 unsigned char *start, 284 const unsigned char *end, 285 size_t *tlen, 286 uint32_t *ticket_lifetime ) 287 { 288 int ret; 289 mbedtls_ssl_ticket_context *ctx = p_ticket; 290 mbedtls_ssl_ticket_key *key; 291 unsigned char *key_name = start; 292 unsigned char *iv = start + 4; 293 unsigned char *state_len_bytes = iv + 12; 294 unsigned char *state = state_len_bytes + 2; 295 unsigned char *tag; 296 size_t clear_len, ciph_len; 297 298 *tlen = 0; 299 300 if( ctx == NULL || ctx->f_rng == NULL ) 301 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 302 303 /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag, 304 * in addition to session itself, that will be checked when writing it. */ 305 if( end - start < 4 + 12 + 2 + 16 ) 306 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); 307 308 #if defined(MBEDTLS_THREADING_C) 309 if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) 310 return( ret ); 311 #endif 312 313 if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 ) 314 goto cleanup; 315 316 key = &ctx->keys[ctx->active]; 317 318 *ticket_lifetime = ctx->ticket_lifetime; 319 320 memcpy( key_name, key->name, 4 ); 321 322 if( ( ret = ctx->f_rng( ctx->p_rng, iv, 12 ) ) != 0 ) 323 goto cleanup; 324 325 /* Dump session state */ 326 if( ( ret = ssl_save_session( session, 327 state, end - state, &clear_len ) ) != 0 || 328 (unsigned long) clear_len > 65535 ) 329 { 330 goto cleanup; 331 } 332 state_len_bytes[0] = ( clear_len >> 8 ) & 0xff; 333 state_len_bytes[1] = ( clear_len ) & 0xff; 334 335 /* Encrypt and authenticate */ 336 tag = state + clear_len; 337 if( ( ret = mbedtls_cipher_auth_encrypt( &key->ctx, 338 iv, 12, key_name, 4 + 12 + 2, 339 state, clear_len, state, &ciph_len, tag, 16 ) ) != 0 ) 340 { 341 goto cleanup; 342 } 343 if( ciph_len != clear_len ) 344 { 345 ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; 346 goto cleanup; 347 } 348 349 *tlen = 4 + 12 + 2 + 16 + ciph_len; 350 351 cleanup: 352 #if defined(MBEDTLS_THREADING_C) 353 if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) 354 return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); 355 #endif 356 357 return( ret ); 358 } 359 360 /* 361 * Select key based on name 362 */ 363 static mbedtls_ssl_ticket_key *ssl_ticket_select_key( 364 mbedtls_ssl_ticket_context *ctx, 365 const unsigned char name[4] ) 366 { 367 unsigned char i; 368 369 for( i = 0; i < sizeof( ctx->keys ) / sizeof( *ctx->keys ); i++ ) 370 if( memcmp( name, ctx->keys[i].name, 4 ) == 0 ) 371 return( &ctx->keys[i] ); 372 373 return( NULL ); 374 } 375 376 /* 377 * Load session ticket (see mbedtls_ssl_ticket_write for structure) 378 */ 379 int mbedtls_ssl_ticket_parse( void *p_ticket, 380 mbedtls_ssl_session *session, 381 unsigned char *buf, 382 size_t len ) 383 { 384 int ret; 385 mbedtls_ssl_ticket_context *ctx = p_ticket; 386 mbedtls_ssl_ticket_key *key; 387 unsigned char *key_name = buf; 388 unsigned char *iv = buf + 4; 389 unsigned char *enc_len_p = iv + 12; 390 unsigned char *ticket = enc_len_p + 2; 391 unsigned char *tag; 392 size_t enc_len, clear_len; 393 394 if( ctx == NULL || ctx->f_rng == NULL ) 395 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 396 397 /* See mbedtls_ssl_ticket_write() */ 398 if( len < 4 + 12 + 2 + 16 ) 399 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); 400 401 #if defined(MBEDTLS_THREADING_C) 402 if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) 403 return( ret ); 404 #endif 405 406 if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 ) 407 goto cleanup; 408 409 enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1]; 410 tag = ticket + enc_len; 411 412 if( len != 4 + 12 + 2 + enc_len + 16 ) 413 { 414 ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA; 415 goto cleanup; 416 } 417 418 /* Select key */ 419 if( ( key = ssl_ticket_select_key( ctx, key_name ) ) == NULL ) 420 { 421 /* We can't know for sure but this is a likely option unless we're 422 * under attack - this is only informative anyway */ 423 ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; 424 goto cleanup; 425 } 426 427 /* Decrypt and authenticate */ 428 if( ( ret = mbedtls_cipher_auth_decrypt( &key->ctx, iv, 12, 429 key_name, 4 + 12 + 2, ticket, enc_len, 430 ticket, &clear_len, tag, 16 ) ) != 0 ) 431 { 432 if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED ) 433 ret = MBEDTLS_ERR_SSL_INVALID_MAC; 434 435 goto cleanup; 436 } 437 if( clear_len != enc_len ) 438 { 439 ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; 440 goto cleanup; 441 } 442 443 /* Actually load session */ 444 if( ( ret = ssl_load_session( session, ticket, clear_len ) ) != 0 ) 445 goto cleanup; 446 447 #if defined(MBEDTLS_HAVE_TIME) 448 { 449 /* Check for expiration */ 450 mbedtls_time_t current_time = mbedtls_time( NULL ); 451 452 if( current_time < session->start || 453 (uint32_t)( current_time - session->start ) > ctx->ticket_lifetime ) 454 { 455 ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; 456 goto cleanup; 457 } 458 } 459 #endif 460 461 cleanup: 462 #if defined(MBEDTLS_THREADING_C) 463 if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) 464 return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); 465 #endif 466 467 return( ret ); 468 } 469 470 /* 471 * Free context 472 */ 473 void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx ) 474 { 475 mbedtls_cipher_free( &ctx->keys[0].ctx ); 476 mbedtls_cipher_free( &ctx->keys[1].ctx ); 477 478 #if defined(MBEDTLS_THREADING_C) 479 mbedtls_mutex_free( &ctx->mutex ); 480 #endif 481 482 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) ); 483 } 484 485 #endif /* MBEDTLS_SSL_TICKET_C */ 486