Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add helper functions to parse extensions in HRR #102

Open
wants to merge 1 commit into
base: tls13-prototype
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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