diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 35e576481..135be0501 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -1094,6 +1094,12 @@ struct mbedtls_ssl_context unsigned badmac_seen; /*!< records with a bad MAC received */ #endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + /** 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 callback */ +#endif + mbedtls_ssl_send_t *f_send; /*!< Callback for network send */ mbedtls_ssl_recv_t *f_recv; /*!< Callback for network receive */ mbedtls_ssl_recv_timeout_t *f_recv_timeout; @@ -1370,13 +1376,17 @@ void mbedtls_ssl_conf_authmode( mbedtls_ssl_config *conf, int authmode ); /** * \brief Set the verification callback (Optional). * - * If set, the verify callback is called for each - * certificate in the chain. For implementation - * information, please see \c mbedtls_x509_crt_verify() + * If set, the provided verify callback is called for each + * certificate in the peer's CRT chain, including the trusted + * root. For more information, please see the documentation of + * \c mbedtls_x509_crt_verify(). * - * \param conf SSL configuration - * \param f_vrfy verification function - * \param p_vrfy verification parameter + * \note For per context callbacks and contexts, please use + * mbedtls_ssl_set_verify() instead. + * + * \param conf The SSL configuration to use. + * \param f_vrfy The verification callback to use during CRT verification. + * \param p_vrfy The opaque context to be passed to the callback. */ void mbedtls_ssl_conf_verify( mbedtls_ssl_config *conf, int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), @@ -1494,6 +1504,30 @@ void mbedtls_ssl_set_bio( mbedtls_ssl_context *ssl, void mbedtls_ssl_set_mtu( mbedtls_ssl_context *ssl, uint16_t mtu ); #endif /* MBEDTLS_SSL_PROTO_DTLS */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Set a connection-specific verification callback (optional). + * + * If set, the provided verify callback is called for each + * certificate in the peer's CRT chain, including the trusted + * root. For more information, please see the documentation of + * \c mbedtls_x509_crt_verify(). + * + * \note This call is analogous to mbedtls_ssl_conf_verify() but + * binds the verification callback and context to an SSL context + * as opposed to an SSL configuration. + * If mbedtls_ssl_conf_verify() and mbedtls_ssl_set_verify() + * are both used, mbedtls_ssl_set_verify() takes precedence. + * + * \param ssl The SSL context to use. + * \param f_vrfy The verification callback to use during CRT verification. + * \param p_vrfy The opaque context to be passed to the callback. + */ +void mbedtls_ssl_set_verify( mbedtls_ssl_context *ssl, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + /** * \brief Set the timeout period for mbedtls_ssl_read() * (Default: no timeout.) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 09645cd0a..dac160dc0 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -6037,9 +6037,25 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl, ssl->transform_negotiate->ciphersuite_info; int have_ca_chain = 0; + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *); + void *p_vrfy; + if( authmode == MBEDTLS_SSL_VERIFY_NONE ) return( 0 ); + if( ssl->f_vrfy != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Use context-specific verification callback" ) ); + f_vrfy = ssl->f_vrfy; + p_vrfy = ssl->p_vrfy; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Use configuration-specific verification callback" ) ); + f_vrfy = ssl->conf->f_vrfy; + p_vrfy = ssl->conf->p_vrfy; + } + /* * Main check: verify certificate */ @@ -6057,7 +6073,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl, ssl->conf->cert_profile, ssl->hostname, &ssl->session_negotiate->verify_result, - ssl->conf->f_vrfy, ssl->conf->p_vrfy ); + f_vrfy, p_vrfy ); } else #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ @@ -6087,7 +6103,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl, ssl->conf->cert_profile, ssl->hostname, &ssl->session_negotiate->verify_result, - ssl->conf->f_vrfy, ssl->conf->p_vrfy, rs_ctx ); + f_vrfy, p_vrfy, rs_ctx ); } if( ret != 0 ) @@ -7949,6 +7965,16 @@ void mbedtls_ssl_set_hs_authmode( mbedtls_ssl_context *ssl, } #endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) +void mbedtls_ssl_set_verify( mbedtls_ssl_context *ssl, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + ssl->f_vrfy = f_vrfy; + ssl->p_vrfy = p_vrfy; +} +#endif + #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) /* * Set EC J-PAKE password for current handshake diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index f0c716441..2cddfb42a 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -82,6 +82,7 @@ int main( void ) #define DFL_REQUEST_PAGE "/" #define DFL_REQUEST_SIZE -1 #define DFL_DEBUG_LEVEL 0 +#define DFL_CONTEXT_CRT_CB 0 #define DFL_NBIO 0 #define DFL_EVENT 0 #define DFL_READ_TIMEOUT 0 @@ -130,6 +131,16 @@ int main( void ) #define GET_REQUEST "GET %s HTTP/1.0\r\nExtra-header: " #define GET_REQUEST_END "\r\n\r\n" +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#define USAGE_CONTEXT_CRT_CB \ + " context_crt_cb=%%d This determines whether the CRT verification callback is bound\n" \ + " to the SSL configuration of the SSL context.\n" \ + " Possible values:\n"\ + " - 0 (default): Use CRT callback bound to configuration\n" \ + " - 1: Use CRT callback bound to SSL context\n" +#else +#define USAGE_CONTEXT_CRT_CB "" +#endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_X509_CRT_PARSE_C) #if defined(MBEDTLS_FS_IO) #define USAGE_IO \ @@ -339,6 +350,7 @@ int main( void ) USAGE_TICKETS \ USAGE_MAX_FRAG_LEN \ USAGE_TRUNC_HMAC \ + USAGE_CONTEXT_CRT_CB \ USAGE_ALPN \ USAGE_FALLBACK \ USAGE_EMS \ @@ -435,6 +447,7 @@ struct options int dgram_packing; /* allow/forbid datagram packing */ int extended_ms; /* negotiate extended master secret? */ int etm; /* negotiate encrypt then mac? */ + int context_crt_cb; /* use context-specific CRT verify callback */ } opt; int query_config( const char *config ); @@ -757,6 +770,7 @@ int main( int argc, char *argv[] ) opt.debug_level = DFL_DEBUG_LEVEL; opt.nbio = DFL_NBIO; opt.event = DFL_EVENT; + opt.context_crt_cb = DFL_CONTEXT_CRT_CB; opt.read_timeout = DFL_READ_TIMEOUT; opt.max_resend = DFL_MAX_RESEND; opt.request_page = DFL_REQUEST_PAGE; @@ -834,6 +848,12 @@ int main( int argc, char *argv[] ) if( opt.debug_level < 0 || opt.debug_level > 65535 ) goto usage; } + else if( strcmp( p, "context_crt_cb" ) == 0 ) + { + opt.context_crt_cb = atoi( q ); + if( opt.context_crt_cb != 0 && opt.context_crt_cb != 1 ) + goto usage; + } else if( strcmp( p, "nbio" ) == 0 ) { opt.nbio = atoi( q ); @@ -1590,7 +1610,9 @@ int main( int argc, char *argv[] ) mbedtls_ssl_conf_sig_hashes( &conf, ssl_sig_hashes_for_test ); } - mbedtls_ssl_conf_verify( &conf, my_verify, NULL ); + if( opt.context_crt_cb == 0 ) + mbedtls_ssl_conf_verify( &conf, my_verify, NULL ); + memset( peer_crt_info, 0, sizeof( peer_crt_info ) ); #endif /* MBEDTLS_X509_CRT_PARSE_C */ @@ -1799,6 +1821,11 @@ int main( int argc, char *argv[] ) } #endif +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if( opt.context_crt_cb == 1 ) + mbedtls_ssl_set_verify( &ssl, my_verify, NULL ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + if( opt.nbio == 2 ) mbedtls_ssl_set_bio( &ssl, &server_fd, my_send, my_recv, NULL ); else diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index ac717ab43..a6d41b11c 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -1031,6 +1031,27 @@ run_test "Unique IV in GCM" \ -u "IV used" \ -U "IV used" +# Tests for certificate verification callback +run_test "Configuration-specific CRT verification callback" \ + "$P_SRV debug_level=3" \ + "$P_CLI context_crt_cb=0 debug_level=3" \ + 0 \ + -S "error" \ + -c "Verify requested for " \ + -c "Use configuration-specific verification callback" \ + -C "Use context-specific verification callback" \ + -C "error" + +run_test "Context-specific CRT verification callback" \ + "$P_SRV debug_level=3" \ + "$P_CLI context_crt_cb=1 debug_level=3" \ + 0 \ + -S "error" \ + -c "Verify requested for " \ + -c "Use context-specific verification callback" \ + -C "Use configuration-specific verification callback" \ + -C "error" + # Tests for rc4 option requires_config_enabled MBEDTLS_REMOVE_ARC4_CIPHERSUITES