blob: 5ce7a359761556e0f0f89ae32e540bed7d1f2e36 [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é-Gonnard69f17282015-05-18 14:35:08 +0200165int mbedtls_ssl_ticket_write( const mbedtls_ssl_config *conf,
166 const mbedtls_ssl_session *session,
167 unsigned char *start,
168 const unsigned char *end,
169 size_t *tlen )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200170{
171 int ret;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200172 unsigned char *p = start;
173 unsigned char *state;
174 unsigned char iv[16];
175 size_t clear_len, enc_len, pad_len, i;
176
177 *tlen = 0;
178
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200179 if( conf->ticket_keys == NULL )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200180 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
181
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200182 /* We need at least 16 bytes for key_name, 16 for IV, 2 for len
183 * 16 for padding, 32 for MAC, in addition to session itself,
184 * that will be checked when writing it. */
185 if( end - start < 16 + 16 + 2 + 16 + 32 )
186 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
187
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200188 /* Write key name */
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200189 memcpy( p, conf->ticket_keys->key_name, 16 );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200190 p += 16;
191
192 /* Generate and write IV (with a copy for aes_crypt) */
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200193 if( ( ret = conf->f_rng( conf->p_rng, p, 16 ) ) != 0 )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200194 return( ret );
195 memcpy( iv, p, 16 );
196 p += 16;
197
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200198 /* Dump session state */
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200199 state = p + 2;
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200200 if( ssl_save_session( session, state, end - state, &clear_len ) != 0 )
201 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200202
203 /* Apply PKCS padding */
204 pad_len = 16 - clear_len % 16;
205 enc_len = clear_len + pad_len;
206 for( i = clear_len; i < enc_len; i++ )
207 state[i] = (unsigned char) pad_len;
208
209 /* Encrypt */
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200210 if( ( ret = mbedtls_aes_crypt_cbc( &conf->ticket_keys->enc, MBEDTLS_AES_ENCRYPT,
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200211 enc_len, iv, state, state ) ) != 0 )
212 {
213 return( ret );
214 }
215
216 /* Write length */
217 *p++ = (unsigned char)( ( enc_len >> 8 ) & 0xFF );
218 *p++ = (unsigned char)( ( enc_len ) & 0xFF );
219 p = state + enc_len;
220
221 /* Compute and write MAC( key_name + iv + enc_state_len + enc_state ) */
222 if( ( ret = mbedtls_md_hmac( mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ),
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200223 conf->ticket_keys->mac_key, 16,
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200224 start, p - start, p ) ) != 0 )
225 {
226 return( ret );
227 }
228 p += 32;
229
230 *tlen = p - start;
231
232 return( 0 );
233}
234
235/*
236 * Load session ticket (see mbedtls_ssl_ticket_write for structure)
237 */
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200238int mbedtls_ssl_ticket_parse( const mbedtls_ssl_config *conf,
239 mbedtls_ssl_session *session,
240 unsigned char *buf,
241 size_t len )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200242{
243 int ret;
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200244 unsigned char *key_name = buf;
245 unsigned char *iv = buf + 16;
246 unsigned char *enc_len_p = iv + 16;
247 unsigned char *ticket = enc_len_p + 2;
248 unsigned char *mac;
249 unsigned char computed_mac[32];
250 size_t enc_len, clear_len, i;
251 unsigned char pad_len, diff;
252
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200253 if( len < 34 || conf->ticket_keys == NULL )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200254 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
255
256 enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1];
257 mac = ticket + enc_len;
258
259 if( len != enc_len + 66 )
260 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
261
262 /* Check name, in constant time though it's not a big secret */
263 diff = 0;
264 for( i = 0; i < 16; i++ )
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200265 diff |= key_name[i] ^ conf->ticket_keys->key_name[i];
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200266 /* don't return yet, check the MAC anyway */
267
268 /* Check mac, with constant-time buffer comparison */
269 if( ( ret = mbedtls_md_hmac( mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ),
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200270 conf->ticket_keys->mac_key, 16,
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200271 buf, len - 32, computed_mac ) ) != 0 )
272 {
273 return( ret );
274 }
275
276 for( i = 0; i < 32; i++ )
277 diff |= mac[i] ^ computed_mac[i];
278
279 /* Now return if ticket is not authentic, since we want to avoid
280 * decrypting arbitrary attacker-chosen data */
281 if( diff != 0 )
282 return( MBEDTLS_ERR_SSL_INVALID_MAC );
283
284 /* Decrypt */
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200285 if( ( ret = mbedtls_aes_crypt_cbc( &conf->ticket_keys->dec, MBEDTLS_AES_DECRYPT,
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200286 enc_len, iv, ticket, ticket ) ) != 0 )
287 {
288 return( ret );
289 }
290
291 /* Check PKCS padding */
292 pad_len = ticket[enc_len - 1];
293
294 ret = 0;
295 for( i = 2; i < pad_len; i++ )
296 if( ticket[enc_len - i] != pad_len )
297 ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
298 if( ret != 0 )
299 return( ret );
300
301 clear_len = enc_len - pad_len;
302
303 /* Actually load session */
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200304 if( ( ret = ssl_load_session( session, ticket, clear_len ) ) != 0 )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200305 return( ret );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200306
307#if defined(MBEDTLS_HAVE_TIME)
308 /* Check if still valid */
Manuel Pégourié-Gonnard69f17282015-05-18 14:35:08 +0200309 if( (int) ( time( NULL) - session->start ) > conf->ticket_lifetime )
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200310 return( MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED );
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200311#endif
312
Manuel Pégourié-Gonnarda4a47352015-05-15 15:14:54 +0200313 return( 0 );
314}
315
Manuel Pégourié-Gonnardfd6d8972015-05-15 12:09:00 +0200316#endif /* MBEDTLS_SSL_TICKET_C */