xref: /optee_os/lib/libmbedtls/mbedtls/library/ssl_ticket.c (revision 11fa71b9ddb429088f325cfda430183003ccd1db)
1 // SPDX-License-Identifier: Apache-2.0
2 /*
3  *  TLS server tickets callbacks implementation
4  *
5  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
6  *
7  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8  *  not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  *
11  *  http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  *
19  *  This file is part of mbed TLS (https://tls.mbed.org)
20  */
21 
22 #if !defined(MBEDTLS_CONFIG_FILE)
23 #include "mbedtls/config.h"
24 #else
25 #include MBEDTLS_CONFIG_FILE
26 #endif
27 
28 #if defined(MBEDTLS_SSL_TICKET_C)
29 
30 #if defined(MBEDTLS_PLATFORM_C)
31 #include "mbedtls/platform.h"
32 #else
33 #include <stdlib.h>
34 #define mbedtls_calloc    calloc
35 #define mbedtls_free      free
36 #endif
37 
38 #include "mbedtls/ssl_ticket.h"
39 #include "mbedtls/error.h"
40 #include "mbedtls/platform_util.h"
41 
42 #include <string.h>
43 
44 /*
45  * Initialze context
46  */
47 void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx )
48 {
49     memset( ctx, 0, sizeof( mbedtls_ssl_ticket_context ) );
50 
51 #if defined(MBEDTLS_THREADING_C)
52     mbedtls_mutex_init( &ctx->mutex );
53 #endif
54 }
55 
56 #define MAX_KEY_BYTES 32    /* 256 bits */
57 
58 #define TICKET_KEY_NAME_BYTES    4
59 #define TICKET_IV_BYTES         12
60 #define TICKET_CRYPT_LEN_BYTES   2
61 #define TICKET_AUTH_TAG_BYTES   16
62 
63 #define TICKET_MIN_LEN ( TICKET_KEY_NAME_BYTES  +        \
64                          TICKET_IV_BYTES        +        \
65                          TICKET_CRYPT_LEN_BYTES +        \
66                          TICKET_AUTH_TAG_BYTES )
67 #define TICKET_ADD_DATA_LEN ( TICKET_KEY_NAME_BYTES  +        \
68                               TICKET_IV_BYTES        +        \
69                               TICKET_CRYPT_LEN_BYTES )
70 
71 /*
72  * Generate/update a key
73  */
74 static int ssl_ticket_gen_key( mbedtls_ssl_ticket_context *ctx,
75                                unsigned char index )
76 {
77     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
78     unsigned char buf[MAX_KEY_BYTES];
79     mbedtls_ssl_ticket_key *key = ctx->keys + index;
80 
81 #if defined(MBEDTLS_HAVE_TIME)
82     key->generation_time = (uint32_t) mbedtls_time( NULL );
83 #endif
84 
85     if( ( ret = ctx->f_rng( ctx->p_rng, key->name, sizeof( key->name ) ) ) != 0 )
86         return( ret );
87 
88     if( ( ret = ctx->f_rng( ctx->p_rng, buf, sizeof( buf ) ) ) != 0 )
89         return( ret );
90 
91     /* With GCM and CCM, same context can encrypt & decrypt */
92     ret = mbedtls_cipher_setkey( &key->ctx, buf,
93                                  mbedtls_cipher_get_key_bitlen( &key->ctx ),
94                                  MBEDTLS_ENCRYPT );
95 
96     mbedtls_platform_zeroize( buf, sizeof( buf ) );
97 
98     return( ret );
99 }
100 
101 /*
102  * Rotate/generate keys if necessary
103  */
104 static int ssl_ticket_update_keys( mbedtls_ssl_ticket_context *ctx )
105 {
106 #if !defined(MBEDTLS_HAVE_TIME)
107     ((void) ctx);
108 #else
109     if( ctx->ticket_lifetime != 0 )
110     {
111         uint32_t current_time = (uint32_t) mbedtls_time( NULL );
112         uint32_t key_time = ctx->keys[ctx->active].generation_time;
113 
114         if( current_time >= key_time &&
115             current_time - key_time < ctx->ticket_lifetime )
116         {
117             return( 0 );
118         }
119 
120         ctx->active = 1 - ctx->active;
121 
122         return( ssl_ticket_gen_key( ctx, ctx->active ) );
123     }
124     else
125 #endif /* MBEDTLS_HAVE_TIME */
126         return( 0 );
127 }
128 
129 /*
130  * Setup context for actual use
131  */
132 int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx,
133     int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
134     mbedtls_cipher_type_t cipher,
135     uint32_t lifetime )
136 {
137     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
138     const mbedtls_cipher_info_t *cipher_info;
139 
140     ctx->f_rng = f_rng;
141     ctx->p_rng = p_rng;
142 
143     ctx->ticket_lifetime = lifetime;
144 
145     cipher_info = mbedtls_cipher_info_from_type( cipher);
146     if( cipher_info == NULL )
147         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
148 
149     if( cipher_info->mode != MBEDTLS_MODE_GCM &&
150         cipher_info->mode != MBEDTLS_MODE_CCM )
151     {
152         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
153     }
154 
155     if( cipher_info->key_bitlen > 8 * MAX_KEY_BYTES )
156         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
157 
158 #if defined(MBEDTLS_USE_PSA_CRYPTO)
159     ret = mbedtls_cipher_setup_psa( &ctx->keys[0].ctx,
160                                     cipher_info, TICKET_AUTH_TAG_BYTES );
161     if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )
162         return( ret );
163     /* We don't yet expect to support all ciphers through PSA,
164      * so allow fallback to ordinary mbedtls_cipher_setup(). */
165     if( ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )
166 #endif /* MBEDTLS_USE_PSA_CRYPTO */
167     if( ( ret = mbedtls_cipher_setup( &ctx->keys[0].ctx, cipher_info ) ) != 0 )
168         return( ret );
169 
170 #if defined(MBEDTLS_USE_PSA_CRYPTO)
171     ret = mbedtls_cipher_setup_psa( &ctx->keys[1].ctx,
172                                     cipher_info, TICKET_AUTH_TAG_BYTES );
173     if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )
174         return( ret );
175     if( ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )
176 #endif /* MBEDTLS_USE_PSA_CRYPTO */
177     if( ( ret = mbedtls_cipher_setup( &ctx->keys[1].ctx, cipher_info ) ) != 0 )
178         return( ret );
179 
180     if( ( ret = ssl_ticket_gen_key( ctx, 0 ) ) != 0 ||
181         ( ret = ssl_ticket_gen_key( ctx, 1 ) ) != 0 )
182     {
183         return( ret );
184     }
185 
186     return( 0 );
187 }
188 
189 /*
190  * Create session ticket, with the following structure:
191  *
192  *    struct {
193  *        opaque key_name[4];
194  *        opaque iv[12];
195  *        opaque encrypted_state<0..2^16-1>;
196  *        opaque tag[16];
197  *    } ticket;
198  *
199  * The key_name, iv, and length of encrypted_state are the additional
200  * authenticated data.
201  */
202 
203 int mbedtls_ssl_ticket_write( void *p_ticket,
204                               const mbedtls_ssl_session *session,
205                               unsigned char *start,
206                               const unsigned char *end,
207                               size_t *tlen,
208                               uint32_t *ticket_lifetime )
209 {
210     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
211     mbedtls_ssl_ticket_context *ctx = p_ticket;
212     mbedtls_ssl_ticket_key *key;
213     unsigned char *key_name = start;
214     unsigned char *iv = start + TICKET_KEY_NAME_BYTES;
215     unsigned char *state_len_bytes = iv + TICKET_IV_BYTES;
216     unsigned char *state = state_len_bytes + TICKET_CRYPT_LEN_BYTES;
217     unsigned char *tag;
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     /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag,
226      * in addition to session itself, that will be checked when writing it. */
227     if( end - start < TICKET_MIN_LEN )
228         return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
229 
230 #if defined(MBEDTLS_THREADING_C)
231     if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
232         return( ret );
233 #endif
234 
235     if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 )
236         goto cleanup;
237 
238     key = &ctx->keys[ctx->active];
239 
240     *ticket_lifetime = ctx->ticket_lifetime;
241 
242     memcpy( key_name, key->name, TICKET_KEY_NAME_BYTES );
243 
244     if( ( ret = ctx->f_rng( ctx->p_rng, iv, TICKET_IV_BYTES ) ) != 0 )
245         goto cleanup;
246 
247     /* Dump session state */
248     if( ( ret = mbedtls_ssl_session_save( session,
249                                           state, end - state,
250                                           &clear_len ) ) != 0 ||
251         (unsigned long) clear_len > 65535 )
252     {
253          goto cleanup;
254     }
255     state_len_bytes[0] = ( clear_len >> 8 ) & 0xff;
256     state_len_bytes[1] = ( clear_len      ) & 0xff;
257 
258     /* Encrypt and authenticate */
259     tag = state + clear_len;
260     if( ( ret = mbedtls_cipher_auth_encrypt( &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, state, &ciph_len,
265                     tag, TICKET_AUTH_TAG_BYTES ) ) != 0 )
266     {
267         goto cleanup;
268     }
269     if( ciph_len != clear_len )
270     {
271         ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
272         goto cleanup;
273     }
274 
275     *tlen = TICKET_MIN_LEN + ciph_len;
276 
277 cleanup:
278 #if defined(MBEDTLS_THREADING_C)
279     if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
280         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
281 #endif
282 
283     return( ret );
284 }
285 
286 /*
287  * Select key based on name
288  */
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     return( NULL );
300 }
301 
302 /*
303  * Load session ticket (see mbedtls_ssl_ticket_write for structure)
304  */
305 int mbedtls_ssl_ticket_parse( void *p_ticket,
306                               mbedtls_ssl_session *session,
307                               unsigned char *buf,
308                               size_t len )
309 {
310     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
311     mbedtls_ssl_ticket_context *ctx = p_ticket;
312     mbedtls_ssl_ticket_key *key;
313     unsigned char *key_name = buf;
314     unsigned char *iv = buf + TICKET_KEY_NAME_BYTES;
315     unsigned char *enc_len_p = iv + TICKET_IV_BYTES;
316     unsigned char *ticket = enc_len_p + TICKET_CRYPT_LEN_BYTES;
317     unsigned char *tag;
318     size_t enc_len, clear_len;
319 
320     if( ctx == NULL || ctx->f_rng == NULL )
321         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
322 
323     if( len < TICKET_MIN_LEN )
324         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
325 
326 #if defined(MBEDTLS_THREADING_C)
327     if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
328         return( ret );
329 #endif
330 
331     if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 )
332         goto cleanup;
333 
334     enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1];
335     tag = ticket + enc_len;
336 
337     if( len != TICKET_MIN_LEN + enc_len )
338     {
339         ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
340         goto cleanup;
341     }
342 
343     /* Select key */
344     if( ( key = ssl_ticket_select_key( ctx, key_name ) ) == NULL )
345     {
346         /* We can't know for sure but this is a likely option unless we're
347          * under attack - this is only informative anyway */
348         ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
349         goto cleanup;
350     }
351 
352     /* Decrypt and authenticate */
353     if( ( ret = mbedtls_cipher_auth_decrypt( &key->ctx,
354                     iv, TICKET_IV_BYTES,
355                     /* Additional data: key name, IV and length */
356                     key_name, TICKET_ADD_DATA_LEN,
357                     ticket, enc_len,
358                     ticket, &clear_len,
359                     tag, TICKET_AUTH_TAG_BYTES ) ) != 0 )
360     {
361         if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED )
362             ret = MBEDTLS_ERR_SSL_INVALID_MAC;
363 
364         goto cleanup;
365     }
366     if( clear_len != enc_len )
367     {
368         ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
369         goto cleanup;
370     }
371 
372     /* Actually load session */
373     if( ( ret = mbedtls_ssl_session_load( session, ticket, clear_len ) ) != 0 )
374         goto cleanup;
375 
376 #if defined(MBEDTLS_HAVE_TIME)
377     {
378         /* Check for expiration */
379         mbedtls_time_t current_time = mbedtls_time( NULL );
380 
381         if( current_time < session->start ||
382             (uint32_t)( current_time - session->start ) > ctx->ticket_lifetime )
383         {
384             ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
385             goto cleanup;
386         }
387     }
388 #endif
389 
390 cleanup:
391 #if defined(MBEDTLS_THREADING_C)
392     if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
393         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
394 #endif
395 
396     return( ret );
397 }
398 
399 /*
400  * Free context
401  */
402 void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx )
403 {
404     mbedtls_cipher_free( &ctx->keys[0].ctx );
405     mbedtls_cipher_free( &ctx->keys[1].ctx );
406 
407 #if defined(MBEDTLS_THREADING_C)
408     mbedtls_mutex_free( &ctx->mutex );
409 #endif
410 
411     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) );
412 }
413 
414 #endif /* MBEDTLS_SSL_TICKET_C */
415