Merge remote-tracking branch 'public/pr/1270' into development
This commit is contained in:
commit
5f57f1e3cc
13 changed files with 1544 additions and 179 deletions
|
@ -709,7 +709,7 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl,
|
|||
MBEDTLS_SSL_DEBUG_CRT( 3, "candidate certificate chain, certificate",
|
||||
cur->cert );
|
||||
|
||||
if( ! mbedtls_pk_can_do( cur->key, pk_alg ) )
|
||||
if( ! mbedtls_pk_can_do( &cur->cert->pk, pk_alg ) )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: key type" ) );
|
||||
continue;
|
||||
|
@ -733,7 +733,7 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl,
|
|||
|
||||
#if defined(MBEDTLS_ECDSA_C)
|
||||
if( pk_alg == MBEDTLS_PK_ECDSA &&
|
||||
ssl_check_key_curve( cur->key, ssl->handshake->curves ) != 0 )
|
||||
ssl_check_key_curve( &cur->cert->pk, ssl->handshake->curves ) != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: elliptic curve" ) );
|
||||
continue;
|
||||
|
@ -2828,54 +2828,56 @@ static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl )
|
|||
#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) ||
|
||||
MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */
|
||||
|
||||
static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl )
|
||||
#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && \
|
||||
defined(MBEDTLS_SSL_ASYNC_PRIVATE)
|
||||
static int ssl_resume_server_key_exchange( mbedtls_ssl_context *ssl,
|
||||
size_t *signature_len )
|
||||
{
|
||||
/* Append the signature to ssl->out_msg, leaving 2 bytes for the
|
||||
* signature length which will be added in ssl_write_server_key_exchange
|
||||
* after the call to ssl_prepare_server_key_exchange.
|
||||
* ssl_write_server_key_exchange also takes care of incrementing
|
||||
* ssl->out_msglen. */
|
||||
unsigned char *sig_start = ssl->out_msg + ssl->out_msglen + 2;
|
||||
size_t sig_max_len = ( ssl->out_buf + MBEDTLS_SSL_MAX_CONTENT_LEN
|
||||
- sig_start );
|
||||
int ret = ssl->conf->f_async_resume( ssl,
|
||||
sig_start, signature_len, sig_max_len );
|
||||
if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS )
|
||||
{
|
||||
ssl->handshake->async_in_progress = 0;
|
||||
mbedtls_ssl_set_async_operation_data( ssl, NULL );
|
||||
}
|
||||
MBEDTLS_SSL_DEBUG_RET( 2, "ssl_resume_server_key_exchange", ret );
|
||||
return( ret );
|
||||
}
|
||||
#endif /* defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) &&
|
||||
defined(MBEDTLS_SSL_ASYNC_PRIVATE) */
|
||||
|
||||
/* Prepare the ServerKeyExchange message, up to and including
|
||||
* calculating the signature if any, but excluding formatting the
|
||||
* signature and sending the message. */
|
||||
static int ssl_prepare_server_key_exchange( mbedtls_ssl_context *ssl,
|
||||
size_t *signature_len )
|
||||
{
|
||||
int ret;
|
||||
size_t n = 0;
|
||||
const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
|
||||
ssl->transform_negotiate->ciphersuite_info;
|
||||
|
||||
#if defined(MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED)
|
||||
unsigned char *p = ssl->out_msg + 4;
|
||||
size_t len;
|
||||
#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED)
|
||||
unsigned char *dig_signed = p;
|
||||
size_t dig_signed_len = 0;
|
||||
unsigned char *dig_signed = NULL;
|
||||
#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */
|
||||
#endif /* MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED */
|
||||
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) );
|
||||
(void) ciphersuite_info; /* unused in some configurations */
|
||||
#if !defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED)
|
||||
(void) signature_len;
|
||||
#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */
|
||||
|
||||
ssl->out_msglen = 4; /* header (type:1, length:3) to be written later */
|
||||
|
||||
/*
|
||||
*
|
||||
* Part 1: Extract static ECDH parameters and abort
|
||||
* if ServerKeyExchange not needed.
|
||||
*
|
||||
*/
|
||||
|
||||
/* For suites involving ECDH, extract DH parameters
|
||||
* from certificate at this point. */
|
||||
#if defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED)
|
||||
if( mbedtls_ssl_ciphersuite_uses_ecdh( ciphersuite_info ) )
|
||||
{
|
||||
ssl_get_ecdh_params_from_cert( ssl );
|
||||
}
|
||||
#endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED */
|
||||
|
||||
/* Key exchanges not involving ephemeral keys don't use
|
||||
* ServerKeyExchange, so end here. */
|
||||
#if defined(MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED)
|
||||
if( mbedtls_ssl_ciphersuite_no_pfs( ciphersuite_info ) )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) );
|
||||
ssl->state++;
|
||||
return( 0 );
|
||||
}
|
||||
#endif /* MBEDTLS_KEY_EXCHANGE__NON_PFS__ENABLED */
|
||||
|
||||
/*
|
||||
*
|
||||
* Part 2: Provide key exchange parameters for chosen ciphersuite.
|
||||
* Part 1: Provide key exchange parameters for chosen ciphersuite.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -2885,18 +2887,21 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl )
|
|||
#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
|
||||
if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
|
||||
{
|
||||
const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN;
|
||||
int ret;
|
||||
size_t len;
|
||||
|
||||
ret = mbedtls_ecjpake_write_round_two( &ssl->handshake->ecjpake_ctx,
|
||||
p, end - p, &len, ssl->conf->f_rng, ssl->conf->p_rng );
|
||||
ret = mbedtls_ecjpake_write_round_two(
|
||||
&ssl->handshake->ecjpake_ctx,
|
||||
ssl->out_msg + ssl->out_msglen,
|
||||
MBEDTLS_SSL_MAX_CONTENT_LEN - ssl->out_msglen, &len,
|
||||
ssl->conf->f_rng, ssl->conf->p_rng );
|
||||
if( ret != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_write_round_two", ret );
|
||||
return( ret );
|
||||
}
|
||||
|
||||
p += len;
|
||||
n += len;
|
||||
ssl->out_msglen += len;
|
||||
}
|
||||
#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
|
||||
|
||||
|
@ -2910,10 +2915,8 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl )
|
|||
if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
|
||||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK )
|
||||
{
|
||||
*(p++) = 0x00;
|
||||
*(p++) = 0x00;
|
||||
|
||||
n += 2;
|
||||
ssl->out_msg[ssl->out_msglen++] = 0x00;
|
||||
ssl->out_msg[ssl->out_msglen++] = 0x00;
|
||||
}
|
||||
#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED ||
|
||||
MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */
|
||||
|
@ -2924,6 +2927,9 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl )
|
|||
#if defined(MBEDTLS_KEY_EXCHANGE__SOME__DHE_ENABLED)
|
||||
if( mbedtls_ssl_ciphersuite_uses_dhe( ciphersuite_info ) )
|
||||
{
|
||||
int ret;
|
||||
size_t len;
|
||||
|
||||
if( ssl->conf->dhm_P.p == NULL || ssl->conf->dhm_G.p == NULL )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 1, ( "no DH parameters set" ) );
|
||||
|
@ -2947,21 +2953,21 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl )
|
|||
return( ret );
|
||||
}
|
||||
|
||||
if( ( ret = mbedtls_dhm_make_params( &ssl->handshake->dhm_ctx,
|
||||
(int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ),
|
||||
p, &len, ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
|
||||
if( ( ret = mbedtls_dhm_make_params(
|
||||
&ssl->handshake->dhm_ctx,
|
||||
(int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ),
|
||||
ssl->out_msg + ssl->out_msglen, &len,
|
||||
ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_make_params", ret );
|
||||
return( ret );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED)
|
||||
dig_signed = p;
|
||||
dig_signed_len = len;
|
||||
dig_signed = ssl->out_msg + ssl->out_msglen;
|
||||
#endif
|
||||
|
||||
p += len;
|
||||
n += len;
|
||||
ssl->out_msglen += len;
|
||||
|
||||
MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: X ", &ssl->handshake->dhm_ctx.X );
|
||||
MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: P ", &ssl->handshake->dhm_ctx.P );
|
||||
|
@ -2986,6 +2992,8 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl )
|
|||
*/
|
||||
const mbedtls_ecp_curve_info **curve = NULL;
|
||||
const mbedtls_ecp_group_id *gid;
|
||||
int ret;
|
||||
size_t len;
|
||||
|
||||
/* Match our preference list against the offered curves */
|
||||
for( gid = ssl->conf->curve_list; *gid != MBEDTLS_ECP_DP_NONE; gid++ )
|
||||
|
@ -3009,21 +3017,21 @@ curve_matching_done:
|
|||
return( ret );
|
||||
}
|
||||
|
||||
if( ( ret = mbedtls_ecdh_make_params( &ssl->handshake->ecdh_ctx, &len,
|
||||
p, MBEDTLS_SSL_MAX_CONTENT_LEN - n,
|
||||
ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
|
||||
if( ( ret = mbedtls_ecdh_make_params(
|
||||
&ssl->handshake->ecdh_ctx, &len,
|
||||
ssl->out_msg + ssl->out_msglen,
|
||||
MBEDTLS_SSL_MAX_CONTENT_LEN - ssl->out_msglen,
|
||||
ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_params", ret );
|
||||
return( ret );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED)
|
||||
dig_signed = p;
|
||||
dig_signed_len = len;
|
||||
dig_signed = ssl->out_msg + ssl->out_msglen;
|
||||
#endif
|
||||
|
||||
p += len;
|
||||
n += len;
|
||||
ssl->out_msglen += len;
|
||||
|
||||
MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q ", &ssl->handshake->ecdh_ctx.Q );
|
||||
}
|
||||
|
@ -3031,19 +3039,20 @@ curve_matching_done:
|
|||
|
||||
/*
|
||||
*
|
||||
* Part 3: For key exchanges involving the server signing the
|
||||
* Part 2: For key exchanges involving the server signing the
|
||||
* exchange parameters, compute and add the signature here.
|
||||
*
|
||||
*/
|
||||
#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED)
|
||||
if( mbedtls_ssl_ciphersuite_uses_server_signature( ciphersuite_info ) )
|
||||
{
|
||||
size_t signature_len = 0;
|
||||
unsigned int hashlen = 0;
|
||||
unsigned char hash[64];
|
||||
size_t dig_signed_len = ssl->out_msg + ssl->out_msglen - dig_signed;
|
||||
size_t hashlen = 0;
|
||||
unsigned char hash[MBEDTLS_MD_MAX_SIZE];
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* 3.1: Choose hash algorithm:
|
||||
* 2.1: Choose hash algorithm:
|
||||
* A: For TLS 1.2, obey signature-hash-algorithm extension
|
||||
* to choose appropriate hash.
|
||||
* B: For SSL3, TLS1.0, TLS1.1 and ECDHE_ECDSA, use SHA1
|
||||
|
@ -3090,7 +3099,7 @@ curve_matching_done:
|
|||
MBEDTLS_SSL_DEBUG_MSG( 3, ( "pick hash algorithm %d for signing", md_alg ) );
|
||||
|
||||
/*
|
||||
* 3.2: Compute the hash to be signed
|
||||
* 2.2: Compute the hash to be signed
|
||||
*/
|
||||
#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \
|
||||
defined(MBEDTLS_SSL_PROTO_TLS1_1)
|
||||
|
@ -3110,9 +3119,7 @@ curve_matching_done:
|
|||
defined(MBEDTLS_SSL_PROTO_TLS1_2)
|
||||
if( md_alg != MBEDTLS_MD_NONE )
|
||||
{
|
||||
/* Info from md_alg will be used instead */
|
||||
hashlen = 0;
|
||||
ret = mbedtls_ssl_get_key_exchange_md_tls1_2( ssl, hash,
|
||||
ret = mbedtls_ssl_get_key_exchange_md_tls1_2( ssl, hash, &hashlen,
|
||||
dig_signed,
|
||||
dig_signed_len,
|
||||
md_alg );
|
||||
|
@ -3127,18 +3134,11 @@ curve_matching_done:
|
|||
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
|
||||
}
|
||||
|
||||
MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen != 0 ? hashlen :
|
||||
(unsigned int) ( mbedtls_md_get_size( mbedtls_md_info_from_type( md_alg ) ) ) );
|
||||
MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen );
|
||||
|
||||
/*
|
||||
* 3.3: Compute and add the signature
|
||||
* 2.3: Compute and add the signature
|
||||
*/
|
||||
if( mbedtls_ssl_own_key( ssl ) == NULL )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no private key" ) );
|
||||
return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
|
||||
if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
|
||||
{
|
||||
|
@ -3158,33 +3158,150 @@ curve_matching_done:
|
|||
*
|
||||
*/
|
||||
|
||||
*(p++) = mbedtls_ssl_hash_from_md_alg( md_alg );
|
||||
*(p++) = mbedtls_ssl_sig_from_pk_alg( sig_alg );
|
||||
|
||||
n += 2;
|
||||
ssl->out_msg[ssl->out_msglen++] =
|
||||
mbedtls_ssl_hash_from_md_alg( md_alg );
|
||||
ssl->out_msg[ssl->out_msglen++] =
|
||||
mbedtls_ssl_sig_from_pk_alg( sig_alg );
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
|
||||
|
||||
if( ( ret = mbedtls_pk_sign( mbedtls_ssl_own_key( ssl ), md_alg, hash, hashlen,
|
||||
p + 2 , &signature_len, ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
|
||||
#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
|
||||
if( ssl->conf->f_async_sign_start != NULL )
|
||||
{
|
||||
ret = ssl->conf->f_async_sign_start( ssl,
|
||||
mbedtls_ssl_own_cert( ssl ),
|
||||
md_alg, hash, hashlen );
|
||||
switch( ret )
|
||||
{
|
||||
case MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH:
|
||||
/* act as if f_async_sign was null */
|
||||
break;
|
||||
case 0:
|
||||
ssl->handshake->async_in_progress = 1;
|
||||
return( ssl_resume_server_key_exchange( ssl, signature_len ) );
|
||||
case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
|
||||
ssl->handshake->async_in_progress = 1;
|
||||
return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS );
|
||||
default:
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "f_async_sign_start", ret );
|
||||
return( ret );
|
||||
}
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
|
||||
|
||||
if( mbedtls_ssl_own_key( ssl ) == NULL )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no private key" ) );
|
||||
return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED );
|
||||
}
|
||||
|
||||
/* Append the signature to ssl->out_msg, leaving 2 bytes for the
|
||||
* signature length which will be added in ssl_write_server_key_exchange
|
||||
* after the call to ssl_prepare_server_key_exchange.
|
||||
* ssl_write_server_key_exchange also takes care of incrementing
|
||||
* ssl->out_msglen. */
|
||||
if( ( ret = mbedtls_pk_sign( mbedtls_ssl_own_key( ssl ),
|
||||
md_alg, hash, hashlen,
|
||||
ssl->out_msg + ssl->out_msglen + 2,
|
||||
signature_len,
|
||||
ssl->conf->f_rng,
|
||||
ssl->conf->p_rng ) ) != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret );
|
||||
return( ret );
|
||||
}
|
||||
|
||||
*(p++) = (unsigned char)( signature_len >> 8 );
|
||||
*(p++) = (unsigned char)( signature_len );
|
||||
n += 2;
|
||||
|
||||
MBEDTLS_SSL_DEBUG_BUF( 3, "my signature", p, signature_len );
|
||||
|
||||
n += signature_len;
|
||||
}
|
||||
#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */
|
||||
|
||||
/* Done with actual work; add header and send. */
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
ssl->out_msglen = 4 + n;
|
||||
/* Prepare the ServerKeyExchange message and send it. For ciphersuites
|
||||
* that do not include a ServerKeyExchange message, do nothing. Either
|
||||
* way, if successful, move on to the next step in the SSL state
|
||||
* machine. */
|
||||
static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl )
|
||||
{
|
||||
int ret;
|
||||
size_t signature_len = 0;
|
||||
#if defined(MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED)
|
||||
const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
|
||||
ssl->transform_negotiate->ciphersuite_info;
|
||||
#endif /* MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED */
|
||||
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) );
|
||||
|
||||
#if defined(MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED)
|
||||
/* Extract static ECDH parameters and abort if ServerKeyExchange
|
||||
* is not needed. */
|
||||
if( mbedtls_ssl_ciphersuite_no_pfs( ciphersuite_info ) )
|
||||
{
|
||||
/* For suites involving ECDH, extract DH parameters
|
||||
* from certificate at this point. */
|
||||
#if defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED)
|
||||
if( mbedtls_ssl_ciphersuite_uses_ecdh( ciphersuite_info ) )
|
||||
{
|
||||
ssl_get_ecdh_params_from_cert( ssl );
|
||||
}
|
||||
#endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED */
|
||||
|
||||
/* Key exchanges not involving ephemeral keys don't use
|
||||
* ServerKeyExchange, so end here. */
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) );
|
||||
ssl->state++;
|
||||
return( 0 );
|
||||
}
|
||||
#endif /* MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED */
|
||||
|
||||
#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && \
|
||||
defined(MBEDTLS_SSL_ASYNC_PRIVATE)
|
||||
/* If we have already prepared the message and there is an ongoing
|
||||
* signature operation, resume signing. */
|
||||
if( ssl->handshake->async_in_progress != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming signature operation" ) );
|
||||
ret = ssl_resume_server_key_exchange( ssl, &signature_len );
|
||||
}
|
||||
else
|
||||
#endif /* defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) &&
|
||||
defined(MBEDTLS_SSL_ASYNC_PRIVATE) */
|
||||
{
|
||||
/* ServerKeyExchange is needed. Prepare the message. */
|
||||
ret = ssl_prepare_server_key_exchange( ssl, &signature_len );
|
||||
}
|
||||
|
||||
if( ret != 0 )
|
||||
{
|
||||
/* If we're starting to write a new message, set ssl->out_msglen
|
||||
* to 0. But if we're resuming after an asynchronous message,
|
||||
* out_msglen is the amount of data written so far and mst be
|
||||
* preserved. */
|
||||
if( ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS )
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange (pending)" ) );
|
||||
else
|
||||
ssl->out_msglen = 0;
|
||||
return( ret );
|
||||
}
|
||||
|
||||
/* If there is a signature, write its length.
|
||||
* ssl_prepare_server_key_exchange already wrote the signature
|
||||
* itself at its proper place in the output buffer. */
|
||||
#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED)
|
||||
if( signature_len != 0 )
|
||||
{
|
||||
ssl->out_msg[ssl->out_msglen++] = (unsigned char)( signature_len >> 8 );
|
||||
ssl->out_msg[ssl->out_msglen++] = (unsigned char)( signature_len );
|
||||
|
||||
MBEDTLS_SSL_DEBUG_BUF( 3, "my signature",
|
||||
ssl->out_msg + ssl->out_msglen,
|
||||
signature_len );
|
||||
|
||||
/* Skip over the already-written signature */
|
||||
ssl->out_msglen += signature_len;
|
||||
}
|
||||
#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */
|
||||
|
||||
/* Add header and send. */
|
||||
ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE;
|
||||
ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE;
|
||||
|
||||
|
@ -3197,7 +3314,6 @@ curve_matching_done:
|
|||
}
|
||||
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange" ) );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
@ -3272,28 +3388,50 @@ static int ssl_parse_client_dh_public( mbedtls_ssl_context *ssl, unsigned char *
|
|||
|
||||
#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \
|
||||
defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)
|
||||
static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl,
|
||||
const unsigned char *p,
|
||||
const unsigned char *end,
|
||||
size_t pms_offset )
|
||||
|
||||
#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
|
||||
static int ssl_resume_decrypt_pms( mbedtls_ssl_context *ssl,
|
||||
unsigned char *peer_pms,
|
||||
size_t *peer_pmslen,
|
||||
size_t peer_pmssize )
|
||||
{
|
||||
int ret = ssl->conf->f_async_resume( ssl,
|
||||
peer_pms, peer_pmslen, peer_pmssize );
|
||||
if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS )
|
||||
{
|
||||
ssl->handshake->async_in_progress = 0;
|
||||
mbedtls_ssl_set_async_operation_data( ssl, NULL );
|
||||
}
|
||||
MBEDTLS_SSL_DEBUG_RET( 2, "ssl_decrypt_encrypted_pms", ret );
|
||||
return( ret );
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
|
||||
|
||||
static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl,
|
||||
const unsigned char *p,
|
||||
const unsigned char *end,
|
||||
unsigned char *peer_pms,
|
||||
size_t *peer_pmslen,
|
||||
size_t peer_pmssize )
|
||||
{
|
||||
int ret;
|
||||
size_t len = mbedtls_pk_get_len( mbedtls_ssl_own_key( ssl ) );
|
||||
unsigned char *pms = ssl->handshake->premaster + pms_offset;
|
||||
unsigned char ver[2];
|
||||
unsigned char fake_pms[48], peer_pms[48];
|
||||
unsigned char mask;
|
||||
size_t i, peer_pmslen;
|
||||
unsigned int diff;
|
||||
mbedtls_pk_context *private_key = mbedtls_ssl_own_key( ssl );
|
||||
mbedtls_pk_context *public_key = &mbedtls_ssl_own_cert( ssl )->pk;
|
||||
size_t len = mbedtls_pk_get_len( public_key );
|
||||
|
||||
if( ! mbedtls_pk_can_do( mbedtls_ssl_own_key( ssl ), MBEDTLS_PK_RSA ) )
|
||||
#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
|
||||
/* If we have already started decoding the message and there is an ongoing
|
||||
* decryption operation, resume signing. */
|
||||
if( ssl->handshake->async_in_progress != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no RSA private key" ) );
|
||||
return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED );
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming decryption operation" ) );
|
||||
return( ssl_resume_decrypt_pms( ssl,
|
||||
peer_pms, peer_pmslen, peer_pmssize ) );
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
|
||||
|
||||
/*
|
||||
* Decrypt the premaster using own private RSA key
|
||||
* Prepare to decrypt the premaster using own private RSA key
|
||||
*/
|
||||
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
|
||||
defined(MBEDTLS_SSL_PROTO_TLS1_2)
|
||||
|
@ -3314,30 +3452,120 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl,
|
|||
return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE );
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrypt the premaster secret
|
||||
*/
|
||||
#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
|
||||
if( ssl->conf->f_async_decrypt_start != NULL )
|
||||
{
|
||||
ret = ssl->conf->f_async_decrypt_start( ssl,
|
||||
mbedtls_ssl_own_cert( ssl ),
|
||||
p, len );
|
||||
switch( ret )
|
||||
{
|
||||
case MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH:
|
||||
/* act as if f_async_decrypt_start was null */
|
||||
break;
|
||||
case 0:
|
||||
ssl->handshake->async_in_progress = 1;
|
||||
return( ssl_resume_decrypt_pms( ssl,
|
||||
peer_pms,
|
||||
peer_pmslen,
|
||||
peer_pmssize ) );
|
||||
case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
|
||||
ssl->handshake->async_in_progress = 1;
|
||||
return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS );
|
||||
default:
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "f_async_decrypt_start", ret );
|
||||
return( ret );
|
||||
}
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
|
||||
|
||||
if( ! mbedtls_pk_can_do( private_key, MBEDTLS_PK_RSA ) )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no RSA private key" ) );
|
||||
return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED );
|
||||
}
|
||||
|
||||
ret = mbedtls_pk_decrypt( private_key, p, len,
|
||||
peer_pms, peer_pmslen, peer_pmssize,
|
||||
ssl->conf->f_rng, ssl->conf->p_rng );
|
||||
return( ret );
|
||||
}
|
||||
|
||||
static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl,
|
||||
const unsigned char *p,
|
||||
const unsigned char *end,
|
||||
size_t pms_offset )
|
||||
{
|
||||
int ret;
|
||||
unsigned char *pms = ssl->handshake->premaster + pms_offset;
|
||||
unsigned char ver[2];
|
||||
unsigned char fake_pms[48], peer_pms[48];
|
||||
unsigned char mask;
|
||||
size_t i, peer_pmslen;
|
||||
unsigned int diff;
|
||||
|
||||
/* In case of a failure in decryption, the decryption may write less than
|
||||
* 2 bytes of output, but we always read the first two bytes. It doesn't
|
||||
* matter in the end because diff will be nonzero in that case due to
|
||||
* peer_pmslen being less than 48, and we only care whether diff is 0.
|
||||
* But do initialize peer_pms for robustness anyway. This also makes
|
||||
* memory analyzers happy (don't access uninitialized memory, even
|
||||
* if it's an unsigned char). */
|
||||
peer_pms[0] = peer_pms[1] = ~0;
|
||||
|
||||
ret = ssl_decrypt_encrypted_pms( ssl, p, end,
|
||||
peer_pms,
|
||||
&peer_pmslen,
|
||||
sizeof( peer_pms ) );
|
||||
|
||||
#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
|
||||
if ( ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS )
|
||||
return( ret );
|
||||
#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
|
||||
|
||||
mbedtls_ssl_write_version( ssl->handshake->max_major_ver,
|
||||
ssl->handshake->max_minor_ver,
|
||||
ssl->conf->transport, ver );
|
||||
ssl->handshake->max_minor_ver,
|
||||
ssl->conf->transport, ver );
|
||||
|
||||
/* Avoid data-dependent branches while checking for invalid
|
||||
* padding, to protect against timing-based Bleichenbacher-type
|
||||
* attacks. */
|
||||
diff = (unsigned int) ret;
|
||||
diff |= peer_pmslen ^ 48;
|
||||
diff |= peer_pms[0] ^ ver[0];
|
||||
diff |= peer_pms[1] ^ ver[1];
|
||||
|
||||
/* mask = diff ? 0xff : 0x00 using bit operations to avoid branches */
|
||||
/* MSVC has a warning about unary minus on unsigned, but this is
|
||||
* well-defined and precisely what we want to do here */
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable : 4146 )
|
||||
#endif
|
||||
mask = - ( ( diff | - diff ) >> ( sizeof( unsigned int ) * 8 - 1 ) );
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning( pop )
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Protection against Bleichenbacher's attack: invalid PKCS#1 v1.5 padding
|
||||
* must not cause the connection to end immediately; instead, send a
|
||||
* bad_record_mac later in the handshake.
|
||||
* Also, avoid data-dependant branches here to protect against
|
||||
* timing-based variants.
|
||||
* To protect against timing-based variants of the attack, we must
|
||||
* not have any branch that depends on whether the decryption was
|
||||
* successful. In particular, always generate the fake premaster secret,
|
||||
* regardless of whether it will ultimately influence the output or not.
|
||||
*/
|
||||
ret = ssl->conf->f_rng( ssl->conf->p_rng, fake_pms, sizeof( fake_pms ) );
|
||||
if( ret != 0 )
|
||||
{
|
||||
/* It's ok to abort on an RNG failure, since this does not reveal
|
||||
* anything about the RSA decryption. */
|
||||
return( ret );
|
||||
|
||||
ret = mbedtls_pk_decrypt( mbedtls_ssl_own_key( ssl ), p, len,
|
||||
peer_pms, &peer_pmslen,
|
||||
sizeof( peer_pms ),
|
||||
ssl->conf->f_rng, ssl->conf->p_rng );
|
||||
|
||||
diff = (unsigned int) ret;
|
||||
diff |= peer_pmslen ^ 48;
|
||||
diff |= peer_pms[0] ^ ver[0];
|
||||
diff |= peer_pms[1] ^ ver[1];
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_SSL_DEBUG_ALL)
|
||||
if( diff != 0 )
|
||||
|
@ -3352,18 +3580,8 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl,
|
|||
}
|
||||
ssl->handshake->pmslen = 48;
|
||||
|
||||
/* mask = diff ? 0xff : 0x00 using bit operations to avoid branches */
|
||||
/* MSVC has a warning about unary minus on unsigned, but this is
|
||||
* well-defined and precisely what we want to do here */
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable : 4146 )
|
||||
#endif
|
||||
mask = - ( ( diff | - diff ) >> ( sizeof( unsigned int ) * 8 - 1 ) );
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning( pop )
|
||||
#endif
|
||||
|
||||
/* Set pms to either the true or the fake PMS, without
|
||||
* data-dependent branches. */
|
||||
for( i = 0; i < ssl->handshake->pmslen; i++ )
|
||||
pms[i] = ( mask & fake_pms[i] ) | ( (~mask) & peer_pms[i] );
|
||||
|
||||
|
@ -3445,6 +3663,20 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl )
|
|||
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client key exchange" ) );
|
||||
|
||||
#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) && \
|
||||
( defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \
|
||||
defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) )
|
||||
if( ( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
|
||||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA ) &&
|
||||
( ssl->handshake->async_in_progress != 0 ) )
|
||||
{
|
||||
/* We've already read a record and there is an asynchronous
|
||||
* operation in progress to decrypt it. So skip reading the
|
||||
* record. */
|
||||
MBEDTLS_SSL_DEBUG_MSG( 3, ( "will resume decryption of previously-read record" ) );
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
|
||||
|
@ -3557,6 +3789,19 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl )
|
|||
#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)
|
||||
if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
|
||||
{
|
||||
#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
|
||||
if ( ssl->handshake->async_in_progress != 0 )
|
||||
{
|
||||
/* There is an asynchronous operation in progress to
|
||||
* decrypt the encrypted premaster secret, so skip
|
||||
* directly to resuming this operation. */
|
||||
MBEDTLS_SSL_DEBUG_MSG( 3, ( "PSK identity already parsed" ) );
|
||||
/* Update p to skip the PSK identity. ssl_parse_encrypted_pms
|
||||
* won't actually use it, but maintain p anyway for robustness. */
|
||||
p += ssl->conf->psk_identity_len + 2;
|
||||
}
|
||||
else
|
||||
#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
|
||||
if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret );
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue