From 488b91929dc20d186913eb896202d634c769dbc4 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 13 Feb 2025 14:39:02 +0100 Subject: [PATCH] Require calling mbedtls_ssl_set_hostname() for security In a TLS client, when using certificate authentication, the client should check that the certificate is valid for the server name that the client expects. Otherwise, in most scenarios, a malicious server can impersonate another server. Normally, the application code should call mbedtls_ssl_set_hostname(). However, it's easy to forget. So raise an error if mandatory certificate authentication is in effect and mbedtls_ssl_set_hostname() has not been called. Raise the new error code MBEDTLS_ERR_SSL_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME, for easy identification. But don't raise the error if the backward compatibility option MBEDTLS_SSL_CLI_ALLOW_WEAK_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME is enabled. Signed-off-by: Gilles Peskine --- library/ssl_tls.c | 4 ++++ tests/ssl-opt.sh | 17 ++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 998cac2ce4..6c401b59bd 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -8872,6 +8872,10 @@ static int get_hostname_for_verification(mbedtls_ssl_context *ssl, { if (!mbedtls_ssl_has_set_hostname_been_called(ssl)) { MBEDTLS_SSL_DEBUG_MSG(1, ("Certificate verification without having set hostname")); + if (mbedtls_ssl_conf_get_endpoint(ssl->conf) == MBEDTLS_SSL_IS_CLIENT && + ssl->conf->authmode == MBEDTLS_SSL_VERIFY_REQUIRED) { + return MBEDTLS_ERR_SSL_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME; + } } *hostname = ssl->hostname; diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index ecff16ec8d..8d417afb1a 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -6049,12 +6049,13 @@ run_test "Authentication: hostname null, client none" \ run_test "Authentication: hostname unset, client required" \ "$P_SRV" \ "$P_CLI auth_mode=required set_hostname=no debug_level=2" \ - 0 \ + 1 \ -C "does not match with the expected CN" \ -c "Certificate verification without having set hostname" \ - -c "Certificate verification without CN verification" \ + -C "Certificate verification without CN verification" \ + -c "get_hostname_for_verification() returned -" \ -C "x509_verify_cert() returned -" \ - -C "! mbedtls_ssl_handshake returned" \ + -c "! mbedtls_ssl_handshake returned" \ -C "X509 - Certificate verification failed" run_test "Authentication: hostname unset, client optional" \ @@ -6080,10 +6081,11 @@ run_test "Authentication: hostname unset, client none" \ run_test "Authentication: hostname unset, client default, server picks cert, 1.2" \ "$P_SRV force_version=tls12 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ "$P_CLI psk=73776f726466697368 psk_identity=foo set_hostname=no debug_level=2" \ - 0 \ + 1 \ -C "does not match with the expected CN" \ -c "Certificate verification without having set hostname" \ - -c "Certificate verification without CN verification" \ + -C "Certificate verification without CN verification" \ + -c "get_hostname_for_verification() returned -" \ -C "x509_verify_cert() returned -" \ -C "X509 - Certificate verification failed" @@ -6091,10 +6093,11 @@ requires_config_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED run_test "Authentication: hostname unset, client default, server picks cert, 1.3" \ "$P_SRV force_version=tls13 tls13_kex_modes=ephemeral" \ "$P_CLI psk=73776f726466697368 psk_identity=foo set_hostname=no debug_level=2" \ - 0 \ + 1 \ -C "does not match with the expected CN" \ -c "Certificate verification without having set hostname" \ - -c "Certificate verification without CN verification" \ + -C "Certificate verification without CN verification" \ + -c "get_hostname_for_verification() returned -" \ -C "x509_verify_cert() returned -" \ -C "X509 - Certificate verification failed"