From: William Lallemand Date: Tue, 1 Sep 2026 08:24:25 +0000 (+0200) Subject: MEDIUM: ssl: do not fall back to Subject CN when a SAN dNSName is present X-Git-Tag: v3.5-dev6~32 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=75129aaacb7a7b172f4e5334db71d6c1c50a3dbf;p=haproxy.git MEDIUM: ssl: do not fall back to Subject CN when a SAN dNSName is present 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. --- diff --git a/src/ssl_sock.c b/src/ssl_sock.c index 92cc4d1a6..0bc0acf43 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -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);