xref: /third_party/mbedtls/library/ssl_ticket.c (revision a8e1175b)
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