source: azure_iot_hub_mbedtls/trunk/mbedtls-2.16.1/library/ssl_ticket.c@ 398

Last change on this file since 398 was 398, checked in by coas-nagasima, 5 years ago

mbedTLS版Azure IoT Hub接続サンプルのソースコードを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 13.0 KB
Line 
1/*
2 * TLS server tickets callbacks implementation
3 *
4 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
5 * SPDX-License-Identifier: Apache-2.0
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/platform_util.h"
40
41#include <string.h>
42
43/*
44 * Initialze context
45 */
46void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx )
47{
48 memset( ctx, 0, sizeof( mbedtls_ssl_ticket_context ) );
49
50#if defined(MBEDTLS_THREADING_C)
51 mbedtls_mutex_init( &ctx->mutex );
52#endif
53}
54
55#define MAX_KEY_BYTES 32 /* 256 bits */
56
57/*
58 * Generate/update a key
59 */
60static int ssl_ticket_gen_key( mbedtls_ssl_ticket_context *ctx,
61 unsigned char index )
62{
63 int ret;
64 unsigned char buf[MAX_KEY_BYTES];
65 mbedtls_ssl_ticket_key *key = ctx->keys + index;
66
67#if defined(MBEDTLS_HAVE_TIME)
68 key->generation_time = (uint32_t) mbedtls_time( NULL );
69#endif
70
71 if( ( ret = ctx->f_rng( ctx->p_rng, key->name, sizeof( key->name ) ) ) != 0 )
72 return( ret );
73
74 if( ( ret = ctx->f_rng( ctx->p_rng, buf, sizeof( buf ) ) ) != 0 )
75 return( ret );
76
77 /* With GCM and CCM, same context can encrypt & decrypt */
78 ret = mbedtls_cipher_setkey( &key->ctx, buf,
79 mbedtls_cipher_get_key_bitlen( &key->ctx ),
80 MBEDTLS_ENCRYPT );
81
82 mbedtls_platform_zeroize( buf, sizeof( buf ) );
83
84 return( ret );
85}
86
87/*
88 * Rotate/generate keys if necessary
89 */
90static int ssl_ticket_update_keys( mbedtls_ssl_ticket_context *ctx )
91{
92#if !defined(MBEDTLS_HAVE_TIME)
93 ((void) ctx);
94#else
95 if( ctx->ticket_lifetime != 0 )
96 {
97 uint32_t current_time = (uint32_t) mbedtls_time( NULL );
98 uint32_t key_time = ctx->keys[ctx->active].generation_time;
99
100 if( current_time >= key_time &&
101 current_time - key_time < ctx->ticket_lifetime )
102 {
103 return( 0 );
104 }
105
106 ctx->active = 1 - ctx->active;
107
108 return( ssl_ticket_gen_key( ctx, ctx->active ) );
109 }
110 else
111#endif /* MBEDTLS_HAVE_TIME */
112 return( 0 );
113}
114
115/*
116 * Setup context for actual use
117 */
118int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx,
119 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
120 mbedtls_cipher_type_t cipher,
121 uint32_t lifetime )
122{
123 int ret;
124 const mbedtls_cipher_info_t *cipher_info;
125
126 ctx->f_rng = f_rng;
127 ctx->p_rng = p_rng;
128
129 ctx->ticket_lifetime = lifetime;
130
131 cipher_info = mbedtls_cipher_info_from_type( cipher);
132 if( cipher_info == NULL )
133 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
134
135 if( cipher_info->mode != MBEDTLS_MODE_GCM &&
136 cipher_info->mode != MBEDTLS_MODE_CCM )
137 {
138 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
139 }
140
141 if( cipher_info->key_bitlen > 8 * MAX_KEY_BYTES )
142 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
143
144 if( ( ret = mbedtls_cipher_setup( &ctx->keys[0].ctx, cipher_info ) ) != 0 ||
145 ( ret = mbedtls_cipher_setup( &ctx->keys[1].ctx, cipher_info ) ) != 0 )
146 {
147 return( ret );
148 }
149
150 if( ( ret = ssl_ticket_gen_key( ctx, 0 ) ) != 0 ||
151 ( ret = ssl_ticket_gen_key( ctx, 1 ) ) != 0 )
152 {
153 return( ret );
154 }
155
156 return( 0 );
157}
158
159/*
160 * Serialize a session in the following format:
161 * 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session)
162 * n . n+2 peer_cert length = m (0 if no certificate)
163 * n+3 . n+2+m peer cert ASN.1
164 */
165static int ssl_save_session( const mbedtls_ssl_session *session,
166 unsigned char *buf, size_t buf_len,
167 size_t *olen )
168{
169 unsigned char *p = buf;
170 size_t left = buf_len;
171#if defined(MBEDTLS_X509_CRT_PARSE_C)
172 size_t cert_len;
173#endif /* MBEDTLS_X509_CRT_PARSE_C */
174
175 if( left < sizeof( mbedtls_ssl_session ) )
176 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
177
178 memcpy( p, session, sizeof( mbedtls_ssl_session ) );
179 p += sizeof( mbedtls_ssl_session );
180 left -= sizeof( mbedtls_ssl_session );
181
182#if defined(MBEDTLS_X509_CRT_PARSE_C)
183 if( session->peer_cert == NULL )
184 cert_len = 0;
185 else
186 cert_len = session->peer_cert->raw.len;
187
188 if( left < 3 + cert_len )
189 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
190
191 *p++ = (unsigned char)( ( cert_len >> 16 ) & 0xFF );
192 *p++ = (unsigned char)( ( cert_len >> 8 ) & 0xFF );
193 *p++ = (unsigned char)( ( cert_len ) & 0xFF );
194
195 if( session->peer_cert != NULL )
196 memcpy( p, session->peer_cert->raw.p, cert_len );
197
198 p += cert_len;
199#endif /* MBEDTLS_X509_CRT_PARSE_C */
200
201 *olen = p - buf;
202
203 return( 0 );
204}
205
206/*
207 * Unserialise session, see ssl_save_session()
208 */
209static int ssl_load_session( mbedtls_ssl_session *session,
210 const unsigned char *buf, size_t len )
211{
212 const unsigned char *p = buf;
213 const unsigned char * const end = buf + len;
214#if defined(MBEDTLS_X509_CRT_PARSE_C)
215 size_t cert_len;
216#endif /* MBEDTLS_X509_CRT_PARSE_C */
217
218 if( sizeof( mbedtls_ssl_session ) > (size_t)( end - p ) )
219 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
220
221 memcpy( session, p, sizeof( mbedtls_ssl_session ) );
222 p += sizeof( mbedtls_ssl_session );
223
224#if defined(MBEDTLS_X509_CRT_PARSE_C)
225 if( 3 > (size_t)( end - p ) )
226 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
227
228 cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2];
229 p += 3;
230
231 if( cert_len == 0 )
232 {
233 session->peer_cert = NULL;
234 }
235 else
236 {
237 int ret;
238
239 if( cert_len > (size_t)( end - p ) )
240 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
241
242 session->peer_cert = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) );
243
244 if( session->peer_cert == NULL )
245 return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
246
247 mbedtls_x509_crt_init( session->peer_cert );
248
249 if( ( ret = mbedtls_x509_crt_parse_der( session->peer_cert,
250 p, cert_len ) ) != 0 )
251 {
252 mbedtls_x509_crt_free( session->peer_cert );
253 mbedtls_free( session->peer_cert );
254 session->peer_cert = NULL;
255 return( ret );
256 }
257
258 p += cert_len;
259 }
260#endif /* MBEDTLS_X509_CRT_PARSE_C */
261
262 if( p != end )
263 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
264
265 return( 0 );
266}
267
268/*
269 * Create session ticket, with the following structure:
270 *
271 * struct {
272 * opaque key_name[4];
273 * opaque iv[12];
274 * opaque encrypted_state<0..2^16-1>;
275 * opaque tag[16];
276 * } ticket;
277 *
278 * The key_name, iv, and length of encrypted_state are the additional
279 * authenticated data.
280 */
281int mbedtls_ssl_ticket_write( void *p_ticket,
282 const mbedtls_ssl_session *session,
283 unsigned char *start,
284 const unsigned char *end,
285 size_t *tlen,
286 uint32_t *ticket_lifetime )
287{
288 int ret;
289 mbedtls_ssl_ticket_context *ctx = p_ticket;
290 mbedtls_ssl_ticket_key *key;
291 unsigned char *key_name = start;
292 unsigned char *iv = start + 4;
293 unsigned char *state_len_bytes = iv + 12;
294 unsigned char *state = state_len_bytes + 2;
295 unsigned char *tag;
296 size_t clear_len, ciph_len;
297
298 *tlen = 0;
299
300 if( ctx == NULL || ctx->f_rng == NULL )
301 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
302
303 /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag,
304 * in addition to session itself, that will be checked when writing it. */
305 if( end - start < 4 + 12 + 2 + 16 )
306 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
307
308#if defined(MBEDTLS_THREADING_C)
309 if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
310 return( ret );
311#endif
312
313 if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 )
314 goto cleanup;
315
316 key = &ctx->keys[ctx->active];
317
318 *ticket_lifetime = ctx->ticket_lifetime;
319
320 memcpy( key_name, key->name, 4 );
321
322 if( ( ret = ctx->f_rng( ctx->p_rng, iv, 12 ) ) != 0 )
323 goto cleanup;
324
325 /* Dump session state */
326 if( ( ret = ssl_save_session( session,
327 state, end - state, &clear_len ) ) != 0 ||
328 (unsigned long) clear_len > 65535 )
329 {
330 goto cleanup;
331 }
332 state_len_bytes[0] = ( clear_len >> 8 ) & 0xff;
333 state_len_bytes[1] = ( clear_len ) & 0xff;
334
335 /* Encrypt and authenticate */
336 tag = state + clear_len;
337 if( ( ret = mbedtls_cipher_auth_encrypt( &key->ctx,
338 iv, 12, key_name, 4 + 12 + 2,
339 state, clear_len, state, &ciph_len, tag, 16 ) ) != 0 )
340 {
341 goto cleanup;
342 }
343 if( ciph_len != clear_len )
344 {
345 ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
346 goto cleanup;
347 }
348
349 *tlen = 4 + 12 + 2 + 16 + ciph_len;
350
351cleanup:
352#if defined(MBEDTLS_THREADING_C)
353 if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
354 return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
355#endif
356
357 return( ret );
358}
359
360/*
361 * Select key based on name
362 */
363static mbedtls_ssl_ticket_key *ssl_ticket_select_key(
364 mbedtls_ssl_ticket_context *ctx,
365 const unsigned char name[4] )
366{
367 unsigned char i;
368
369 for( i = 0; i < sizeof( ctx->keys ) / sizeof( *ctx->keys ); i++ )
370 if( memcmp( name, ctx->keys[i].name, 4 ) == 0 )
371 return( &ctx->keys[i] );
372
373 return( NULL );
374}
375
376/*
377 * Load session ticket (see mbedtls_ssl_ticket_write for structure)
378 */
379int mbedtls_ssl_ticket_parse( void *p_ticket,
380 mbedtls_ssl_session *session,
381 unsigned char *buf,
382 size_t len )
383{
384 int ret;
385 mbedtls_ssl_ticket_context *ctx = p_ticket;
386 mbedtls_ssl_ticket_key *key;
387 unsigned char *key_name = buf;
388 unsigned char *iv = buf + 4;
389 unsigned char *enc_len_p = iv + 12;
390 unsigned char *ticket = enc_len_p + 2;
391 unsigned char *tag;
392 size_t enc_len, clear_len;
393
394 if( ctx == NULL || ctx->f_rng == NULL )
395 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
396
397 /* See mbedtls_ssl_ticket_write() */
398 if( len < 4 + 12 + 2 + 16 )
399 return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
400
401#if defined(MBEDTLS_THREADING_C)
402 if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
403 return( ret );
404#endif
405
406 if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 )
407 goto cleanup;
408
409 enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1];
410 tag = ticket + enc_len;
411
412 if( len != 4 + 12 + 2 + enc_len + 16 )
413 {
414 ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
415 goto cleanup;
416 }
417
418 /* Select key */
419 if( ( key = ssl_ticket_select_key( ctx, key_name ) ) == NULL )
420 {
421 /* We can't know for sure but this is a likely option unless we're
422 * under attack - this is only informative anyway */
423 ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
424 goto cleanup;
425 }
426
427 /* Decrypt and authenticate */
428 if( ( ret = mbedtls_cipher_auth_decrypt( &key->ctx, iv, 12,
429 key_name, 4 + 12 + 2, ticket, enc_len,
430 ticket, &clear_len, tag, 16 ) ) != 0 )
431 {
432 if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED )
433 ret = MBEDTLS_ERR_SSL_INVALID_MAC;
434
435 goto cleanup;
436 }
437 if( clear_len != enc_len )
438 {
439 ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
440 goto cleanup;
441 }
442
443 /* Actually load session */
444 if( ( ret = ssl_load_session( session, ticket, clear_len ) ) != 0 )
445 goto cleanup;
446
447#if defined(MBEDTLS_HAVE_TIME)
448 {
449 /* Check for expiration */
450 mbedtls_time_t current_time = mbedtls_time( NULL );
451
452 if( current_time < session->start ||
453 (uint32_t)( current_time - session->start ) > ctx->ticket_lifetime )
454 {
455 ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
456 goto cleanup;
457 }
458 }
459#endif
460
461cleanup:
462#if defined(MBEDTLS_THREADING_C)
463 if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
464 return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
465#endif
466
467 return( ret );
468}
469
470/*
471 * Free context
472 */
473void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx )
474{
475 mbedtls_cipher_free( &ctx->keys[0].ctx );
476 mbedtls_cipher_free( &ctx->keys[1].ctx );
477
478#if defined(MBEDTLS_THREADING_C)
479 mbedtls_mutex_free( &ctx->mutex );
480#endif
481
482 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) );
483}
484
485#endif /* MBEDTLS_SSL_TICKET_C */
Note: See TracBrowser for help on using the repository browser.