From ae59c5232274df36b1b58dd52eb74cb153829a1a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 13 Feb 2025 13:46:58 +0100 Subject: [PATCH] Create configuration option to bypass the mbedtls_ssl_set_hostname check Update generated files. Signed-off-by: Gilles Peskine --- include/mbedtls/config.h | 40 +++++++++++++++++++ include/mbedtls/ssl.h | 3 ++ library/error.c | 2 +- library/version_features.c | 3 ++ programs/test/query_config.c | 12 ++++++ scripts/config.py | 1 + .../test_suite_config.mbedtls_boolean.data | 8 ++++ 7 files changed, 68 insertions(+), 1 deletion(-) diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 84af7f767e..9590dd3cac 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -1713,6 +1713,46 @@ */ //#define MBEDTLS_SSL_ASYNC_PRIVATE +/** \def MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME + * + * In TLS clients, when a client authenticates a server through its + * certificate, the client normally checks three things: + * - the certificate chain must be valid; + * - the chain must start from a trusted CA; + * - the certificate must cover the server name that is expected by the client. + * + * Omitting any of these checks is generally insecure, and can allow a + * malicious server to impersonate a legitimate server. + * + * The third check may be safely skipped in some unusual scenarios, + * such as networks where eavesdropping is a risk but not active attacks, + * or a private PKI where the client equally trusts all servers that are + * accredited by the root CA. + * + * You should call mbedtls_ssl_set_hostname() with the expected server name + * before starting a TLS handshake on a client (unless the client is + * set up to only use PSK-based authentication, which does not rely on the + * host name). This configuration option controls what happens if a TLS client + * is configured with the authentication mode #MBEDTLS_SSL_VERIFY_REQUIRED + * (default), certificate authentication is enabled and the client does not + * call mbedtls_ssl_set_hostname(): + * + * - If this option is unset (default), the connection attempt is aborted + * with the error #MBEDTLS_ERR_SSL_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME. + * - If this option is set, the TLS library does not check the server name + * that the certificate is valid for. This is the historical behavior + * of Mbed TLS, but may be insecure as explained above. + * + * Enable this option for strict backward compatibility if you have + * determined that it is secure in the scenario where you are using + * Mbed TLS. + * + * \deprecated This option exists only for backward compatibility and will + * be removed in the next major version of Mbed TLS. + * + */ +//#define MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME + /** * \def MBEDTLS_SSL_CONTEXT_SERIALIZATION * diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 4b3a67c48d..541b879331 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -213,6 +213,9 @@ * #MBEDTLS_SSL_VERIFY_REQUIRED (default). * - Certificate authentication is enabled. * - The client does not call mbedtls_ssl_set_hostname(). + * - The configuration option + * #MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME + * is not enabled. */ #define MBEDTLS_ERR_SSL_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME -0x5D80 diff --git a/library/error.c b/library/error.c index dc7590461c..a0667e177d 100644 --- a/library/error.c +++ b/library/error.c @@ -509,7 +509,7 @@ const char *mbedtls_high_level_strerr(int error_code) case -(MBEDTLS_ERR_SSL_CACHE_ENTRY_NOT_FOUND): return( "SSL - Cache entry not found" ); case -(MBEDTLS_ERR_SSL_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME): - return( "SSL - Attempt to verify a certificate without an expected hostname. This is usually insecure. In TLS clients, when a client authenticates a server through its certificate, the client normally checks three things: - the certificate chain must be valid; - the chain must start from a trusted CA; - the certificate must cover the server name that is expected by the client. Omitting any of these checks is generally insecure, and can allow a malicious server to impersonate a legitimate server. The third check may be safely skipped in some unusual scenarios, such as networks where eavesdropping is a risk but not active attacks, or a private PKI where the client equally trusts all servers that are accredited by the root CA. You should call mbedtls_ssl_set_hostname() with the expected server name before starting a TLS handshake on a client (unless the client is set up to only use PSK-based authentication, which does not rely on the host name). If you have determined that server name verification is not required for security in your scenario, call mbedtls_ssl_set_hostname() with \\p NULL as the server name. This error is raised if all of the following conditions are met: - A TLS client is configured with the authentication mode #MBEDTLS_SSL_VERIFY_REQUIRED (default). - Certificate authentication is enabled. - The client does not call mbedtls_ssl_set_hostname()" ); + return( "SSL - Attempt to verify a certificate without an expected hostname. This is usually insecure. In TLS clients, when a client authenticates a server through its certificate, the client normally checks three things: - the certificate chain must be valid; - the chain must start from a trusted CA; - the certificate must cover the server name that is expected by the client. Omitting any of these checks is generally insecure, and can allow a malicious server to impersonate a legitimate server. The third check may be safely skipped in some unusual scenarios, such as networks where eavesdropping is a risk but not active attacks, or a private PKI where the client equally trusts all servers that are accredited by the root CA. You should call mbedtls_ssl_set_hostname() with the expected server name before starting a TLS handshake on a client (unless the client is set up to only use PSK-based authentication, which does not rely on the host name). If you have determined that server name verification is not required for security in your scenario, call mbedtls_ssl_set_hostname() with \\p NULL as the server name. This error is raised if all of the following conditions are met: - A TLS client is configured with the authentication mode #MBEDTLS_SSL_VERIFY_REQUIRED (default). - Certificate authentication is enabled. - The client does not call mbedtls_ssl_set_hostname(). - The configuration option #MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME is not enabled" ); #endif /* MBEDTLS_SSL_TLS_C */ #if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) diff --git a/library/version_features.c b/library/version_features.c index 6f663b12a7..f5734c4577 100644 --- a/library/version_features.c +++ b/library/version_features.c @@ -486,6 +486,9 @@ static const char * const features[] = { #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) "MBEDTLS_SSL_ASYNC_PRIVATE", #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ +#if defined(MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME) + "MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME", +#endif /* MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME */ #if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION) "MBEDTLS_SSL_CONTEXT_SERIALIZATION", #endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */ diff --git a/programs/test/query_config.c b/programs/test/query_config.c index 5d9886bcd9..d09b7f69d4 100644 --- a/programs/test/query_config.c +++ b/programs/test/query_config.c @@ -1376,6 +1376,14 @@ int query_config(const char *config) } #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ +#if defined(MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME) + if( strcmp( "MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME", config ) == 0 ) + { + MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME ); + return( 0 ); + } +#endif /* MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME */ + #if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION) if( strcmp( "MBEDTLS_SSL_CONTEXT_SERIALIZATION", config ) == 0 ) { @@ -3506,6 +3514,10 @@ void list_config(void) OUTPUT_MACRO_NAME_VALUE(MBEDTLS_SSL_ASYNC_PRIVATE); #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ +#if defined(MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME) + OUTPUT_MACRO_NAME_VALUE(MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME); +#endif /* MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME */ + #if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION) OUTPUT_MACRO_NAME_VALUE(MBEDTLS_SSL_CONTEXT_SERIALIZATION); #endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */ diff --git a/scripts/config.py b/scripts/config.py index 766b5af9c1..ef72db324e 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -326,6 +326,7 @@ def crypto_adapter(adapter): DEPRECATED = frozenset([ 'MBEDTLS_SSL_PROTO_SSL3', + 'MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME', 'MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO', ]) diff --git a/tests/suites/test_suite_config.mbedtls_boolean.data b/tests/suites/test_suite_config.mbedtls_boolean.data index 1a1d13f370..718bd280bd 100644 --- a/tests/suites/test_suite_config.mbedtls_boolean.data +++ b/tests/suites/test_suite_config.mbedtls_boolean.data @@ -1264,6 +1264,14 @@ Config: !MBEDTLS_SSL_CBC_RECORD_SPLITTING depends_on:!MBEDTLS_SSL_CBC_RECORD_SPLITTING:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C pass: +Config: MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME +depends_on:MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C +pass: + +Config: !MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME +depends_on:!MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C +pass: + Config: MBEDTLS_SSL_CLI_C depends_on:MBEDTLS_SSL_CLI_C pass: