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