Skip to content

Commit

Permalink
Add helper functions to parse extensions in HRR
Browse files Browse the repository at this point in the history
  • Loading branch information
gbryant-arm committed Mar 8, 2021
1 parent c1ece20 commit 63eda4f
Showing 1 changed file with 173 additions and 137 deletions.
310 changes: 173 additions & 137 deletions library/ssl_tls13_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -3585,12 +3585,177 @@ static int ssl_server_hello_postprocess( mbedtls_ssl_context* ssl )
}


#if defined(MBEDTLS_SSL_COOKIE_C)
static int ssl_parse_hrr_cookie_ext( mbedtls_ssl_context *ssl,
const unsigned char *buf,
size_t len )
{
int ret = 0;
size_t cookie_len;

MBEDTLS_SSL_DEBUG_MSG( 3, ( "parse cookie extension" ) );

/* Retrieve length field of cookie */
if( len >= 2 )
{
cookie_len = ( buf[0] << 8 ) | buf[1];
buf += 2;
}
else
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad HRR message - cookie length mismatch" ) );
return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST );
}

if( ( cookie_len + 2 ) != len )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad HRR message - cookie length mismatch" ) );
return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST );
}

MBEDTLS_SSL_DEBUG_BUF( 3, "cookie extension", buf, cookie_len );

mbedtls_free( ssl->handshake->verify_cookie );

ssl->handshake->verify_cookie = mbedtls_calloc( 1, cookie_len );
if( ssl->handshake->verify_cookie == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc failed ( %d bytes )", cookie_len ) );
return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
}

memcpy( ssl->handshake->verify_cookie, buf, cookie_len );
ssl->handshake->verify_cookie_len = (unsigned char) cookie_len;

return( ret );
}
#endif /* MBEDTLS_SSL_COOKIE_C */

#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C)
/*
ssl_parse_hrr_key_shares_ext( ) verifies whether the information in the extension
is correct and stores the provided key shares.
*/

/* The ssl_parse_hrr_key_shares_ext( ) function is used
* by the client to parse a KeyShare extension in
* a HelloRetryRequest message.
*
* The server only provides a single KeyShareEntry.
*/
static int ssl_parse_hrr_key_shares_ext( mbedtls_ssl_context *ssl,
const unsigned char *buf,
size_t len )
{
((void) len);

int ret = 0;
const mbedtls_ecp_group_id* grp_id;
const mbedtls_ecp_curve_info* info, * curve = NULL;
int tls_id;
int found = 0;

/* Read selected_group */
tls_id = ( ( buf[0] << 8 ) | ( buf[1] ) );
MBEDTLS_SSL_DEBUG_MSG( 3, ( "selected_group ( %d )", tls_id ) );

info = mbedtls_ecp_curve_info_from_tls_id( tls_id );

if( info != NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "selected_group by name ( %s )", info->name ) );
}
/*
* Upon receipt of this extension in a HelloRetryRequest, the client
* MUST first verify that the selected_group field corresponds to a
* group which was provided in the "supported_groups" extension in the
* original ClientHello.
*
* The supported_group was based on the info in ssl->conf->curve_list.
*/

for ( grp_id = ssl->conf->curve_list; *grp_id != MBEDTLS_ECP_DP_NONE; grp_id++ ) {
/* In the initial ClientHello we transmitted the key shares based on
* key_shares_curve_list.
*/
info = mbedtls_ecp_curve_info_from_grp_id( *grp_id );

if( info == NULL ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );

if( info->tls_id == tls_id )
{
/* We found a match */
found = 1;
break;
}
}

/* If the server provided a key share that was not sent in the ClientHello
* then the client MUST abort the handshake with an "illegal_parameter" alert.
*/
if( found == 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad HRR ( server provided key share that was not sent in ClientHello )" ) );
SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER,
MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST );
return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST );
}

/*
* Client MUST verify that the selected_group
* field does not correspond to a group which was provided in the
* "key_share" extension in the original ClientHello.
*/
found = 0;
for ( grp_id = ssl->conf->key_shares_curve_list; *grp_id != MBEDTLS_ECP_DP_NONE; grp_id++ ) {

info = mbedtls_ecp_curve_info_from_grp_id( *grp_id );

if( info == NULL ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );

if( info->tls_id == tls_id )
{
/* We found a match */
found = 1;
break;
}
}

/* If the server sent an HRR message with a key share already
* provided in the ClientHello then the client MUST abort the
* handshake with an "illegal_parameter" alert.
*/
if( found == 1 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad HRR ( server sent HRR with a key share already provided in ClientHello )" ) );
SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER,
MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST );
return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST );
}

/* Modify key_shares_curve_list for next ClientHello
* based on info provided by server. For the second
* ClientHello we only send the key share expected
* by the server.
*/
curve = mbedtls_ecp_curve_info_from_tls_id( tls_id );

if( curve == NULL ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );

ssl->handshake->key_shares_curve_list[0] = curve->grp_id;
ssl->handshake->key_shares_curve_list[1] = MBEDTLS_ECP_DP_NONE;

return( ret );
}
#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */

