Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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 #endif
00037 
00038 #include "mbedtls/ssl_ticket.h"
00039 #include "mbedtls/platform_util.h"
00040 
00041 #include <string.h>
00042 
00043 /*
00044  * Initialze context
00045  */
00046 void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx )
00047 {
00048     memset( ctx, 0, sizeof( mbedtls_ssl_ticket_context ) );
00049 
00050 #if defined(MBEDTLS_THREADING_C)
00051     mbedtls_mutex_init( &ctx->mutex );
00052 #endif
00053 }
00054 
00055 #define MAX_KEY_BYTES 32    /* 256 bits */
00056 
00057 #define TICKET_KEY_NAME_BYTES    4
00058 #define TICKET_IV_BYTES         12
00059 #define TICKET_CRYPT_LEN_BYTES   2
00060 #define TICKET_AUTH_TAG_BYTES   16
00061 
00062 #define TICKET_MIN_LEN ( TICKET_KEY_NAME_BYTES  +        \
00063                          TICKET_IV_BYTES        +        \
00064                          TICKET_CRYPT_LEN_BYTES +        \
00065                          TICKET_AUTH_TAG_BYTES )
00066 #define TICKET_ADD_DATA_LEN ( TICKET_KEY_NAME_BYTES  +        \
00067                               TICKET_IV_BYTES        +        \
00068                               TICKET_CRYPT_LEN_BYTES )
00069 
00070 /*
00071  * Generate/update a key
00072  */
00073 static int ssl_ticket_gen_key( mbedtls_ssl_ticket_context *ctx,
00074                                unsigned char index )
00075 {
00076     int ret;
00077     unsigned char buf[MAX_KEY_BYTES];
00078     mbedtls_ssl_ticket_key *key = ctx->keys  + index;
00079 
00080 #if defined(MBEDTLS_HAVE_TIME)
00081     key->generation_time  = (uint32_t) mbedtls_time( NULL );
00082 #endif
00083 
00084     if( ( ret = ctx->f_rng( ctx->p_rng , key->name , sizeof( key->name  ) ) ) != 0 )
00085         return( ret );
00086 
00087     if( ( ret = ctx->f_rng( ctx->p_rng , buf, sizeof( buf ) ) ) != 0 )
00088         return( ret );
00089 
00090     /* With GCM and CCM, same context can encrypt & decrypt */
00091     ret = mbedtls_cipher_setkey( &key->ctx , buf,
00092                                  mbedtls_cipher_get_key_bitlen( &key->ctx  ),
00093                                  MBEDTLS_ENCRYPT );
00094 
00095     mbedtls_platform_zeroize( buf, sizeof( buf ) );
00096 
00097     return( ret );
00098 }
00099 
00100 /*
00101  * Rotate/generate keys if necessary
00102  */
00103 static int ssl_ticket_update_keys( mbedtls_ssl_ticket_context *ctx )
00104 {
00105 #if !defined(MBEDTLS_HAVE_TIME)
00106     ((void) ctx);
00107 #else
00108     if( ctx->ticket_lifetime  != 0 )
00109     {
00110         uint32_t current_time = (uint32_t) mbedtls_time( NULL );
00111         uint32_t key_time = ctx->keys [ctx->active ].generation_time ;
00112 
00113         if( current_time >= key_time &&
00114             current_time - key_time < ctx->ticket_lifetime )
00115         {
00116             return( 0 );
00117         }
00118 
00119         ctx->active  = 1 - ctx->active ;
00120 
00121         return( ssl_ticket_gen_key( ctx, ctx->active  ) );
00122     }
00123     else
00124 #endif /* MBEDTLS_HAVE_TIME */
00125         return( 0 );
00126 }
00127 
00128 /*
00129  * Setup context for actual use
00130  */
00131 int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx,
00132     int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
00133     mbedtls_cipher_type_t cipher,
00134     uint32_t lifetime )
00135 {
00136     int ret;
00137     const mbedtls_cipher_info_t *cipher_info;
00138 
00139     ctx->f_rng = f_rng;
00140     ctx->p_rng  = p_rng;
00141 
00142     ctx->ticket_lifetime  = lifetime;
00143 
00144     cipher_info = mbedtls_cipher_info_from_type( cipher);
00145     if( cipher_info == NULL )
00146         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00147 
00148     if( cipher_info->mode != MBEDTLS_MODE_GCM &&
00149         cipher_info->mode != MBEDTLS_MODE_CCM )
00150     {
00151         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00152     }
00153 
00154     if( cipher_info->key_bitlen > 8 * MAX_KEY_BYTES )
00155         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00156 
00157 #if defined(MBEDTLS_USE_PSA_CRYPTO)
00158     ret = mbedtls_cipher_setup_psa( &ctx->keys [0].ctx ,
00159                                     cipher_info, TICKET_AUTH_TAG_BYTES );
00160     if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )
00161         return( ret );
00162     /* We don't yet expect to support all ciphers through PSA,
00163      * so allow fallback to ordinary mbedtls_cipher_setup(). */
00164     if( ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )
00165 #endif /* MBEDTLS_USE_PSA_CRYPTO */
00166     if( ( ret = mbedtls_cipher_setup( &ctx->keys [0].ctx , cipher_info ) ) != 0 )
00167         return( ret );
00168 
00169 #if defined(MBEDTLS_USE_PSA_CRYPTO)
00170     ret = mbedtls_cipher_setup_psa( &ctx->keys [1].ctx ,
00171                                     cipher_info, TICKET_AUTH_TAG_BYTES );
00172     if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )
00173         return( ret );
00174     if( ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )
00175 #endif /* MBEDTLS_USE_PSA_CRYPTO */
00176     if( ( ret = mbedtls_cipher_setup( &ctx->keys [1].ctx , cipher_info ) ) != 0 )
00177         return( ret );
00178 
00179     if( ( ret = ssl_ticket_gen_key( ctx, 0 ) ) != 0 ||
00180         ( ret = ssl_ticket_gen_key( ctx, 1 ) ) != 0 )
00181     {
00182         return( ret );
00183     }
00184 
00185     return( 0 );
00186 }
00187 
00188 /*
00189  * Create session ticket, with the following structure:
00190  *
00191  *    struct {
00192  *        opaque key_name[4];
00193  *        opaque iv[12];
00194  *        opaque encrypted_state<0..2^16-1>;
00195  *        opaque tag[16];
00196  *    } ticket;
00197  *
00198  * The key_name, iv, and length of encrypted_state are the additional
00199  * authenticated data.
00200  */
00201 
00202 int mbedtls_ssl_ticket_write( void *p_ticket,
00203                               const mbedtls_ssl_session *session,
00204                               unsigned char *start,
00205                               const unsigned char *end,
00206                               size_t *tlen,
00207                               uint32_t *ticket_lifetime )
00208 {
00209     int ret;
00210     mbedtls_ssl_ticket_context *ctx = p_ticket;
00211     mbedtls_ssl_ticket_key *key;
00212     unsigned char *key_name = start;
00213     unsigned char *iv = start + TICKET_KEY_NAME_BYTES;
00214     unsigned char *state_len_bytes = iv + TICKET_IV_BYTES;
00215     unsigned char *state = state_len_bytes + TICKET_CRYPT_LEN_BYTES;
00216     unsigned char *tag;
00217     size_t clear_len, ciph_len;
00218 
00219     *tlen = 0;
00220 
00221     if( ctx == NULL || ctx->f_rng == NULL )
00222         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00223 
00224     /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag,
00225      * in addition to session itself, that will be checked when writing it. */
00226     if( end - start < TICKET_MIN_LEN )
00227         return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
00228 
00229 #if defined(MBEDTLS_THREADING_C)
00230     if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
00231         return( ret );
00232 #endif
00233 
00234     if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 )
00235         goto cleanup;
00236 
00237     key = &ctx->keys [ctx->active ];
00238 
00239     *ticket_lifetime = ctx->ticket_lifetime ;
00240 
00241     memcpy( key_name, key->name , TICKET_KEY_NAME_BYTES );
00242 
00243     if( ( ret = ctx->f_rng( ctx->p_rng , iv, TICKET_IV_BYTES ) ) != 0 )
00244         goto cleanup;
00245 
00246     /* Dump session state */
00247     if( ( ret = mbedtls_ssl_session_save( session,
00248                                           state, end - state,
00249                                           &clear_len ) ) != 0 ||
00250         (unsigned long) clear_len > 65535 )
00251     {
00252          goto cleanup;
00253     }
00254     state_len_bytes[0] = ( clear_len >> 8 ) & 0xff;
00255     state_len_bytes[1] = ( clear_len      ) & 0xff;
00256 
00257     /* Encrypt and authenticate */
00258     tag = state + clear_len;
00259     if( ( ret = mbedtls_cipher_auth_encrypt( &key->ctx ,
00260                     iv, TICKET_IV_BYTES,
00261                     /* Additional data: key name, IV and length */
00262                     key_name, TICKET_ADD_DATA_LEN,
00263                     state, clear_len, state, &ciph_len,
00264                     tag, TICKET_AUTH_TAG_BYTES ) ) != 0 )
00265     {
00266         goto cleanup;
00267     }
00268     if( ciph_len != clear_len )
00269     {
00270         ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
00271         goto cleanup;
00272     }
00273 
00274     *tlen = TICKET_MIN_LEN + ciph_len;
00275 
00276 cleanup:
00277 #if defined(MBEDTLS_THREADING_C)
00278     if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
00279         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
00280 #endif
00281 
00282     return( ret );
00283 }
00284 
00285 /*
00286  * Select key based on name
00287  */
00288 static mbedtls_ssl_ticket_key *ssl_ticket_select_key(
00289         mbedtls_ssl_ticket_context *ctx,
00290         const unsigned char name[4] )
00291 {
00292     unsigned char i;
00293 
00294     for( i = 0; i < sizeof( ctx->keys  ) / sizeof( *ctx->keys  ); i++ )
00295         if( memcmp( name, ctx->keys [i].name , 4 ) == 0 )
00296             return( &ctx->keys [i] );
00297 
00298     return( NULL );
00299 }
00300 
00301 /*
00302  * Load session ticket (see mbedtls_ssl_ticket_write for structure)
00303  */
00304 int mbedtls_ssl_ticket_parse( void *p_ticket,
00305                               mbedtls_ssl_session *session,
00306                               unsigned char *buf,
00307                               size_t len )
00308 {
00309     int ret;
00310     mbedtls_ssl_ticket_context *ctx = p_ticket;
00311     mbedtls_ssl_ticket_key *key;
00312     unsigned char *key_name = buf;
00313     unsigned char *iv = buf + TICKET_KEY_NAME_BYTES;
00314     unsigned char *enc_len_p = iv + TICKET_IV_BYTES;
00315     unsigned char *ticket = enc_len_p + TICKET_CRYPT_LEN_BYTES;
00316     unsigned char *tag;
00317     size_t enc_len, clear_len;
00318 
00319     if( ctx == NULL || ctx->f_rng == NULL )
00320         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00321 
00322     if( len < TICKET_MIN_LEN )
00323         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00324 
00325 #if defined(MBEDTLS_THREADING_C)
00326     if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
00327         return( ret );
00328 #endif
00329 
00330     if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 )
00331         goto cleanup;
00332 
00333     enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1];
00334     tag = ticket + enc_len;
00335 
00336     if( len != TICKET_MIN_LEN + enc_len )
00337     {
00338         ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
00339         goto cleanup;
00340     }
00341 
00342     /* Select key */
00343     if( ( key = ssl_ticket_select_key( ctx, key_name ) ) == NULL )
00344     {
00345         /* We can't know for sure but this is a likely option unless we're
00346          * under attack - this is only informative anyway */
00347         ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
00348         goto cleanup;
00349     }
00350 
00351     /* Decrypt and authenticate */
00352     if( ( ret = mbedtls_cipher_auth_decrypt( &key->ctx ,
00353                     iv, TICKET_IV_BYTES,
00354                     /* Additional data: key name, IV and length */
00355                     key_name, TICKET_ADD_DATA_LEN,
00356                     ticket, enc_len,
00357                     ticket, &clear_len,
00358                     tag, TICKET_AUTH_TAG_BYTES ) ) != 0 )
00359     {
00360         if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED )
00361             ret = MBEDTLS_ERR_SSL_INVALID_MAC;
00362 
00363         goto cleanup;
00364     }
00365     if( clear_len != enc_len )
00366     {
00367         ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
00368         goto cleanup;
00369     }
00370 
00371     /* Actually load session */
00372     if( ( ret = mbedtls_ssl_session_load( session, ticket, clear_len ) ) != 0 )
00373         goto cleanup;
00374 
00375 #if defined(MBEDTLS_HAVE_TIME)
00376     {
00377         /* Check for expiration */
00378         mbedtls_time_t current_time = mbedtls_time( NULL );
00379 
00380         if( current_time < session->start ||
00381             (uint32_t)( current_time - session->start ) > ctx->ticket_lifetime  )
00382         {
00383             ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
00384             goto cleanup;
00385         }
00386     }
00387 #endif
00388 
00389 cleanup:
00390 #if defined(MBEDTLS_THREADING_C)
00391     if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
00392         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
00393 #endif
00394 
00395     return( ret );
00396 }
00397 
00398 /*
00399  * Free context
00400  */
00401 void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx )
00402 {
00403     mbedtls_cipher_free( &ctx->keys [0].ctx  );
00404     mbedtls_cipher_free( &ctx->keys [1].ctx  );
00405 
00406 #if defined(MBEDTLS_THREADING_C)
00407     mbedtls_mutex_free( &ctx->mutex );
00408 #endif
00409 
00410     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) );
00411 }
00412 
00413 #endif /* MBEDTLS_SSL_TICKET_C */