From 39ae8cd2077d2e9e7d00161162ad8d3fb45dba27 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 8 May 2017 16:31:14 +0100 Subject: [PATCH] Fix implementation of VERIFY_OPTIONAL verification mode This commit changes the behaviour of mbedtls_ssl_parse_certificate to make the two authentication modes MBEDTLS_SSL_VERIFY_REQUIRED and MBEDTLS_SSL_VERIFY_OPTIONAL be in the following relationship: Mode == MBEDTLS_SSL_VERIFY_REQUIRED <=> Mode == MBEDTLS_SSL_VERIFY_OPTIONAL + check verify result Also, it changes the behaviour to perform the certificate chain verification even if the trusted CA chain is empty. Previously, the function failed in this case, even when using optional verification, which was brought up in #864. --- ChangeLog | 7 +++++++ library/ssl_tls.c | 33 ++++++++++++++++++++++----------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1b6a3542d..da0755ad5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -17,6 +17,13 @@ Bugfix that triggered the alert. * In SSLv3, if refusing a renegotiation attempt, don't process any further data. + * Accept empty trusted CA chain in authentication mode + MBEDTLS_SSL_VERIFY_OPTIONAL. + Fixes #864. Found by jethrogb. + * Fix implementation of mbedtls_ssl_parse_certificate + to not annihilate fatal errors in authentication mode + MBEDTLS_SSL_VERIFY_OPTIONAL and to reflect bad EC curves + within verification result. Changes * Send fatal alerts in many more cases instead of dropping the connection. diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 1e5f8e493..ff951a536 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -4472,14 +4472,6 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) ca_crl = ssl->conf->ca_crl; } - if( ca_chain == NULL ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) ); - mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, - MBEDTLS_SSL_ALERT_MSG_BAD_CERT ); - return( MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED ); - } - /* * Main check: verify certificate */ @@ -4508,6 +4500,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) && mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ) != 0 ) { + ssl->session_negotiate->verify_result |= MBEDTLS_X509_BADCERT_BAD_KEY; + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (EC key curve)" ) ); if( ret == 0 ) ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; @@ -4516,8 +4510,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) #endif /* MBEDTLS_ECP_C */ if( mbedtls_ssl_check_cert_usage( ssl->session_negotiate->peer_cert, - ciphersuite_info, - ! ssl->conf->endpoint, + ciphersuite_info, + ! ssl->conf->endpoint, &ssl->session_negotiate->verify_result ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (usage extensions)" ) ); @@ -4525,8 +4519,24 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; } - if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) + /* mbedtls_x509_crt_verify_with_profile is supposed to report a + * verification failure through MBEDTLS_ERR_X509_CERT_VERIFY_FAILED, + * with details encoded in the verification flags. All other kinds + * of error codes, including those from the user provided f_vrfy + * functions, are treated as fatal and lead to a failure of + * ssl_parse_certificate even if verification was optional. */ + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL && + ( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED || + ret == MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ) ) + { ret = 0; + } + + if( ca_chain == NULL && authmode == MBEDTLS_SSL_VERIFY_REQUIRED ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) ); + ret = MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED; + } if( ret != 0 ) { @@ -4558,6 +4568,7 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, alert ); } + } MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) );