static int ssl_hrr_parse( mbedtls_ssl_context* ssl,
const unsigned char* buf, size_t buflen )
{
int ret; /* return value */
int i; /* scratch value */
int found = 0;
const unsigned char* msg_end = buf + buflen; /* pointer to the end of the buffer for length checks */

size_t ext_len; /* stores length of all extensions */
Expand All @@ -3600,18 +3765,6 @@ static int ssl_hrr_parse( mbedtls_ssl_context* ssl,

const mbedtls_ssl_ciphersuite_t* suite_info; /* pointer to ciphersuite */

#if defined(MBEDTLS_ECDH_C)
/* Variables for parsing the key_share */
const mbedtls_ecp_group_id* grp_id;
const mbedtls_ecp_curve_info* info, * curve = NULL;
int tls_id;
#endif /* MBEDTLS_ECDH_C */

#if defined(MBEDTLS_SSL_COOKIE_C)
size_t cookie_len;
unsigned char *cookie;
#endif /* MBEDTLS_SSL_COOKIE_C */

#if defined(MBEDTLS_SSL_USE_MPS)
size_t hs_hdr_add = 0;
#else
Expand Down Expand Up @@ -3885,43 +4038,14 @@ static int ssl_hrr_parse( mbedtls_ssl_context* ssl,
{
#if defined(MBEDTLS_SSL_COOKIE_C)
case MBEDTLS_TLS_EXT_COOKIE:
MBEDTLS_SSL_DEBUG_MSG( 3, ( "found cookie extension" ) );

/* Retrieve length field of cookie */
if( ext_size >= 2 )
{
cookie = (unsigned char *) ( ext + 4 );
cookie_len = ( cookie[0] << 8 ) | cookie[1];
cookie += 2;
}
else
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad HRR message - cookie length mismatch" ) );
return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST );
}

if( ( cookie_len + 2 ) != ext_size )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad HRR message - cookie length mismatch" ) );
return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST );
}

MBEDTLS_SSL_DEBUG_BUF( 3, "cookie extension", cookie, cookie_len );

mbedtls_free( ssl->handshake->verify_cookie );

ssl->handshake->verify_cookie = mbedtls_calloc( 1, cookie_len );
if( ssl->handshake->verify_cookie == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc failed ( %d bytes )", cookie_len ) );
return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
}

memcpy( ssl->handshake->verify_cookie, cookie, cookie_len );
ssl->handshake->verify_cookie_len = (unsigned char) cookie_len;
ret = ssl_parse_hrr_cookie_ext( ssl, ext + 4, ext_size );
if( ret != 0 )
return( ret );
break;
#endif /* MBEDTLS_SSL_COOKIE_C */


case MBEDTLS_TLS_EXT_SUPPORTED_VERSIONS:
MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported_versions extension" ) );

Expand All @@ -3932,99 +4056,11 @@ static int ssl_hrr_parse( mbedtls_ssl_context* ssl,

#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C)
case MBEDTLS_TLS_EXT_KEY_SHARES:

MBEDTLS_SSL_DEBUG_BUF( 3, "key_share extension", ext + 4, ext_size );

/* Read selected_group */
tls_id = ( ( ext[4] << 8 ) | ( ext[5] ) );
MBEDTLS_SSL_DEBUG_MSG( 3, ( "selected_group ( %d )", tls_id ) );

info = mbedtls_ecp_curve_info_from_tls_id( tls_id );

if( info != NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "selected_group by name ( %s )", info->name ) );
}
/*
* Upon receipt of this extension in a HelloRetryRequest, the client
* MUST first verify that the selected_group field corresponds to a
* group which was provided in the "supported_groups" extension in the
* original ClientHello.
*
* The supported_group was based on the info in ssl->conf->curve_list.
*/

for ( grp_id = ssl->conf->curve_list; *grp_id != MBEDTLS_ECP_DP_NONE; grp_id++ ) {
/* In the initial ClientHello we transmitted the key shares based on
* key_shares_curve_list.
*/
info = mbedtls_ecp_curve_info_from_grp_id( *grp_id );

if( info == NULL ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );

if( info->tls_id == tls_id )
{
/* We found a match */
found = 1;
break;
}
}

/* If the server provided a key share that was not sent in the ClientHello
* then the client MUST abort the handshake with an "illegal_parameter" alert.
*/
if( found == 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad HRR ( server provided key share that was not sent in ClientHello )" ) );
SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER,
MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST );
return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST );
}

/*
* Client MUST verify that the selected_group
* field does not correspond to a group which was provided in the
* "key_share" extension in the original ClientHello.
*/
found = 0;
for ( grp_id = ssl->conf->key_shares_curve_list; *grp_id != MBEDTLS_ECP_DP_NONE; grp_id++ ) {

info = mbedtls_ecp_curve_info_from_grp_id( *grp_id );

if( info == NULL ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );

if( info->tls_id == tls_id )
{
/* We found a match */
found = 1;
break;
}
}

/* If the server sent an HRR message with a key share already
* provided in the ClientHello then the client MUST abort the
* handshake with an "illegal_parameter" alert.
*/
if( found == 1 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad HRR ( server sent HRR with a key share already provided in ClientHello )" ) );
SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER,
MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST );
return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST );
}

/* Modify key_shares_curve_list for next ClientHello
* based on info provided by server. For the second
* ClientHello we only send the key share expected
* by the server.
*/
curve = mbedtls_ecp_curve_info_from_tls_id( tls_id );

if( curve == NULL ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );

ssl->handshake->key_shares_curve_list[0] = curve->grp_id;
ssl->handshake->key_shares_curve_list[1] = MBEDTLS_ECP_DP_NONE;

ret = ssl_parse_hrr_key_shares_ext( ssl, ext + 4, ext_size );
if( ret != 0 )
return( ret );
break;
#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */
default:
Expand Down

0 comments on commit 63eda4f

Please sign in to comment.