Commit e7f3a42c23 for openssl.org
commit e7f3a42c237558214d0ca47b80e0465acd2fe9a7
Author: Bob Beck <beck@openssl.org>
Date: Thu Aug 20 09:46:32 2026 -0600
Apply DNS name constraints to the subject CN only when it may match
Now that the subject DN is not consulted for host checks by default,
call NAME_CONSTRAINTS_check_CN() on the leaf only under
X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT - matching the verify logic
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
Reviewed-by: Andrew Dinh <andrewd@openssl.org>
MergeDate: Wed Aug 26 15:21:53 2026
(Merged from https://github.com/openssl/openssl/pull/31982)
diff --git a/CHANGES.md b/CHANGES.md
index 6a1523e593..bb66efbfa4 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -281,10 +281,14 @@ OpenSSL Releases
* X509 certificate verification no longer consults the subject
distinguished name by default. Previously, when a certificate
- contained no subject alternative name of the type being checked, the
- subject commonName (for host name checks) or emailAddress (for email
- checks) was matched instead. This fallback now happens only when the
- `X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT` flag is set.
+ contained no subject alternative name of the type being checked,
+ the subject commonName (for host name checks) or emailAddress (for
+ email checks) was matched instead. The subject dn is now checked
+ only when the `X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT` flag is set.
+ Correspondingly, during chain verification DNS name constraints are
+ applied to the subject commonName of the leaf certificate only when
+ that flag is set, rather than whenever the leaf had no DNS subject
+ alternative name.
*Bob Beck*
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index 977d6165ca..1163698c73 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -778,27 +778,6 @@ static int check_extensions(X509_STORE_CTX *ctx)
return 1;
}
-static int has_san_id(const X509 *x, int gtype)
-{
- int i;
- int ret = 0;
- GENERAL_NAMES *gs = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
-
- if (gs == NULL)
- return 0;
-
- for (i = 0; i < sk_GENERAL_NAME_num(gs); i++) {
- GENERAL_NAME *g = sk_GENERAL_NAME_value(gs, i);
-
- if (g->type == gtype) {
- ret = 1;
- break;
- }
- }
- GENERAL_NAMES_free(gs);
- return ret;
-}
-
/*-
* Returns -1 on internal error.
* Sadly, returns 0 also on internal error in ctx->verify_cb().
@@ -895,20 +874,22 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
if (nc) {
int rv = NAME_CONSTRAINTS_check(x, nc);
- int ret = 1;
- /* If EE certificate check commonName too */
+ /*
+ * Apply DNS name constraints to the EE subject commonName
+ * only when the commonName may be used for host name checks,
+ * mirroring do_x509_check(): only when the caller opted in
+ * with X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT, and never when
+ * X509_CHECK_FLAG_NEVER_CHECK_SUBJECT is set.
+ */
if (rv == X509_V_OK && i == 0
&& (ctx->param->hostflags
& X509_CHECK_FLAG_NEVER_CHECK_SUBJECT)
== 0
- && ((ctx->param->hostflags
- & X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT)
- != 0
- || (ret = has_san_id(x, GEN_DNS)) == 0))
+ && (ctx->param->hostflags
+ & X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT)
+ != 0)
rv = NAME_CONSTRAINTS_check_CN(x, nc);
- if (ret < 0)
- return ret;
switch (rv) {
case X509_V_OK:
diff --git a/doc/man3/X509_VERIFY_PARAM_set_hostflags.pod b/doc/man3/X509_VERIFY_PARAM_set_hostflags.pod
index bfe6d155f4..6963adcb93 100644
--- a/doc/man3/X509_VERIFY_PARAM_set_hostflags.pod
+++ b/doc/man3/X509_VERIFY_PARAM_set_hostflags.pod
@@ -50,7 +50,10 @@ The B<X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT> flag causes the function to
also match against the subject DN (the B<commonName> attribute for DNS
names, the B<emailAddress> attribute for email addresses), whether or not
the certificate contains a subject alternative name of the corresponding
-type.
+type. During certificate chain verification this flag additionally
+causes DNS name constraints to be applied to the subject B<commonName>
+of the leaf certificate, since the B<commonName> may then be used as a
+DNS identity; see L<NAME_CONSTRAINTS_check(3)>.
The B<X509_CHECK_FLAG_NEVER_CHECK_SUBJECT> flag suppresses matching against
the subject DN. As that is already the default, this flag has an effect
diff --git a/test/recipes/25-test_verify.t b/test/recipes/25-test_verify.t
index 53cc4f9795..040b36383e 100644
--- a/test/recipes/25-test_verify.t
+++ b/test/recipes/25-test_verify.t
@@ -492,8 +492,8 @@ ok(verify("goodcn1-cert", "", ["root-cert"], ["ncca1-cert"], ),
ok(verify("goodcn2-cert", "", ["root-cert"], ["ncca1-cert"], ),
"Name Constraints CNs permitted - no SAN extension");
-ok(!verify("badcn1-cert", "", ["root-cert"], ["ncca1-cert"], ),
- "Name Constraints CNs not permitted");
+ok(verify("badcn1-cert", "", ["root-cert"], ["ncca1-cert"], ),
+ "Name Constraints DNS-like CN not checked by default");
ok(!verify("badalt1-cert", "", ["root-cert"], ["ncca1-cert"], ),
"Name Constraints hostname not permitted");
@@ -510,11 +510,11 @@ ok(!verify("badalt4-cert", "", ["root-cert"], ["ncca1-cert"], ),
ok(!verify("badalt5-cert", "", ["root-cert"], ["ncca1-cert"], ),
"Name Constraints IP address not permitted");
-ok(!verify("badalt6-cert", "", ["root-cert"], ["ncca1-cert"], ),
- "Name Constraints CN hostname not permitted");
+ok(verify("badalt6-cert", "", ["root-cert"], ["ncca1-cert"], ),
+ "Name Constraints CN hostname not checked by default");
-ok(!verify("badalt7-cert", "", ["root-cert"], ["ncca1-cert"], ),
- "Name Constraints CN BMPSTRING hostname not permitted");
+ok(verify("badalt7-cert", "", ["root-cert"], ["ncca1-cert"], ),
+ "Name Constraints CN BMPSTRING hostname not checked by default");
ok(!verify("badalt8-cert", "", ["root-cert"], ["ncca1-cert", "ncca3-cert"], ),
"Name constraints nested DNS name not permitted 1");