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