]> git.kaiwu.me - haproxy.git/commitdiff
MEDIUM: ssl: do not fall back to Subject CN when a SAN dNSName is present
authorWilliam Lallemand <wlallemand@irq6.net>
Tue, 1 Sep 2026 08:24:25 +0000 (10:24 +0200)
committerWilliam Lallemand <wlallemand@haproxy.com>
Tue, 1 Sep 2026 11:47:07 +0000 (13:47 +0200)
Historically, ssl_sock_srv_verifycbk() checked the certificate's
subjectAltName (SAN) extension first, but fell back to checking the
Subject Common Name (CN) whenever no SAN matched the expected hostname
(from SNI or "verifyhost").

However, per RFC 6125 section 6.4.4:
https://datatracker.ietf.org/doc/html/rfc6125#section-6.4.4

  "As noted, a client MUST NOT seek a match for a reference identifier
   of CN-ID if the presented identifiers include a DNS-ID, SRV-ID,
   URI-ID, or any application-specific identifier types supported by the
   client."

This patch changes the behavior by tracking whether any dNSName entry was
encountered in the SAN extension and skipping the Subject CN check entirely
if one was present, even if none of the SAN entries matched. Fallback to CN
is only preserved for legacy certificates lacking a dNSName SAN.

This issue was reported in GitHub issue #3486.

src/ssl_sock.c

index 92cc4d1a6ac2b9b5fa5c40dfefc3ead76962443e..0bc0acf43e030150f37443e402352e54810f2997 100644 (file)
@@ -5279,6 +5279,7 @@ static int ssl_sock_srv_verifycbk(int ok, X509_STORE_CTX *ctx)
        __X509_NAME_CONST__ X509_NAME *cert_subject;
        char *str;
        int len;
+       int dnsname_present = 0;
 
        if (ok == 0)
                return ok;
@@ -5327,6 +5328,7 @@ static int ssl_sock_srv_verifycbk(int ok, X509_STORE_CTX *ctx)
                for (i = 0; !ok && i < sk_GENERAL_NAME_num(alt_names); i++) {
                        GENERAL_NAME *name = sk_GENERAL_NAME_value(alt_names, i);
                        if (name->type == GEN_DNS) {
+                               dnsname_present = 1;
 #if HA_OPENSSL_VERSION_NUMBER < 0x00907000L
                                if ((len = ASN1_STRING_to_UTF8((unsigned char **)&str, name->d.ia5)) >= 0) {
 #else
@@ -5348,7 +5350,7 @@ static int ssl_sock_srv_verifycbk(int ok, X509_STORE_CTX *ctx)
 
        cert_subject = X509_get_subject_name(cert);
        i = -1;
-       while (!ok && (i = X509_NAME_get_index_by_NID(cert_subject, NID_commonName, i)) != -1) {
+       while (!dnsname_present && !ok && (i = X509_NAME_get_index_by_NID(cert_subject, NID_commonName, i)) != -1) {
                __X509_NAME_CONST__ X509_NAME_ENTRY *entry = X509_NAME_get_entry(cert_subject, i);
                __X509_NAME_CONST__ ASN1_STRING *value;
                value = X509_NAME_ENTRY_get_data(entry);