Knight KE / Mbed OS Game_Master
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 /*
00058  * Generate/update a key
00059  */
00060 static int ssl_ticket_gen_key( mbedtls_ssl_ticket_context *ctx,
00061                                unsigned char index )
00062 {
00063     int ret;
00064     unsigned char buf[MAX_KEY_BYTES];
00065     mbedtls_ssl_ticket_key *key = ctx->keys  + index;
00066 
00067 #if defined(MBEDTLS_HAVE_TIME)
00068     key->generation_time  = (uint32_t) mbedtls_time( NULL );
00069 #endif
00070 
00071     if( ( ret = ctx->f_rng( ctx->p_rng , key->name , sizeof( key->name  ) ) ) != 0 )
00072         return( ret );
00073 
00074     if( ( ret = ctx->f_rng( ctx->p_rng , buf, sizeof( buf ) ) ) != 0 )
00075         return( ret );
00076 
00077     /* With GCM and CCM, same context can encrypt & decrypt */
00078     ret = mbedtls_cipher_setkey( &key->ctx , buf,
00079                                  mbedtls_cipher_get_key_bitlen( &key->ctx  ),
00080                                  MBEDTLS_ENCRYPT );
00081 
00082     mbedtls_platform_zeroize( buf, sizeof( buf ) );
00083 
00084     return( ret );
00085 }
00086 
00087 /*
00088  * Rotate/generate keys if necessary
00089  */
00090 static int ssl_ticket_update_keys( mbedtls_ssl_ticket_context *ctx )
00091 {
00092 #if !defined(MBEDTLS_HAVE_TIME)
00093     ((void) ctx);
00094 #else
00095     if( ctx->ticket_lifetime  != 0 )
00096     {
00097         uint32_t current_time = (uint32_t) mbedtls_time( NULL );
00098         uint32_t key_time = ctx->keys [ctx->active ].generation_time ;
00099 
00100         if( current_time > key_time &&
00101             current_time - key_time < ctx->ticket_lifetime )
00102         {
00103             return( 0 );
00104         }
00105 
00106         ctx->active  = 1 - ctx->active ;
00107 
00108         return( ssl_ticket_gen_key( ctx, ctx->active  ) );
00109     }
00110     else
00111 #endif /* MBEDTLS_HAVE_TIME */
00112         return( 0 );
00113 }
00114 
00115 /*
00116  * Setup context for actual use
00117  */
00118 int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx,
00119     int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
00120     mbedtls_cipher_type_t cipher,
00121     uint32_t lifetime )
00122 {
00123     int ret;
00124     const mbedtls_cipher_info_t *cipher_info;
00125 
00126     ctx->f_rng = f_rng;
00127     ctx->p_rng  = p_rng;
00128 
00129     ctx->ticket_lifetime  = lifetime;
00130 
00131     cipher_info = mbedtls_cipher_info_from_type( cipher);
00132     if( cipher_info == NULL )
00133         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00134 
00135     if( cipher_info->mode != MBEDTLS_MODE_GCM &&
00136         cipher_info->mode != MBEDTLS_MODE_CCM )
00137     {
00138         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00139     }
00140 
00141     if( cipher_info->key_bitlen > 8 * MAX_KEY_BYTES )
00142         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00143 
00144     if( ( ret = mbedtls_cipher_setup( &ctx->keys [0].ctx , cipher_info ) ) != 0 ||
00145         ( ret = mbedtls_cipher_setup( &ctx->keys [1].ctx , cipher_info ) ) != 0 )
00146     {
00147         return( ret );
00148     }
00149 
00150     if( ( ret = ssl_ticket_gen_key( ctx, 0 ) ) != 0 ||
00151         ( ret = ssl_ticket_gen_key( ctx, 1 ) ) != 0 )
00152     {
00153         return( ret );
00154     }
00155 
00156     return( 0 );
00157 }
00158 
00159 /*
00160  * Serialize a session in the following format:
00161  *  0   .   n-1     session structure, n = sizeof(mbedtls_ssl_session)
00162  *  n   .   n+2     peer_cert length = m (0 if no certificate)
00163  *  n+3 .   n+2+m   peer cert ASN.1
00164  */
00165 static int ssl_save_session( const mbedtls_ssl_session *session,
00166                              unsigned char *buf, size_t buf_len,
00167                              size_t *olen )
00168 {
00169     unsigned char *p = buf;
00170     size_t left = buf_len;
00171 #if defined(MBEDTLS_X509_CRT_PARSE_C)
00172     size_t cert_len;
00173 #endif /* MBEDTLS_X509_CRT_PARSE_C */
00174 
00175     if( left < sizeof( mbedtls_ssl_session ) )
00176         return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
00177 
00178     memcpy( p, session, sizeof( mbedtls_ssl_session ) );
00179     p += sizeof( mbedtls_ssl_session );
00180     left -= sizeof( mbedtls_ssl_session );
00181 
00182 #if defined(MBEDTLS_X509_CRT_PARSE_C)
00183     if( session->peer_cert == NULL )
00184         cert_len = 0;
00185     else
00186         cert_len = session->peer_cert->raw.len;
00187 
00188     if( left < 3 + cert_len )
00189         return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
00190 
00191     *p++ = (unsigned char)( cert_len >> 16 & 0xFF );
00192     *p++ = (unsigned char)( cert_len >>  8 & 0xFF );
00193     *p++ = (unsigned char)( cert_len       & 0xFF );
00194 
00195     if( session->peer_cert != NULL )
00196         memcpy( p, session->peer_cert->raw.p, cert_len );
00197 
00198     p += cert_len;
00199 #endif /* MBEDTLS_X509_CRT_PARSE_C */
00200 
00201     *olen = p - buf;
00202 
00203     return( 0 );
00204 }
00205 
00206 /*
00207  * Unserialise session, see ssl_save_session()
00208  */
00209 static int ssl_load_session( mbedtls_ssl_session *session,
00210                              const unsigned char *buf, size_t len )
00211 {
00212     const unsigned char *p = buf;
00213     const unsigned char * const end = buf + len;
00214 #if defined(MBEDTLS_X509_CRT_PARSE_C)
00215     size_t cert_len;
00216 #endif /* MBEDTLS_X509_CRT_PARSE_C */
00217 
00218     if( p + sizeof( mbedtls_ssl_session ) > end )
00219         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00220 
00221     memcpy( session, p, sizeof( mbedtls_ssl_session ) );
00222     p += sizeof( mbedtls_ssl_session );
00223 
00224 #if defined(MBEDTLS_X509_CRT_PARSE_C)
00225     if( p + 3 > end )
00226         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00227 
00228     cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2];
00229     p += 3;
00230 
00231     if( cert_len == 0 )
00232     {
00233         session->peer_cert = NULL;
00234     }
00235     else
00236     {
00237         int ret;
00238 
00239         if( p + cert_len > end )
00240             return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00241 
00242         session->peer_cert = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) );
00243 
00244         if( session->peer_cert == NULL )
00245             return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
00246 
00247         mbedtls_x509_crt_init( session->peer_cert );
00248 
00249         if( ( ret = mbedtls_x509_crt_parse_der( session->peer_cert,
00250                                         p, cert_len ) ) != 0 )
00251         {
00252             mbedtls_x509_crt_free( session->peer_cert );
00253             mbedtls_free( session->peer_cert );
00254             session->peer_cert = NULL;
00255             return( ret );
00256         }
00257 
00258         p += cert_len;
00259     }
00260 #endif /* MBEDTLS_X509_CRT_PARSE_C */
00261 
00262     if( p != end )
00263         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00264 
00265     return( 0 );
00266 }
00267 
00268 /*
00269  * Create session ticket, with the following structure:
00270  *
00271  *    struct {
00272  *        opaque key_name[4];
00273  *        opaque iv[12];
00274  *        opaque encrypted_state<0..2^16-1>;
00275  *        opaque tag[16];
00276  *    } ticket;
00277  *
00278  * The key_name, iv, and length of encrypted_state are the additional
00279  * authenticated data.
00280  */
00281 int mbedtls_ssl_ticket_write( void *p_ticket,
00282                               const mbedtls_ssl_session *session,
00283                               unsigned char *start,
00284                               const unsigned char *end,
00285                               size_t *tlen,
00286                               uint32_t *ticket_lifetime )
00287 {
00288     int ret;
00289     mbedtls_ssl_ticket_context *ctx = p_ticket;
00290     mbedtls_ssl_ticket_key *key;
00291     unsigned char *key_name = start;
00292     unsigned char *iv = start + 4;
00293     unsigned char *state_len_bytes = iv + 12;
00294     unsigned char *state = state_len_bytes + 2;
00295     unsigned char *tag;
00296     size_t clear_len, ciph_len;
00297 
00298     *tlen = 0;
00299 
00300     if( ctx == NULL || ctx->f_rng == NULL )
00301         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00302 
00303     /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag,
00304      * in addition to session itself, that will be checked when writing it. */
00305     if( end - start < 4 + 12 + 2 + 16 )
00306         return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
00307 
00308 #if defined(MBEDTLS_THREADING_C)
00309     if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
00310         return( ret );
00311 #endif
00312 
00313     if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 )
00314         goto cleanup;
00315 
00316     key = &ctx->keys [ctx->active ];
00317 
00318     *ticket_lifetime = ctx->ticket_lifetime ;
00319 
00320     memcpy( key_name, key->name , 4 );
00321 
00322     if( ( ret = ctx->f_rng( ctx->p_rng , iv, 12 ) ) != 0 )
00323         goto cleanup;
00324 
00325     /* Dump session state */
00326     if( ( ret = ssl_save_session( session,
00327                                   state, end - state, &clear_len ) ) != 0 ||
00328         (unsigned long) clear_len > 65535 )
00329     {
00330          goto cleanup;
00331     }
00332     state_len_bytes[0] = ( clear_len >> 8 ) & 0xff;
00333     state_len_bytes[1] = ( clear_len      ) & 0xff;
00334 
00335     /* Encrypt and authenticate */
00336     tag = state + clear_len;
00337     if( ( ret = mbedtls_cipher_auth_encrypt( &key->ctx ,
00338                     iv, 12, key_name, 4 + 12 + 2,
00339                     state, clear_len, state, &ciph_len, tag, 16 ) ) != 0 )
00340     {
00341         goto cleanup;
00342     }
00343     if( ciph_len != clear_len )
00344     {
00345         ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
00346         goto cleanup;
00347     }
00348 
00349     *tlen = 4 + 12 + 2 + 16 + ciph_len;
00350 
00351 cleanup:
00352 #if defined(MBEDTLS_THREADING_C)
00353     if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
00354         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
00355 #endif
00356 
00357     return( ret );
00358 }
00359 
00360 /*
00361  * Select key based on name
00362  */
00363 static mbedtls_ssl_ticket_key *ssl_ticket_select_key(
00364         mbedtls_ssl_ticket_context *ctx,
00365         const unsigned char name[4] )
00366 {
00367     unsigned char i;
00368 
00369     for( i = 0; i < sizeof( ctx->keys  ) / sizeof( *ctx->keys  ); i++ )
00370         if( memcmp( name, ctx->keys [i].name , 4 ) == 0 )
00371             return( &ctx->keys [i] );
00372 
00373     return( NULL );
00374 }
00375 
00376 /*
00377  * Load session ticket (see mbedtls_ssl_ticket_write for structure)
00378  */
00379 int mbedtls_ssl_ticket_parse( void *p_ticket,
00380                               mbedtls_ssl_session *session,
00381                               unsigned char *buf,
00382                               size_t len )
00383 {
00384     int ret;
00385     mbedtls_ssl_ticket_context *ctx = p_ticket;
00386     mbedtls_ssl_ticket_key *key;
00387     unsigned char *key_name = buf;
00388     unsigned char *iv = buf + 4;
00389     unsigned char *enc_len_p = iv + 12;
00390     unsigned char *ticket = enc_len_p + 2;
00391     unsigned char *tag;
00392     size_t enc_len, clear_len;
00393 
00394     if( ctx == NULL || ctx->f_rng == NULL )
00395         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00396 
00397     /* See mbedtls_ssl_ticket_write() */
00398     if( len < 4 + 12 + 2 + 16 )
00399         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
00400 
00401 #if defined(MBEDTLS_THREADING_C)
00402     if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
00403         return( ret );
00404 #endif
00405 
00406     if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 )
00407         goto cleanup;
00408 
00409     enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1];
00410     tag = ticket + enc_len;
00411 
00412     if( len != 4 + 12 + 2 + enc_len + 16 )
00413     {
00414         ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
00415         goto cleanup;
00416     }
00417 
00418     /* Select key */
00419     if( ( key = ssl_ticket_select_key( ctx, key_name ) ) == NULL )
00420     {
00421         /* We can't know for sure but this is a likely option unless we're
00422          * under attack - this is only informative anyway */
00423         ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
00424         goto cleanup;
00425     }
00426 
00427     /* Decrypt and authenticate */
00428     if( ( ret = mbedtls_cipher_auth_decrypt( &key->ctx , iv, 12,
00429                     key_name, 4 + 12 + 2, ticket, enc_len,
00430                     ticket, &clear_len, tag, 16 ) ) != 0 )
00431     {
00432         if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED )
00433             ret = MBEDTLS_ERR_SSL_INVALID_MAC;
00434 
00435         goto cleanup;
00436     }
00437     if( clear_len != enc_len )
00438     {
00439         ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
00440         goto cleanup;
00441     }
00442 
00443     /* Actually load session */
00444     if( ( ret = ssl_load_session( session, ticket, clear_len ) ) != 0 )
00445         goto cleanup;
00446 
00447 #if defined(MBEDTLS_HAVE_TIME)
00448     {
00449         /* Check for expiration */
00450         mbedtls_time_t current_time = mbedtls_time( NULL );
00451 
00452         if( current_time < session->start ||
00453             (uint32_t)( current_time - session->start ) > ctx->ticket_lifetime  )
00454         {
00455             ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
00456             goto cleanup;
00457         }
00458     }
00459 #endif
00460 
00461 cleanup:
00462 #if defined(MBEDTLS_THREADING_C)
00463     if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
00464         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
00465 #endif
00466 
00467     return( ret );
00468 }
00469 
00470 /*
00471  * Free context
00472  */
00473 void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx )
00474 {
00475     mbedtls_cipher_free( &ctx->keys [0].ctx  );
00476     mbedtls_cipher_free( &ctx->keys [1].ctx  );
00477 
00478 #if defined(MBEDTLS_THREADING_C)
00479     mbedtls_mutex_free( &ctx->mutex );
00480 #endif
00481 
00482     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) );
00483 }
00484 
00485 #endif /* MBEDTLS_SSL_TICKET_C */