1
7
8
9
10
11
12
20
21
22
31
32
33
36
44
45
46
47
48
49
50
51
52
56
59
60
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
81
82
83
86
87
90
91
92
93
94
95
96
97
98
99
100
101
102
103
107
108
109
110
111
112
113
114
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
136
137
138
139
140
144
145
146
147
148
149
150
151
154
155
156
157
158
159
160
161
162
163
164
167
168
169
170
171
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
193
194
199
200
201
202
203
204
205
206
207
208
209
210
211
214
215
216
217
218
219
220
221
222
223
225
226
227
228
229
230
239
248
249
250
253
254
255
256
257
258
259
260
267
268
276
277
278
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
324
325
327
328
329
330
334
335
338
339
340
341
342
343
344
345
348
349
350
351
352
353
356
357
358
359
360
369
370
371
372
373
374
375
378
379
380
384
385
386
387
388
389
393
394
395
396
397
400
401
402
403
404
405
406
411
412
413
414
415
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
439
440
443
444
445
449
450
453
454
455
456
460
461
462
468
469
470
471
479
480
481
482
483
484
485
492
493
494
498
499
500
503
504
505
506
507
508
509
510
511
514
515
516
520
521
522
523
524
528
529
530
531
532
535
536
537
540
541
542
544
545
547
548
549
550
551
552
553
554
555
556
/* ... */
#include "common.h"
#if defined(MBEDTLS_SSL_TICKET_C)
#include "mbedtls/platform.h"
#include "ssl_misc.h"
#include "mbedtls/ssl_ticket.h"
#include "mbedtls/error.h"
#include "mbedtls/platform_util.h"
#include <string.h>6 includes
#if defined(MBEDTLS_USE_PSA_CRYPTO)
/* ... */
static int local_err_translation(psa_status_t status)
{
return psa_status_to_mbedtls(status, psa_to_ssl_errors,
ARRAY_LENGTH(psa_to_ssl_errors),
psa_generic_status_to_mbedtls);
}{...}
#define PSA_TO_MBEDTLS_ERR(status) local_err_translation(status)/* ... */
#endif
/* ... */
void mbedtls_ssl_ticket_init(mbedtls_ssl_ticket_context *ctx)
{
memset(ctx, 0, sizeof(mbedtls_ssl_ticket_context));
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_init(&ctx->mutex);
#endif
}{ ... }
#define MAX_KEY_BYTES MBEDTLS_SSL_TICKET_MAX_KEY_BYTES
#define TICKET_KEY_NAME_BYTES MBEDTLS_SSL_TICKET_KEY_NAME_BYTES
#define TICKET_IV_BYTES 12
#define TICKET_CRYPT_LEN_BYTES 2
#define TICKET_AUTH_TAG_BYTES 16
#define TICKET_MIN_LEN (TICKET_KEY_NAME_BYTES + \
TICKET_IV_BYTES + \
TICKET_CRYPT_LEN_BYTES + \
TICKET_AUTH_TAG_BYTES)...
#define TICKET_ADD_DATA_LEN (TICKET_KEY_NAME_BYTES + \
TICKET_IV_BYTES + \
TICKET_CRYPT_LEN_BYTES)...
7 defines
/* ... */
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_ticket_gen_key(mbedtls_ssl_ticket_context *ctx,
unsigned char index)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char buf[MAX_KEY_BYTES] = { 0 };
mbedtls_ssl_ticket_key *key = ctx->keys + index;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
#endif
#if defined(MBEDTLS_HAVE_TIME)
key->generation_time = mbedtls_time(NULL);
#endif
/* ... */
key->lifetime = ctx->ticket_lifetime;
if ((ret = ctx->f_rng(ctx->p_rng, key->name, sizeof(key->name))) != 0) {
return ret;
}{...}
if ((ret = ctx->f_rng(ctx->p_rng, buf, sizeof(buf))) != 0) {
return ret;
}{...}
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_set_key_usage_flags(&attributes,
PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
psa_set_key_algorithm(&attributes, key->alg);
psa_set_key_type(&attributes, key->key_type);
psa_set_key_bits(&attributes, key->key_bits);
ret = PSA_TO_MBEDTLS_ERR(
psa_import_key(&attributes, buf,
PSA_BITS_TO_BYTES(key->key_bits),
&key->key));/* ... */
#else
ret = mbedtls_cipher_setkey(&key->ctx, buf,
mbedtls_cipher_get_key_bitlen(&key->ctx),
MBEDTLS_ENCRYPT);/* ... */
#endif
mbedtls_platform_zeroize(buf, sizeof(buf));
return ret;
}{ ... }
/* ... */
MBEDTLS_CHECK_RETURN_CRITICAL
static int ssl_ticket_update_keys(mbedtls_ssl_ticket_context *ctx)
{
#if !defined(MBEDTLS_HAVE_TIME)
((void) ctx);
#else
mbedtls_ssl_ticket_key * const key = ctx->keys + ctx->active;
if (key->lifetime != 0) {
mbedtls_time_t current_time = mbedtls_time(NULL);
mbedtls_time_t key_time = key->generation_time;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
#endif
if (current_time >= key_time &&
(uint64_t) (current_time - key_time) < key->lifetime) {
return 0;
}{...}
ctx->active = 1 - ctx->active;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
if ((status = psa_destroy_key(ctx->keys[ctx->active].key)) != PSA_SUCCESS) {
return PSA_TO_MBEDTLS_ERR(status);
}{...}
#endif/* ... */
return ssl_ticket_gen_key(ctx, ctx->active);
}{...} else/* ... */
#endif
return 0;
}{ ... }
/* ... */
int mbedtls_ssl_ticket_rotate(mbedtls_ssl_ticket_context *ctx,
const unsigned char *name, size_t nlength,
const unsigned char *k, size_t klength,
uint32_t lifetime)
{
const unsigned char idx = 1 - ctx->active;
mbedtls_ssl_ticket_key * const key = ctx->keys + idx;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
const size_t bitlen = key->key_bits;/* ... */
#else
const int bitlen = mbedtls_cipher_get_key_bitlen(&key->ctx);
#endif
if (nlength < TICKET_KEY_NAME_BYTES || klength * 8 < (size_t) bitlen) {
return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
}{...}
#if defined(MBEDTLS_USE_PSA_CRYPTO)
if ((status = psa_destroy_key(key->key)) != PSA_SUCCESS) {
ret = PSA_TO_MBEDTLS_ERR(status);
return ret;
}{...}
psa_set_key_usage_flags(&attributes,
PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
psa_set_key_algorithm(&attributes, key->alg);
psa_set_key_type(&attributes, key->key_type);
psa_set_key_bits(&attributes, key->key_bits);
if ((status = psa_import_key(&attributes, k,
PSA_BITS_TO_BYTES(key->key_bits),
&key->key)) != PSA_SUCCESS) {
ret = PSA_TO_MBEDTLS_ERR(status);
return ret;
}{...}
#else/* ... */
ret = mbedtls_cipher_setkey(&key->ctx, k, bitlen, MBEDTLS_ENCRYPT);
if (ret != 0) {
return ret;
}{...}
#endif/* ... */
ctx->active = idx;
ctx->ticket_lifetime = lifetime;
memcpy(key->name, name, TICKET_KEY_NAME_BYTES);
#if defined(MBEDTLS_HAVE_TIME)
key->generation_time = mbedtls_time(NULL);
#endif
key->lifetime = lifetime;
return 0;
}{ ... }
/* ... */
int mbedtls_ssl_ticket_setup(mbedtls_ssl_ticket_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
mbedtls_cipher_type_t cipher,
uint32_t lifetime)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t key_bits;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_algorithm_t alg;
psa_key_type_t key_type;/* ... */
#else
const mbedtls_cipher_info_t *cipher_info;
#endif
#if defined(MBEDTLS_USE_PSA_CRYPTO)
if (mbedtls_ssl_cipher_to_psa(cipher, TICKET_AUTH_TAG_BYTES,
&alg, &key_type, &key_bits) != PSA_SUCCESS) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}{...}
if (PSA_ALG_IS_AEAD(alg) == 0) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}{...}
#else/* ... */
cipher_info = mbedtls_cipher_info_from_type(cipher);
if (mbedtls_cipher_info_get_mode(cipher_info) != MBEDTLS_MODE_GCM &&
mbedtls_cipher_info_get_mode(cipher_info) != MBEDTLS_MODE_CCM &&
mbedtls_cipher_info_get_mode(cipher_info) != MBEDTLS_MODE_CHACHAPOLY) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}{...}
key_bits = mbedtls_cipher_info_get_key_bitlen(cipher_info);/* ... */
#endif
if (key_bits > 8 * MAX_KEY_BYTES) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}{...}
ctx->f_rng = f_rng;
ctx->p_rng = p_rng;
ctx->ticket_lifetime = lifetime;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
ctx->keys[0].alg = alg;
ctx->keys[0].key_type = key_type;
ctx->keys[0].key_bits = key_bits;
ctx->keys[1].alg = alg;
ctx->keys[1].key_type = key_type;
ctx->keys[1].key_bits = key_bits;/* ... */
#else
if ((ret = mbedtls_cipher_setup(&ctx->keys[0].ctx, cipher_info)) != 0) {
return ret;
}{...}
if ((ret = mbedtls_cipher_setup(&ctx->keys[1].ctx, cipher_info)) != 0) {
return ret;
}{...}
#endif/* ... */
if ((ret = ssl_ticket_gen_key(ctx, 0)) != 0 ||
(ret = ssl_ticket_gen_key(ctx, 1)) != 0) {
return ret;
}{...}
return 0;
}{ ... }
/* ... */
int mbedtls_ssl_ticket_write(void *p_ticket,
const mbedtls_ssl_session *session,
unsigned char *start,
const unsigned char *end,
size_t *tlen,
uint32_t *ticket_lifetime)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_ssl_ticket_context *ctx = p_ticket;
mbedtls_ssl_ticket_key *key;
unsigned char *key_name = start;
unsigned char *iv = start + TICKET_KEY_NAME_BYTES;
unsigned char *state_len_bytes = iv + TICKET_IV_BYTES;
unsigned char *state = state_len_bytes + TICKET_CRYPT_LEN_BYTES;
size_t clear_len, ciph_len;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
#endif
*tlen = 0;
if (ctx == NULL || ctx->f_rng == NULL) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}{...}
/* ... */
MBEDTLS_SSL_CHK_BUF_PTR(start, end, TICKET_MIN_LEN);
#if defined(MBEDTLS_THREADING_C)
if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) {
return ret;
}{...}
#endif/* ... */
if ((ret = ssl_ticket_update_keys(ctx)) != 0) {
goto cleanup;
}{...}
key = &ctx->keys[ctx->active];
*ticket_lifetime = key->lifetime;
memcpy(key_name, key->name, TICKET_KEY_NAME_BYTES);
if ((ret = ctx->f_rng(ctx->p_rng, iv, TICKET_IV_BYTES)) != 0) {
goto cleanup;
}{...}
if ((ret = mbedtls_ssl_session_save(session,
state, (size_t) (end - state),
&clear_len)) != 0 ||
(unsigned long) clear_len > 65535) {
goto cleanup;
}{...}
MBEDTLS_PUT_UINT16_BE(clear_len, state_len_bytes, 0);
#if defined(MBEDTLS_USE_PSA_CRYPTO)
if ((status = psa_aead_encrypt(key->key, key->alg, iv, TICKET_IV_BYTES,
key_name, TICKET_ADD_DATA_LEN,
state, clear_len,
state, end - state,
&ciph_len)) != PSA_SUCCESS) {
ret = PSA_TO_MBEDTLS_ERR(status);
goto cleanup;
}{...}
#else/* ... */
if ((ret = mbedtls_cipher_auth_encrypt_ext(&key->ctx,
iv, TICKET_IV_BYTES,
key_name, TICKET_ADD_DATA_LEN,
state, clear_len,
state, (size_t) (end - state), &ciph_len,
TICKET_AUTH_TAG_BYTES)) != 0) {
goto cleanup;
}{...}
#endif/* ... */
if (ciph_len != clear_len + TICKET_AUTH_TAG_BYTES) {
ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
goto cleanup;
}{...}
*tlen = TICKET_MIN_LEN + ciph_len - TICKET_AUTH_TAG_BYTES;
cleanup:
#if defined(MBEDTLS_THREADING_C)
if (mbedtls_mutex_unlock(&ctx->mutex) != 0) {
return MBEDTLS_ERR_THREADING_MUTEX_ERROR;
}{...}
#endif/* ... */
return ret;
}{ ... }
/* ... */
static mbedtls_ssl_ticket_key *ssl_ticket_select_key(
mbedtls_ssl_ticket_context *ctx,
const unsigned char name[4])
{
unsigned char i;
for (i = 0; i < sizeof(ctx->keys) / sizeof(*ctx->keys); i++) {
if (memcmp(name, ctx->keys[i].name, 4) == 0) {
return &ctx->keys[i];
}{...}
}{...}
return NULL;
}{ ... }
/* ... */
int mbedtls_ssl_ticket_parse(void *p_ticket,
mbedtls_ssl_session *session,
unsigned char *buf,
size_t len)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_ssl_ticket_context *ctx = p_ticket;
mbedtls_ssl_ticket_key *key;
unsigned char *key_name = buf;
unsigned char *iv = buf + TICKET_KEY_NAME_BYTES;
unsigned char *enc_len_p = iv + TICKET_IV_BYTES;
unsigned char *ticket = enc_len_p + TICKET_CRYPT_LEN_BYTES;
size_t enc_len, clear_len;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
#endif
if (ctx == NULL || ctx->f_rng == NULL) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}{...}
if (len < TICKET_MIN_LEN) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}{...}
#if defined(MBEDTLS_THREADING_C)
if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) {
return ret;
}{...}
#endif/* ... */
if ((ret = ssl_ticket_update_keys(ctx)) != 0) {
goto cleanup;
}{...}
enc_len = MBEDTLS_GET_UINT16_BE(enc_len_p, 0);
if (len != TICKET_MIN_LEN + enc_len) {
ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
goto cleanup;
}{...}
if ((key = ssl_ticket_select_key(ctx, key_name)) == NULL) {
/* ... */
ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
goto cleanup;
}{...}
#if defined(MBEDTLS_USE_PSA_CRYPTO)
if ((status = psa_aead_decrypt(key->key, key->alg, iv, TICKET_IV_BYTES,
key_name, TICKET_ADD_DATA_LEN,
ticket, enc_len + TICKET_AUTH_TAG_BYTES,
ticket, enc_len, &clear_len)) != PSA_SUCCESS) {
ret = PSA_TO_MBEDTLS_ERR(status);
goto cleanup;
}{...}
#else/* ... */
if ((ret = mbedtls_cipher_auth_decrypt_ext(&key->ctx,
iv, TICKET_IV_BYTES,
key_name, TICKET_ADD_DATA_LEN,
ticket, enc_len + TICKET_AUTH_TAG_BYTES,
ticket, enc_len, &clear_len,
TICKET_AUTH_TAG_BYTES)) != 0) {
if (ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED) {
ret = MBEDTLS_ERR_SSL_INVALID_MAC;
}{...}
goto cleanup;
}{...}
#endif/* ... */
if (clear_len != enc_len) {
ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
goto cleanup;
}{...}
if ((ret = mbedtls_ssl_session_load(session, ticket, clear_len)) != 0) {
goto cleanup;
}{...}
#if defined(MBEDTLS_HAVE_TIME)
mbedtls_ms_time_t ticket_creation_time, ticket_age;
mbedtls_ms_time_t ticket_lifetime =
(mbedtls_ms_time_t) key->lifetime * 1000;
ret = mbedtls_ssl_session_get_ticket_creation_time(session,
&ticket_creation_time);
if (ret != 0) {
goto cleanup;
}{...}
ticket_age = mbedtls_ms_time() - ticket_creation_time;
if (ticket_age < 0 || ticket_age > ticket_lifetime) {
ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
goto cleanup;
}{...}
/* ... */#endif
cleanup:
#if defined(MBEDTLS_THREADING_C)
if (mbedtls_mutex_unlock(&ctx->mutex) != 0) {
return MBEDTLS_ERR_THREADING_MUTEX_ERROR;
}{...}
#endif/* ... */
return ret;
}{ ... }
/* ... */
void mbedtls_ssl_ticket_free(mbedtls_ssl_ticket_context *ctx)
{
if (ctx == NULL) {
return;
}{...}
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_destroy_key(ctx->keys[0].key);
psa_destroy_key(ctx->keys[1].key);/* ... */
#else
mbedtls_cipher_free(&ctx->keys[0].ctx);
mbedtls_cipher_free(&ctx->keys[1].ctx);/* ... */
#endif
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_free(&ctx->mutex);
#endif
mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ssl_ticket_context));
}{ ... }
/* ... */#endif