joey shelton / LED_Demo

Dependencies:   MAX44000 PWM_Tone_Library nexpaq_mdk

Fork of LED_Demo by Maxim nexpaq

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ssl_ticket.c Source File

ssl_ticket.c

00001 /*
00002  *  TLS server tickets callbacks implementation
00003  *
00004  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
00005  *  SPDX-License-Identifier: Apache-2.0
00006  *
00007  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
00008  *  not use this file except in compliance with the License.
00009  *  You may obtain a copy of the License at
00010  *
00011  *  http://www.apache.org/licenses/LICENSE-2.0
00012  *
00013  *  Unless required by applicable law or agreed to in writing, software
00014  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00015  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00016  *  See the License for the specific language governing permissions and
00017  *  limitations under the License.
00018  *
00019  *  This file is part of mbed TLS (https://tls.mbed.org)
00020  */
00021 
00022 #if !defined(MBEDTLS_CONFIG_FILE)
00023 #include "mbedtls/config.h"
00024 #else
00025 #include MBEDTLS_CONFIG_FILE
00026 #endif
00027 
00028 #if defined(MBEDTLS_SSL_TICKET_C)
00029 
00030 #if defined(MBEDTLS_PLATFORM_C)
00031 #include "mbedtls/platform.h"
00032 #else
00033 #include <stdlib.h>
00034 #define mbedtls_calloc    calloc
00035 #define mbedtls_free      free
00036 #define mbedtls_time      time
00037 #define mbedtls_time_t    time_t
00038 #endif
00039 
00040 #include "mbedtls/ssl_ticket.h"
00041 
00042 #include <string.h>
00043 
00044 /* Implementation that should never be optimized out by the compiler */
00045 static void mbedtls_zeroize( void *v, size_t n ) {
00046     volatile unsigned char *p = v; while( n-- ) *p++ = 0;
00047 }
00048 
00049 /*
00050  * Initialze context
00051  */
00052 void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx )
00053 {
00054     memset( ctx, 0, sizeof( mbedtls_ssl_ticket_context ) );
00055 
00056 #if defined(MBEDTLS_THREADING_C)
00057     mbedtls_mutex_init( &ctx->mutex );
00058 #endif
00059 }
00060 
00061 #define MAX_KEY_BYTES 32    /* 256 bits */
00062 
00063 /*
00064  * Generate/update a key
00065  */
00066 static int ssl_ticket_gen_key( mbedtls_ssl_ticket_context *ctx,
00067                                unsigned char index )
00068 {
00069     int ret;
00070     unsigned char buf[MAX_KEY_BYTES];
00071     mbedtls_ssl_ticket_key *key = ctx->keys  + index;
00072 
00073 #if defined(MBEDTLS_HAVE_TIME)
00074     key->generation_time  = (uint32_t) mbedtls_time( NULL );
00075 #endif
00076 
00077     if( ( ret = ctx->f_rng( ctx->p_rng , key->name , sizeof( key->name  ) ) ) != 0 )
00078         return( ret );
00079 
00080     if( ( ret = ctx->f_rng( ctx->p_rng , buf, sizeof( buf ) ) ) != 0 )
00081         return( ret );
00082 
00083     /* With GCM and CCM, same context can encrypt & decrypt */
00084     ret = mbedtls_cipher_setkey( &key->ctx , buf,
00085                                  mbedtls_cipher_get_key_bitlen( &key->ctx  ),
00086                                  MBEDTLS_ENCRYPT );
00087 
00088     mbedtls_zeroize( buf, sizeof( buf ) );
00089 
00090     return( ret );
00091 }
00092 
00093 /*
00094  * Rotate/generate keys if necessary
00095  */
00096 static int ssl_ticket_update_keys( mbedtls_ssl_ticket_context *ctx )
00097 {
00098 #if !defined(MBEDTLS_HAVE_TIME)
00099     ((void) ctx);
00100 #else
00101     if( ctx->ticket_lifetime  != 0 )
00102     {
00103         uint32_t current_time = (uint32_t) mbedtls_time( NULL );
00104         uint32_t key_time = ctx->keys [ctx->active ].generation_time ;
00105 
00106         if( current_time > key_time &&
00107             current_time - key_time < ctx->ticket_lifetime )
00108         {
00109             return( 0 );
00110         }
00111 
00112         ctx->active  = 1 - ctx->active ;
00113 
00114         return( ssl_ticket_gen_key( ctx, ctx->active  ) );
00115     }
00116     else
00117 #endif /* MBEDTLS_HAVE_TIME */
00118         return( 0 );
00119 }
00120 
00121 /*
00122  * Setup context for actual use
00123  */
00124 int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx,
00125     int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
00126     mbedtls_cipher_type_t cipher,
00127     uint32_t lifetime )
00128 {
00129     int ret;
00130     const mbedtls_cipher_info_t *cipher_info;
00131 
00132     ctx->f_rng = f_rng;
00133     ctx->p_rng  = p_rng;
00134 
00135     ctx->ticket_lifetime  = lifetime;
00136 
00137     cipher_info = mbedtls_cipher_info_from_type( cipher);
00138     if( cipher_info == NULL )
00139         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00140 
00141     if( cipher_info->mode != MBEDTLS_MODE_GCM &&
00142         cipher_info->mode != MBEDTLS_MODE_CCM )
00143     {
00144         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00145     }
00146 
00147     if( cipher_info->key_bitlen > 8 * MAX_KEY_BYTES )
00148         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00149 
00150     if( ( ret = mbedtls_cipher_setup( &ctx->keys [0].ctx , cipher_info ) ) != 0 ||
00151         ( ret = mbedtls_cipher_setup( &ctx->keys [1].ctx , cipher_info ) ) != 0 )
00152     {
00153         return( ret );
00154     }
00155 
00156     if( ( ret = ssl_ticket_gen_key( ctx, 0 ) ) != 0 ||
00157         ( ret = ssl_ticket_gen_key( ctx, 1 ) ) != 0 )
00158     {
00159         return( ret );
00160     }
00161 
00162     return( 0 );
00163 }
00164 
00165 /*
00166  * Serialize a session in the following format:
00167  *  0   .   n-1     session structure, n = sizeof(mbedtls_ssl_session)
00168  *  n   .   n+2     peer_cert length = m (0 if no certificate)
00169  *  n+3 .   n+2+m   peer cert ASN.1
00170  */
00171 static int ssl_save_session( const mbedtls_ssl_session *session,
00172                              unsigned char *buf, size_t buf_len,
00173                              size_t *olen )
00174 {
00175     unsigned char *p = buf;
00176     size_t left = buf_len;
00177 #if defined(MBEDTLS_X509_CRT_PARSE_C)
00178     size_t cert_len;
00179 #endif /* MBEDTLS_X509_CRT_PARSE_C */
00180 
00181     if( left < sizeof( mbedtls_ssl_session ) )
00182         return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
00183 
00184     memcpy( p, session, sizeof( mbedtls_ssl_session ) );
00185     p += sizeof( mbedtls_ssl_session );
00186     left -= sizeof( mbedtls_ssl_session );
00187 
00188 #if defined(MBEDTLS_X509_CRT_PARSE_C)
00189     if( session->peer_cert == NULL )
00190         cert_len = 0;
00191     else
00192         cert_len = session->peer_cert->raw.len;
00193 
00194     if( left < 3 + cert_len )
00195         return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
00196 
00197     *p++ = (unsigned char)( cert_len >> 16 & 0xFF );
00198     *p++ = (unsigned char)( cert_len >>  8 & 0xFF );
00199     *p++ = (unsigned char)( cert_len       & 0xFF );
00200 
00201     if( session->peer_cert != NULL )
00202         memcpy( p, session->peer_cert->raw.p, cert_len );
00203 
00204     p += cert_len;
00205 #endif /* MBEDTLS_X509_CRT_PARSE_C */
00206 
00207     *olen = p - buf;
00208 
00209     return( 0 );
00210 }
00211 
00212 /*
00213  * Unserialise session, see ssl_save_session()
00214  */
00215 static int ssl_load_session( mbedtls_ssl_session *session,
00216                              const unsigned char *buf, size_t len )
00217 {
00218     const unsigned char *p = buf;
00219     const unsigned char * const end = buf + len;
00220 #if defined(MBEDTLS_X509_CRT_PARSE_C)
00221     size_t cert_len;
00222 #endif /* MBEDTLS_X509_CRT_PARSE_C */
00223 
00224     if( p + sizeof( mbedtls_ssl_session ) > end )
00225         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00226 
00227     memcpy( session, p, sizeof( mbedtls_ssl_session ) );
00228     p += sizeof( mbedtls_ssl_session );
00229 
00230 #if defined(MBEDTLS_X509_CRT_PARSE_C)
00231     if( p + 3 > end )
00232         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00233 
00234     cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2];
00235     p += 3;
00236 
00237     if( cert_len == 0 )
00238     {
00239         session->peer_cert = NULL;
00240     }
00241     else
00242     {
00243         int ret;
00244 
00245         if( p + cert_len > end )
00246             return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00247 
00248         session->peer_cert = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) );
00249 
00250         if( session->peer_cert == NULL )
00251             return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
00252 
00253         mbedtls_x509_crt_init( session->peer_cert );
00254 
00255         if( ( ret = mbedtls_x509_crt_parse_der( session->peer_cert,
00256                                         p, cert_len ) ) != 0 )
00257         {
00258             mbedtls_x509_crt_free( session->peer_cert );
00259             mbedtls_free( session->peer_cert );
00260             session->peer_cert = NULL;
00261             return( ret );
00262         }
00263 
00264         p += cert_len;
00265     }
00266 #endif /* MBEDTLS_X509_CRT_PARSE_C */
00267 
00268     if( p != end )
00269         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00270 
00271     return( 0 );
00272 }
00273 
00274 /*
00275  * Create session ticket, with the following structure:
00276  *
00277  *    struct {
00278  *        opaque key_name[4];
00279  *        opaque iv[12];
00280  *        opaque encrypted_state<0..2^16-1>;
00281  *        opaque tag[16];
00282  *    } ticket;
00283  *
00284  * The key_name, iv, and length of encrypted_state are the additional
00285  * authenticated data.
00286  */
00287 int mbedtls_ssl_ticket_write( void *p_ticket,
00288                               const mbedtls_ssl_session *session,
00289                               unsigned char *start,
00290                               const unsigned char *end,
00291                               size_t *tlen,
00292                               uint32_t *ticket_lifetime )
00293 {
00294     int ret;
00295     mbedtls_ssl_ticket_context *ctx = p_ticket;
00296     mbedtls_ssl_ticket_key *key;
00297     unsigned char *key_name = start;
00298     unsigned char *iv = start + 4;
00299     unsigned char *state_len_bytes = iv + 12;
00300     unsigned char *state = state_len_bytes + 2;
00301     unsigned char *tag;
00302     size_t clear_len, ciph_len;
00303 
00304     *tlen = 0;
00305 
00306     if( ctx == NULL || ctx->f_rng == NULL )
00307         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00308 
00309     /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag,
00310      * in addition to session itself, that will be checked when writing it. */
00311     if( end - start < 4 + 12 + 2 + 16 )
00312         return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
00313 
00314 #if defined(MBEDTLS_THREADING_C)
00315     if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
00316         return( ret );
00317 #endif
00318 
00319     if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 )
00320         goto cleanup;
00321 
00322     key = &ctx->keys [ctx->active ];
00323 
00324     *ticket_lifetime = ctx->ticket_lifetime ;
00325 
00326     memcpy( key_name, key->name , 4 );
00327 
00328     if( ( ret = ctx->f_rng( ctx->p_rng , iv, 12 ) ) != 0 )
00329         goto cleanup;
00330 
00331     /* Dump session state */
00332     if( ( ret = ssl_save_session( session,
00333                                   state, end - state, &clear_len ) ) != 0 ||
00334         (unsigned long) clear_len > 65535 )
00335     {
00336          goto cleanup;
00337     }
00338     state_len_bytes[0] = ( clear_len >> 8 ) & 0xff;
00339     state_len_bytes[1] = ( clear_len      ) & 0xff;
00340 
00341     /* Encrypt and authenticate */
00342     tag = state + clear_len;
00343     if( ( ret = mbedtls_cipher_auth_encrypt( &key->ctx ,
00344                     iv, 12, key_name, 4 + 12 + 2,
00345                     state, clear_len, state, &ciph_len, tag, 16 ) ) != 0 )
00346     {
00347         goto cleanup;
00348     }
00349     if( ciph_len != clear_len )
00350     {
00351         ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
00352         goto cleanup;
00353     }
00354 
00355     *tlen = 4 + 12 + 2 + 16 + ciph_len;
00356 
00357 cleanup:
00358 #if defined(MBEDTLS_THREADING_C)
00359     if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
00360         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
00361 #endif
00362 
00363     return( ret );
00364 }
00365 
00366 /*
00367  * Select key based on name
00368  */
00369 static mbedtls_ssl_ticket_key *ssl_ticket_select_key(
00370         mbedtls_ssl_ticket_context *ctx,
00371         const unsigned char name[4] )
00372 {
00373     unsigned char i;
00374 
00375     for( i = 0; i < sizeof( ctx->keys  ) / sizeof( *ctx->keys  ); i++ )
00376         if( memcmp( name, ctx->keys [i].name , 4 ) == 0 )
00377             return( &ctx->keys [i] );
00378 
00379     return( NULL );
00380 }
00381 
00382 /*
00383  * Load session ticket (see mbedtls_ssl_ticket_write for structure)
00384  */
00385 int mbedtls_ssl_ticket_parse( void *p_ticket,
00386                               mbedtls_ssl_session *session,
00387                               unsigned char *buf,
00388                               size_t len )
00389 {
00390     int ret;
00391     mbedtls_ssl_ticket_context *ctx = p_ticket;
00392     mbedtls_ssl_ticket_key *key;
00393     unsigned char *key_name = buf;
00394     unsigned char *iv = buf + 4;
00395     unsigned char *enc_len_p = iv + 12;
00396     unsigned char *ticket = enc_len_p + 2;
00397     unsigned char *tag;
00398     size_t enc_len, clear_len;
00399 
00400     if( ctx == NULL || ctx->f_rng == NULL )
00401         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00402 
00403     /* See mbedtls_ssl_ticket_write() */
00404     if( len < 4 + 12 + 2 + 16 )
00405         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00406 
00407 #if defined(MBEDTLS_THREADING_C)
00408     if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
00409         return( ret );
00410 #endif
00411 
00412     if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 )
00413         goto cleanup;
00414 
00415     enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1];
00416     tag = ticket + enc_len;
00417 
00418     if( len != 4 + 12 + 2 + enc_len + 16 )
00419     {
00420         ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
00421         goto cleanup;
00422     }
00423 
00424     /* Select key */
00425     if( ( key = ssl_ticket_select_key( ctx, key_name ) ) == NULL )
00426     {
00427         /* We can't know for sure but this is a likely option unless we're
00428          * under attack - this is only informative anyway */
00429         ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
00430         goto cleanup;
00431     }
00432 
00433     /* Decrypt and authenticate */
00434     if( ( ret = mbedtls_cipher_auth_decrypt( &key->ctx , iv, 12,
00435                     key_name, 4 + 12 + 2, ticket, enc_len,
00436                     ticket, &clear_len, tag, 16 ) ) != 0 )
00437     {
00438         if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED )
00439             ret = MBEDTLS_ERR_SSL_INVALID_MAC;
00440 
00441         goto cleanup;
00442     }
00443     if( clear_len != enc_len )
00444     {
00445         ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
00446         goto cleanup;
00447     }
00448 
00449     /* Actually load session */
00450     if( ( ret = ssl_load_session( session, ticket, clear_len ) ) != 0 )
00451         goto cleanup;
00452 
00453 #if defined(MBEDTLS_HAVE_TIME)
00454     {
00455         /* Check for expiration */
00456         mbedtls_time_t current_time = mbedtls_time( NULL );
00457 
00458         if( current_time < session->start ||
00459             (uint32_t)( current_time - session->start ) > ctx->ticket_lifetime  )
00460         {
00461             ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
00462             goto cleanup;
00463         }
00464     }
00465 #endif
00466 
00467 cleanup:
00468 #if defined(MBEDTLS_THREADING_C)
00469     if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
00470         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
00471 #endif
00472 
00473     return( ret );
00474 }
00475 
00476 /*
00477  * Free context
00478  */
00479 void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx )
00480 {
00481     mbedtls_cipher_free( &ctx->keys [0].ctx  );
00482     mbedtls_cipher_free( &ctx->keys [1].ctx  );
00483 
00484 #if defined(MBEDTLS_THREADING_C)
00485     mbedtls_mutex_free( &ctx->mutex );
00486 #endif
00487 
00488     mbedtls_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) );
00489 }
00490 
00491 #endif /* MBEDTLS_SSL_TICKET_C */