diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index 5cb0511787fa..362ad9e3b128 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -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 */ @@ -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 @@ -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" ) ); @@ -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: