1/* 2 * TLS server tickets callbacks implementation 3 * 4 * Copyright The Mbed TLS Contributors 5 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 6 */ 7 8#include "common.h" 9 10#if defined(MBEDTLS_SSL_TICKET_C) 11 12#include "mbedtls/platform.h" 13 14#include "ssl_misc.h" 15#include "mbedtls/ssl_ticket.h" 16#include "mbedtls/error.h" 17#include "mbedtls/platform_util.h" 18 19#include <string.h> 20 21#if defined(MBEDTLS_USE_PSA_CRYPTO) 22/* Define a local translating function to save code size by not using too many 23 * arguments in each translating place. */ 24static int local_err_translation(psa_status_t status) 25{ 26 return psa_status_to_mbedtls(status, psa_to_ssl_errors, 27 ARRAY_LENGTH(psa_to_ssl_errors), 28 psa_generic_status_to_mbedtls); 29} 30#define PSA_TO_MBEDTLS_ERR(status) local_err_translation(status) 31#endif 32 33/* 34 * Initialize context 35 */ 36void mbedtls_ssl_ticket_init(mbedtls_ssl_ticket_context *ctx) 37{ 38 memset(ctx, 0, sizeof(mbedtls_ssl_ticket_context)); 39 40#if defined(MBEDTLS_THREADING_C) 41 mbedtls_mutex_init(&ctx->mutex); 42#endif 43} 44 45#define MAX_KEY_BYTES MBEDTLS_SSL_TICKET_MAX_KEY_BYTES 46 47#define TICKET_KEY_NAME_BYTES MBEDTLS_SSL_TICKET_KEY_NAME_BYTES 48#define TICKET_IV_BYTES 12 49#define TICKET_CRYPT_LEN_BYTES 2 50#define TICKET_AUTH_TAG_BYTES 16 51 52#define TICKET_MIN_LEN (TICKET_KEY_NAME_BYTES + \ 53 TICKET_IV_BYTES + \ 54 TICKET_CRYPT_LEN_BYTES + \ 55 TICKET_AUTH_TAG_BYTES) 56#define TICKET_ADD_DATA_LEN (TICKET_KEY_NAME_BYTES + \ 57 TICKET_IV_BYTES + \ 58 TICKET_CRYPT_LEN_BYTES) 59 60/* 61 * Generate/update a key 62 */ 63MBEDTLS_CHECK_RETURN_CRITICAL 64static int ssl_ticket_gen_key(mbedtls_ssl_ticket_context *ctx, 65 unsigned char index) 66{ 67 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 68 unsigned char buf[MAX_KEY_BYTES] = { 0 }; 69 mbedtls_ssl_ticket_key *key = ctx->keys + index; 70 71#if defined(MBEDTLS_USE_PSA_CRYPTO) 72 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 73#endif 74 75#if defined(MBEDTLS_HAVE_TIME) 76 key->generation_time = mbedtls_time(NULL); 77#endif 78 /* The lifetime of a key is the configured lifetime of the tickets when 79 * the key is created. 80 */ 81 key->lifetime = ctx->ticket_lifetime; 82 83 if ((ret = ctx->f_rng(ctx->p_rng, key->name, sizeof(key->name))) != 0) { 84 return ret; 85 } 86 87 if ((ret = ctx->f_rng(ctx->p_rng, buf, sizeof(buf))) != 0) { 88 return ret; 89 } 90 91#if defined(MBEDTLS_USE_PSA_CRYPTO) 92 psa_set_key_usage_flags(&attributes, 93 PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); 94 psa_set_key_algorithm(&attributes, key->alg); 95 psa_set_key_type(&attributes, key->key_type); 96 psa_set_key_bits(&attributes, key->key_bits); 97 98 ret = PSA_TO_MBEDTLS_ERR( 99 psa_import_key(&attributes, buf, 100 PSA_BITS_TO_BYTES(key->key_bits), 101 &key->key)); 102#else 103 /* With GCM and CCM, same context can encrypt & decrypt */ 104 ret = mbedtls_cipher_setkey(&key->ctx, buf, 105 mbedtls_cipher_get_key_bitlen(&key->ctx), 106 MBEDTLS_ENCRYPT); 107#endif /* MBEDTLS_USE_PSA_CRYPTO */ 108 109 mbedtls_platform_zeroize(buf, sizeof(buf)); 110 111 return ret; 112} 113 114/* 115 * Rotate/generate keys if necessary 116 */ 117MBEDTLS_CHECK_RETURN_CRITICAL 118static int ssl_ticket_update_keys(mbedtls_ssl_ticket_context *ctx) 119{ 120#if !defined(MBEDTLS_HAVE_TIME) 121 ((void) ctx); 122#else 123 mbedtls_ssl_ticket_key * const key = ctx->keys + ctx->active; 124 if (key->lifetime != 0) { 125 mbedtls_time_t current_time = mbedtls_time(NULL); 126 mbedtls_time_t key_time = key->generation_time; 127 128#if defined(MBEDTLS_USE_PSA_CRYPTO) 129 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; 130#endif 131 132 if (current_time >= key_time && 133 (uint64_t) (current_time - key_time) < key->lifetime) { 134 return 0; 135 } 136 137 ctx->active = 1 - ctx->active; 138 139#if defined(MBEDTLS_USE_PSA_CRYPTO) 140 if ((status = psa_destroy_key(ctx->keys[ctx->active].key)) != PSA_SUCCESS) { 141 return PSA_TO_MBEDTLS_ERR(status); 142 } 143#endif /* MBEDTLS_USE_PSA_CRYPTO */ 144 145 return ssl_ticket_gen_key(ctx, ctx->active); 146 } else 147#endif /* MBEDTLS_HAVE_TIME */ 148 return 0; 149} 150 151/* 152 * Rotate active session ticket encryption key 153 */ 154int mbedtls_ssl_ticket_rotate(mbedtls_ssl_ticket_context *ctx, 155 const unsigned char *name, size_t nlength, 156 const unsigned char *k, size_t klength, 157 uint32_t lifetime) 158{ 159 const unsigned char idx = 1 - ctx->active; 160 mbedtls_ssl_ticket_key * const key = ctx->keys + idx; 161 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 162 163#if defined(MBEDTLS_USE_PSA_CRYPTO) 164 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; 165 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 166 const size_t bitlen = key->key_bits; 167#else 168 const int bitlen = mbedtls_cipher_get_key_bitlen(&key->ctx); 169#endif 170 171 if (nlength < TICKET_KEY_NAME_BYTES || klength * 8 < (size_t) bitlen) { 172 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; 173 } 174 175#if defined(MBEDTLS_USE_PSA_CRYPTO) 176 if ((status = psa_destroy_key(key->key)) != PSA_SUCCESS) { 177 ret = PSA_TO_MBEDTLS_ERR(status); 178 return ret; 179 } 180 181 psa_set_key_usage_flags(&attributes, 182 PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); 183 psa_set_key_algorithm(&attributes, key->alg); 184 psa_set_key_type(&attributes, key->key_type); 185 psa_set_key_bits(&attributes, key->key_bits); 186 187 if ((status = psa_import_key(&attributes, k, 188 PSA_BITS_TO_BYTES(key->key_bits), 189 &key->key)) != PSA_SUCCESS) { 190 ret = PSA_TO_MBEDTLS_ERR(status); 191 return ret; 192 } 193#else 194 ret = mbedtls_cipher_setkey(&key->ctx, k, bitlen, MBEDTLS_ENCRYPT); 195 if (ret != 0) { 196 return ret; 197 } 198#endif /* MBEDTLS_USE_PSA_CRYPTO */ 199 200 ctx->active = idx; 201 ctx->ticket_lifetime = lifetime; 202 memcpy(key->name, name, TICKET_KEY_NAME_BYTES); 203#if defined(MBEDTLS_HAVE_TIME) 204 key->generation_time = mbedtls_time(NULL); 205#endif 206 key->lifetime = lifetime; 207 208 return 0; 209} 210 211/* 212 * Setup context for actual use 213 */ 214int mbedtls_ssl_ticket_setup(mbedtls_ssl_ticket_context *ctx, 215 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, 216 mbedtls_cipher_type_t cipher, 217 uint32_t lifetime) 218{ 219 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 220 size_t key_bits; 221 222#if defined(MBEDTLS_USE_PSA_CRYPTO) 223 psa_algorithm_t alg; 224 psa_key_type_t key_type; 225#else 226 const mbedtls_cipher_info_t *cipher_info; 227#endif /* MBEDTLS_USE_PSA_CRYPTO */ 228 229#if defined(MBEDTLS_USE_PSA_CRYPTO) 230 if (mbedtls_ssl_cipher_to_psa(cipher, TICKET_AUTH_TAG_BYTES, 231 &alg, &key_type, &key_bits) != PSA_SUCCESS) { 232 return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; 233 } 234 235 if (PSA_ALG_IS_AEAD(alg) == 0) { 236 return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; 237 } 238#else 239 cipher_info = mbedtls_cipher_info_from_type(cipher); 240 241 if (mbedtls_cipher_info_get_mode(cipher_info) != MBEDTLS_MODE_GCM && 242 mbedtls_cipher_info_get_mode(cipher_info) != MBEDTLS_MODE_CCM && 243 mbedtls_cipher_info_get_mode(cipher_info) != MBEDTLS_MODE_CHACHAPOLY) { 244 return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; 245 } 246 247 key_bits = mbedtls_cipher_info_get_key_bitlen(cipher_info); 248#endif /* MBEDTLS_USE_PSA_CRYPTO */ 249 250 if (key_bits > 8 * MAX_KEY_BYTES) { 251 return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; 252 } 253 254 ctx->f_rng = f_rng; 255 ctx->p_rng = p_rng; 256 257 ctx->ticket_lifetime = lifetime; 258 259#if defined(MBEDTLS_USE_PSA_CRYPTO) 260 ctx->keys[0].alg = alg; 261 ctx->keys[0].key_type = key_type; 262 ctx->keys[0].key_bits = key_bits; 263 264 ctx->keys[1].alg = alg; 265 ctx->keys[1].key_type = key_type; 266 ctx->keys[1].key_bits = key_bits; 267#else 268 if ((ret = mbedtls_cipher_setup(&ctx->keys[0].ctx, cipher_info)) != 0) { 269 return ret; 270 } 271 272 if ((ret = mbedtls_cipher_setup(&ctx->keys[1].ctx, cipher_info)) != 0) { 273 return ret; 274 } 275#endif /* MBEDTLS_USE_PSA_CRYPTO */ 276 277 if ((ret = ssl_ticket_gen_key(ctx, 0)) != 0 || 278 (ret = ssl_ticket_gen_key(ctx, 1)) != 0) { 279 return ret; 280 } 281 282 return 0; 283} 284 285/* 286 * Create session ticket, with the following structure: 287 * 288 * struct { 289 * opaque key_name[4]; 290 * opaque iv[12]; 291 * opaque encrypted_state<0..2^16-1>; 292 * opaque tag[16]; 293 * } ticket; 294 * 295 * The key_name, iv, and length of encrypted_state are the additional 296 * authenticated data. 297 */ 298 299int mbedtls_ssl_ticket_write(void *p_ticket, 300 const mbedtls_ssl_session *session, 301 unsigned char *start, 302 const unsigned char *end, 303 size_t *tlen, 304 uint32_t *ticket_lifetime) 305{ 306 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 307 mbedtls_ssl_ticket_context *ctx = p_ticket; 308 mbedtls_ssl_ticket_key *key; 309 unsigned char *key_name = start; 310 unsigned char *iv = start + TICKET_KEY_NAME_BYTES; 311 unsigned char *state_len_bytes = iv + TICKET_IV_BYTES; 312 unsigned char *state = state_len_bytes + TICKET_CRYPT_LEN_BYTES; 313 size_t clear_len, ciph_len; 314 315#if defined(MBEDTLS_USE_PSA_CRYPTO) 316 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; 317#endif 318 319 *tlen = 0; 320 321 if (ctx == NULL || ctx->f_rng == NULL) { 322 return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; 323 } 324 325 /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag, 326 * in addition to session itself, that will be checked when writing it. */ 327 MBEDTLS_SSL_CHK_BUF_PTR(start, end, TICKET_MIN_LEN); 328 329#if defined(MBEDTLS_THREADING_C) 330 if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) { 331 return ret; 332 } 333#endif 334 335 if ((ret = ssl_ticket_update_keys(ctx)) != 0) { 336 goto cleanup; 337 } 338 339 key = &ctx->keys[ctx->active]; 340 341 *ticket_lifetime = key->lifetime; 342 343 memcpy(key_name, key->name, TICKET_KEY_NAME_BYTES); 344 345 if ((ret = ctx->f_rng(ctx->p_rng, iv, TICKET_IV_BYTES)) != 0) { 346 goto cleanup; 347 } 348 349 /* Dump session state */ 350 if ((ret = mbedtls_ssl_session_save(session, 351 state, (size_t) (end - state), 352 &clear_len)) != 0 || 353 (unsigned long) clear_len > 65535) { 354 goto cleanup; 355 } 356 MBEDTLS_PUT_UINT16_BE(clear_len, state_len_bytes, 0); 357 358 /* Encrypt and authenticate */ 359#if defined(MBEDTLS_USE_PSA_CRYPTO) 360 if ((status = psa_aead_encrypt(key->key, key->alg, iv, TICKET_IV_BYTES, 361 key_name, TICKET_ADD_DATA_LEN, 362 state, clear_len, 363 state, end - state, 364 &ciph_len)) != PSA_SUCCESS) { 365 ret = PSA_TO_MBEDTLS_ERR(status); 366 goto cleanup; 367 } 368#else 369 if ((ret = mbedtls_cipher_auth_encrypt_ext(&key->ctx, 370 iv, TICKET_IV_BYTES, 371 /* Additional data: key name, IV and length */ 372 key_name, TICKET_ADD_DATA_LEN, 373 state, clear_len, 374 state, (size_t) (end - state), &ciph_len, 375 TICKET_AUTH_TAG_BYTES)) != 0) { 376 goto cleanup; 377 } 378#endif /* MBEDTLS_USE_PSA_CRYPTO */ 379 380 if (ciph_len != clear_len + TICKET_AUTH_TAG_BYTES) { 381 ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; 382 goto cleanup; 383 } 384 385 *tlen = TICKET_MIN_LEN + ciph_len - TICKET_AUTH_TAG_BYTES; 386 387cleanup: 388#if defined(MBEDTLS_THREADING_C) 389 if (mbedtls_mutex_unlock(&ctx->mutex) != 0) { 390 return MBEDTLS_ERR_THREADING_MUTEX_ERROR; 391 } 392#endif 393 394 return ret; 395} 396 397/* 398 * Select key based on name 399 */ 400static mbedtls_ssl_ticket_key *ssl_ticket_select_key( 401 mbedtls_ssl_ticket_context *ctx, 402 const unsigned char name[4]) 403{ 404 unsigned char i; 405 406 for (i = 0; i < sizeof(ctx->keys) / sizeof(*ctx->keys); i++) { 407 if (memcmp(name, ctx->keys[i].name, 4) == 0) { 408 return &ctx->keys[i]; 409 } 410 } 411 412 return NULL; 413} 414 415/* 416 * Load session ticket (see mbedtls_ssl_ticket_write for structure) 417 */ 418int mbedtls_ssl_ticket_parse(void *p_ticket, 419 mbedtls_ssl_session *session, 420 unsigned char *buf, 421 size_t len) 422{ 423 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 424 mbedtls_ssl_ticket_context *ctx = p_ticket; 425 mbedtls_ssl_ticket_key *key; 426 unsigned char *key_name = buf; 427 unsigned char *iv = buf + TICKET_KEY_NAME_BYTES; 428 unsigned char *enc_len_p = iv + TICKET_IV_BYTES; 429 unsigned char *ticket = enc_len_p + TICKET_CRYPT_LEN_BYTES; 430 size_t enc_len, clear_len; 431 432#if defined(MBEDTLS_USE_PSA_CRYPTO) 433 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; 434#endif 435 436 if (ctx == NULL || ctx->f_rng == NULL) { 437 return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; 438 } 439 440 if (len < TICKET_MIN_LEN) { 441 return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; 442 } 443 444#if defined(MBEDTLS_THREADING_C) 445 if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) { 446 return ret; 447 } 448#endif 449 450 if ((ret = ssl_ticket_update_keys(ctx)) != 0) { 451 goto cleanup; 452 } 453 454 enc_len = MBEDTLS_GET_UINT16_BE(enc_len_p, 0); 455 456 if (len != TICKET_MIN_LEN + enc_len) { 457 ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA; 458 goto cleanup; 459 } 460 461 /* Select key */ 462 if ((key = ssl_ticket_select_key(ctx, key_name)) == NULL) { 463 /* We can't know for sure but this is a likely option unless we're 464 * under attack - this is only informative anyway */ 465 ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; 466 goto cleanup; 467 } 468 469 /* Decrypt and authenticate */ 470#if defined(MBEDTLS_USE_PSA_CRYPTO) 471 if ((status = psa_aead_decrypt(key->key, key->alg, iv, TICKET_IV_BYTES, 472 key_name, TICKET_ADD_DATA_LEN, 473 ticket, enc_len + TICKET_AUTH_TAG_BYTES, 474 ticket, enc_len, &clear_len)) != PSA_SUCCESS) { 475 ret = PSA_TO_MBEDTLS_ERR(status); 476 goto cleanup; 477 } 478#else 479 if ((ret = mbedtls_cipher_auth_decrypt_ext(&key->ctx, 480 iv, TICKET_IV_BYTES, 481 /* Additional data: key name, IV and length */ 482 key_name, TICKET_ADD_DATA_LEN, 483 ticket, enc_len + TICKET_AUTH_TAG_BYTES, 484 ticket, enc_len, &clear_len, 485 TICKET_AUTH_TAG_BYTES)) != 0) { 486 if (ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED) { 487 ret = MBEDTLS_ERR_SSL_INVALID_MAC; 488 } 489 490 goto cleanup; 491 } 492#endif /* MBEDTLS_USE_PSA_CRYPTO */ 493 494 if (clear_len != enc_len) { 495 ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; 496 goto cleanup; 497 } 498 499 /* Actually load session */ 500 if ((ret = mbedtls_ssl_session_load(session, ticket, clear_len)) != 0) { 501 goto cleanup; 502 } 503 504#if defined(MBEDTLS_HAVE_TIME) 505 mbedtls_ms_time_t ticket_creation_time, ticket_age; 506 mbedtls_ms_time_t ticket_lifetime = 507 (mbedtls_ms_time_t) key->lifetime * 1000; 508 509 ret = mbedtls_ssl_session_get_ticket_creation_time(session, 510 &ticket_creation_time); 511 if (ret != 0) { 512 goto cleanup; 513 } 514 515 ticket_age = mbedtls_ms_time() - ticket_creation_time; 516 if (ticket_age < 0 || ticket_age > ticket_lifetime) { 517 ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; 518 goto cleanup; 519 } 520#endif 521 522cleanup: 523#if defined(MBEDTLS_THREADING_C) 524 if (mbedtls_mutex_unlock(&ctx->mutex) != 0) { 525 return MBEDTLS_ERR_THREADING_MUTEX_ERROR; 526 } 527#endif 528 529 return ret; 530} 531 532/* 533 * Free context 534 */ 535void mbedtls_ssl_ticket_free(mbedtls_ssl_ticket_context *ctx) 536{ 537#if defined(MBEDTLS_USE_PSA_CRYPTO) 538 psa_destroy_key(ctx->keys[0].key); 539 psa_destroy_key(ctx->keys[1].key); 540#else 541 mbedtls_cipher_free(&ctx->keys[0].ctx); 542 mbedtls_cipher_free(&ctx->keys[1].ctx); 543#endif /* MBEDTLS_USE_PSA_CRYPTO */ 544 545#if defined(MBEDTLS_THREADING_C) 546 mbedtls_mutex_free(&ctx->mutex); 547#endif 548 549 mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ssl_ticket_context)); 550} 551 552#endif /* MBEDTLS_SSL_TICKET_C */ 553