blob: 181f045da71eebea4e24b54024e63e1ff46803ff [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é-Gonnarda4a47352015-05-15 15:14:54 +020042/*
43 * Serialize a session in the following format:
44 * 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session)
45 * n . n+2 peer_cert length = m (0 if no certificate)
46 * n+3 . n+2+m peer cert ASN.1
47 *
48 * Assumes ticket is NULL (always true on server side).
49 */
50static int ssl_save_session( const mbedtls_ssl_session *session,
51 unsigned char *buf, size_t buf_len,
52 size_t *olen )
53{
54 unsigned char *p = buf;
55 size_t left = buf_len;
56#if defined(MBEDTLS_X509_CRT_PARSE_C)
57 size_t cert_len;
58#endif /* MBEDTLS_X509_CRT_PARSE_C */
59
60 if( left < sizeof( mbedtls_ssl_session ) )
61 return( -1 );
62
63 memcpy( p, session, sizeof( mbedtls_ssl_session ) );
64 p += sizeof( mbedtls_ssl_session );
65 left -= sizeof( mbedtls_ssl_session );
66
67#if defined(MBEDTLS_X509_CRT_PARSE_C)
68 if( session->peer_cert == NULL )
69 cert_len = 0;
70 else
71 cert_len = session->peer_cert->raw.len;
72
73 if( left < 3 + cert_len )
74 return( -1 );
75
76 *p++ = (unsigned char)( cert_len >> 16 & 0xFF );
77 *p++ = (unsigned char)( cert_len >> 8 & 0xFF );
78 *p++ = (unsigned char)( cert_len & 0xFF );
79
80 if( session->peer_cert != NULL )
81 memcpy( p, session->peer_cert->raw.p, cert_len );
82
83 p += cert_len;
84#endif /* MBEDTLS_X509_CRT_PARSE_C */
85
86 *olen = p - buf;
87
88 return( 0 );
89}
90
91/*
92 * Unserialise session, see ssl_save_session()
93 */
94static int ssl_load_session( mbedtls_ssl_session *session,
95 const unsigned char *buf, size_t len )
96{
97 const unsigned char *p = buf;
98 const unsigned char * const end = buf + len;
99#if defined(MBEDTLS_X509_CRT_PARSE_C)
100 size_t cert_len;
101#endif /* MBEDTLS_X509_CRT_PARSE_C */
102
103 if( p + sizeof( mbedtls_ssl_session ) > end )
104 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
105
106 memcpy( session, p, sizeof( mbedtls_ssl_session ) );
107 p += sizeof( mbedtls_ssl_session );
108
109#if defined(MBEDTLS_X509_CRT_PARSE_C)
110 if( p + 3 > end )
111 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
112
113 cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2];
114 p += 3;
115
116 if( cert_len == 0 )
117 {
118 session->peer_cert = NULL;
119 }
120 else
121 {
122 int ret;
123
124 if( p + cert_len > end )
125 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
126
127 session->peer_cert = mbedtls_malloc( sizeof( mbedtls_x509_crt ) );
128
129 if( session->peer_cert == NULL )
130 return( MBEDTLS_ERR_SSL_MALLOC_FAILED );
131
132 mbedtls_x509_crt_init( session->peer_cert );
133
134 if( ( ret = mbedtls_x509_crt_parse_der( session->peer_cert,
135 p, cert_len ) ) != 0 )
136 {
137 mbedtls_x509_crt_free( session->peer_cert );
138 mbedtls_free( session->peer_cert );
139 session->peer_cert = NULL;
140 return( ret );
141 }
142
143 p += cert_len;
144 }
145#endif /* MBEDTLS_X509_CRT_PARSE_C */
146
147 if( p != end )
148 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
149
150 return( 0 );
151}
152
153/*
154 * Create session ticket, secured as recommended in RFC 5077 section 4:
155 *
156 * struct {
157 * opaque key_name[16];
158 * opaque iv[16];
159 * opaque encrypted_state<0..2^16-1>;
160 * opaque mac[32];
161 * } ticket;
162 *
163 * (the internal state structure differs, however).
164 */
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200165int mbedtls_ssl_ticket_write( void *p_ticket,
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200166 const mbedtls_ssl_session *session,
167 unsigned char *start,
168 const unsigned char *end,
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200169 size_t *tlen,
170 uint32_t *ticket_lifetime )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200171{
172 int ret;
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200173 mbedtls_ssl_ticket_keys *ctx = p_ticket;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200174 unsigned char *p = start;
175 unsigned char *state;
176 unsigned char iv[16];
177 size_t clear_len, enc_len, pad_len, i;
178
179 *tlen = 0;
180
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200181 if( ctx == NULL )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200182 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
183
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200184 *ticket_lifetime = ctx->ticket_lifetime;
185
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200186 /* We need at least 16 bytes for key_name, 16 for IV, 2 for len
187 * 16 for padding, 32 for MAC, in addition to session itself,
188 * that will be checked when writing it. */
189 if( end - start < 16 + 16 + 2 + 16 + 32 )
190 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
191
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200192 /* Write key name */
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200193 memcpy( p, ctx->key_name, 16 );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200194 p += 16;
195
196 /* Generate and write IV (with a copy for aes_crypt) */
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200197 memset( p, 0x2a, 16 ); /* Temporary WIP */
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200198 memcpy( iv, p, 16 );
199 p += 16;
200
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200201 /* Dump session state */
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200202 state = p + 2;
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200203 if( ssl_save_session( session, state, end - state, &clear_len ) != 0 )
204 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200205
206 /* Apply PKCS padding */
207 pad_len = 16 - clear_len % 16;
208 enc_len = clear_len + pad_len;
209 for( i = clear_len; i < enc_len; i++ )
210 state[i] = (unsigned char) pad_len;
211
212 /* Encrypt */
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200213 if( ( ret = mbedtls_aes_crypt_cbc( &ctx->enc, MBEDTLS_AES_ENCRYPT,
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200214 enc_len, iv, state, state ) ) != 0 )
215 {
216 return( ret );
217 }
218
219 /* Write length */
220 *p++ = (unsigned char)( ( enc_len >> 8 ) & 0xFF );
221 *p++ = (unsigned char)( ( enc_len ) & 0xFF );
222 p = state + enc_len;
223
224 /* Compute and write MAC( key_name + iv + enc_state_len + enc_state ) */
225 if( ( ret = mbedtls_md_hmac( mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ),
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200226 ctx->mac_key, 16,
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200227 start, p - start, p ) ) != 0 )
228 {
229 return( ret );
230 }
231 p += 32;
232
233 *tlen = p - start;
234
235 return( 0 );
236}
237
238/*
239 * Load session ticket (see mbedtls_ssl_ticket_write for structure)
240 */
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200241int mbedtls_ssl_ticket_parse( void *p_ticket,
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200242 mbedtls_ssl_session *session,
243 unsigned char *buf,
244 size_t len )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200245{
246 int ret;
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200247 mbedtls_ssl_ticket_keys *ctx = p_ticket;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200248 unsigned char *key_name = buf;
249 unsigned char *iv = buf + 16;
250 unsigned char *enc_len_p = iv + 16;
251 unsigned char *ticket = enc_len_p + 2;
252 unsigned char *mac;
253 unsigned char computed_mac[32];
254 size_t enc_len, clear_len, i;
255 unsigned char pad_len, diff;
256
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200257 if( len < 34 || ctx == NULL )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200258 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
259
260 enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1];
261 mac = ticket + enc_len;
262
263 if( len != enc_len + 66 )
264 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
265
266 /* Check name, in constant time though it's not a big secret */
267 diff = 0;
268 for( i = 0; i < 16; i++ )
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200269 diff |= key_name[i] ^ ctx->key_name[i];
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200270 /* don't return yet, check the MAC anyway */
271
272 /* Check mac, with constant-time buffer comparison */
273 if( ( ret = mbedtls_md_hmac( mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ),
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200274 ctx->mac_key, 16,
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200275 buf, len - 32, computed_mac ) ) != 0 )
276 {
277 return( ret );
278 }
279
280 for( i = 0; i < 32; i++ )
281 diff |= mac[i] ^ computed_mac[i];
282
283 /* Now return if ticket is not authentic, since we want to avoid
284 * decrypting arbitrary attacker-chosen data */
285 if( diff != 0 )
286 return( MBEDTLS_ERR_SSL_INVALID_MAC );
287
288 /* Decrypt */
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200289 if( ( ret = mbedtls_aes_crypt_cbc( &ctx->dec, MBEDTLS_AES_DECRYPT,
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200290 enc_len, iv, ticket, ticket ) ) != 0 )
291 {
292 return( ret );
293 }
294
295 /* Check PKCS padding */
296 pad_len = ticket[enc_len - 1];
297
298 ret = 0;
299 for( i = 2; i < pad_len; i++ )
300 if( ticket[enc_len - i] != pad_len )
301 ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
302 if( ret != 0 )
303 return( ret );
304
305 clear_len = enc_len - pad_len;
306
307 /* Actually load session */
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200308 if( ( ret = ssl_load_session( session, ticket, clear_len ) ) != 0 )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200309 return( ret );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200310
311#if defined(MBEDTLS_HAVE_TIME)
312 /* Check if still valid */
Manuel Pégourié-Gonnardb0394be2015-05-19 11:40:30 +0200313 if( ( time( NULL) - session->start ) > ctx->ticket_lifetime )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200314 return( MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200315#endif
316
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200317 return( 0 );
318}
319
Manuel Pégourié-Gonnardfd6d8972015-05-15 12:09:00 +0200320#endif /* MBEDTLS_SSL_TICKET_C */