From acc31e7a40ffb2844dd8ce53c65e5a55b5d6fc6a Mon Sep 17 00:00:00 2001 From: lhuang04 Date: Sun, 20 Dec 2020 08:15:04 -0800 Subject: [PATCH] Set call back to delegate entire certificate validation process Summary: Set call back, `f_verify_callback`, to delegate the entire certificate validation process to application. The application has additional validation logic which is not supported in default mbedtls implementation, such as cert pinning. It may also delegate some validation process to OS. Test Plan: Build and make test Reviewers: hanno.becker@arm.com,hannes.tschofenig@arm.com,junqi.wang@live.com,zhi.han@gmail.com Subscribers: Tasks: Tags: --- include/mbedtls/ssl.h | 23 +++++++++++++++++++++++ library/ssl_tls.c | 10 ++++++++++ library/ssl_tls13_generic.c | 27 ++++++++++++++++++++++++--- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index ce5bb376b0ff..a889ead699b4 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -1221,6 +1221,10 @@ struct mbedtls_ssl_config /** Callback to customize X.509 certificate chain verification */ int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *); void *p_vrfy; /*!< context for X.509 verify calllback */ +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + int (*f_verify_callback)(void *, const mbedtls_x509_crt *, const char *); + void *p_verify_callback; +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) @@ -1953,6 +1957,25 @@ void mbedtls_ssl_conf_early_data(mbedtls_ssl_config* conf, int early_data, char* void mbedtls_ssl_conf_verify( mbedtls_ssl_config *conf, int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), void *p_vrfy ); +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +/** + * \brief Set the verification callback (Optional). + * + * If the application does not explicitly specify a + * verification callback function, the built-in verification + * function is used. If a verification callback is specified via + * mbedtls_ssl_conf_set_verify_callback(), the supplied callback + * function is called instead. By setting callback to NULL, the + * default behaviour is restored. + * + * \param conf SSL configuration + * \param f_verify_callback verification function + * \param p_verify_callback verification parameter + */ +void mbedtls_ssl_conf_set_verify_callback( mbedtls_ssl_config *conf, + int (*f_verify_callback)(void *, const mbedtls_x509_crt *, const char *), + void *p_verify_callback ); +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_X509_CRT_PARSE_C) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index b43cd79eda07..30c571fde550 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -4514,6 +4514,16 @@ void mbedtls_ssl_conf_verify( mbedtls_ssl_config *conf, conf->f_vrfy = f_vrfy; conf->p_vrfy = p_vrfy; } + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +void mbedtls_ssl_conf_set_verify_callback( mbedtls_ssl_config *conf, + int (*f_verify_callback)(void *, const mbedtls_x509_crt *, const char *), + void *p_verify_callback ) { + conf->f_verify_callback = f_verify_callback; + conf->p_verify_callback = p_verify_callback; +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #endif /* MBEDTLS_X509_CRT_PARSE_C */ void mbedtls_ssl_conf_rng( mbedtls_ssl_config *conf, diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index 6bcb3d604a09..320103678637 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -2912,8 +2912,9 @@ static int ssl_read_certificate_validate( mbedtls_ssl_context* ssl ) { int ret = 0; int authmode = ssl->conf->authmode; - mbedtls_x509_crt* ca_chain; - mbedtls_x509_crl* ca_crl; + int have_ca_chain = 0; + mbedtls_x509_crt* ca_chain = NULL; + mbedtls_x509_crl* ca_crl = NULL; /* If SNI was used, overwrite authentication mode * from the configuration. */ @@ -2961,6 +2962,21 @@ static int ssl_read_certificate_validate( mbedtls_ssl_context* ssl ) return( 0 ); } +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if (ssl->conf->f_verify_callback) { + if (ssl->conf->f_verify_callback( + ssl->conf->p_verify_callback, + ssl->session_negotiate->peer_cert, + ssl->hostname) != 0) + { + ssl->session_negotiate->verify_result |= MBEDTLS_X509_BADCERT_OTHER; + ret = MBEDTLS_ERR_X509_CERT_VERIFY_FAILED; + } + have_ca_chain = 1; + } + else +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + { #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) if( ssl->handshake->sni_ca_chain != NULL ) { @@ -2974,6 +2990,8 @@ static int ssl_read_certificate_validate( mbedtls_ssl_context* ssl ) ca_crl = ssl->conf->ca_crl; } + if( ca_chain != NULL ) + have_ca_chain = 1; /* * Main check: verify certificate */ @@ -2984,10 +3002,13 @@ static int ssl_read_certificate_validate( mbedtls_ssl_context* ssl ) ssl->hostname, &ssl->session_negotiate->verify_result, ssl->conf->f_vrfy, ssl->conf->p_vrfy ); + } if( ret != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret ); + mbedtls_ssl_send_alert_message(ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN); } /* @@ -3034,7 +3055,7 @@ static int ssl_read_certificate_validate( mbedtls_ssl_context* ssl ) ret = 0; } - if( ca_chain == NULL && authmode == MBEDTLS_SSL_VERIFY_REQUIRED ) + if( have_ca_chain == 0 && authmode == MBEDTLS_SSL_VERIFY_REQUIRED ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) ); ret = MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED;