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  *  This file is provided under the Apache License 2.0, or the
8  *  GNU General Public License v2.0 or later.
9  *
10  *  **********
11  *  Apache License 2.0:
12  *
13  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
14  *  not use this file except in compliance with the License.
15  *  You may obtain a copy of the License at
16  *
17  *  http://www.apache.org/licenses/LICENSE-2.0
18  *
19  *  Unless required by applicable law or agreed to in writing, software
20  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
21  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22  *  See the License for the specific language governing permissions and
23  *  limitations under the License.
24  *
25  *  **********
26  *
27  *  **********
28  *  GNU General Public License v2.0 or later:
29  *
30  *  This program is free software; you can redistribute it and/or modify
31  *  it under the terms of the GNU General Public License as published by
32  *  the Free Software Foundation; either version 2 of the License, or
33  *  (at your option) any later version.
34  *
35  *  This program is distributed in the hope that it will be useful,
36  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
37  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38  *  GNU General Public License for more details.
39  *
40  *  You should have received a copy of the GNU General Public License along
41  *  with this program; if not, write to the Free Software Foundation, Inc.,
42  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
43  *
44  *  **********
45  */
46 
47 #if !defined(MBEDTLS_CONFIG_FILE)
48 #include "mbedtls/config.h"
49 #else
50 #include MBEDTLS_CONFIG_FILE
51 #endif
52 
53 #if defined(MBEDTLS_SSL_TICKET_C)
54 
55 #if defined(MBEDTLS_PLATFORM_C)
56 #include "mbedtls/platform.h"
57 #else
58 #include <stdlib.h>
59 #define mbedtls_calloc    calloc
60 #define mbedtls_free      free
61 #endif
62 
63 #include "mbedtls/ssl_internal.h"
64 #include "mbedtls/ssl_ticket.h"
65 
66 #include <string.h>
67 
68 /* Implementation that should never be optimized out by the compiler */
mbedtls_zeroize(void * v,size_t n)69 static void mbedtls_zeroize( void *v, size_t n ) {
70     volatile unsigned char *p = v; while( n-- ) *p++ = 0;
71 }
72 
73 /*
74  * Initialze context
75  */
mbedtls_ssl_ticket_init(mbedtls_ssl_ticket_context * ctx)76 void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx )
77 {
78     memset( ctx, 0, sizeof( mbedtls_ssl_ticket_context ) );
79 
80 #if defined(MBEDTLS_THREADING_C)
81     mbedtls_mutex_init( &ctx->mutex );
82 #endif
83 }
84 
85 #define MAX_KEY_BYTES 32    /* 256 bits */
86 
87 #define TICKET_KEY_NAME_BYTES    4
88 #define TICKET_IV_BYTES         12
89 #define TICKET_CRYPT_LEN_BYTES   2
90 #define TICKET_AUTH_TAG_BYTES   16
91 
92 #define TICKET_MIN_LEN ( TICKET_KEY_NAME_BYTES  +        \
93                          TICKET_IV_BYTES        +        \
94                          TICKET_CRYPT_LEN_BYTES +        \
95                          TICKET_AUTH_TAG_BYTES )
96 #define TICKET_ADD_DATA_LEN ( TICKET_KEY_NAME_BYTES  +        \
97                               TICKET_IV_BYTES        +        \
98                               TICKET_CRYPT_LEN_BYTES )
99 
100 /*
101  * Generate/update a key
102  */
ssl_ticket_gen_key(mbedtls_ssl_ticket_context * ctx,unsigned char index)103 static int ssl_ticket_gen_key( mbedtls_ssl_ticket_context *ctx,
104                                unsigned char index )
105 {
106     int ret;
107     unsigned char buf[MAX_KEY_BYTES];
108     mbedtls_ssl_ticket_key *key = ctx->keys + index;
109 
110 #if defined(MBEDTLS_HAVE_TIME)
111     key->generation_time = (uint32_t) mbedtls_time( NULL );
112 #endif
113 
114     if( ( ret = ctx->f_rng( ctx->p_rng, key->name, sizeof( key->name ) ) ) != 0 )
115         return( ret );
116 
117     if( ( ret = ctx->f_rng( ctx->p_rng, buf, sizeof( buf ) ) ) != 0 )
118         return( ret );
119 
120     /* With GCM and CCM, same context can encrypt & decrypt */
121     ret = mbedtls_cipher_setkey( &key->ctx, buf,
122                                  mbedtls_cipher_get_key_bitlen( &key->ctx ),
123                                  MBEDTLS_ENCRYPT );
124 
125     mbedtls_zeroize( buf, sizeof( buf ) );
126 
127     return( ret );
128 }
129 
130 /*
131  * Rotate/generate keys if necessary
132  */
ssl_ticket_update_keys(mbedtls_ssl_ticket_context * ctx)133 static int ssl_ticket_update_keys( mbedtls_ssl_ticket_context *ctx )
134 {
135 #if !defined(MBEDTLS_HAVE_TIME)
136     ((void) ctx);
137 #else
138     if( ctx->ticket_lifetime != 0 )
139     {
140         uint32_t current_time = (uint32_t) mbedtls_time( NULL );
141         uint32_t key_time = ctx->keys[ctx->active].generation_time;
142 
143         if( current_time >= key_time &&
144             current_time - key_time < ctx->ticket_lifetime )
145         {
146             return( 0 );
147         }
148 
149         ctx->active = 1 - ctx->active;
150 
151         return( ssl_ticket_gen_key( ctx, ctx->active ) );
152     }
153     else
154 #endif /* MBEDTLS_HAVE_TIME */
155         return( 0 );
156 }
157 
158 /*
159  * Setup context for actual use
160  */
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)161 int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx,
162     int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
163     mbedtls_cipher_type_t cipher,
164     uint32_t lifetime )
165 {
166     int ret;
167     const mbedtls_cipher_info_t *cipher_info;
168 
169     ctx->f_rng = f_rng;
170     ctx->p_rng = p_rng;
171 
172     ctx->ticket_lifetime = lifetime;
173 
174     cipher_info = mbedtls_cipher_info_from_type( cipher);
175     if( cipher_info == NULL )
176         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
177 
178     if( cipher_info->mode != MBEDTLS_MODE_GCM &&
179         cipher_info->mode != MBEDTLS_MODE_CCM )
180     {
181         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
182     }
183 
184     if( cipher_info->key_bitlen > 8 * MAX_KEY_BYTES )
185         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
186 
187     if( ( ret = mbedtls_cipher_setup( &ctx->keys[0].ctx, cipher_info ) ) != 0 ||
188         ( ret = mbedtls_cipher_setup( &ctx->keys[1].ctx, cipher_info ) ) != 0 )
189     {
190         return( ret );
191     }
192 
193     if( ( ret = ssl_ticket_gen_key( ctx, 0 ) ) != 0 ||
194         ( ret = ssl_ticket_gen_key( ctx, 1 ) ) != 0 )
195     {
196         return( ret );
197     }
198 
199     return( 0 );
200 }
201 
202 /*
203  * Serialize a session in the following format:
204  *  0   .   n-1     session structure, n = sizeof(mbedtls_ssl_session)
205  *  n   .   n+2     peer_cert length = m (0 if no certificate)
206  *  n+3 .   n+2+m   peer cert ASN.1
207  */
ssl_save_session(const mbedtls_ssl_session * session,unsigned char * buf,size_t buf_len,size_t * olen)208 static int ssl_save_session( const mbedtls_ssl_session *session,
209                              unsigned char *buf, size_t buf_len,
210                              size_t *olen )
211 {
212     unsigned char *p = buf;
213     size_t left = buf_len;
214 #if defined(MBEDTLS_X509_CRT_PARSE_C)
215     size_t cert_len;
216 #endif /* MBEDTLS_X509_CRT_PARSE_C */
217 
218     if( left < sizeof( mbedtls_ssl_session ) )
219         return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
220 
221     memcpy( p, session, sizeof( mbedtls_ssl_session ) );
222     p += sizeof( mbedtls_ssl_session );
223     left -= sizeof( mbedtls_ssl_session );
224 
225 #if defined(MBEDTLS_X509_CRT_PARSE_C)
226     if( session->peer_cert == NULL )
227         cert_len = 0;
228     else
229         cert_len = session->peer_cert->raw.len;
230 
231     if( left < 3 + cert_len )
232         return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
233 
234     *p++ = (unsigned char)( ( cert_len >> 16 ) & 0xFF );
235     *p++ = (unsigned char)( ( cert_len >>  8 ) & 0xFF );
236     *p++ = (unsigned char)( ( cert_len       ) & 0xFF );
237 
238     if( session->peer_cert != NULL )
239         memcpy( p, session->peer_cert->raw.p, cert_len );
240 
241     p += cert_len;
242 #endif /* MBEDTLS_X509_CRT_PARSE_C */
243 
244     *olen = p - buf;
245 
246     return( 0 );
247 }
248 
249 /*
250  * Unserialise session, see ssl_save_session()
251  */
ssl_load_session(mbedtls_ssl_session * session,const unsigned char * buf,size_t len)252 static int ssl_load_session( mbedtls_ssl_session *session,
253                              const unsigned char *buf, size_t len )
254 {
255     const unsigned char *p = buf;
256     const unsigned char * const end = buf + len;
257 #if defined(MBEDTLS_X509_CRT_PARSE_C)
258     size_t cert_len;
259 #endif /* MBEDTLS_X509_CRT_PARSE_C */
260 
261     if( sizeof( mbedtls_ssl_session ) > (size_t)( end - p ) )
262         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
263 
264     memcpy( session, p, sizeof( mbedtls_ssl_session ) );
265     p += sizeof( mbedtls_ssl_session );
266 
267 #if defined(MBEDTLS_X509_CRT_PARSE_C)
268     if( 3 > (size_t)( end - p ) )
269         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
270 
271     cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2];
272     p += 3;
273 
274     if( cert_len == 0 )
275     {
276         session->peer_cert = NULL;
277     }
278     else
279     {
280         int ret;
281 
282         if( cert_len > (size_t)( end - p ) )
283             return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
284 
285         session->peer_cert = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) );
286 
287         if( session->peer_cert == NULL )
288             return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
289 
290         mbedtls_x509_crt_init( session->peer_cert );
291 
292         if( ( ret = mbedtls_x509_crt_parse_der( session->peer_cert,
293                                                 p, cert_len ) ) != 0 )
294         {
295             mbedtls_x509_crt_free( session->peer_cert );
296             mbedtls_free( session->peer_cert );
297             session->peer_cert = NULL;
298             return( ret );
299         }
300 
301         p += cert_len;
302     }
303 #endif /* MBEDTLS_X509_CRT_PARSE_C */
304 
305     if( p != end )
306         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
307 
308     return( 0 );
309 }
310 
311 /*
312  * Create session ticket, with the following structure:
313  *
314  *    struct {
315  *        opaque key_name[4];
316  *        opaque iv[12];
317  *        opaque encrypted_state<0..2^16-1>;
318  *        opaque tag[16];
319  *    } ticket;
320  *
321  * The key_name, iv, and length of encrypted_state are the additional
322  * authenticated data.
323  */
324 
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)325 int mbedtls_ssl_ticket_write( void *p_ticket,
326                               const mbedtls_ssl_session *session,
327                               unsigned char *start,
328                               const unsigned char *end,
329                               size_t *tlen,
330                               uint32_t *ticket_lifetime )
331 {
332     int ret;
333     mbedtls_ssl_ticket_context *ctx = p_ticket;
334     mbedtls_ssl_ticket_key *key;
335     unsigned char *key_name = start;
336     unsigned char *iv = start + TICKET_KEY_NAME_BYTES;
337     unsigned char *state_len_bytes = iv + TICKET_IV_BYTES;
338     unsigned char *state = state_len_bytes + TICKET_CRYPT_LEN_BYTES;
339     unsigned char *tag;
340     size_t clear_len, ciph_len;
341 
342     *tlen = 0;
343 
344     if( ctx == NULL || ctx->f_rng == NULL )
345         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
346 
347     /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag,
348      * in addition to session itself, that will be checked when writing it. */
349     MBEDTLS_SSL_CHK_BUF_PTR( start, end, TICKET_MIN_LEN );
350 
351 #if defined(MBEDTLS_THREADING_C)
352     if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
353         return( ret );
354 #endif
355 
356     if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 )
357         goto cleanup;
358 
359     key = &ctx->keys[ctx->active];
360 
361     *ticket_lifetime = ctx->ticket_lifetime;
362 
363     memcpy( key_name, key->name, TICKET_KEY_NAME_BYTES );
364 
365     if( ( ret = ctx->f_rng( ctx->p_rng, iv, TICKET_IV_BYTES ) ) != 0 )
366         goto cleanup;
367 
368     /* Dump session state */
369     if( ( ret = ssl_save_session( session,
370                                   state, end - state, &clear_len ) ) != 0 ||
371         (unsigned long) clear_len > 65535 )
372     {
373          goto cleanup;
374     }
375     state_len_bytes[0] = ( clear_len >> 8 ) & 0xff;
376     state_len_bytes[1] = ( clear_len      ) & 0xff;
377 
378     /* Encrypt and authenticate */
379     tag = state + clear_len;
380     if( ( ret = mbedtls_cipher_auth_encrypt( &key->ctx,
381                     iv, TICKET_IV_BYTES,
382                     /* Additional data: key name, IV and length */
383                     key_name, TICKET_ADD_DATA_LEN,
384                     state, clear_len, state, &ciph_len,
385                     tag, TICKET_AUTH_TAG_BYTES ) ) != 0 )
386     {
387         goto cleanup;
388     }
389     if( ciph_len != clear_len )
390     {
391         ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
392         goto cleanup;
393     }
394 
395     *tlen = TICKET_MIN_LEN + ciph_len;
396 
397 cleanup:
398 #if defined(MBEDTLS_THREADING_C)
399     if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
400         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
401 #endif
402 
403     return( ret );
404 }
405 
406 /*
407  * Select key based on name
408  */
ssl_ticket_select_key(mbedtls_ssl_ticket_context * ctx,const unsigned char name[4])409 static mbedtls_ssl_ticket_key *ssl_ticket_select_key(
410         mbedtls_ssl_ticket_context *ctx,
411         const unsigned char name[4] )
412 {
413     unsigned char i;
414 
415     for( i = 0; i < sizeof( ctx->keys ) / sizeof( *ctx->keys ); i++ )
416         if( memcmp( name, ctx->keys[i].name, 4 ) == 0 )
417             return( &ctx->keys[i] );
418 
419     return( NULL );
420 }
421 
422 /*
423  * Load session ticket (see mbedtls_ssl_ticket_write for structure)
424  */
mbedtls_ssl_ticket_parse(void * p_ticket,mbedtls_ssl_session * session,unsigned char * buf,size_t len)425 int mbedtls_ssl_ticket_parse( void *p_ticket,
426                               mbedtls_ssl_session *session,
427                               unsigned char *buf,
428                               size_t len )
429 {
430     int ret;
431     mbedtls_ssl_ticket_context *ctx = p_ticket;
432     mbedtls_ssl_ticket_key *key;
433     unsigned char *key_name = buf;
434     unsigned char *iv = buf + TICKET_KEY_NAME_BYTES;
435     unsigned char *enc_len_p = iv + TICKET_IV_BYTES;
436     unsigned char *ticket = enc_len_p + TICKET_CRYPT_LEN_BYTES;
437     unsigned char *tag;
438     size_t enc_len, clear_len;
439 
440     if( ctx == NULL || ctx->f_rng == NULL )
441         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
442 
443     if( len < TICKET_MIN_LEN )
444         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
445 
446 #if defined(MBEDTLS_THREADING_C)
447     if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
448         return( ret );
449 #endif
450 
451     if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 )
452         goto cleanup;
453 
454     enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1];
455     tag = ticket + enc_len;
456 
457     if( len != TICKET_MIN_LEN + enc_len )
458     {
459         ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
460         goto cleanup;
461     }
462 
463     /* Select key */
464     if( ( key = ssl_ticket_select_key( ctx, key_name ) ) == NULL )
465     {
466         /* We can't know for sure but this is a likely option unless we're
467          * under attack - this is only informative anyway */
468         ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
469         goto cleanup;
470     }
471 
472     /* Decrypt and authenticate */
473     if( ( ret = mbedtls_cipher_auth_decrypt( &key->ctx,
474                     iv, TICKET_IV_BYTES,
475                     /* Additional data: key name, IV and length */
476                     key_name, TICKET_ADD_DATA_LEN,
477                     ticket, enc_len,
478                     ticket, &clear_len,
479                     tag, TICKET_AUTH_TAG_BYTES ) ) != 0 )
480     {
481         if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED )
482             ret = MBEDTLS_ERR_SSL_INVALID_MAC;
483 
484         goto cleanup;
485     }
486     if( clear_len != enc_len )
487     {
488         ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
489         goto cleanup;
490     }
491 
492     /* Actually load session */
493     if( ( ret = ssl_load_session( session, ticket, clear_len ) ) != 0 )
494         goto cleanup;
495 
496 #if defined(MBEDTLS_HAVE_TIME)
497     {
498         /* Check for expiration */
499         mbedtls_time_t current_time = mbedtls_time( NULL );
500 
501         if( current_time < session->start ||
502             (uint32_t)( current_time - session->start ) > ctx->ticket_lifetime )
503         {
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 #endif
515 
516     return( ret );
517 }
518 
519 /*
520  * Free context
521  */
mbedtls_ssl_ticket_free(mbedtls_ssl_ticket_context * ctx)522 void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx )
523 {
524     mbedtls_cipher_free( &ctx->keys[0].ctx );
525     mbedtls_cipher_free( &ctx->keys[1].ctx );
526 
527 #if defined(MBEDTLS_THREADING_C)
528     mbedtls_mutex_free( &ctx->mutex );
529 #endif
530 
531     mbedtls_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) );
532 }
533 
534 #endif /* MBEDTLS_SSL_TICKET_C */
535