• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "mbedtls/ssl_internal.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 /*
22  * Initialize context
23  */
mbedtls_ssl_ticket_init(mbedtls_ssl_ticket_context * ctx)24 void mbedtls_ssl_ticket_init(mbedtls_ssl_ticket_context *ctx)
25 {
26     memset(ctx, 0, sizeof(mbedtls_ssl_ticket_context));
27 
28 #if defined(MBEDTLS_THREADING_C)
29     mbedtls_mutex_init(&ctx->mutex);
30 #endif
31 }
32 
33 #define MAX_KEY_BYTES 32    /* 256 bits */
34 
35 #define TICKET_KEY_NAME_BYTES    4
36 #define TICKET_IV_BYTES         12
37 #define TICKET_CRYPT_LEN_BYTES   2
38 #define TICKET_AUTH_TAG_BYTES   16
39 
40 #define TICKET_MIN_LEN (TICKET_KEY_NAME_BYTES  +        \
41                         TICKET_IV_BYTES        +        \
42                         TICKET_CRYPT_LEN_BYTES +        \
43                         TICKET_AUTH_TAG_BYTES)
44 #define TICKET_ADD_DATA_LEN (TICKET_KEY_NAME_BYTES  +        \
45                              TICKET_IV_BYTES        +        \
46                              TICKET_CRYPT_LEN_BYTES)
47 
48 /*
49  * Generate/update a key
50  */
51 MBEDTLS_CHECK_RETURN_CRITICAL
ssl_ticket_gen_key(mbedtls_ssl_ticket_context * ctx,unsigned char index)52 static int ssl_ticket_gen_key(mbedtls_ssl_ticket_context *ctx,
53                               unsigned char index)
54 {
55     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
56     unsigned char buf[MAX_KEY_BYTES];
57     mbedtls_ssl_ticket_key *key = ctx->keys + index;
58 
59 #if defined(MBEDTLS_HAVE_TIME)
60     key->generation_time = (uint32_t) mbedtls_time(NULL);
61 #endif
62 
63     if ((ret = ctx->f_rng(ctx->p_rng, key->name, sizeof(key->name))) != 0) {
64         return ret;
65     }
66 
67     if ((ret = ctx->f_rng(ctx->p_rng, buf, sizeof(buf))) != 0) {
68         return ret;
69     }
70 
71     /* With GCM and CCM, same context can encrypt & decrypt */
72     ret = mbedtls_cipher_setkey(&key->ctx, buf,
73                                 mbedtls_cipher_get_key_bitlen(&key->ctx),
74                                 MBEDTLS_ENCRYPT);
75 
76     mbedtls_platform_zeroize(buf, sizeof(buf));
77 
78     return ret;
79 }
80 
81 /*
82  * Rotate/generate keys if necessary
83  */
84 MBEDTLS_CHECK_RETURN_CRITICAL
ssl_ticket_update_keys(mbedtls_ssl_ticket_context * ctx)85 static int ssl_ticket_update_keys(mbedtls_ssl_ticket_context *ctx)
86 {
87 #if !defined(MBEDTLS_HAVE_TIME)
88     ((void) ctx);
89 #else
90     if (ctx->ticket_lifetime != 0) {
91         uint32_t current_time = (uint32_t) mbedtls_time(NULL);
92         uint32_t key_time = ctx->keys[ctx->active].generation_time;
93 
94         if (current_time >= key_time &&
95             current_time - key_time < ctx->ticket_lifetime) {
96             return 0;
97         }
98 
99         ctx->active = 1 - ctx->active;
100 
101         return ssl_ticket_gen_key(ctx, ctx->active);
102     } else
103 #endif /* MBEDTLS_HAVE_TIME */
104     return 0;
105 }
106 
107 /*
108  * Setup context for actual use
109  */
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)110 int mbedtls_ssl_ticket_setup(mbedtls_ssl_ticket_context *ctx,
111                              int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
112                              mbedtls_cipher_type_t cipher,
113                              uint32_t lifetime)
114 {
115     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
116     const mbedtls_cipher_info_t *cipher_info;
117 
118     ctx->f_rng = f_rng;
119     ctx->p_rng = p_rng;
120 
121     ctx->ticket_lifetime = lifetime;
122 
123     cipher_info = mbedtls_cipher_info_from_type(cipher);
124     if (cipher_info == NULL) {
125         return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
126     }
127 
128     if (cipher_info->mode != MBEDTLS_MODE_GCM &&
129         cipher_info->mode != MBEDTLS_MODE_CCM) {
130         return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
131     }
132 
133     if (cipher_info->key_bitlen > 8 * MAX_KEY_BYTES) {
134         return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
135     }
136 
137     int do_mbedtls_cipher_setup = 1;
138 #if defined(MBEDTLS_USE_PSA_CRYPTO)
139     ret = mbedtls_cipher_setup_psa(&ctx->keys[0].ctx,
140                                    cipher_info, TICKET_AUTH_TAG_BYTES);
141 
142     switch (ret) {
143         case 0:
144             do_mbedtls_cipher_setup = 0;
145             break;
146         case MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE:
147             /* We don't yet expect to support all ciphers through PSA,
148              * so allow fallback to ordinary mbedtls_cipher_setup(). */
149             do_mbedtls_cipher_setup = 1;
150             break;
151         default:
152             return ret;
153     }
154 #endif /* MBEDTLS_USE_PSA_CRYPTO */
155     if (do_mbedtls_cipher_setup) {
156         if ((ret = mbedtls_cipher_setup(&ctx->keys[0].ctx, cipher_info))
157             != 0) {
158             return ret;
159         }
160     }
161 
162     do_mbedtls_cipher_setup = 1;
163 #if defined(MBEDTLS_USE_PSA_CRYPTO)
164     do_mbedtls_cipher_setup = 0;
165 
166     ret = mbedtls_cipher_setup_psa(&ctx->keys[1].ctx,
167                                    cipher_info, TICKET_AUTH_TAG_BYTES);
168     if (ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE) {
169         return ret;
170     }
171     if (ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE) {
172         do_mbedtls_cipher_setup = 1;
173     }
174 #endif /* MBEDTLS_USE_PSA_CRYPTO */
175     if (do_mbedtls_cipher_setup) {
176         if ((ret = mbedtls_cipher_setup(&ctx->keys[1].ctx, cipher_info))
177             != 0) {
178             return ret;
179         }
180     }
181 
182     if ((ret = ssl_ticket_gen_key(ctx, 0)) != 0 ||
183         (ret = ssl_ticket_gen_key(ctx, 1)) != 0) {
184         return ret;
185     }
186 
187     return 0;
188 }
189 
190 /*
191  * Create session ticket, with the following structure:
192  *
193  *    struct {
194  *        opaque key_name[4];
195  *        opaque iv[12];
196  *        opaque encrypted_state<0..2^16-1>;
197  *        opaque tag[16];
198  *    } ticket;
199  *
200  * The key_name, iv, and length of encrypted_state are the additional
201  * authenticated data.
202  */
203 
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)204 int mbedtls_ssl_ticket_write(void *p_ticket,
205                              const mbedtls_ssl_session *session,
206                              unsigned char *start,
207                              const unsigned char *end,
208                              size_t *tlen,
209                              uint32_t *ticket_lifetime)
210 {
211     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
212     mbedtls_ssl_ticket_context *ctx = p_ticket;
213     mbedtls_ssl_ticket_key *key;
214     unsigned char *key_name = start;
215     unsigned char *iv = start + TICKET_KEY_NAME_BYTES;
216     unsigned char *state_len_bytes = iv + TICKET_IV_BYTES;
217     unsigned char *state = state_len_bytes + TICKET_CRYPT_LEN_BYTES;
218     size_t clear_len, ciph_len;
219 
220     *tlen = 0;
221 
222     if (ctx == NULL || ctx->f_rng == NULL) {
223         return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
224     }
225 
226     /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag,
227      * in addition to session itself, that will be checked when writing it. */
228     MBEDTLS_SSL_CHK_BUF_PTR(start, end, TICKET_MIN_LEN);
229 
230 #if defined(MBEDTLS_THREADING_C)
231     if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) {
232         return ret;
233     }
234 #endif
235 
236     if ((ret = ssl_ticket_update_keys(ctx)) != 0) {
237         goto cleanup;
238     }
239 
240     key = &ctx->keys[ctx->active];
241 
242     *ticket_lifetime = ctx->ticket_lifetime;
243 
244     memcpy(key_name, key->name, TICKET_KEY_NAME_BYTES);
245 
246     if ((ret = ctx->f_rng(ctx->p_rng, iv, TICKET_IV_BYTES)) != 0) {
247         goto cleanup;
248     }
249 
250     /* Dump session state */
251     if ((ret = mbedtls_ssl_session_save(session,
252                                         state, end - state,
253                                         &clear_len)) != 0 ||
254         (unsigned long) clear_len > 65535) {
255         goto cleanup;
256     }
257     MBEDTLS_PUT_UINT16_BE(clear_len, state_len_bytes, 0);
258 
259     /* Encrypt and authenticate */
260     if ((ret = mbedtls_cipher_auth_encrypt_ext(&key->ctx,
261                                                iv, TICKET_IV_BYTES,
262                                                /* Additional data: key name, IV and length */
263                                                key_name, TICKET_ADD_DATA_LEN,
264                                                state, clear_len,
265                                                state, end - state, &ciph_len,
266                                                TICKET_AUTH_TAG_BYTES)) != 0) {
267         goto cleanup;
268     }
269     if (ciph_len != clear_len + TICKET_AUTH_TAG_BYTES) {
270         ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
271         goto cleanup;
272     }
273 
274     *tlen = TICKET_MIN_LEN + ciph_len - TICKET_AUTH_TAG_BYTES;
275 
276 cleanup:
277 #if defined(MBEDTLS_THREADING_C)
278     if (mbedtls_mutex_unlock(&ctx->mutex) != 0) {
279         return MBEDTLS_ERR_THREADING_MUTEX_ERROR;
280     }
281 #endif
282 
283     return ret;
284 }
285 
286 /*
287  * Select key based on name
288  */
ssl_ticket_select_key(mbedtls_ssl_ticket_context * ctx,const unsigned char name[4])289 static mbedtls_ssl_ticket_key *ssl_ticket_select_key(
290     mbedtls_ssl_ticket_context *ctx,
291     const unsigned char name[4])
292 {
293     unsigned char i;
294 
295     for (i = 0; i < sizeof(ctx->keys) / sizeof(*ctx->keys); i++) {
296         if (memcmp(name, ctx->keys[i].name, 4) == 0) {
297             return &ctx->keys[i];
298         }
299     }
300 
301     return NULL;
302 }
303 
304 /*
305  * Load session ticket (see mbedtls_ssl_ticket_write for structure)
306  */
mbedtls_ssl_ticket_parse(void * p_ticket,mbedtls_ssl_session * session,unsigned char * buf,size_t len)307 int mbedtls_ssl_ticket_parse(void *p_ticket,
308                              mbedtls_ssl_session *session,
309                              unsigned char *buf,
310                              size_t len)
311 {
312     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
313     mbedtls_ssl_ticket_context *ctx = p_ticket;
314     mbedtls_ssl_ticket_key *key;
315     unsigned char *key_name = buf;
316     unsigned char *iv = buf + TICKET_KEY_NAME_BYTES;
317     unsigned char *enc_len_p = iv + TICKET_IV_BYTES;
318     unsigned char *ticket = enc_len_p + TICKET_CRYPT_LEN_BYTES;
319     size_t enc_len, clear_len;
320 
321     if (ctx == NULL || ctx->f_rng == NULL) {
322         return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
323     }
324 
325     if (len < TICKET_MIN_LEN) {
326         return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
327     }
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     enc_len = (enc_len_p[0] << 8) | enc_len_p[1];
340 
341     if (len != TICKET_MIN_LEN + enc_len) {
342         ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
343         goto cleanup;
344     }
345 
346     /* Select key */
347     if ((key = ssl_ticket_select_key(ctx, key_name)) == NULL) {
348         /* We can't know for sure but this is a likely option unless we're
349          * under attack - this is only informative anyway */
350         ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
351         goto cleanup;
352     }
353 
354     /* Decrypt and authenticate */
355     if ((ret = mbedtls_cipher_auth_decrypt_ext(&key->ctx,
356                                                iv, TICKET_IV_BYTES,
357                                                /* Additional data: key name, IV and length */
358                                                key_name, TICKET_ADD_DATA_LEN,
359                                                ticket, enc_len + TICKET_AUTH_TAG_BYTES,
360                                                ticket, enc_len, &clear_len,
361                                                TICKET_AUTH_TAG_BYTES)) != 0) {
362         if (ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED) {
363             ret = MBEDTLS_ERR_SSL_INVALID_MAC;
364         }
365 
366         goto cleanup;
367     }
368     if (clear_len != enc_len) {
369         ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
370         goto cleanup;
371     }
372 
373     /* Actually load session */
374     if ((ret = mbedtls_ssl_session_load(session, ticket, clear_len)) != 0) {
375         goto cleanup;
376     }
377 
378 #if defined(MBEDTLS_HAVE_TIME)
379     {
380         /* Check for expiration */
381         mbedtls_time_t current_time = mbedtls_time(NULL);
382 
383         if (current_time < session->start ||
384             (uint32_t) (current_time - session->start) > ctx->ticket_lifetime) {
385             ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
386             goto cleanup;
387         }
388     }
389 #endif
390 
391 cleanup:
392 #if defined(MBEDTLS_THREADING_C)
393     if (mbedtls_mutex_unlock(&ctx->mutex) != 0) {
394         return MBEDTLS_ERR_THREADING_MUTEX_ERROR;
395     }
396 #endif
397 
398     return ret;
399 }
400 
401 /*
402  * Free context
403  */
mbedtls_ssl_ticket_free(mbedtls_ssl_ticket_context * ctx)404 void mbedtls_ssl_ticket_free(mbedtls_ssl_ticket_context *ctx)
405 {
406     mbedtls_cipher_free(&ctx->keys[0].ctx);
407     mbedtls_cipher_free(&ctx->keys[1].ctx);
408 
409 #if defined(MBEDTLS_THREADING_C)
410     mbedtls_mutex_free(&ctx->mutex);
411 #endif
412 
413     mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ssl_ticket_context));
414 }
415 
416 #endif /* MBEDTLS_SSL_TICKET_C */
417