blob: 99550601a50783e44f60f29d6d6dd1d4ffb6f508 [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 ) );
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +020053
54#if defined(MBEDTLS_THREADING_C)
55 mbedtls_mutex_init( &ctx->mutex );
56#endif
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +020057}
58
59/*
60 * Setup context for actual use
61 */
62int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx,
63 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
64 uint32_t lifetime )
65{
66 int ret;
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +020067 unsigned char buf[32];
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +020068
69 ctx->f_rng = f_rng;
70 ctx->p_rng = p_rng;
71
72 ctx->ticket_lifetime = lifetime;
73
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +020074 if( ( ret = mbedtls_cipher_setup( &ctx->cipher,
75 mbedtls_cipher_info_from_type(
76 MBEDTLS_CIPHER_AES_256_GCM ) ) ) != 0 )
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +020077 {
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +020078 goto cleanup;
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +020079 }
80
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +020081 if( ( ret = f_rng( p_rng, buf, sizeof( buf ) ) != 0 ) )
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +020082 {
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +020083 goto cleanup;
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +020084 }
85
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +020086 /* With GCM and CCM, same context can encrypt & decrypt */
87 if( ( ret = mbedtls_cipher_setkey( &ctx->cipher, buf, 256,
88 MBEDTLS_ENCRYPT ) ) != 0 )
89 {
90 goto cleanup;
91 }
92
93cleanup:
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +020094 mbedtls_zeroize( buf, sizeof( buf ) );
95
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +020096 if( ret != 0 )
97 mbedtls_ssl_ticket_free( ctx );
98
99 return( ret );
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +0200100}
101
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200102/*
103 * Serialize a session in the following format:
104 * 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session)
105 * n . n+2 peer_cert length = m (0 if no certificate)
106 * n+3 . n+2+m peer cert ASN.1
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200107 */
108static int ssl_save_session( const mbedtls_ssl_session *session,
109 unsigned char *buf, size_t buf_len,
110 size_t *olen )
111{
112 unsigned char *p = buf;
113 size_t left = buf_len;
114#if defined(MBEDTLS_X509_CRT_PARSE_C)
115 size_t cert_len;
116#endif /* MBEDTLS_X509_CRT_PARSE_C */
117
118 if( left < sizeof( mbedtls_ssl_session ) )
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200119 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200120
121 memcpy( p, session, sizeof( mbedtls_ssl_session ) );
122 p += sizeof( mbedtls_ssl_session );
123 left -= sizeof( mbedtls_ssl_session );
124
125#if defined(MBEDTLS_X509_CRT_PARSE_C)
126 if( session->peer_cert == NULL )
127 cert_len = 0;
128 else
129 cert_len = session->peer_cert->raw.len;
130
131 if( left < 3 + cert_len )
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200132 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200133
134 *p++ = (unsigned char)( cert_len >> 16 & 0xFF );
135 *p++ = (unsigned char)( cert_len >> 8 & 0xFF );
136 *p++ = (unsigned char)( cert_len & 0xFF );
137
138 if( session->peer_cert != NULL )
139 memcpy( p, session->peer_cert->raw.p, cert_len );
140
141 p += cert_len;
142#endif /* MBEDTLS_X509_CRT_PARSE_C */
143
144 *olen = p - buf;
145
146 return( 0 );
147}
148
149/*
150 * Unserialise session, see ssl_save_session()
151 */
152static int ssl_load_session( mbedtls_ssl_session *session,
153 const unsigned char *buf, size_t len )
154{
155 const unsigned char *p = buf;
156 const unsigned char * const end = buf + len;
157#if defined(MBEDTLS_X509_CRT_PARSE_C)
158 size_t cert_len;
159#endif /* MBEDTLS_X509_CRT_PARSE_C */
160
161 if( p + sizeof( mbedtls_ssl_session ) > end )
162 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
163
164 memcpy( session, p, sizeof( mbedtls_ssl_session ) );
165 p += sizeof( mbedtls_ssl_session );
166
167#if defined(MBEDTLS_X509_CRT_PARSE_C)
168 if( p + 3 > end )
169 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
170
171 cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2];
172 p += 3;
173
174 if( cert_len == 0 )
175 {
176 session->peer_cert = NULL;
177 }
178 else
179 {
180 int ret;
181
182 if( p + cert_len > end )
183 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
184
185 session->peer_cert = mbedtls_malloc( sizeof( mbedtls_x509_crt ) );
186
187 if( session->peer_cert == NULL )
188 return( MBEDTLS_ERR_SSL_MALLOC_FAILED );
189
190 mbedtls_x509_crt_init( session->peer_cert );
191
192 if( ( ret = mbedtls_x509_crt_parse_der( session->peer_cert,
193 p, cert_len ) ) != 0 )
194 {
195 mbedtls_x509_crt_free( session->peer_cert );
196 mbedtls_free( session->peer_cert );
197 session->peer_cert = NULL;
198 return( ret );
199 }
200
201 p += cert_len;
202 }
203#endif /* MBEDTLS_X509_CRT_PARSE_C */
204
205 if( p != end )
206 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
207
208 return( 0 );
209}
210
211/*
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200212 * Create session ticket, with the following structure:
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200213 *
214 * struct {
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200215 * opaque key_name[4];
216 * opaque iv[12];
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200217 * opaque encrypted_state<0..2^16-1>;
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200218 * opaque tag[16];
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200219 * } ticket;
220 *
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200221 * The key_name, iv, and length of encrypted_state are the additional
222 * authenticated data.
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200223 */
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200224int mbedtls_ssl_ticket_write( void *p_ticket,
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200225 const mbedtls_ssl_session *session,
226 unsigned char *start,
227 const unsigned char *end,
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200228 size_t *tlen,
229 uint32_t *ticket_lifetime )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200230{
231 int ret;
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +0200232 mbedtls_ssl_ticket_context *ctx = p_ticket;
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200233 unsigned char *key_name = start;
234 unsigned char *iv = start + 4;
235 unsigned char *state_len_bytes = iv + 12;
236 unsigned char *state = state_len_bytes + 2;
237 unsigned char *tag;
238 size_t clear_len, ciph_len;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200239
240 *tlen = 0;
241
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200242 if( ctx == NULL || ctx->f_rng == NULL )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200243 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
244
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200245 /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag,
246 * in addition to session itself, that will be checked when writing it. */
247 if( end - start < 4 + 12 + 2 + 16 )
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200248 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
249
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200250#if defined(MBEDTLS_THREADING_C)
251 if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
252 return( ret );
253#endif
254
255 *ticket_lifetime = ctx->ticket_lifetime;
256
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200257 memcpy( key_name, ctx->key_name, 4 );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200258
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200259 if( ( ret = ctx->f_rng( ctx->p_rng, iv, 12 ) ) != 0 )
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200260 goto cleanup;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200261
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200262 /* Dump session state */
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200263 if( ( ret = ssl_save_session( session,
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200264 state, end - state, &clear_len ) ) != 0 ||
265 (unsigned long) clear_len > 65535 )
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200266 {
267 goto cleanup;
268 }
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200269 state_len_bytes[0] = ( clear_len >> 8 ) & 0xff;
270 state_len_bytes[1] = ( clear_len ) & 0xff;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200271
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200272 /* Encrypt and authenticate */
273 tag = state + clear_len;
274 if( ( ret = mbedtls_cipher_auth_encrypt( &ctx->cipher,
275 iv, 12, key_name, 4 + 12 + 2,
276 state, clear_len, state, &ciph_len, tag, 16 ) ) != 0 )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200277 {
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200278 goto cleanup;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200279 }
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200280 if( ciph_len != clear_len )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200281 {
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200282 ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200283 goto cleanup;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200284 }
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200285
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200286 *tlen = 4 + 12 + 2 + 16 + ciph_len;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200287
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200288cleanup:
289#if defined(MBEDTLS_THREADING_C)
290 if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
291 return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
292#endif
293
294 return( ret );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200295}
296
297/*
298 * Load session ticket (see mbedtls_ssl_ticket_write for structure)
299 */
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200300int mbedtls_ssl_ticket_parse( void *p_ticket,
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200301 mbedtls_ssl_session *session,
302 unsigned char *buf,
303 size_t len )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200304{
305 int ret;
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +0200306 mbedtls_ssl_ticket_context *ctx = p_ticket;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200307 unsigned char *key_name = buf;
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200308 unsigned char *iv = buf + 4;
309 unsigned char *enc_len_p = iv + 12;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200310 unsigned char *ticket = enc_len_p + 2;
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200311 unsigned char *tag;
312 size_t enc_len, clear_len;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200313
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200314 if( ctx == NULL || ctx->f_rng == NULL ||
315 len < 4 + 12 + 2 + 16 )
316 {
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200317 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200318 }
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200319
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200320#if defined(MBEDTLS_THREADING_C)
321 if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
322 return( ret );
323#endif
324
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200325 enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1];
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200326 tag = ticket + enc_len;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200327
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200328 if( len != 4 + 12 + 2 + enc_len + 16 )
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200329 {
330 ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
331 goto cleanup;
332 }
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200333
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200334 /* Check name (public data) */
335 if( memcmp( key_name, ctx->key_name, 4 ) != 0 )
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200336 {
337 ret = MBEDTLS_ERR_SSL_INVALID_MAC;
338 goto cleanup;
339 }
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200340
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200341 /* Decrypt and authenticate */
342 if( ( ret = mbedtls_cipher_auth_decrypt( &ctx->cipher, iv, 12,
343 key_name, 4 + 12 + 2, ticket, enc_len,
344 ticket, &clear_len, tag, 16 ) ) != 0 )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200345 {
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200346 /* TODO: convert AUTH_FAILED to INVALID_MAC */
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200347 goto cleanup;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200348 }
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200349 if( clear_len != enc_len )
350 {
351 ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200352 goto cleanup;
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200353 }
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200354
355 /* Actually load session */
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200356 if( ( ret = ssl_load_session( session, ticket, clear_len ) ) != 0 )
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200357 goto cleanup;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200358
359#if defined(MBEDTLS_HAVE_TIME)
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200360 {
Manuel Pégourié-Gonnard8eff5122015-05-20 11:41:36 +0200361 /* Check for expiration */
362 time_t current_time = time( NULL );
363
364 if( current_time < session->start ||
365 (uint32_t)( current_time - session->start ) > ctx->ticket_lifetime )
366 {
367 ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
368 goto cleanup;
369 }
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200370 }
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200371#endif
372
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200373cleanup:
374#if defined(MBEDTLS_THREADING_C)
375 if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
376 return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
377#endif
378
379 return( ret );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200380}
381
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +0200382/*
383 * Free context
384 */
385void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx )
386{
Manuel Pégourié-Gonnard1041a392015-05-20 19:59:39 +0200387 mbedtls_cipher_free( &ctx->cipher );
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +0200388
Manuel Pégourié-Gonnard0849a0a2015-05-20 11:34:54 +0200389#if defined(MBEDTLS_THREADING_C)
390 mbedtls_mutex_free( &ctx->mutex );
391#endif
392
Manuel Pégourié-Gonnardd59675d2015-05-19 15:28:00 +0200393 mbedtls_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) );
394}
395
Manuel Pégourié-Gonnardfd6d8972015-05-15 12:09:00 +0200396#endif /* MBEDTLS_SSL_TICKET_C */