diff --git a/library/ssl_misc.h b/library/ssl_misc.h index 6af9964b8a..aaed88bd13 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -267,6 +267,8 @@ /* Maximum size in bytes of list in supported elliptic curve ext., RFC 4492 */ #define MBEDTLS_SSL_MAX_CURVE_LIST_LEN 65535 +#define MBEDTLS_RECEIVED_SIG_ALGS_SIZE 20 + /* * Check that we obey the standard's message size bounds */ @@ -601,6 +603,11 @@ struct mbedtls_ssl_handshake_params mbedtls_ssl_sig_hash_set_t hash_algs; /*!< Set of suitable sig-hash pairs */ #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && \ + defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) + uint16_t received_sig_algs[MBEDTLS_RECEIVED_SIG_ALGS_SIZE]; +#endif + #if !defined(MBEDTLS_DEPRECATED_REMOVED) const uint16_t *group_list; const uint16_t *sig_algs; @@ -811,6 +818,11 @@ struct mbedtls_ssl_handshake_params represents an extension and defined as \c MBEDTLS_SSL_EXT_XXX */ +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) + unsigned char certificate_request_context_len; + unsigned char *certificate_request_context; +#endif + union { unsigned char early [MBEDTLS_TLS1_3_MD_MAX_SIZE]; @@ -1751,6 +1763,12 @@ int mbedtls_ssl_reset_transcript_for_hrr( mbedtls_ssl_context *ssl ); int mbedtls_ssl_write_sig_alg_ext( mbedtls_ssl_context *ssl, unsigned char *buf, const unsigned char *end, size_t *out_len ); +/* + * Parse TLS 1.3 Signature Algorithm extension + */ +int mbedtls_ssl_tls13_parse_sig_alg_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + const unsigned char *end ); #endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ /* Get handshake transcript */ diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 099bd55c47..ec8dbfb530 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -5756,7 +5756,12 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ) mbedtls_free( (void*) handshake->sig_algs ); handshake->sig_algs = NULL; #endif /* MBEDTLS_DEPRECATED_REMOVED */ - +#if defined(MBEDTLS_SSL_PROTO_TLS1_3) + if( ssl->handshake->certificate_request_context ) + { + mbedtls_free( (void*) handshake->certificate_request_context ); + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */ #endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index ca91d67da1..2ba2d00113 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -1662,31 +1662,213 @@ static int ssl_tls13_postprocess_encrypted_extensions( mbedtls_ssl_context *ssl #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) /* - * Handler for MBEDTLS_SSL_CERTIFICATE_REQUEST + * + * STATE HANDLING: CertificateRequest + * */ -static int ssl_tls13_process_certificate_request( mbedtls_ssl_context *ssl ) +#define SSL_CERTIFICATE_REQUEST_EXPECT_REQUEST 0 +#define SSL_CERTIFICATE_REQUEST_SKIP 1 +/* Coordination: + * Deals with the ambiguity of not knowing if a CertificateRequest + * will be sent. Returns a negative code on failure, or + * - SSL_CERTIFICATE_REQUEST_EXPECT_REQUEST + * - SSL_CERTIFICATE_REQUEST_SKIP + * indicating if a Certificate Request is expected or not. + */ +static int ssl_tls13_certificate_request_coordinate( mbedtls_ssl_context *ssl ) { - int ret = mbedtls_ssl_read_record( ssl, 0 ); + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - if( ret != 0 ) + if( mbedtls_ssl_tls13_some_psk_enabled( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= skip parse certificate request" ) ); + return( SSL_CERTIFICATE_REQUEST_SKIP ); + } + + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); return( ret ); } + ssl->keep_current_message = 1; if( ( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) && ( ssl->in_msg[0] == MBEDTLS_SSL_HS_CERTIFICATE_REQUEST ) ) { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "CertificateRequest not supported" ) ); - MBEDTLS_SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE, - MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE ); - return( MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE ); + return( SSL_CERTIFICATE_REQUEST_EXPECT_REQUEST ); } - ssl->keep_current_message = 1; + return( SSL_CERTIFICATE_REQUEST_SKIP ); +} + +/* + * ssl_tls13_parse_certificate_request() + * Parse certificate request + * struct { + * opaque certificate_request_context<0..2^8-1>; + * Extension extensions<2..2^16-1>; + * } CertificateRequest; + */ +static int ssl_tls13_parse_certificate_request( mbedtls_ssl_context *ssl, + const unsigned char *buf, + const unsigned char *end ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + const unsigned char *p = buf; + size_t certificate_request_context_len = 0; + size_t extensions_len = 0; + const unsigned char *extensions_end; + unsigned char sig_alg_ext_found = 0; + + /* ... + * opaque certificate_request_context<0..2^8-1> + * ... + */ + MBEDTLS_SSL_CHK_BUF_READ_PTR( p, end, 1 ); + certificate_request_context_len = (size_t) p[0]; + p += 1; + + if( certificate_request_context_len > 0 ) + { + MBEDTLS_SSL_CHK_BUF_READ_PTR( p, end, certificate_request_context_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "Certificate Request Context", + p, certificate_request_context_len ); + + mbedtls_ssl_handshake_params *handshake = ssl->handshake; + handshake->certificate_request_context = + mbedtls_calloc( 1, certificate_request_context_len ); + if( handshake->certificate_request_context == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return ( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + memcpy( handshake->certificate_request_context, p, + certificate_request_context_len ); + p += certificate_request_context_len; + } + + /* ... + * Extension extensions<2..2^16-1>; + * ... + */ + MBEDTLS_SSL_CHK_BUF_READ_PTR( p, end, 2 ); + extensions_len = MBEDTLS_GET_UINT16_BE( p, 0 ); + p += 2; + + MBEDTLS_SSL_CHK_BUF_READ_PTR( p, end, extensions_len ); + extensions_end = p + extensions_len; + + while( p < extensions_end ) + { + unsigned int extension_type; + size_t extension_data_len; + + MBEDTLS_SSL_CHK_BUF_READ_PTR( p, extensions_end, 4 ); + extension_type = MBEDTLS_GET_UINT16_BE( p, 0 ); + extension_data_len = MBEDTLS_GET_UINT16_BE( p, 2 ); + p += 4; + + MBEDTLS_SSL_CHK_BUF_READ_PTR( p, extensions_end, extension_data_len ); + + switch( extension_type ) + { + case MBEDTLS_TLS_EXT_SIG_ALG: + MBEDTLS_SSL_DEBUG_MSG( 3, + ( "found signature algorithms extension" ) ); + ret = mbedtls_ssl_tls13_parse_sig_alg_ext( ssl, p, + p + extension_data_len ); + if( ret != 0 ) + return( ret ); + if( ! sig_alg_ext_found ) + sig_alg_ext_found = 1; + else + { + MBEDTLS_SSL_DEBUG_MSG( 3, + ( "Duplicate signature algorithms extensions found" ) ); + goto decode_error; + } + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( + 3, + ( "unknown extension found: %u ( ignoring )", + extension_type ) ); + break; + } + p += extension_data_len; + } + /* Check that we consumed all the message. */ + if( p != end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, + ( "CertificateRequest misaligned" ) ); + goto decode_error; + } + /* Check that we found signature algorithms extension */ + if( ! sig_alg_ext_found ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, + ( "no signature algorithms extension found" ) ); + goto decode_error; + } + + ssl->client_auth = 1; + return( 0 ); + +decode_error: + MBEDTLS_SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_DECODE_ERROR ); +} + +/* + * Handler for MBEDTLS_SSL_CERTIFICATE_REQUEST + */ +static int ssl_tls13_process_certificate_request( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) ); + + MBEDTLS_SSL_PROC_CHK_NEG( ssl_tls13_certificate_request_coordinate( ssl ) ); + + if( ret == SSL_CERTIFICATE_REQUEST_EXPECT_REQUEST ) + { + unsigned char *buf; + size_t buf_len; + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_tls13_fetch_handshake_msg( ssl, + MBEDTLS_SSL_HS_CERTIFICATE_REQUEST, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_tls13_parse_certificate_request( ssl, + buf, buf + buf_len ) ); + + mbedtls_ssl_tls13_add_hs_msg_to_checksum( + ssl, MBEDTLS_SSL_HS_CERTIFICATE_REQUEST, buf, buf_len ); + } + else if( ret == SSL_CERTIFICATE_REQUEST_SKIP ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate request" ) ); + ret = 0; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto cleanup; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "got %s certificate request", + ssl->client_auth ? "a" : "no" ) ); + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_CERTIFICATE ); - return( 0 ); +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate request" ) ); + return( ret ); } /* diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index 9aa2148733..1ad03a9b1a 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -136,6 +136,80 @@ void mbedtls_ssl_tls13_add_hs_hdr_to_checksum( mbedtls_ssl_context *ssl, } #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) +/* mbedtls_ssl_tls13_parse_sig_alg_ext() + * + * enum { + * .... + * ecdsa_secp256r1_sha256( 0x0403 ), + * ecdsa_secp384r1_sha384( 0x0503 ), + * ecdsa_secp521r1_sha512( 0x0603 ), + * .... + * } SignatureScheme; + * + * struct { + * SignatureScheme supported_signature_algorithms<2..2^16-2>; + * } SignatureSchemeList; + */ +int mbedtls_ssl_tls13_parse_sig_alg_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + const unsigned char *end ) +{ + const unsigned char *p = buf; + size_t supported_sig_algs_len = 0; + const unsigned char *supported_sig_algs_end; + uint16_t sig_alg; + uint32_t common_idx = 0; + + MBEDTLS_SSL_CHK_BUF_READ_PTR( p, end, 2 ); + supported_sig_algs_len = MBEDTLS_GET_UINT16_BE( p, 0 ); + p += 2; + + memset( ssl->handshake->received_sig_algs, 0, + sizeof(ssl->handshake->received_sig_algs) ); + + MBEDTLS_SSL_CHK_BUF_READ_PTR( p, end, supported_sig_algs_len ); + supported_sig_algs_end = p + supported_sig_algs_len; + while( p < supported_sig_algs_end ) + { + MBEDTLS_SSL_CHK_BUF_READ_PTR( p, supported_sig_algs_end, 2 ); + sig_alg = MBEDTLS_GET_UINT16_BE( p, 0 ); + p += 2; + + MBEDTLS_SSL_DEBUG_MSG( 4, ( "received signature algorithm: 0x%x", + sig_alg ) ); + + if( ! mbedtls_ssl_sig_alg_is_offered( ssl, sig_alg ) || + ! mbedtls_ssl_sig_alg_is_supported( ssl, sig_alg ) ) + continue; + + if( common_idx + 1 < MBEDTLS_RECEIVED_SIG_ALGS_SIZE ) + { + ssl->handshake->received_sig_algs[common_idx] = sig_alg; + common_idx += 1; + } + } + /* Check that we consumed all the message. */ + if( p != end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, + ( "Signature algorithms extension length misaligned" ) ); + MBEDTLS_SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_DECODE_ERROR ); + } + + if( common_idx == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "no signature algorithm in common" ) ); + MBEDTLS_SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE, + MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE ); + } + + ssl->handshake->received_sig_algs[common_idx] = MBEDTLS_TLS1_3_SIG_NONE; + return( 0 ); +} + /* * STATE HANDLING: Read CertificateVerify */ diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 299cbbd8aa..4ec62ae1a9 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -9185,7 +9185,9 @@ run_test "TLS 1.3: CertificateRequest check - openssl" \ "$O_NEXT_SRV -msg -tls1_3 -num_tickets 0 -no_resume_ephemeral -no_cache -Verify 10" \ "$P_CLI debug_level=4 force_version=tls13 " \ 1 \ - -c "CertificateRequest not supported" + -c "=> parse certificate request" \ + -c "got a certificate request" \ + -c "<= parse certificate request" requires_gnutls_tls1_3 requires_gnutls_next_no_ticket @@ -9198,7 +9200,9 @@ run_test "TLS 1.3: CertificateRequest check - gnutls" \ "$G_NEXT_SRV --debug=4 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:+CIPHER-ALL:%NO_TICKETS" \ "$P_CLI debug_level=3 min_version=tls13 max_version=tls13" \ 1 \ - -c "CertificateRequest not supported" + -c "=> parse certificate request" \ + -c "got a certificate request" \ + -c "<= parse certificate request" requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 requires_config_enabled MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE