blob: 614bb046e41bec1fb7982790859ccfcaa6ea1777 [file] [log] [blame]
/*
* TLS shared functions
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* http://www.ietf.org/rfc/rfc2246.txt
* http://www.ietf.org/rfc/rfc4346.txt
*/
#include "common.h"
#if defined(MBEDTLS_SSL_TLS_C)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdlib.h>
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
#include "mbedtls/ssl.h"
#include "ssl_misc.h"
#include "mbedtls/debug.h"
#include "mbedtls/error.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/version.h"
#include <string.h>
#if defined(MBEDTLS_USE_PSA_CRYPTO)
#include "mbedtls/psa_util.h"
#include "psa/crypto.h"
#endif
#if defined(MBEDTLS_X509_CRT_PARSE_C)
#include "mbedtls/oid.h"
#endif
#if defined(MBEDTLS_SSL_PROTO_DTLS)
#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
/* Top-level Connection ID API */
int mbedtls_ssl_conf_cid( mbedtls_ssl_config *conf,
size_t len,
int ignore_other_cid )
{
if( len > MBEDTLS_SSL_CID_IN_LEN_MAX )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
if( ignore_other_cid != MBEDTLS_SSL_UNEXPECTED_CID_FAIL &&
ignore_other_cid != MBEDTLS_SSL_UNEXPECTED_CID_IGNORE )
{
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
conf->ignore_unexpected_cid = ignore_other_cid;
conf->cid_len = len;
return( 0 );
}
int mbedtls_ssl_set_cid( mbedtls_ssl_context *ssl,
int enable,
unsigned char const *own_cid,
size_t own_cid_len )
{
if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
ssl->negotiate_cid = enable;
if( enable == MBEDTLS_SSL_CID_DISABLED )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "Disable use of CID extension." ) );
return( 0 );
}
MBEDTLS_SSL_DEBUG_MSG( 3, ( "Enable use of CID extension." ) );
MBEDTLS_SSL_DEBUG_BUF( 3, "Own CID", own_cid, own_cid_len );
if( own_cid_len != ssl->conf->cid_len )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "CID length %u does not match CID length %u in config",
(unsigned) own_cid_len,
(unsigned) ssl->conf->cid_len ) );
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
memcpy( ssl->own_cid, own_cid, own_cid_len );
/* Truncation is not an issue here because
* MBEDTLS_SSL_CID_IN_LEN_MAX at most 255. */
ssl->own_cid_len = (uint8_t) own_cid_len;
return( 0 );
}
int mbedtls_ssl_get_peer_cid( mbedtls_ssl_context *ssl,
int *enabled,
unsigned char peer_cid[ MBEDTLS_SSL_CID_OUT_LEN_MAX ],
size_t *peer_cid_len )
{
*enabled = MBEDTLS_SSL_CID_DISABLED;
if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM ||
ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER )
{
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
/* We report MBEDTLS_SSL_CID_DISABLED in case the CID extensions
* were used, but client and server requested the empty CID.
* This is indistinguishable from not using the CID extension
* in the first place. */
if( ssl->transform_in->in_cid_len == 0 &&
ssl->transform_in->out_cid_len == 0 )
{
return( 0 );
}
if( peer_cid_len != NULL )
{
*peer_cid_len = ssl->transform_in->out_cid_len;
if( peer_cid != NULL )
{
memcpy( peer_cid, ssl->transform_in->out_cid,
ssl->transform_in->out_cid_len );
}
}
*enabled = MBEDTLS_SSL_CID_ENABLED;
return( 0 );
}
#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
#endif /* MBEDTLS_SSL_PROTO_DTLS */
#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
/*
* Convert max_fragment_length codes to length.
* RFC 6066 says:
* enum{
* 2^9(1), 2^10(2), 2^11(3), 2^12(4), (255)
* } MaxFragmentLength;
* and we add 0 -> extension unused
*/
static unsigned int ssl_mfl_code_to_length( int mfl )
{
switch( mfl )
{
case MBEDTLS_SSL_MAX_FRAG_LEN_NONE:
return ( MBEDTLS_TLS_EXT_ADV_CONTENT_LEN );
case MBEDTLS_SSL_MAX_FRAG_LEN_512:
return 512;
case MBEDTLS_SSL_MAX_FRAG_LEN_1024:
return 1024;
case MBEDTLS_SSL_MAX_FRAG_LEN_2048:
return 2048;
case MBEDTLS_SSL_MAX_FRAG_LEN_4096:
return 4096;
default:
return ( MBEDTLS_TLS_EXT_ADV_CONTENT_LEN );
}
}
#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst,
const mbedtls_ssl_session *src )
{
mbedtls_ssl_session_free( dst );
memcpy( dst, src, sizeof( mbedtls_ssl_session ) );
#if defined(MBEDTLS_X509_CRT_PARSE_C)
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
if( src->peer_cert != NULL )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
dst->peer_cert = mbedtls_calloc( 1, sizeof(mbedtls_x509_crt) );
if( dst->peer_cert == NULL )
return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
mbedtls_x509_crt_init( dst->peer_cert );
if( ( ret = mbedtls_x509_crt_parse_der( dst->peer_cert, src->peer_cert->raw.p,
src->peer_cert->raw.len ) ) != 0 )
{
mbedtls_free( dst->peer_cert );
dst->peer_cert = NULL;
return( ret );
}
}
#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
if( src->peer_cert_digest != NULL )
{
dst->peer_cert_digest =
mbedtls_calloc( 1, src->peer_cert_digest_len );
if( dst->peer_cert_digest == NULL )
return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
memcpy( dst->peer_cert_digest, src->peer_cert_digest,
src->peer_cert_digest_len );
dst->peer_cert_digest_type = src->peer_cert_digest_type;
dst->peer_cert_digest_len = src->peer_cert_digest_len;
}
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
#endif /* MBEDTLS_X509_CRT_PARSE_C */
#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
if( src->ticket != NULL )
{
dst->ticket = mbedtls_calloc( 1, src->ticket_len );
if( dst->ticket == NULL )
return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
memcpy( dst->ticket, src->ticket, src->ticket_len );
}
#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
return( 0 );
}
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
static int resize_buffer( unsigned char **buffer, size_t len_new, size_t *len_old )
{
unsigned char* resized_buffer = mbedtls_calloc( 1, len_new );
if( resized_buffer == NULL )
return -1;
/* We want to copy len_new bytes when downsizing the buffer, and
* len_old bytes when upsizing, so we choose the smaller of two sizes,
* to fit one buffer into another. Size checks, ensuring that no data is
* lost, are done outside of this function. */
memcpy( resized_buffer, *buffer,
( len_new < *len_old ) ? len_new : *len_old );
mbedtls_platform_zeroize( *buffer, *len_old );
mbedtls_free( *buffer );
*buffer = resized_buffer;
*len_old = len_new;
return 0;
}
static void handle_buffer_resizing( mbedtls_ssl_context *ssl, int downsizing,
size_t in_buf_new_len,
size_t out_buf_new_len )
{
int modified = 0;
size_t written_in = 0, iv_offset_in = 0, len_offset_in = 0;
size_t written_out = 0, iv_offset_out = 0, len_offset_out = 0;
if( ssl->in_buf != NULL )
{
written_in = ssl->in_msg - ssl->in_buf;
iv_offset_in = ssl->in_iv - ssl->in_buf;
len_offset_in = ssl->in_len - ssl->in_buf;
if( downsizing ?
ssl->in_buf_len > in_buf_new_len && ssl->in_left < in_buf_new_len :
ssl->in_buf_len < in_buf_new_len )
{
if( resize_buffer( &ssl->in_buf, in_buf_new_len, &ssl->in_buf_len ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "input buffer resizing failed - out of memory" ) );
}
else
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reallocating in_buf to %" MBEDTLS_PRINTF_SIZET,
in_buf_new_len ) );
modified = 1;
}
}
}
if( ssl->out_buf != NULL )
{
written_out = ssl->out_msg - ssl->out_buf;
iv_offset_out = ssl->out_iv - ssl->out_buf;
len_offset_out = ssl->out_len - ssl->out_buf;
if( downsizing ?
ssl->out_buf_len > out_buf_new_len && ssl->out_left < out_buf_new_len :
ssl->out_buf_len < out_buf_new_len )
{
if( resize_buffer( &ssl->out_buf, out_buf_new_len, &ssl->out_buf_len ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "output buffer resizing failed - out of memory" ) );
}
else
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reallocating out_buf to %" MBEDTLS_PRINTF_SIZET,
out_buf_new_len ) );
modified = 1;
}
}
}
if( modified )
{
/* Update pointers here to avoid doing it twice. */
mbedtls_ssl_reset_in_out_pointers( ssl );
/* Fields below might not be properly updated with record
* splitting or with CID, so they are manually updated here. */
ssl->out_msg = ssl->out_buf + written_out;
ssl->out_len = ssl->out_buf + len_offset_out;
ssl->out_iv = ssl->out_buf + iv_offset_out;
ssl->in_msg = ssl->in_buf + written_in;
ssl->in_len = ssl->in_buf + len_offset_in;
ssl->in_iv = ssl->in_buf + iv_offset_in;
}
}
#endif /* MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH */
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
static int tls1_prf( const unsigned char *secret, size_t slen,
const char *label,
const unsigned char *random, size_t rlen,
unsigned char *dstbuf, size_t dlen )
{
size_t nb, hs;
size_t i, j, k;
const unsigned char *S1, *S2;
unsigned char *tmp;
size_t tmp_len = 0;
unsigned char h_i[20];
const mbedtls_md_info_t *md_info;
mbedtls_md_context_t md_ctx;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_md_init( &md_ctx );
tmp_len = 20 + strlen( label ) + rlen;
tmp = mbedtls_calloc( 1, tmp_len );
if( tmp == NULL )
{
ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
goto exit;
}
hs = ( slen + 1 ) / 2;
S1 = secret;
S2 = secret + slen - hs;
nb = strlen( label );
memcpy( tmp + 20, label, nb );
memcpy( tmp + 20 + nb, random, rlen );
nb += rlen;
/*
* First compute P_md5(secret,label+random)[0..dlen]
*/
if( ( md_info = mbedtls_md_info_from_type( MBEDTLS_MD_MD5 ) ) == NULL )
{
ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
goto exit;
}
if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 )
{
goto exit;
}
mbedtls_md_hmac_starts( &md_ctx, S1, hs );
mbedtls_md_hmac_update( &md_ctx, tmp + 20, nb );
mbedtls_md_hmac_finish( &md_ctx, 4 + tmp );
for( i = 0; i < dlen; i += 16 )
{
mbedtls_md_hmac_reset ( &md_ctx );
mbedtls_md_hmac_update( &md_ctx, 4 + tmp, 16 + nb );
mbedtls_md_hmac_finish( &md_ctx, h_i );
mbedtls_md_hmac_reset ( &md_ctx );
mbedtls_md_hmac_update( &md_ctx, 4 + tmp, 16 );
mbedtls_md_hmac_finish( &md_ctx, 4 + tmp );
k = ( i + 16 > dlen ) ? dlen % 16 : 16;
for( j = 0; j < k; j++ )
dstbuf[i + j] = h_i[j];
}
mbedtls_md_free( &md_ctx );
/*
* XOR out with P_sha1(secret,label+random)[0..dlen]
*/
if( ( md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ) ) == NULL )
{
ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
goto exit;
}
if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 )
{
goto exit;
}
mbedtls_md_hmac_starts( &md_ctx, S2, hs );
mbedtls_md_hmac_update( &md_ctx, tmp + 20, nb );
mbedtls_md_hmac_finish( &md_ctx, tmp );
for( i = 0; i < dlen; i += 20 )
{
mbedtls_md_hmac_reset ( &md_ctx );
mbedtls_md_hmac_update( &md_ctx, tmp, 20 + nb );
mbedtls_md_hmac_finish( &md_ctx, h_i );
mbedtls_md_hmac_reset ( &md_ctx );
mbedtls_md_hmac_update( &md_ctx, tmp, 20 );
mbedtls_md_hmac_finish( &md_ctx, tmp );
k = ( i + 20 > dlen ) ? dlen % 20 : 20;
for( j = 0; j < k; j++ )
dstbuf[i + j] = (unsigned char)( dstbuf[i + j] ^ h_i[j] );
}
exit:
mbedtls_md_free( &md_ctx );
mbedtls_platform_zeroize( tmp, tmp_len );
mbedtls_platform_zeroize( h_i, sizeof( h_i ) );
mbedtls_free( tmp );
return( ret );
}
#endif /* MBEDTLS_SSL_PROTO_TLS1) || MBEDTLS_SSL_PROTO_TLS1_1 */
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#if defined(MBEDTLS_USE_PSA_CRYPTO)
static psa_status_t setup_psa_key_derivation( psa_key_derivation_operation_t* derivation,
psa_key_id_t key,
psa_algorithm_t alg,
const unsigned char* seed, size_t seed_length,
const unsigned char* label, size_t label_length,
size_t capacity )
{
psa_status_t status;
status = psa_key_derivation_setup( derivation, alg );
if( status != PSA_SUCCESS )
return( status );
if( PSA_ALG_IS_TLS12_PRF( alg ) || PSA_ALG_IS_TLS12_PSK_TO_MS( alg ) )
{
status = psa_key_derivation_input_bytes( derivation,
PSA_KEY_DERIVATION_INPUT_SEED,
seed, seed_length );
if( status != PSA_SUCCESS )
return( status );
if( mbedtls_svc_key_id_is_null( key ) )
{
status = psa_key_derivation_input_bytes(
derivation, PSA_KEY_DERIVATION_INPUT_SECRET,
NULL, 0 );
}
else
{
status = psa_key_derivation_input_key(
derivation, PSA_KEY_DERIVATION_INPUT_SECRET, key );
}
if( status != PSA_SUCCESS )
return( status );
status = psa_key_derivation_input_bytes( derivation,
PSA_KEY_DERIVATION_INPUT_LABEL,
label, label_length );
if( status != PSA_SUCCESS )
return( status );
}
else
{
return( PSA_ERROR_NOT_SUPPORTED );
}
status = psa_key_derivation_set_capacity( derivation, capacity );
if( status != PSA_SUCCESS )
return( status );
return( PSA_SUCCESS );
}
static int tls_prf_generic( mbedtls_md_type_t md_type,
const unsigned char *secret, size_t slen,
const char *label,
const unsigned char *random, size_t rlen,
unsigned char *dstbuf, size_t dlen )
{
psa_status_t status;
psa_algorithm_t alg;
psa_key_id_t master_key = MBEDTLS_SVC_KEY_ID_INIT;
psa_key_derivation_operation_t derivation =
PSA_KEY_DERIVATION_OPERATION_INIT;
if( md_type == MBEDTLS_MD_SHA384 )
alg = PSA_ALG_TLS12_PRF(PSA_ALG_SHA_384);
else
alg = PSA_ALG_TLS12_PRF(PSA_ALG_SHA_256);
/* Normally a "secret" should be long enough to be impossible to
* find by brute force, and in particular should not be empty. But
* this PRF is also used to derive an IV, in particular in EAP-TLS,
* and for this use case it makes sense to have a 0-length "secret".
* Since the key API doesn't allow importing a key of length 0,
* keep master_key=0, which setup_psa_key_derivation() understands
* to mean a 0-length "secret" input. */
if( slen != 0 )
{
psa_key_attributes_t key_attributes = psa_key_attributes_init();
psa_set_key_usage_flags( &key_attributes, PSA_KEY_USAGE_DERIVE );
psa_set_key_algorithm( &key_attributes, alg );
psa_set_key_type( &key_attributes, PSA_KEY_TYPE_DERIVE );
status = psa_import_key( &key_attributes, secret, slen, &master_key );
if( status != PSA_SUCCESS )
return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
}
status = setup_psa_key_derivation( &derivation,
master_key, alg,
random, rlen,
(unsigned char const *) label,
(size_t) strlen( label ),
dlen );
if( status != PSA_SUCCESS )
{
psa_key_derivation_abort( &derivation );
psa_destroy_key( master_key );
return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
}
status = psa_key_derivation_output_bytes( &derivation, dstbuf, dlen );
if( status != PSA_SUCCESS )
{
psa_key_derivation_abort( &derivation );
psa_destroy_key( master_key );
return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
}
status = psa_key_derivation_abort( &derivation );
if( status != PSA_SUCCESS )
{
psa_destroy_key( master_key );
return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
}
if( ! mbedtls_svc_key_id_is_null( master_key ) )
status = psa_destroy_key( master_key );
if( status != PSA_SUCCESS )
return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
return( 0 );
}
#else /* MBEDTLS_USE_PSA_CRYPTO */
static int tls_prf_generic( mbedtls_md_type_t md_type,
const unsigned char *secret, size_t slen,
const char *label,
const unsigned char *random, size_t rlen,
unsigned char *dstbuf, size_t dlen )
{
size_t nb;
size_t i, j, k, md_len;
unsigned char *tmp;
size_t tmp_len = 0;
unsigned char h_i[MBEDTLS_MD_MAX_SIZE];
const mbedtls_md_info_t *md_info;
mbedtls_md_context_t md_ctx;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_md_init( &md_ctx );
if( ( md_info = mbedtls_md_info_from_type( md_type ) ) == NULL )
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
md_len = mbedtls_md_get_size( md_info );
tmp_len = md_len + strlen( label ) + rlen;
tmp = mbedtls_calloc( 1, tmp_len );
if( tmp == NULL )
{
ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
goto exit;
}
nb = strlen( label );
memcpy( tmp + md_len, label, nb );
memcpy( tmp + md_len + nb, random, rlen );
nb += rlen;
/*
* Compute P_<hash>(secret, label + random)[0..dlen]
*/
if ( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 )
goto exit;
mbedtls_md_hmac_starts( &md_ctx, secret, slen );
mbedtls_md_hmac_update( &md_ctx, tmp + md_len, nb );
mbedtls_md_hmac_finish( &md_ctx, tmp );
for( i = 0; i < dlen; i += md_len )
{
mbedtls_md_hmac_reset ( &md_ctx );
mbedtls_md_hmac_update( &md_ctx, tmp, md_len + nb );
mbedtls_md_hmac_finish( &md_ctx, h_i );
mbedtls_md_hmac_reset ( &md_ctx );
mbedtls_md_hmac_update( &md_ctx, tmp, md_len );
mbedtls_md_hmac_finish( &md_ctx, tmp );
k = ( i + md_len > dlen ) ? dlen % md_len : md_len;
for( j = 0; j < k; j++ )
dstbuf[i + j] = h_i[j];
}
exit:
mbedtls_md_free( &md_ctx );
mbedtls_platform_zeroize( tmp, tmp_len );
mbedtls_platform_zeroize( h_i, sizeof( h_i ) );
mbedtls_free( tmp );
return( ret );
}
#endif /* MBEDTLS_USE_PSA_CRYPTO */
#if defined(MBEDTLS_SHA256_C)
static int tls_prf_sha256( const unsigned char *secret, size_t slen,
const char *label,
const unsigned char *random, size_t rlen,
unsigned char *dstbuf, size_t dlen )
{
return( tls_prf_generic( MBEDTLS_MD_SHA256, secret, slen,
label, random, rlen, dstbuf, dlen ) );
}
#endif /* MBEDTLS_SHA256_C */
#if defined(MBEDTLS_SHA512_C)
static int tls_prf_sha384( const unsigned char *secret, size_t slen,
const char *label,
const unsigned char *random, size_t rlen,
unsigned char *dstbuf, size_t dlen )
{
return( tls_prf_generic( MBEDTLS_MD_SHA384, secret, slen,
label, random, rlen, dstbuf, dlen ) );
}
#endif /* MBEDTLS_SHA512_C */
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
static void ssl_update_checksum_start( mbedtls_ssl_context *, const unsigned char *, size_t );
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
static void ssl_update_checksum_md5sha1( mbedtls_ssl_context *, const unsigned char *, size_t );
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
static void ssl_calc_verify_tls( const mbedtls_ssl_context *, unsigned char*, size_t * );
static void ssl_calc_finished_tls( mbedtls_ssl_context *, unsigned char *, int );
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#if defined(MBEDTLS_SHA256_C)
static void ssl_update_checksum_sha256( mbedtls_ssl_context *, const unsigned char *, size_t );
static void ssl_calc_verify_tls_sha256( const mbedtls_ssl_context *,unsigned char*, size_t * );
static void ssl_calc_finished_tls_sha256( mbedtls_ssl_context *,unsigned char *, int );
#endif
#if defined(MBEDTLS_SHA512_C)
static void ssl_update_checksum_sha384( mbedtls_ssl_context *, const unsigned char *, size_t );
static void ssl_calc_verify_tls_sha384( const mbedtls_ssl_context *, unsigned char*, size_t * );
static void ssl_calc_finished_tls_sha384( mbedtls_ssl_context *, unsigned char *, int );
#endif
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) && \
defined(MBEDTLS_USE_PSA_CRYPTO)
static int ssl_use_opaque_psk( mbedtls_ssl_context const *ssl )
{
if( ssl->conf->f_psk != NULL )
{
/* If we've used a callback to select the PSK,
* the static configuration is irrelevant. */
if( ! mbedtls_svc_key_id_is_null( ssl->handshake->psk_opaque ) )
return( 1 );
return( 0 );
}
if( ! mbedtls_svc_key_id_is_null( ssl->conf->psk_opaque ) )
return( 1 );
return( 0 );
}
#endif /* MBEDTLS_USE_PSA_CRYPTO &&
MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */
#if defined(MBEDTLS_SSL_EXPORT_KEYS)
static mbedtls_tls_prf_types tls_prf_get_type( mbedtls_ssl_tls_prf_cb *tls_prf )
{
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
if( tls_prf == tls1_prf )
{
return( MBEDTLS_SSL_TLS_PRF_TLS1 );
}
else
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#if defined(MBEDTLS_SHA512_C)
if( tls_prf == tls_prf_sha384 )
{
return( MBEDTLS_SSL_TLS_PRF_SHA384 );
}
else
#endif
#if defined(MBEDTLS_SHA256_C)
if( tls_prf == tls_prf_sha256 )
{
return( MBEDTLS_SSL_TLS_PRF_SHA256 );
}
else
#endif
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
return( MBEDTLS_SSL_TLS_PRF_NONE );
}
#endif /* MBEDTLS_SSL_EXPORT_KEYS */
int mbedtls_ssl_tls_prf( const mbedtls_tls_prf_types prf,
const unsigned char *secret, size_t slen,
const char *label,
const unsigned char *random, size_t rlen,
unsigned char *dstbuf, size_t dlen )
{
mbedtls_ssl_tls_prf_cb *tls_prf = NULL;
switch( prf )
{
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
case MBEDTLS_SSL_TLS_PRF_TLS1:
tls_prf = tls1_prf;
break;
#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 */
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#if defined(MBEDTLS_SHA512_C)
case MBEDTLS_SSL_TLS_PRF_SHA384:
tls_prf = tls_prf_sha384;
break;
#endif /* MBEDTLS_SHA512_C */
#if defined(MBEDTLS_SHA256_C)
case MBEDTLS_SSL_TLS_PRF_SHA256:
tls_prf = tls_prf_sha256;
break;
#endif /* MBEDTLS_SHA256_C */
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
default:
return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
}
return( tls_prf( secret, slen, label, random, rlen, dstbuf, dlen ) );
}
/* Type for the TLS PRF */
typedef int ssl_tls_prf_t(const unsigned char *, size_t, const char *,
const unsigned char *, size_t,
unsigned char *, size_t);
/*
* Populate a transform structure with session keys and all the other
* necessary information.
*
* Parameters:
* - [in/out]: transform: structure to populate
* [in] must be just initialised with mbedtls_ssl_transform_init()
* [out] fully populated, ready for use by mbedtls_ssl_{en,de}crypt_buf()
* - [in] ciphersuite
* - [in] master
* - [in] encrypt_then_mac
* - [in] trunc_hmac
* - [in] compression
* - [in] tls_prf: pointer to PRF to use for key derivation
* - [in] randbytes: buffer holding ServerHello.random + ClientHello.random
* - [in] minor_ver: SSL/TLS minor version
* - [in] endpoint: client or server
* - [in] ssl: optionally used for:
* - MBEDTLS_SSL_EXPORT_KEYS: ssl->conf->{f,p}_export_keys
* - MBEDTLS_DEBUG_C: ssl->conf->{f,p}_dbg
*/
static int ssl_populate_transform( mbedtls_ssl_transform *transform,
int ciphersuite,
const unsigned char master[48],
#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
int encrypt_then_mac,
#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */
#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
int trunc_hmac,
#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */
#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
ssl_tls_prf_t tls_prf,
const unsigned char randbytes[64],
int minor_ver,
unsigned endpoint,
const mbedtls_ssl_context *ssl )
{
int ret = 0;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
int psa_fallthrough;
#endif /* MBEDTLS_USE_PSA_CRYPTO */
unsigned char keyblk[256];
unsigned char *key1;
unsigned char *key2;
unsigned char *mac_enc;
unsigned char *mac_dec;
size_t mac_key_len = 0;
size_t iv_copy_len;
unsigned keylen;
const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
const mbedtls_cipher_info_t *cipher_info;
const mbedtls_md_info_t *md_info;
#if !defined(MBEDTLS_SSL_EXPORT_KEYS) && \
!defined(MBEDTLS_DEBUG_C)
ssl = NULL; /* make sure we don't use it except for those cases */
(void) ssl;
#endif
/*
* Some data just needs copying into the structure
*/
#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) && \
defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
transform->encrypt_then_mac = encrypt_then_mac;
#endif
transform->minor_ver = minor_ver;
#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
memcpy( transform->randbytes, randbytes, sizeof( transform->randbytes ) );
#endif
/*
* Get various info structures
*/
ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuite );
if( ciphersuite_info == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "ciphersuite info for %d not found",
ciphersuite ) );
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
cipher_info = mbedtls_cipher_info_from_type( ciphersuite_info->cipher );
if( cipher_info == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "cipher info for %u not found",
ciphersuite_info->cipher ) );
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
md_info = mbedtls_md_info_from_type( ciphersuite_info->mac );
if( md_info == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "mbedtls_md info for %u not found",
(unsigned) ciphersuite_info->mac ) );
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
/* Copy own and peer's CID if the use of the CID
* extension has been negotiated. */
if( ssl->handshake->cid_in_use == MBEDTLS_SSL_CID_ENABLED )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "Copy CIDs into SSL transform" ) );
transform->in_cid_len = ssl->own_cid_len;
memcpy( transform->in_cid, ssl->own_cid, ssl->own_cid_len );
MBEDTLS_SSL_DEBUG_BUF( 3, "Incoming CID", transform->in_cid,
transform->in_cid_len );
transform->out_cid_len = ssl->handshake->peer_cid_len;
memcpy( transform->out_cid, ssl->handshake->peer_cid,
ssl->handshake->peer_cid_len );
MBEDTLS_SSL_DEBUG_BUF( 3, "Outgoing CID", transform->out_cid,
transform->out_cid_len );
}
#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
/*
* Compute key block using the PRF
*/
ret = tls_prf( master, 48, "key expansion", randbytes, 64, keyblk, 256 );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret );
return( ret );
}
MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite = %s",
mbedtls_ssl_get_ciphersuite_name( ciphersuite ) ) );
MBEDTLS_SSL_DEBUG_BUF( 3, "master secret", master, 48 );
MBEDTLS_SSL_DEBUG_BUF( 4, "random bytes", randbytes, 64 );
MBEDTLS_SSL_DEBUG_BUF( 4, "key block", keyblk, 256 );
/*
* Determine the appropriate key, IV and MAC length.
*/
keylen = cipher_info->key_bitlen / 8;
#if defined(MBEDTLS_GCM_C) || \
defined(MBEDTLS_CCM_C) || \
defined(MBEDTLS_CHACHAPOLY_C)
if( cipher_info->mode == MBEDTLS_MODE_GCM ||
cipher_info->mode == MBEDTLS_MODE_CCM ||
cipher_info->mode == MBEDTLS_MODE_CHACHAPOLY )
{
size_t explicit_ivlen;
transform->maclen = 0;
mac_key_len = 0;
transform->taglen =
ciphersuite_info->flags & MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16;
/* All modes haves 96-bit IVs, but the length of the static parts vary
* with mode and version:
* - For GCM and CCM in TLS 1.2, there's a static IV of 4 Bytes
* (to be concatenated with a dynamically chosen IV of 8 Bytes)
* - For ChaChaPoly in TLS 1.2, and all modes in TLS 1.3, there's
* a static IV of 12 Bytes (to be XOR'ed with the 8 Byte record
* sequence number).
*/
transform->ivlen = 12;
#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)
if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 )
{
transform->fixed_ivlen = 12;
}
else
#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */
{
if( cipher_info->mode == MBEDTLS_MODE_CHACHAPOLY )
transform->fixed_ivlen = 12;
else
transform->fixed_ivlen = 4;
}
/* Minimum length of encrypted record */
explicit_ivlen = transform->ivlen - transform->fixed_ivlen;
transform->minlen = explicit_ivlen + transform->taglen;
}
else
#endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C || MBEDTLS_CHACHAPOLY_C */
#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
if( cipher_info->mode == MBEDTLS_MODE_STREAM ||
cipher_info->mode == MBEDTLS_MODE_CBC )
{
/* Initialize HMAC contexts */
if( ( ret = mbedtls_md_setup( &transform->md_ctx_enc, md_info, 1 ) ) != 0 ||
( ret = mbedtls_md_setup( &transform->md_ctx_dec, md_info, 1 ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_setup", ret );
goto end;
}
/* Get MAC length */
mac_key_len = mbedtls_md_get_size( md_info );
transform->maclen = mac_key_len;
#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
/*
* If HMAC is to be truncated, we shall keep the leftmost bytes,
* (rfc 6066 page 13 or rfc 2104 section 4),
* so we only need to adjust the length here.
*/
if( trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_ENABLED )
{
transform->maclen = MBEDTLS_SSL_TRUNCATED_HMAC_LEN;
}
#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */
/* IV length */
transform->ivlen = cipher_info->iv_size;
/* Minimum length */
if( cipher_info->mode == MBEDTLS_MODE_STREAM )
transform->minlen = transform->maclen;
else
{
/*
* GenericBlockCipher:
* 1. if EtM is in use: one block plus MAC
* otherwise: * first multiple of blocklen greater than maclen
* 2. IV except for TLS 1.0
*/
#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
if( encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED )
{
transform->minlen = transform->maclen
+ cipher_info->block_size;
}
else
#endif
{
transform->minlen = transform->maclen
+ cipher_info->block_size
- transform->maclen % cipher_info->block_size;
}
#if defined(MBEDTLS_SSL_PROTO_TLS1)
if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_1 )
; /* No need to adjust minlen */
else
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2)
if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_2 ||
minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
{
transform->minlen += transform->ivlen;
}
else
#endif
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
goto end;
}
}
}
else
#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
MBEDTLS_SSL_DEBUG_MSG( 3, ( "keylen: %u, minlen: %u, ivlen: %u, maclen: %u",
(unsigned) keylen,
(unsigned) transform->minlen,
(unsigned) transform->ivlen,
(unsigned) transform->maclen ) );
/*
* Finally setup the cipher contexts, IVs and MAC secrets.
*/
#if defined(MBEDTLS_SSL_CLI_C)
if( endpoint == MBEDTLS_SSL_IS_CLIENT )
{
key1 = keyblk + mac_key_len * 2;
key2 = keyblk + mac_key_len * 2 + keylen;
mac_enc = keyblk;
mac_dec = keyblk + mac_key_len;
/*
* This is not used in TLS v1.1.
*/
iv_copy_len = ( transform->fixed_ivlen ) ?
transform->fixed_ivlen : transform->ivlen;
memcpy( transform->iv_enc, key2 + keylen, iv_copy_len );
memcpy( transform->iv_dec, key2 + keylen + iv_copy_len,
iv_copy_len );
}
else
#endif /* MBEDTLS_SSL_CLI_C */
#if defined(MBEDTLS_SSL_SRV_C)
if( endpoint == MBEDTLS_SSL_IS_SERVER )
{
key1 = keyblk + mac_key_len * 2 + keylen;
key2 = keyblk + mac_key_len * 2;
mac_enc = keyblk + mac_key_len;
mac_dec = keyblk;
/*
* This is not used in TLS v1.1.
*/
iv_copy_len = ( transform->fixed_ivlen ) ?
transform->fixed_ivlen : transform->ivlen;
memcpy( transform->iv_dec, key1 + keylen, iv_copy_len );
memcpy( transform->iv_enc, key1 + keylen + iv_copy_len,
iv_copy_len );
}
else
#endif /* MBEDTLS_SSL_SRV_C */
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
goto end;
}
#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
defined(MBEDTLS_SSL_PROTO_TLS1_2)
if( minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 )
{
/* For HMAC-based ciphersuites, initialize the HMAC transforms.
For AEAD-based ciphersuites, there is nothing to do here. */
if( mac_key_len != 0 )
{
mbedtls_md_hmac_starts( &transform->md_ctx_enc, mac_enc, mac_key_len );
mbedtls_md_hmac_starts( &transform->md_ctx_dec, mac_dec, mac_key_len );
}
}
else
#endif
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
goto end;
}
#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
((void) mac_dec);
((void) mac_enc);
#if defined(MBEDTLS_SSL_EXPORT_KEYS)
if( ssl->conf->f_export_keys != NULL )
{
ssl->conf->f_export_keys( ssl->conf->p_export_keys,
master, keyblk,
mac_key_len, keylen,
iv_copy_len );
}
if( ssl->conf->f_export_keys_ext != NULL )
{
ssl->conf->f_export_keys_ext( ssl->conf->p_export_keys,
master, keyblk,
mac_key_len, keylen,
iv_copy_len,
randbytes + 32,
randbytes,
tls_prf_get_type( tls_prf ) );
}
#endif
#if defined(MBEDTLS_USE_PSA_CRYPTO)
/* Only use PSA-based ciphers for TLS-1.2.
* That's relevant at least for TLS-1.0, where
* we assume that mbedtls_cipher_crypt() updates
* the structure field for the IV, which the PSA-based
* implementation currently doesn't. */
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
{
ret = mbedtls_cipher_setup_psa( &transform->cipher_ctx_enc,
cipher_info, transform->taglen );
if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup_psa", ret );
goto end;
}
if( ret == 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "Successfully setup PSA-based encryption cipher context" ) );
psa_fallthrough = 0;
}
else
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "Failed to setup PSA-based cipher context for record encryption - fall through to default setup." ) );
psa_fallthrough = 1;
}
}
else
psa_fallthrough = 1;
#else
psa_fallthrough = 1;
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
if( psa_fallthrough == 1 )
#endif /* MBEDTLS_USE_PSA_CRYPTO */
if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_enc,
cipher_info ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret );
goto end;
}
#if defined(MBEDTLS_USE_PSA_CRYPTO)
/* Only use PSA-based ciphers for TLS-1.2.
* That's relevant at least for TLS-1.0, where
* we assume that mbedtls_cipher_crypt() updates
* the structure field for the IV, which the PSA-based
* implementation currently doesn't. */
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
{
ret = mbedtls_cipher_setup_psa( &transform->cipher_ctx_dec,
cipher_info, transform->taglen );
if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup_psa", ret );
goto end;
}
if( ret == 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "Successfully setup PSA-based decryption cipher context" ) );
psa_fallthrough = 0;
}
else
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "Failed to setup PSA-based cipher context for record decryption - fall through to default setup." ) );
psa_fallthrough = 1;
}
}
else
psa_fallthrough = 1;
#else
psa_fallthrough = 1;
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
if( psa_fallthrough == 1 )
#endif /* MBEDTLS_USE_PSA_CRYPTO */
if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_dec,
cipher_info ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret );
goto end;
}
if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_enc, key1,
cipher_info->key_bitlen,
MBEDTLS_ENCRYPT ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret );
goto end;
}
if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_dec, key2,
cipher_info->key_bitlen,
MBEDTLS_DECRYPT ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret );
goto end;
}
#if defined(MBEDTLS_CIPHER_MODE_CBC)
if( cipher_info->mode == MBEDTLS_MODE_CBC )
{
if( ( ret = mbedtls_cipher_set_padding_mode( &transform->cipher_ctx_enc,
MBEDTLS_PADDING_NONE ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_set_padding_mode", ret );
goto end;
}
if( ( ret = mbedtls_cipher_set_padding_mode( &transform->cipher_ctx_dec,
MBEDTLS_PADDING_NONE ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_set_padding_mode", ret );
goto end;
}
}
#endif /* MBEDTLS_CIPHER_MODE_CBC */
end:
mbedtls_platform_zeroize( keyblk, sizeof( keyblk ) );
return( ret );
}
/*
* Set appropriate PRF function and other SSL / TLS 1.0/1.1 / TLS1.2 functions
*
* Inputs:
* - SSL/TLS minor version
* - hash associated with the ciphersuite (only used by TLS 1.2)
*
* Outputs:
* - the tls_prf, calc_verify and calc_finished members of handshake structure
*/
static int ssl_set_handshake_prfs( mbedtls_ssl_handshake_params *handshake,
int minor_ver,
mbedtls_md_type_t hash )
{
#if !defined(MBEDTLS_SSL_PROTO_TLS1_2) || !defined(MBEDTLS_SHA512_C)
(void) hash;
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
if( minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 )
{
handshake->tls_prf = tls1_prf;
handshake->calc_verify = ssl_calc_verify_tls;
handshake->calc_finished = ssl_calc_finished_tls;
}
else
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#if defined(MBEDTLS_SHA512_C)
if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 &&
hash == MBEDTLS_MD_SHA384 )
{
handshake->tls_prf = tls_prf_sha384;
handshake->calc_verify = ssl_calc_verify_tls_sha384;
handshake->calc_finished = ssl_calc_finished_tls_sha384;
}
else
#endif
#if defined(MBEDTLS_SHA256_C)
if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
{
handshake->tls_prf = tls_prf_sha256;
handshake->calc_verify = ssl_calc_verify_tls_sha256;
handshake->calc_finished = ssl_calc_finished_tls_sha256;
}
else
#endif
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
{
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
return( 0 );
}
/*
* Compute master secret if needed
*
* Parameters:
* [in/out] handshake
* [in] resume, premaster, extended_ms, calc_verify, tls_prf
* (PSA-PSK) ciphersuite_info, psk_opaque
* [out] premaster (cleared)
* [out] master
* [in] ssl: optionally used for debugging, EMS and PSA-PSK
* debug: conf->f_dbg, conf->p_dbg
* EMS: passed to calc_verify (debug + session_negotiate)
* PSA-PSA: minor_ver, conf
*/
static int ssl_compute_master( mbedtls_ssl_handshake_params *handshake,
unsigned char *master,
const mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
/* cf. RFC 5246, Section 8.1:
* "The master secret is always exactly 48 bytes in length." */
size_t const master_secret_len = 48;
#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
unsigned char session_hash[48];
#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */
/* The label for the KDF used for key expansion.
* This is either "master secret" or "extended master secret"
* depending on whether the Extended Master Secret extension
* is used. */
char const *lbl = "master secret";
/* The salt for the KDF used for key expansion.
* - If the Extended Master Secret extension is not used,
* this is ClientHello.Random + ServerHello.Random
* (see Sect. 8.1 in RFC 5246).
* - If the Extended Master Secret extension is used,
* this is the transcript of the handshake so far.
* (see Sect. 4 in RFC 7627). */
unsigned char const *salt = handshake->randbytes;
size_t salt_len = 64;
#if !defined(MBEDTLS_DEBUG_C) && \
!defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) && \
!(defined(MBEDTLS_USE_PSA_CRYPTO) && \
defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED))
ssl = NULL; /* make sure we don't use it except for those cases */
(void) ssl;
#endif
if( handshake->resume != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "no premaster (session resumed)" ) );
return( 0 );
}
#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
if( handshake->extended_ms == MBEDTLS_SSL_EXTENDED_MS_ENABLED )
{
lbl = "extended master secret";
salt = session_hash;
handshake->calc_verify( ssl, session_hash, &salt_len );
MBEDTLS_SSL_DEBUG_BUF( 3, "session hash for extended master secret",
session_hash, salt_len );
}
#endif /* MBEDTLS_SSL_EXTENDED_MS_ENABLED */
#if defined(MBEDTLS_USE_PSA_CRYPTO) && \
defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
if( handshake->ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK &&
ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 &&
ssl_use_opaque_psk( ssl ) == 1 )
{
/* Perform PSK-to-MS expansion in a single step. */
psa_status_t status;
psa_algorithm_t alg;
psa_key_id_t psk;
psa_key_derivation_operation_t derivation =
PSA_KEY_DERIVATION_OPERATION_INIT;
mbedtls_md_type_t hash_alg = handshake->ciphersuite_info->mac;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "perform PSA-based PSK-to-MS expansion" ) );
psk = mbedtls_ssl_get_opaque_psk( ssl );
if( hash_alg == MBEDTLS_MD_SHA384 )
alg = PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_384);
else
alg = PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256);
status = setup_psa_key_derivation( &derivation, psk, alg,
salt, salt_len,
(unsigned char const *) lbl,
(size_t) strlen( lbl ),
master_secret_len );
if( status != PSA_SUCCESS )
{
psa_key_derivation_abort( &derivation );
return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
}
status = psa_key_derivation_output_bytes( &derivation,
master,
master_secret_len );
if( status != PSA_SUCCESS )
{
psa_key_derivation_abort( &derivation );
return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
}
status = psa_key_derivation_abort( &derivation );
if( status != PSA_SUCCESS )
return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
}
else
#endif
{
ret = handshake->tls_prf( handshake->premaster, handshake->pmslen,
lbl, salt, salt_len,
master,
master_secret_len );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret );
return( ret );
}
MBEDTLS_SSL_DEBUG_BUF( 3, "premaster secret",
handshake->premaster,
handshake->pmslen );
mbedtls_platform_zeroize( handshake->premaster,
sizeof(handshake->premaster) );
}
return( 0 );
}
int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
const mbedtls_ssl_ciphersuite_t * const ciphersuite_info =
ssl->handshake->ciphersuite_info;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> derive keys" ) );
/* Set PRF, calc_verify and calc_finished function pointers */
ret = ssl_set_handshake_prfs( ssl->handshake,
ssl->minor_ver,
ciphersuite_info->mac );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "ssl_set_handshake_prfs", ret );
return( ret );
}
/* Compute master secret if needed */
ret = ssl_compute_master( ssl->handshake,
ssl->session_negotiate->master,
ssl );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "ssl_compute_master", ret );
return( ret );
}
/* Swap the client and server random values:
* - MS derivation wanted client+server (RFC 5246 8.1)
* - key derivation wants server+client (RFC 5246 6.3) */
{
unsigned char tmp[64];
memcpy( tmp, ssl->handshake->randbytes, 64 );
memcpy( ssl->handshake->randbytes, tmp + 32, 32 );
memcpy( ssl->handshake->randbytes + 32, tmp, 32 );
mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
}
/* Populate transform structure */
ret = ssl_populate_transform( ssl->transform_negotiate,
ssl->session_negotiate->ciphersuite,
ssl->session_negotiate->master,
#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
ssl->session_negotiate->encrypt_then_mac,
#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */
#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
ssl->session_negotiate->trunc_hmac,
#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */
#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
ssl->handshake->tls_prf,
ssl->handshake->randbytes,
ssl->minor_ver,
ssl->conf->endpoint,
ssl );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "ssl_populate_transform", ret );
return( ret );
}
/* We no longer need Server/ClientHello.random values */
mbedtls_platform_zeroize( ssl->handshake->randbytes,
sizeof( ssl->handshake->randbytes ) );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= derive keys" ) );
return( 0 );
}
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
void ssl_calc_verify_tls( const mbedtls_ssl_context *ssl,
unsigned char *hash,
size_t *hlen )
{
mbedtls_md5_context md5;
mbedtls_sha1_context sha1;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify tls" ) );
mbedtls_md5_init( &md5 );
mbedtls_sha1_init( &sha1 );
mbedtls_md5_clone( &md5, &ssl->handshake->fin_md5 );
mbedtls_sha1_clone( &sha1, &ssl->handshake->fin_sha1 );
mbedtls_md5_finish_ret( &md5, hash );
mbedtls_sha1_finish_ret( &sha1, hash + 16 );
*hlen = 36;
MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, *hlen );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) );
mbedtls_md5_free( &md5 );
mbedtls_sha1_free( &sha1 );
return;
}
#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 */
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#if defined(MBEDTLS_SHA256_C)
void ssl_calc_verify_tls_sha256( const mbedtls_ssl_context *ssl,
unsigned char *hash,
size_t *hlen )
{
#if defined(MBEDTLS_USE_PSA_CRYPTO)
size_t hash_size;
psa_status_t status;
psa_hash_operation_t sha256_psa = psa_hash_operation_init();
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> PSA calc verify sha256" ) );
status = psa_hash_clone( &ssl->handshake->fin_sha256_psa, &sha256_psa );
if( status != PSA_SUCCESS )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash clone failed" ) );
return;
}
status = psa_hash_finish( &sha256_psa, hash, 32, &hash_size );
if( status != PSA_SUCCESS )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash finish failed" ) );
return;
}
*hlen = 32;
MBEDTLS_SSL_DEBUG_BUF( 3, "PSA calculated verify result", hash, *hlen );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= PSA calc verify" ) );
#else
mbedtls_sha256_context sha256;
mbedtls_sha256_init( &sha256 );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify sha256" ) );
mbedtls_sha256_clone( &sha256, &ssl->handshake->fin_sha256 );
mbedtls_sha256_finish_ret( &sha256, hash );
*hlen = 32;
MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, *hlen );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) );
mbedtls_sha256_free( &sha256 );
#endif /* MBEDTLS_USE_PSA_CRYPTO */
return;
}
#endif /* MBEDTLS_SHA256_C */
#if defined(MBEDTLS_SHA512_C)
void ssl_calc_verify_tls_sha384( const mbedtls_ssl_context *ssl,
unsigned char *hash,
size_t *hlen )
{
#if defined(MBEDTLS_USE_PSA_CRYPTO)
size_t hash_size;
psa_status_t status;
psa_hash_operation_t sha384_psa = psa_hash_operation_init();
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> PSA calc verify sha384" ) );
status = psa_hash_clone( &ssl->handshake->fin_sha384_psa, &sha384_psa );
if( status != PSA_SUCCESS )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash clone failed" ) );
return;
}
status = psa_hash_finish( &sha384_psa, hash, 48, &hash_size );
if( status != PSA_SUCCESS )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash finish failed" ) );
return;
}
*hlen = 48;
MBEDTLS_SSL_DEBUG_BUF( 3, "PSA calculated verify result", hash, *hlen );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= PSA calc verify" ) );
#else
mbedtls_sha512_context sha512;
mbedtls_sha512_init( &sha512 );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify sha384" ) );
mbedtls_sha512_clone( &sha512, &ssl->handshake->fin_sha512 );
mbedtls_sha512_finish_ret( &sha512, hash );
*hlen = 48;
MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, *hlen );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) );
mbedtls_sha512_free( &sha512 );
#endif /* MBEDTLS_USE_PSA_CRYPTO */
return;
}
#endif /* MBEDTLS_SHA512_C */
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exchange_type_t key_ex )
{
unsigned char *p = ssl->handshake->premaster;
unsigned char *end = p + sizeof( ssl->handshake->premaster );
const unsigned char *psk = NULL;
size_t psk_len = 0;
if( mbedtls_ssl_get_psk( ssl, &psk, &psk_len )
== MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED )
{
/*
* This should never happen because the existence of a PSK is always
* checked before calling this function
*/
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
/*
* PMS = struct {
* opaque other_secret<0..2^16-1>;
* opaque psk<0..2^16-1>;
* };
* with "other_secret" depending on the particular key exchange
*/
#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
if( key_ex == MBEDTLS_KEY_EXCHANGE_PSK )
{
if( end - p < 2 )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
*(p++) = (unsigned char)( psk_len >> 8 );
*(p++) = (unsigned char)( psk_len );
if( end < p || (size_t)( end - p ) < psk_len )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
memset( p, 0, psk_len );
p += psk_len;
}
else
#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */
#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)
if( key_ex == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
{
/*
* other_secret already set by the ClientKeyExchange message,
* and is 48 bytes long
*/
if( end - p < 2 )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
*p++ = 0;
*p++ = 48;
p += 48;
}
else
#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */
#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED)
if( key_ex == MBEDTLS_KEY_EXCHANGE_DHE_PSK )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len;
/* Write length only when we know the actual value */
if( ( ret = mbedtls_dhm_calc_secret( &ssl->handshake->dhm_ctx,
p + 2, end - ( p + 2 ), &len,
ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_calc_secret", ret );
return( ret );
}
*(p++) = (unsigned char)( len >> 8 );
*(p++) = (unsigned char)( len );
p += len;
MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: K ", &ssl->handshake->dhm_ctx.K );
}
else
#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)
if( key_ex == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t zlen;
if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx, &zlen,
p + 2, end - ( p + 2 ),
ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret );
return( ret );
}
*(p++) = (unsigned char)( zlen >> 8 );
*(p++) = (unsigned char)( zlen );
p += zlen;
MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx,
MBEDTLS_DEBUG_ECDH_Z );
}
else
#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
/* opaque psk<0..2^16-1>; */
if( end - p < 2 )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
*(p++) = (unsigned char)( psk_len >> 8 );
*(p++) = (unsigned char)( psk_len );
if( end < p || (size_t)( end - p ) < psk_len )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
memcpy( p, psk, psk_len );
p += psk_len;
ssl->handshake->pmslen = p - ssl->handshake->premaster;
return( 0 );
}
#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */
#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_RENEGOTIATION)
static int ssl_write_hello_request( mbedtls_ssl_context *ssl );
#if defined(MBEDTLS_SSL_PROTO_DTLS)
int mbedtls_ssl_resend_hello_request( mbedtls_ssl_context *ssl )
{
/* If renegotiation is not enforced, retransmit until we would reach max
* timeout if we were using the usual handshake doubling scheme */
if( ssl->conf->renego_max_records < 0 )
{
uint32_t ratio = ssl->conf->hs_timeout_max / ssl->conf->hs_timeout_min + 1;
unsigned char doublings = 1;
while( ratio != 0 )
{
++doublings;
ratio >>= 1;
}
if( ++ssl->renego_records_seen > doublings )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "no longer retransmitting hello request" ) );
return( 0 );
}
}
return( ssl_write_hello_request( ssl ) );
}
#endif
#endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_SSL_RENEGOTIATION */
#if defined(MBEDTLS_X509_CRT_PARSE_C)
static void ssl_clear_peer_cert( mbedtls_ssl_session *session )
{
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
if( session->peer_cert != NULL )
{
mbedtls_x509_crt_free( session->peer_cert );
mbedtls_free( session->peer_cert );
session->peer_cert = NULL;
}
#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
if( session->peer_cert_digest != NULL )
{
/* Zeroization is not necessary. */
mbedtls_free( session->peer_cert_digest );
session->peer_cert_digest = NULL;
session->peer_cert_digest_type = MBEDTLS_MD_NONE;
session->peer_cert_digest_len = 0;
}
#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
}
#endif /* MBEDTLS_X509_CRT_PARSE_C */
/*
* Handshake functions
*/
#if !defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED)
/* No certificate support -> dummy functions */
int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl )
{
const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
ssl->handshake->ciphersuite_info;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) );
if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) );
ssl->state++;
return( 0 );
}
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
{
const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
ssl->handshake->ciphersuite_info;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) );
if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
ssl->state++;
return( 0 );
}
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
#else /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */
/* Some certificate support -> implement write and parse */
int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
size_t i, n;
const mbedtls_x509_crt *crt;
const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
ssl->handshake->ciphersuite_info;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) );
if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) );
ssl->state++;
return( 0 );
}
#if defined(MBEDTLS_SSL_CLI_C)
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT )
{
if( ssl->client_auth == 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) );
ssl->state++;
return( 0 );
}
}
#endif /* MBEDTLS_SSL_CLI_C */
#if defined(MBEDTLS_SSL_SRV_C)
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER )
{
if( mbedtls_ssl_own_cert( ssl ) == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no certificate to send" ) );
return( MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED );
}
}
#endif
MBEDTLS_SSL_DEBUG_CRT( 3, "own certificate", mbedtls_ssl_own_cert( ssl ) );
/*
* 0 . 0 handshake type
* 1 . 3 handshake length
* 4 . 6 length of all certs
* 7 . 9 length of cert. 1
* 10 . n-1 peer certificate
* n . n+2 length of cert. 2
* n+3 . ... upper level cert, etc.
*/
i = 7;
crt = mbedtls_ssl_own_cert( ssl );
while( crt != NULL )
{
n = crt->raw.len;
if( n > MBEDTLS_SSL_OUT_CONTENT_LEN - 3 - i )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate too large, %" MBEDTLS_PRINTF_SIZET
" > %" MBEDTLS_PRINTF_SIZET,
i + 3 + n, (size_t) MBEDTLS_SSL_OUT_CONTENT_LEN ) );
return( MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE );
}
ssl->out_msg[i ] = (unsigned char)( n >> 16 );
ssl->out_msg[i + 1] = (unsigned char)( n >> 8 );
ssl->out_msg[i + 2] = (unsigned char)( n );
i += 3; memcpy( ssl->out_msg + i, crt->raw.p, n );
i += n; crt = crt->next;
}
ssl->out_msg[4] = (unsigned char)( ( i - 7 ) >> 16 );
ssl->out_msg[5] = (unsigned char)( ( i - 7 ) >> 8 );
ssl->out_msg[6] = (unsigned char)( ( i - 7 ) );
ssl->out_msglen = i;
ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE;
ssl->out_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE;
ssl->state++;
if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret );
return( ret );
}
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate" ) );
return( ret );
}
#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
static int ssl_check_peer_crt_unchanged( mbedtls_ssl_context *ssl,
unsigned char *crt_buf,
size_t crt_buf_len )
{
mbedtls_x509_crt const * const peer_crt = ssl->session->peer_cert;
if( peer_crt == NULL )
return( -1 );
if( peer_crt->raw.len != crt_buf_len )
return( -1 );
return( memcmp( peer_crt->raw.p, crt_buf, peer_crt->raw.len ) );
}
#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
static int ssl_check_peer_crt_unchanged( mbedtls_ssl_context *ssl,
unsigned char *crt_buf,
size_t crt_buf_len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char const * const peer_cert_digest =
ssl->session->peer_cert_digest;
mbedtls_md_type_t const peer_cert_digest_type =
ssl->session->peer_cert_digest_type;
mbedtls_md_info_t const * const digest_info =
mbedtls_md_info_from_type( peer_cert_digest_type );
unsigned char tmp_digest[MBEDTLS_SSL_PEER_CERT_DIGEST_MAX_LEN];
size_t digest_len;
if( peer_cert_digest == NULL || digest_info == NULL )
return( -1 );
digest_len = mbedtls_md_get_size( digest_info );
if( digest_len > MBEDTLS_SSL_PEER_CERT_DIGEST_MAX_LEN )
return( -1 );
ret = mbedtls_md( digest_info, crt_buf, crt_buf_len, tmp_digest );
if( ret != 0 )
return( -1 );
return( memcmp( tmp_digest, peer_cert_digest, digest_len ) );
}
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */
/*
* Once the certificate message is read, parse it into a cert chain and
* perform basic checks, but leave actual verification to the caller
*/
static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl,
mbedtls_x509_crt *chain )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
int crt_cnt=0;
#endif
size_t i, n;
uint8_t alert;
if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
}
if( ssl->in_msg[0] != MBEDTLS_SSL_HS_CERTIFICATE ||
ssl->in_hslen < mbedtls_ssl_hs_hdr_len( ssl ) + 3 + 3 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
}
i = mbedtls_ssl_hs_hdr_len( ssl );
/*
* Same message structure as in mbedtls_ssl_write_certificate()
*/
n = ( ssl->in_msg[i+1] << 8 ) | ssl->in_msg[i+2];
if( ssl->in_msg[i] != 0 ||
ssl->in_hslen != n + 3 + mbedtls_ssl_hs_hdr_len( ssl ) )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
}
/* Make &ssl->in_msg[i] point to the beginning of the CRT chain. */
i += 3;
/* Iterate through and parse the CRTs in the provided chain. */
while( i < ssl->in_hslen )
{
/* Check that there's room for the next CRT's length fields. */
if ( i + 3 > ssl->in_hslen ) {
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
mbedtls_ssl_send_alert_message( ssl,
MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
}
/* In theory, the CRT can be up to 2**24 Bytes, but we don't support
* anything beyond 2**16 ~ 64K. */
if( ssl->in_msg[i] != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
mbedtls_ssl_send_alert_message( ssl,
MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
}
/* Read length of the next CRT in the chain. */
n = ( (unsigned int) ssl->in_msg[i + 1] << 8 )
| (unsigned int) ssl->in_msg[i + 2];
i += 3;
if( n < 128 || i + n > ssl->in_hslen )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
mbedtls_ssl_send_alert_message( ssl,
MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
}
/* Check if we're handling the first CRT in the chain. */
#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
if( crt_cnt++ == 0 &&
ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT &&
ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS )
{
/* During client-side renegotiation, check that the server's
* end-CRTs hasn't changed compared to the initial handshake,
* mitigating the triple handshake attack. On success, reuse
* the original end-CRT instead of parsing it again. */
MBEDTLS_SSL_DEBUG_MSG( 3, ( "Check that peer CRT hasn't changed during renegotiation" ) );
if( ssl_check_peer_crt_unchanged( ssl,
&ssl->in_msg[i],
n ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "new server cert during renegotiation" ) );
mbedtls_ssl_send_alert_message( ssl,
MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
}
/* Now we can safely free the original chain. */
ssl_clear_peer_cert( ssl->session );
}
#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */
/* Parse the next certificate in the chain. */
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
ret = mbedtls_x509_crt_parse_der( chain, ssl->in_msg + i, n );
#else
/* If we don't need to store the CRT chain permanently, parse
* it in-place from the input buffer instead of making a copy. */
ret = mbedtls_x509_crt_parse_der_nocopy( chain, ssl->in_msg + i, n );
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
switch( ret )
{
case 0: /*ok*/
case MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + MBEDTLS_ERR_OID_NOT_FOUND:
/* Ignore certificate with an unknown algorithm: maybe a
prior certificate was already trusted. */
break;
case MBEDTLS_ERR_X509_ALLOC_FAILED:
alert = MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR;
goto crt_parse_der_failed;
case MBEDTLS_ERR_X509_UNKNOWN_VERSION:
alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
goto crt_parse_der_failed;
default:
alert = MBEDTLS_SSL_ALERT_MSG_BAD_CERT;
crt_parse_der_failed:
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, alert );
MBEDTLS_SSL_DEBUG_RET( 1, " mbedtls_x509_crt_parse_der", ret );
return( ret );
}
i += n;
}
MBEDTLS_SSL_DEBUG_CRT( 3, "peer certificate", chain );
return( 0 );
}
#if defined(MBEDTLS_SSL_SRV_C)
static int ssl_srv_check_client_no_crt_notification( mbedtls_ssl_context *ssl )
{
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT )
return( -1 );
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
defined(MBEDTLS_SSL_PROTO_TLS1_2)
if( ssl->in_hslen == 3 + mbedtls_ssl_hs_hdr_len( ssl ) &&
ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE &&
ssl->in_msg[0] == MBEDTLS_SSL_HS_CERTIFICATE &&
memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ), "\0\0\0", 3 ) == 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "TLSv1 client has no certificate" ) );
return( 0 );
}
return( -1 );
#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \
MBEDTLS_SSL_PROTO_TLS1_2 */
}
#endif /* MBEDTLS_SSL_SRV_C */
/* Check if a certificate message is expected.
* Return either
* - SSL_CERTIFICATE_EXPECTED, or
* - SSL_CERTIFICATE_SKIP
* indicating whether a Certificate message is expected or not.
*/
#define SSL_CERTIFICATE_EXPECTED 0
#define SSL_CERTIFICATE_SKIP 1
static int ssl_parse_certificate_coordinate( mbedtls_ssl_context *ssl,
int authmode )
{
const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
ssl->handshake->ciphersuite_info;
if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) )
return( SSL_CERTIFICATE_SKIP );
#if defined(MBEDTLS_SSL_SRV_C)
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER )
{
if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
return( SSL_CERTIFICATE_SKIP );
if( authmode == MBEDTLS_SSL_VERIFY_NONE )
{
ssl->session_negotiate->verify_result =
MBEDTLS_X509_BADCERT_SKIP_VERIFY;
return( SSL_CERTIFICATE_SKIP );
}
}
#else
((void) authmode);
#endif /* MBEDTLS_SSL_SRV_C */
return( SSL_CERTIFICATE_EXPECTED );
}
static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl,
int authmode,
mbedtls_x509_crt *chain,
void *rs_ctx )
{
int ret = 0;
const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
ssl->handshake->ciphersuite_info;
int have_ca_chain = 0;
int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *);
void *p_vrfy;
if( authmode == MBEDTLS_SSL_VERIFY_NONE )
return( 0 );
if( ssl->f_vrfy != NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "Use context-specific verification callback" ) );
f_vrfy = ssl->f_vrfy;
p_vrfy = ssl->p_vrfy;
}
else
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "Use configuration-specific verification callback" ) );
f_vrfy = ssl->conf->f_vrfy;
p_vrfy = ssl->conf->p_vrfy;
}
/*
* Main check: verify certificate
*/
#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
if( ssl->conf->f_ca_cb != NULL )
{
((void) rs_ctx);
have_ca_chain = 1;
MBEDTLS_SSL_DEBUG_MSG( 3, ( "use CA callback for X.509 CRT verification" ) );
ret = mbedtls_x509_crt_verify_with_ca_cb(
chain,
ssl->conf->f_ca_cb,
ssl->conf->p_ca_cb,
ssl->conf->cert_profile,
ssl->hostname,
&ssl->session_negotiate->verify_result,
f_vrfy, p_vrfy );
}
else
#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */
{
mbedtls_x509_crt *ca_chain;
mbedtls_x509_crl *ca_crl;
#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
if( ssl->handshake->sni_ca_chain != NULL )
{
ca_chain = ssl->handshake->sni_ca_chain;
ca_crl = ssl->handshake->sni_ca_crl;
}
else
#endif
{
ca_chain = ssl->conf->ca_chain;
ca_crl = ssl->conf->ca_crl;
}
if( ca_chain != NULL )
have_ca_chain = 1;
ret = mbedtls_x509_crt_verify_restartable(
chain,
ca_chain, ca_crl,
ssl->conf->cert_profile,
ssl->hostname,
&ssl->session_negotiate->verify_result,
f_vrfy, p_vrfy, rs_ctx );
}
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret );
}
#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED)
if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
return( MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS );
#endif
/*
* Secondary checks: always done, but change 'ret' only if it was 0
*/
#if defined(MBEDTLS_ECP_C)
{
const mbedtls_pk_context *pk = &chain->pk;
/* If certificate uses an EC key, make sure the curve is OK */
if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) &&
mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ) != 0 )
{
ssl->session_negotiate->verify_result |= MBEDTLS_X509_BADCERT_BAD_KEY;
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (EC key curve)" ) );
if( ret == 0 )
ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE;
}
}
#endif /* MBEDTLS_ECP_C */
if( mbedtls_ssl_check_cert_usage( chain,
ciphersuite_info,
! ssl->conf->endpoint,
&ssl->session_negotiate->verify_result ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (usage extensions)" ) );
if( ret == 0 )
ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE;
}
/* mbedtls_x509_crt_verify_with_profile is supposed to report a
* verification failure through MBEDTLS_ERR_X509_CERT_VERIFY_FAILED,
* with details encoded in the verification flags. All other kinds
* of error codes, including those from the user provided f_vrfy
* functions, are treated as fatal and lead to a failure of
* ssl_parse_certificate even if verification was optional. */
if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL &&
( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ||
ret == MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ) )
{
ret = 0;
}
if( have_ca_chain == 0 && authmode == MBEDTLS_SSL_VERIFY_REQUIRED )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) );
ret = MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED;
}
if( ret != 0 )
{
uint8_t alert;
/* The certificate may have been rejected for several reasons.
Pick one and send the corresponding alert. Which alert to send
may be a subject of debate in some cases. */
if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_OTHER )
alert = MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_CN_MISMATCH )
alert = MBEDTLS_SSL_ALERT_MSG_BAD_CERT;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_KEY_USAGE )
alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXT_KEY_USAGE )
alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NS_CERT_TYPE )
alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_PK )
alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_KEY )
alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXPIRED )
alert = MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_REVOKED )
alert = MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED;
else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NOT_TRUSTED )
alert = MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA;
else
alert = MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN;
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
alert );
}
#if defined(MBEDTLS_DEBUG_C)
if( ssl->session_negotiate->verify_result != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "! Certificate verification flags %08x",
(unsigned int) ssl->session_negotiate->verify_result ) );
}
else
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "Certificate verification flags clear" ) );
}
#endif /* MBEDTLS_DEBUG_C */
return( ret );
}
#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
static int ssl_remember_peer_crt_digest( mbedtls_ssl_context *ssl,
unsigned char *start, size_t len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
/* Remember digest of the peer's end-CRT. */
ssl->session_negotiate->peer_cert_digest =
mbedtls_calloc( 1, MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN );
if( ssl->session_negotiate->peer_cert_digest == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed",
MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN ) );
mbedtls_ssl_send_alert_message( ssl,
MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
}
ret = mbedtls_md( mbedtls_md_info_from_type(
MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE ),
start, len,
ssl->session_negotiate->peer_cert_digest );
ssl->session_negotiate->peer_cert_digest_type =
MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE;
ssl->session_negotiate->peer_cert_digest_len =
MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN;
return( ret );
}
static int ssl_remember_peer_pubkey( mbedtls_ssl_context *ssl,
unsigned char *start, size_t len )
{
unsigned char *end = start + len;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
/* Make a copy of the peer's raw public key. */
mbedtls_pk_init( &ssl->handshake->peer_pubkey );
ret = mbedtls_pk_parse_subpubkey( &start, end,
&ssl->handshake->peer_pubkey );
if( ret != 0 )
{
/* We should have parsed the public key before. */
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
return( 0 );
}
#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
{
int ret = 0;
int crt_expected;
#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
const int authmode = ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET
? ssl->handshake->sni_authmode
: ssl->conf->authmode;
#else
const int authmode = ssl->conf->authmode;
#endif
void *rs_ctx = NULL;
mbedtls_x509_crt *chain = NULL;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) );
crt_expected = ssl_parse_certificate_coordinate( ssl, authmode );
if( crt_expected == SSL_CERTIFICATE_SKIP )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
goto exit;
}
#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED)
if( ssl->handshake->ecrs_enabled &&
ssl->handshake->ecrs_state == ssl_ecrs_crt_verify )
{
chain = ssl->handshake->ecrs_peer_cert;
ssl->handshake->ecrs_peer_cert = NULL;
goto crt_verify;
}
#endif
if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
/* mbedtls_ssl_read_record may have sent an alert already. We
let it decide whether to alert. */
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
goto exit;
}
#if defined(MBEDTLS_SSL_SRV_C)
if( ssl_srv_check_client_no_crt_notification( ssl ) == 0 )
{
ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING;
if( authmode != MBEDTLS_SSL_VERIFY_OPTIONAL )
ret = MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE;
goto exit;
}
#endif /* MBEDTLS_SSL_SRV_C */
/* Clear existing peer CRT structure in case we tried to
* reuse a session but it failed, and allocate a new one. */
ssl_clear_peer_cert( ssl->session_negotiate );
chain = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) );
if( chain == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%" MBEDTLS_PRINTF_SIZET " bytes) failed",
sizeof( mbedtls_x509_crt ) ) );
mbedtls_ssl_send_alert_message( ssl,
MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
goto exit;
}
mbedtls_x509_crt_init( chain );
ret = ssl_parse_certificate_chain( ssl, chain );
if( ret != 0 )
goto exit;
#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED)
if( ssl->handshake->ecrs_enabled)
ssl->handshake->ecrs_state = ssl_ecrs_crt_verify;
crt_verify:
if( ssl->handshake->ecrs_enabled)
rs_ctx = &ssl->handshake->ecrs_ctx;
#endif
ret = ssl_parse_certificate_verify( ssl, authmode,
chain, rs_ctx );
if( ret != 0 )
goto exit;
#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
{
unsigned char *crt_start, *pk_start;
size_t crt_len, pk_len;
/* We parse the CRT chain without copying, so
* these pointers point into the input buffer,
* and are hence still valid after freeing the
* CRT chain. */
crt_start = chain->raw.p;
crt_len = chain->raw.len;
pk_start = chain->pk_raw.p;
pk_len = chain->pk_raw.len;
/* Free the CRT structures before computing
* digest and copying the peer's public key. */
mbedtls_x509_crt_free( chain );
mbedtls_free( chain );
chain = NULL;
ret = ssl_remember_peer_crt_digest( ssl, crt_start, crt_len );
if( ret != 0 )
goto exit;
ret = ssl_remember_peer_pubkey( ssl, pk_start, pk_len );
if( ret != 0 )
goto exit;
}
#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
/* Pass ownership to session structure. */
ssl->session_negotiate->peer_cert = chain;
chain = NULL;
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) );
exit:
if( ret == 0 )
ssl->state++;
#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED)
if( ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS )
{
ssl->handshake->ecrs_peer_cert = chain;
chain = NULL;
}
#endif
if( chain != NULL )
{
mbedtls_x509_crt_free( chain );
mbedtls_free( chain );
}
return( ret );
}
#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */
void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl,
const mbedtls_ssl_ciphersuite_t *ciphersuite_info )
{
((void) ciphersuite_info);
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 )
ssl->handshake->update_checksum = ssl_update_checksum_md5sha1;
else
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#if defined(MBEDTLS_SHA512_C)
if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 )
ssl->handshake->update_checksum = ssl_update_checksum_sha384;
else
#endif
#if defined(MBEDTLS_SHA256_C)
if( ciphersuite_info->mac != MBEDTLS_MD_SHA384 )
ssl->handshake->update_checksum = ssl_update_checksum_sha256;
else
#endif
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return;
}
}
void mbedtls_ssl_reset_checksum( mbedtls_ssl_context *ssl )
{
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
mbedtls_md5_starts_ret( &ssl->handshake->fin_md5 );
mbedtls_sha1_starts_ret( &ssl->handshake->fin_sha1 );
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#if defined(MBEDTLS_SHA256_C)
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_hash_abort( &ssl->handshake->fin_sha256_psa );
psa_hash_setup( &ssl->handshake->fin_sha256_psa, PSA_ALG_SHA_256 );
#else
mbedtls_sha256_starts_ret( &ssl->handshake->fin_sha256, 0 );
#endif
#endif
#if defined(MBEDTLS_SHA512_C)
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_hash_abort( &ssl->handshake->fin_sha384_psa );
psa_hash_setup( &ssl->handshake->fin_sha384_psa, PSA_ALG_SHA_384 );
#else
mbedtls_sha512_starts_ret( &ssl->handshake->fin_sha512, 1 );
#endif
#endif
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
}
static void ssl_update_checksum_start( mbedtls_ssl_context *ssl,
const unsigned char *buf, size_t len )
{
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
mbedtls_md5_update_ret( &ssl->handshake->fin_md5 , buf, len );
mbedtls_sha1_update_ret( &ssl->handshake->fin_sha1, buf, len );
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#if defined(MBEDTLS_SHA256_C)
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_hash_update( &ssl->handshake->fin_sha256_psa, buf, len );
#else
mbedtls_sha256_update_ret( &ssl->handshake->fin_sha256, buf, len );
#endif
#endif
#if defined(MBEDTLS_SHA512_C)
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_hash_update( &ssl->handshake->fin_sha384_psa, buf, len );
#else
mbedtls_sha512_update_ret( &ssl->handshake->fin_sha512, buf, len );
#endif
#endif
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
}
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
static void ssl_update_checksum_md5sha1( mbedtls_ssl_context *ssl,
const unsigned char *buf, size_t len )
{
mbedtls_md5_update_ret( &ssl->handshake->fin_md5 , buf, len );
mbedtls_sha1_update_ret( &ssl->handshake->fin_sha1, buf, len );
}
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#if defined(MBEDTLS_SHA256_C)
static void ssl_update_checksum_sha256( mbedtls_ssl_context *ssl,
const unsigned char *buf, size_t len )
{
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_hash_update( &ssl->handshake->fin_sha256_psa, buf, len );
#else
mbedtls_sha256_update_ret( &ssl->handshake->fin_sha256, buf, len );
#endif
}
#endif
#if defined(MBEDTLS_SHA512_C)
static void ssl_update_checksum_sha384( mbedtls_ssl_context *ssl,
const unsigned char *buf, size_t len )
{
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_hash_update( &ssl->handshake->fin_sha384_psa, buf, len );
#else
mbedtls_sha512_update_ret( &ssl->handshake->fin_sha512, buf, len );
#endif
}
#endif
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
static void ssl_calc_finished_tls(
mbedtls_ssl_context *ssl, unsigned char *buf, int from )
{
int len = 12;
const char *sender;
mbedtls_md5_context md5;
mbedtls_sha1_context sha1;
unsigned char padbuf[36];
mbedtls_ssl_session *session = ssl->session_negotiate;
if( !session )
session = ssl->session;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc finished tls" ) );
mbedtls_md5_init( &md5 );
mbedtls_sha1_init( &sha1 );
mbedtls_md5_clone( &md5, &ssl->handshake->fin_md5 );
mbedtls_sha1_clone( &sha1, &ssl->handshake->fin_sha1 );
/*
* TLSv1:
* hash = PRF( master, finished_label,
* MD5( handshake ) + SHA1( handshake ) )[0..11]
*/
#if !defined(MBEDTLS_MD5_ALT)
MBEDTLS_SSL_DEBUG_BUF( 4, "finished md5 state", (unsigned char *)
md5.state, sizeof( md5.state ) );
#endif
#if !defined(MBEDTLS_SHA1_ALT)
MBEDTLS_SSL_DEBUG_BUF( 4, "finished sha1 state", (unsigned char *)
sha1.state, sizeof( sha1.state ) );
#endif
sender = ( from == MBEDTLS_SSL_IS_CLIENT )
? "client finished"
: "server finished";
mbedtls_md5_finish_ret( &md5, padbuf );
mbedtls_sha1_finish_ret( &sha1, padbuf + 16 );
ssl->handshake->tls_prf( session->master, 48, sender,
padbuf, 36, buf, len );
MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, len );
mbedtls_md5_free( &md5 );
mbedtls_sha1_free( &sha1 );
mbedtls_platform_zeroize( padbuf, sizeof( padbuf ) );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) );
}
#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 */
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#if defined(MBEDTLS_SHA256_C)
static void ssl_calc_finished_tls_sha256(
mbedtls_ssl_context *ssl, unsigned char *buf, int from )
{
int len = 12;
const char *sender;
unsigned char padbuf[32];
#if defined(MBEDTLS_USE_PSA_CRYPTO)
size_t hash_size;
psa_hash_operation_t sha256_psa = PSA_HASH_OPERATION_INIT;
psa_status_t status;
#else
mbedtls_sha256_context sha256;
#endif
mbedtls_ssl_session *session = ssl->session_negotiate;
if( !session )
session = ssl->session;
sender = ( from == MBEDTLS_SSL_IS_CLIENT )
? "client finished"
: "server finished";
#if defined(MBEDTLS_USE_PSA_CRYPTO)
sha256_psa = psa_hash_operation_init();
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc PSA finished tls sha256" ) );
status = psa_hash_clone( &ssl->handshake->fin_sha256_psa, &sha256_psa );
if( status != PSA_SUCCESS )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash clone failed" ) );
return;
}
status = psa_hash_finish( &sha256_psa, padbuf, sizeof( padbuf ), &hash_size );
if( status != PSA_SUCCESS )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash finish failed" ) );
return;
}
MBEDTLS_SSL_DEBUG_BUF( 3, "PSA calculated padbuf", padbuf, 32 );
#else
mbedtls_sha256_init( &sha256 );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc finished tls sha256" ) );
mbedtls_sha256_clone( &sha256, &ssl->handshake->fin_sha256 );
/*
* TLSv1.2:
* hash = PRF( master, finished_label,
* Hash( handshake ) )[0.11]
*/
#if !defined(MBEDTLS_SHA256_ALT)
MBEDTLS_SSL_DEBUG_BUF( 4, "finished sha2 state", (unsigned char *)
sha256.state, sizeof( sha256.state ) );
#endif
mbedtls_sha256_finish_ret( &sha256, padbuf );
mbedtls_sha256_free( &sha256 );
#endif /* MBEDTLS_USE_PSA_CRYPTO */
ssl->handshake->tls_prf( session->master, 48, sender,
padbuf, 32, buf, len );
MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, len );
mbedtls_platform_zeroize( padbuf, sizeof( padbuf ) );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) );
}
#endif /* MBEDTLS_SHA256_C */
#if defined(MBEDTLS_SHA512_C)
typedef int (*finish_sha384_t)(mbedtls_sha512_context*, unsigned char*);
static void ssl_calc_finished_tls_sha384(
mbedtls_ssl_context *ssl, unsigned char *buf, int from )
{
int len = 12;
const char *sender;
unsigned char padbuf[48];
#if defined(MBEDTLS_USE_PSA_CRYPTO)
size_t hash_size;
psa_hash_operation_t sha384_psa = PSA_HASH_OPERATION_INIT;
psa_status_t status;
#else
mbedtls_sha512_context sha512;
#endif
mbedtls_ssl_session *session = ssl->session_negotiate;
if( !session )
session = ssl->session;
sender = ( from == MBEDTLS_SSL_IS_CLIENT )
? "client finished"
: "server finished";
#if defined(MBEDTLS_USE_PSA_CRYPTO)
sha384_psa = psa_hash_operation_init();
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc PSA finished tls sha384" ) );
status = psa_hash_clone( &ssl->handshake->fin_sha384_psa, &sha384_psa );
if( status != PSA_SUCCESS )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash clone failed" ) );
return;
}
status = psa_hash_finish( &sha384_psa, padbuf, sizeof( padbuf ), &hash_size );
if( status != PSA_SUCCESS )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash finish failed" ) );
return;
}
MBEDTLS_SSL_DEBUG_BUF( 3, "PSA calculated padbuf", padbuf, 48 );
#else
mbedtls_sha512_init( &sha512 );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc finished tls sha384" ) );
mbedtls_sha512_clone( &sha512, &ssl->handshake->fin_sha512 );
/*
* TLSv1.2:
* hash = PRF( master, finished_label,
* Hash( handshake ) )[0.11]
*/
#if !defined(MBEDTLS_SHA512_ALT)
MBEDTLS_SSL_DEBUG_BUF( 4, "finished sha512 state", (unsigned char *)
sha512.state, sizeof( sha512.state ) );
#endif
/*
* For SHA-384, we can save 16 bytes by keeping padbuf 48 bytes long.
* However, to avoid stringop-overflow warning in gcc, we have to cast
* mbedtls_sha512_finish_ret().
*/
finish_sha384_t finish = (finish_sha384_t)mbedtls_sha512_finish_ret;
finish( &sha512, padbuf );
mbedtls_sha512_free( &sha512 );
#endif
ssl->handshake->tls_prf( session->master, 48, sender,
padbuf, 48, buf, len );
MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, len );
mbedtls_platform_zeroize( padbuf, sizeof( padbuf ) );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) );
}
#endif /* MBEDTLS_SHA512_C */
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
void mbedtls_ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "=> handshake wrapup: final free" ) );
/*
* Free our handshake params
*/
mbedtls_ssl_handshake_free( ssl );
mbedtls_free( ssl->handshake );
ssl->handshake = NULL;
/*
* Free the previous transform and swith in the current one
*/
if( ssl->transform )
{
mbedtls_ssl_transform_free( ssl->transform );
mbedtls_free( ssl->transform );
}
ssl->transform = ssl->transform_negotiate;
ssl->transform_negotiate = NULL;
MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= handshake wrapup: final free" ) );
}
void mbedtls_ssl_handshake_wrapup( mbedtls_ssl_context *ssl )
{
int resume = ssl->handshake->resume;
MBEDTLS_SSL_DEBUG_MSG( 3, ( "=> handshake wrapup" ) );
#if defined(MBEDTLS_SSL_RENEGOTIATION)
if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS )
{
ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_DONE;
ssl->renego_records_seen = 0;
}
#endif
/*
* Free the previous session and switch in the current one
*/
if( ssl->session )
{
#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
/* RFC 7366 3.1: keep the EtM state */
ssl->session_negotiate->encrypt_then_mac =
ssl->session->encrypt_then_mac;
#endif
mbedtls_ssl_session_free( ssl->session );
mbedtls_free( ssl->session );
}
ssl->session = ssl->session_negotiate;
ssl->session_negotiate = NULL;
/*
* Add cache entry
*/
if( ssl->conf->f_set_cache != NULL &&
ssl->session->id_len != 0 &&
resume == 0 )
{
if( ssl->conf->f_set_cache( ssl->conf->p_cache, ssl->session ) != 0 )
MBEDTLS_SSL_DEBUG_MSG( 1, ( "cache did not store session" ) );
}
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
ssl->handshake->flight != NULL )
{
/* Cancel handshake timer */
mbedtls_ssl_set_timer( ssl, 0 );
/* Keep last flight around in case we need to resend it:
* we need the handshake and transform structures for that */
MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip freeing handshake and transform" ) );
}
else
#endif
mbedtls_ssl_handshake_wrapup_free_hs_transform( ssl );
ssl->state++;
MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= handshake wrapup" ) );
}
int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl )