blob: c1881b721e512c0560eff64f1832a8d5da34ce45 [file] [log] [blame]
Manuel Pégourié-Gonnardfd6d8972015-05-15 12:09:00 +02001/*
2 * TLS server tickets callbacks implementation
3 *
4 * Copyright (C) 2015, ARM Limited, All Rights Reserved
5 *
6 * This file is part of mbed TLS (https://tls.mbed.org)
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#if !defined(MBEDTLS_CONFIG_FILE)
24#include "mbedtls/config.h"
25#else
26#include MBEDTLS_CONFIG_FILE
27#endif
28
29#if defined(MBEDTLS_SSL_TICKET_C)
30
31#include "mbedtls/ssl_ticket.h"
32
33#if defined(MBEDTLS_PLATFORM_C)
34#include "mbedtls/platform.h"
35#else
36#define mbedtls_malloc malloc
37#define mbedtls_free free
38#endif
39
40#include <string.h>
41
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +020042/* Implementation that should never be optimized out by the compiler */
43static void mbedtls_zeroize( void *v, size_t n ) {
44 volatile unsigned char *p = v; while( n-- ) *p++ = 0;
45}
46
47/*
48 * Initialze context
49 */
50void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx )
51{
52 memset( ctx, 0, sizeof( mbedtls_ssl_ticket_context ) );
53}
54
55/*
56 * Setup context for actual use
57 */
58int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx,
59 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
60 uint32_t lifetime )
61{
62 int ret;
63 unsigned char buf[16];
64
65 ctx->f_rng = f_rng;
66 ctx->p_rng = p_rng;
67
68 ctx->ticket_lifetime = lifetime;
69
70 mbedtls_aes_init( &ctx->enc );
71 mbedtls_aes_init( &ctx->dec );
72
73 if( ( ret = f_rng( p_rng, ctx->key_name, 16 ) != 0 ) ||
74 ( ret = f_rng( p_rng, ctx->mac_key, 16 ) != 0 ) ||
75 ( ret = f_rng( p_rng, buf, 16 ) != 0 ) )
76 {
77 return( ret );
78 }
79
80 if( ( ret = mbedtls_aes_setkey_enc( &ctx->enc, buf, 128 ) ) != 0 ||
81 ( ret = mbedtls_aes_setkey_dec( &ctx->dec, buf, 128 ) ) != 0 )
82 {
83 mbedtls_ssl_ticket_free( ctx );
84 return( ret );
85 }
86
87 mbedtls_zeroize( buf, sizeof( buf ) );
88
89 return( 0 );
90}
91
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +020092/*
93 * Serialize a session in the following format:
94 * 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session)
95 * n . n+2 peer_cert length = m (0 if no certificate)
96 * n+3 . n+2+m peer cert ASN.1
97 *
98 * Assumes ticket is NULL (always true on server side).
99 */
100static int ssl_save_session( const mbedtls_ssl_session *session,
101 unsigned char *buf, size_t buf_len,
102 size_t *olen )
103{
104 unsigned char *p = buf;
105 size_t left = buf_len;
106#if defined(MBEDTLS_X509_CRT_PARSE_C)
107 size_t cert_len;
108#endif /* MBEDTLS_X509_CRT_PARSE_C */
109
110 if( left < sizeof( mbedtls_ssl_session ) )
111 return( -1 );
112
113 memcpy( p, session, sizeof( mbedtls_ssl_session ) );
114 p += sizeof( mbedtls_ssl_session );
115 left -= sizeof( mbedtls_ssl_session );
116
117#if defined(MBEDTLS_X509_CRT_PARSE_C)
118 if( session->peer_cert == NULL )
119 cert_len = 0;
120 else
121 cert_len = session->peer_cert->raw.len;
122
123 if( left < 3 + cert_len )
124 return( -1 );
125
126 *p++ = (unsigned char)( cert_len >> 16 & 0xFF );
127 *p++ = (unsigned char)( cert_len >> 8 & 0xFF );
128 *p++ = (unsigned char)( cert_len & 0xFF );
129
130 if( session->peer_cert != NULL )
131 memcpy( p, session->peer_cert->raw.p, cert_len );
132
133 p += cert_len;
134#endif /* MBEDTLS_X509_CRT_PARSE_C */
135
136 *olen = p - buf;
137
138 return( 0 );
139}
140
141/*
142 * Unserialise session, see ssl_save_session()
143 */
144static int ssl_load_session( mbedtls_ssl_session *session,
145 const unsigned char *buf, size_t len )
146{
147 const unsigned char *p = buf;
148 const unsigned char * const end = buf + len;
149#if defined(MBEDTLS_X509_CRT_PARSE_C)
150 size_t cert_len;
151#endif /* MBEDTLS_X509_CRT_PARSE_C */
152
153 if( p + sizeof( mbedtls_ssl_session ) > end )
154 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
155
156 memcpy( session, p, sizeof( mbedtls_ssl_session ) );
157 p += sizeof( mbedtls_ssl_session );
158
159#if defined(MBEDTLS_X509_CRT_PARSE_C)
160 if( p + 3 > end )
161 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
162
163 cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2];
164 p += 3;
165
166 if( cert_len == 0 )
167 {
168 session->peer_cert = NULL;
169 }
170 else
171 {
172 int ret;
173
174 if( p + cert_len > end )
175 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
176
177 session->peer_cert = mbedtls_malloc( sizeof( mbedtls_x509_crt ) );
178
179 if( session->peer_cert == NULL )
180 return( MBEDTLS_ERR_SSL_MALLOC_FAILED );
181
182 mbedtls_x509_crt_init( session->peer_cert );
183
184 if( ( ret = mbedtls_x509_crt_parse_der( session->peer_cert,
185 p, cert_len ) ) != 0 )
186 {
187 mbedtls_x509_crt_free( session->peer_cert );
188 mbedtls_free( session->peer_cert );
189 session->peer_cert = NULL;
190 return( ret );
191 }
192
193 p += cert_len;
194 }
195#endif /* MBEDTLS_X509_CRT_PARSE_C */
196
197 if( p != end )
198 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
199
200 return( 0 );
201}
202
203/*
204 * Create session ticket, secured as recommended in RFC 5077 section 4:
205 *
206 * struct {
207 * opaque key_name[16];
208 * opaque iv[16];
209 * opaque encrypted_state<0..2^16-1>;
210 * opaque mac[32];
211 * } ticket;
212 *
213 * (the internal state structure differs, however).
214 */
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200215int mbedtls_ssl_ticket_write( void *p_ticket,
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200216 const mbedtls_ssl_session *session,
217 unsigned char *start,
218 const unsigned char *end,
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200219 size_t *tlen,
220 uint32_t *ticket_lifetime )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200221{
222 int ret;
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +0200223 mbedtls_ssl_ticket_context *ctx = p_ticket;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200224 unsigned char *p = start;
225 unsigned char *state;
226 unsigned char iv[16];
227 size_t clear_len, enc_len, pad_len, i;
228
229 *tlen = 0;
230
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200231 if( ctx == NULL )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200232 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
233
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200234 *ticket_lifetime = ctx->ticket_lifetime;
235
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200236 /* We need at least 16 bytes for key_name, 16 for IV, 2 for len
237 * 16 for padding, 32 for MAC, in addition to session itself,
238 * that will be checked when writing it. */
239 if( end - start < 16 + 16 + 2 + 16 + 32 )
240 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
241
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200242 /* Write key name */
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200243 memcpy( p, ctx->key_name, 16 );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200244 p += 16;
245
246 /* Generate and write IV (with a copy for aes_crypt) */
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +0200247 if( ( ret = ctx->f_rng( ctx->p_rng, p, 16 ) ) != 0 )
248 return( ret );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200249 memcpy( iv, p, 16 );
250 p += 16;
251
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200252 /* Dump session state */
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200253 state = p + 2;
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200254 if( ssl_save_session( session, state, end - state, &clear_len ) != 0 )
255 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200256
257 /* Apply PKCS padding */
258 pad_len = 16 - clear_len % 16;
259 enc_len = clear_len + pad_len;
260 for( i = clear_len; i < enc_len; i++ )
261 state[i] = (unsigned char) pad_len;
262
263 /* Encrypt */
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200264 if( ( ret = mbedtls_aes_crypt_cbc( &ctx->enc, MBEDTLS_AES_ENCRYPT,
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200265 enc_len, iv, state, state ) ) != 0 )
266 {
267 return( ret );
268 }
269
270 /* Write length */
271 *p++ = (unsigned char)( ( enc_len >> 8 ) & 0xFF );
272 *p++ = (unsigned char)( ( enc_len ) & 0xFF );
273 p = state + enc_len;
274
275 /* Compute and write MAC( key_name + iv + enc_state_len + enc_state ) */
276 if( ( ret = mbedtls_md_hmac( mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ),
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200277 ctx->mac_key, 16,
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200278 start, p - start, p ) ) != 0 )
279 {
280 return( ret );
281 }
282 p += 32;
283
284 *tlen = p - start;
285
286 return( 0 );
287}
288
289/*
290 * Load session ticket (see mbedtls_ssl_ticket_write for structure)
291 */
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200292int mbedtls_ssl_ticket_parse( void *p_ticket,
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200293 mbedtls_ssl_session *session,
294 unsigned char *buf,
295 size_t len )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200296{
297 int ret;
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +0200298 mbedtls_ssl_ticket_context *ctx = p_ticket;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200299 unsigned char *key_name = buf;
300 unsigned char *iv = buf + 16;
301 unsigned char *enc_len_p = iv + 16;
302 unsigned char *ticket = enc_len_p + 2;
303 unsigned char *mac;
304 unsigned char computed_mac[32];
305 size_t enc_len, clear_len, i;
306 unsigned char pad_len, diff;
307
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200308 if( len < 34 || ctx == NULL )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200309 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
310
311 enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1];
312 mac = ticket + enc_len;
313
314 if( len != enc_len + 66 )
315 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
316
317 /* Check name, in constant time though it's not a big secret */
318 diff = 0;
319 for( i = 0; i < 16; i++ )
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200320 diff |= key_name[i] ^ ctx->key_name[i];
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200321 /* don't return yet, check the MAC anyway */
322
323 /* Check mac, with constant-time buffer comparison */
324 if( ( ret = mbedtls_md_hmac( mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ),
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200325 ctx->mac_key, 16,
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200326 buf, len - 32, computed_mac ) ) != 0 )
327 {
328 return( ret );
329 }
330
331 for( i = 0; i < 32; i++ )
332 diff |= mac[i] ^ computed_mac[i];
333
334 /* Now return if ticket is not authentic, since we want to avoid
335 * decrypting arbitrary attacker-chosen data */
336 if( diff != 0 )
337 return( MBEDTLS_ERR_SSL_INVALID_MAC );
338
339 /* Decrypt */
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200340 if( ( ret = mbedtls_aes_crypt_cbc( &ctx->dec, MBEDTLS_AES_DECRYPT,
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200341 enc_len, iv, ticket, ticket ) ) != 0 )
342 {
343 return( ret );
344 }
345
346 /* Check PKCS padding */
347 pad_len = ticket[enc_len - 1];
348
349 ret = 0;
350 for( i = 2; i < pad_len; i++ )
351 if( ticket[enc_len - i] != pad_len )
352 ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
353 if( ret != 0 )
354 return( ret );
355
356 clear_len = enc_len - pad_len;
357
358 /* Actually load session */
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200359 if( ( ret = ssl_load_session( session, ticket, clear_len ) ) != 0 )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200360 return( ret );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200361
362#if defined(MBEDTLS_HAVE_TIME)
363 /* Check if still valid */
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200364 if( ( time( NULL) - session->start ) > ctx->ticket_lifetime )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200365 return( MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200366#endif
367
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200368 return( 0 );
369}
370
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +0200371/*
372 * Free context
373 */
374void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx )
375{
376 mbedtls_aes_free( &ctx->enc );
377 mbedtls_aes_free( &ctx->dec );
378
379 mbedtls_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) );
380}
381
Manuel Pégourié-Gonnardfd6d8972015-05-15 12:09:00 +0200382#endif /* MBEDTLS_SSL_TICKET_C */