aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2021-05-08 12:15:41 -0400
committerJack Lloyd <[email protected]>2021-05-08 12:15:41 -0400
commitef372a35d7dbbfa574650b9a275e1d9e61cbfdc9 (patch)
tree6dcb4b8ff1472385527cbd0c6a61f36c50293911
parentbb9ef685d13fd0e979acc0c3943ff7eee4a5df40 (diff)
Name constraint fixes
Do not require name constraint extension to be critical. It is certainly a bad idea to issue non-critical name constraints, but it seems some CAs do use them in practice, and also most other implementations seem to accept such non-critical extensions. Fix name constraint DNS comparisons: previously these were case sensitive, which is wrong for DNS. GH #2735 and #2736
-rw-r--r--src/lib/utils/parsing.cpp4
-rw-r--r--src/lib/utils/parsing.h2
-rw-r--r--src/lib/x509/name_constraint.cpp8
-rw-r--r--src/lib/x509/x509_ext.cpp4
-rw-r--r--src/tests/data/x509/bsi/expected.txt2
-rw-r--r--src/tests/data/x509/misc/name_constraint_ci/int.pem101
-rw-r--r--src/tests/data/x509/misc/name_constraint_ci/leaf.pem45
-rw-r--r--src/tests/data/x509/misc/name_constraint_ci/root.pem33
-rw-r--r--src/tests/test_x509_path.cpp46
9 files changed, 236 insertions, 9 deletions
diff --git a/src/lib/utils/parsing.cpp b/src/lib/utils/parsing.cpp
index d44e59fc6..6b6fff967 100644
--- a/src/lib/utils/parsing.cpp
+++ b/src/lib/utils/parsing.cpp
@@ -195,8 +195,6 @@ std::string ipv4_to_string(uint32_t ip)
return str;
}
-namespace {
-
std::string tolower_string(const std::string& in)
{
std::string s = in;
@@ -209,8 +207,6 @@ std::string tolower_string(const std::string& in)
return s;
}
-}
-
bool host_wildcard_match(const std::string& issued_, const std::string& host_)
{
const std::string issued = tolower_string(issued_);
diff --git a/src/lib/utils/parsing.h b/src/lib/utils/parsing.h
index 49eacba81..699b7449b 100644
--- a/src/lib/utils/parsing.h
+++ b/src/lib/utils/parsing.h
@@ -92,6 +92,8 @@ std::map<std::string, std::string> read_kv(const std::string& kv);
std::string clean_ws(const std::string& s);
+std::string tolower_string(const std::string& s);
+
/**
* Check if the given hostname is a match for the specified wildcard
*/
diff --git a/src/lib/x509/name_constraint.cpp b/src/lib/x509/name_constraint.cpp
index 2b102ecac..cd7ece6d1 100644
--- a/src/lib/x509/name_constraint.cpp
+++ b/src/lib/x509/name_constraint.cpp
@@ -166,17 +166,19 @@ bool GeneralName::matches_dns(const std::string& nam) const
{
if(nam.size() == name().size())
{
- return nam == name();
+ return tolower_string(nam) == tolower_string(name());
}
else if(name().size() > nam.size())
{
+ // The constraint is longer than the issued name: not possibly a match
return false;
}
else // name.size() < nam.size()
{
- std::string constr = name().front() == '.' ? name() : "." + name();
// constr is suffix of nam
- return constr == nam.substr(nam.size() - constr.size(), constr.size());
+ const std::string constr = name().front() == '.' ? name() : "." + name();
+ const std::string substr = nam.substr(nam.size() - constr.size(), constr.size());
+ return tolower_string(constr) == tolower_string(substr);
}
}
diff --git a/src/lib/x509/x509_ext.cpp b/src/lib/x509/x509_ext.cpp
index 82633af5e..123f48d99 100644
--- a/src/lib/x509/x509_ext.cpp
+++ b/src/lib/x509/x509_ext.cpp
@@ -555,8 +555,10 @@ void Name_Constraints::validate(const X509_Certificate& subject, const X509_Cert
{
if(!m_name_constraints.permitted().empty() || !m_name_constraints.excluded().empty())
{
- if(!subject.is_CA_cert() || !subject.is_critical("X509v3.NameConstraints"))
+ if(!subject.is_CA_cert())
+ {
cert_status.at(pos).insert(Certificate_Status_Code::NAME_CONSTRAINT_ERROR);
+ }
const bool issuer_name_constraint_critical =
issuer.is_critical("X509v3.NameConstraints");
diff --git a/src/tests/data/x509/bsi/expected.txt b/src/tests/data/x509/bsi/expected.txt
index 9099ab58a..a3f957a81 100644
--- a/src/tests/data/x509/bsi/expected.txt
+++ b/src/tests/data/x509/bsi/expected.txt
@@ -48,7 +48,7 @@ cert_path_ext_12$Certificate contains duplicate policy
cert_path_ext_13$Unknown critical extension encountered
cert_path_ext_14$Unknown critical extension encountered
cert_path_ext_15$Certificate does not pass name constraint
-cert_path_ext_16$Certificate does not pass name constraint
+cert_path_ext_16$Verified
#cert_path_ext_17$
cert_path_ext_18$Unknown critical extension encountered
cert_path_ext_19$Unknown critical extension encountered
diff --git a/src/tests/data/x509/misc/name_constraint_ci/int.pem b/src/tests/data/x509/misc/name_constraint_ci/int.pem
new file mode 100644
index 000000000..e72186198
--- /dev/null
+++ b/src/tests/data/x509/misc/name_constraint_ci/int.pem
@@ -0,0 +1,101 @@
+-----BEGIN CERTIFICATE-----
+MIISZjCCEE6gAwIBAgIQL+DBBkUO02gMUQKcjFQSXTANBgkqhkiG9w0BAQsFADBr
+MQswCQYDVQQGEwJJVDEOMAwGA1UEBwwFTWlsYW4xIzAhBgNVBAoMGkFjdGFsaXMg
+Uy5wLkEuLzAzMzU4NTIwOTY3MScwJQYDVQQDDB5BY3RhbGlzIEF1dGhlbnRpY2F0
+aW9uIFJvb3QgQ0EwHhcNMTkwNjEzMDc0ODQ3WhcNMjkwNjEyMDc0ODQ3WjCBkDEL
+MAkGA1UEBhMCSVQxDTALBgNVBAcMBFJvbWExJjAkBgNVBAoMHUFnZW56aWEgcGVy
+IGwnSXRhbGlhIERpZ2l0YWxlMTcwNQYDVQQLDC5BcmVhIFNvbHV6aW9uaSBwZXIg
+bGEgUHViYmxpY2EgQW1taW5pc3RyYXppb25lMREwDwYDVQQDDAhBZ0lEIENBMTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANU2n0Xri8wepI2AarzJVG5E
+9/kQpXhuLbX3sQgN0RjTfhvPB9fwXRrfvar5upsWGvwPuUB2Z3A2jseDa1hbvHee
+fkkfjKT/UkUidqZEKprb176t/zJoNVI7lgRCjjz90ByVjUHIFuwQUHOVMbfHyeBW
+pTQrzYsxnofRKRep3ZESLlhKaln4/8/rSICxnD8KpeTQ41Qn8VYpj0RV0NU0+k9V
+gR9C/K4zX1z4AonMemcRP/8B1XFyjk2LaqUXHt8LBw6Wb+OYO+n9rXKT8pDyr9/z
+d+kSJxxI2gvooye7Xt3xJGqODkpZru3Q3Gb5c8T2UZ2mnKZwOciN4p/5tcOaC1cC
+AwEAAaOCDd4wgg3aMIIL2gYDVR0eBIIL0TCCC82ggguXMA2BC2FnaWQuZ292Lml0
+MBmBF2NlcnQuaW5mb3JtYXRpY2EuYWNpLml0MBGBD2NlcnQuaW50ZXJuby5pdDAM
+gQplbWFyY2hlLml0MBCBDmZhc3R3ZWItcGVjLml0MBWBE2dlc3RvcmVwZWMudW5p
+bmEuaXQwDIEKa21haWxlci5pdDAOgQxsZWdhbG1haWwuaXQwEIEOcGNlcnQuc29n
+ZWkuaXQwEIEOcGVjLmFjdGFsaXMuaXQwEIEOcGVjLmFuY2l0ZWwuaXQwDoEMcGVj
+LmFydWJhLml0MBaBFHBlYy5iYXNpbGljYXRhbmV0Lml0MA+BDXBlYy1lbWFpbC5j
+b20wEoEQcGVjLnBvc3RlY2VydC5pdDAWgRRwZWMucG9zdGVpdGFsaWFuZS5pdDAV
+gRNwZWMucnVwYXIucHVnbGlhLml0MBaBFHBvc3RhY2VydC5jZWRhY3JpLml0MB+B
+HXBvc3RhY2VydGlmaWNhdGEubm90YXJpYXRvLml0MBKBEHBvc3RhY2VydC5pdC5u
+ZXQwDoEMcG9zdGVjZXJ0Lml0MBWBE3NpY3VyZXp6YXBvc3RhbGUuaXQwEIEOdGVs
+ZWNvbXBvc3QuaXQwF4EVdHJ1c3RlZG1haWwuaW50ZXNhLml0MAyBCnR3dGNlcnQu
+aXQwEYEPenVjY2hldHRpcGVjLml0MBCBDmNlcnQuaW50ZXNhLml0MBaBFGNlcnRt
+YWlsLmtwbnF3ZXN0Lml0MBWBE2NlcnRtYWlsLmlyaWRlb3MuaXQwGoEYcHVwZWMu
+aW5mb3JtYXRpY2EuYWNpLml0MBmBF3Byby5zaWN1cmV6emFwb3N0YWxlLml0MBCB
+DnBlYy5iaWxsNG1lLml0MBGBD3BlYy5ub3RhcnRlbC5pdDATghFhZ2VuZGFkaWdp
+dGFsZS5pdDASghBhZ2lkLWNhMS10ZXN0Lml0MAmCB2FnaWQuaXQwCYIHYWlwYS5p
+dDANggtjZXJ0LXNwYy5pdDAOggxjcmNpdGFsaWEuaXQwHIIaZGlmZW5zb3JlY2l2
+aWNvZGlnaXRhbGUuaXQwEoIQZGlnaXRhbGFnZW5kYS5pdDAMggpkaWdpdHBhLml0
+MAiCBmdvdi5pdDALgglpdGFsaWEuaXQwCoIIY25pcGEuaXQwDIIKY2VydC1wYS5p
+dDANggtpbmRpY2VwYS5pdDBQpE4wTDELMAkGA1UEBhMCSVQxDTALBgNVBAgMBFJv
+bWExDTALBgNVBAcMBFJvbWExHzAdBgNVBAoMFkFDSSBJbmZvcm1hdGljYSBTLnAu
+QS4wWaRXMFUxCzAJBgNVBAYTAklUMRAwDgYDVQQIDAdCZXJnYW1vMRkwFwYDVQQH
+DBBQb250ZSBTYW4gUGlldHJvMRkwFwYDVQQKDBBBcnViYSBQRUMgUy5wLkEuMFek
+VTBTMQswCQYDVQQGEwJJVDEQMA4GA1UECAwHQmVyZ2FtbzEZMBcGA1UEBwwQUG9u
+dGUgU2FuIFBpZXRybzEXMBUGA1UECgwOQWN0YWxpcyBTLnAuQS4wV6RVMFMxCzAJ
+BgNVBAYTAklUMQ0wCwYDVQQIDARSb21hMQ0wCwYDVQQHDARSb21hMSYwJAYDVQQK
+DB1BZ2VuemlhIHBlciBsJ0l0YWxpYSBEaWdpdGFsZTBIpEYwRDELMAkGA1UEBhMC
+SVQxDTALBgNVBAgMBFJvbWExDTALBgNVBAcMBFJvbWExFzAVBgNVBAoMDkFuY2l0
+ZWwgUy5wLkEuME+kTTBLMQswCQYDVQQGEwJJVDEOMAwGA1UECAwFUGFybWExEzAR
+BgNVBAcMCkNvbGxlY2NoaW8xFzAVBgNVBAoMDkNlZGFjcmkgUy5wLkEuMFukWTBX
+MQswCQYDVQQGEwJJVDENMAsGA1UECAwEUm9tYTENMAsGA1UEBwwEUm9tYTEqMCgG
+A1UECgwhQ29uc2lnbGlvIE5hemlvbmFsZSBkZWwgTm90YXJpYXRvMEykSjBIMQsw
+CQYDVQQGEwJJVDEPMA0GA1UECAwGTWlsYW5vMQ8wDQYDVQQHDAZNaWxhbm8xFzAV
+BgNVBAoMDkZhc3R3ZWIgUy5wLkEuMEqkSDBGMQswCQYDVQQGEwJJVDEPMA0GA1UE
+CAwGTWlsYW5vMQ8wDQYDVQQHDAZBc3NhZ28xFTATBgNVBAoMDElUbmV0IFMuci5s
+LjBPpE0wSzELMAkGA1UEBhMCSVQxDzANBgNVBAgMBlRvcmlubzEPMA0GA1UEBwwG
+VG9yaW5vMRowGAYDVQQKDBFJbi5UZS5TLkEuIFMucC5BLjBJpEcwRTELMAkGA1UE
+BhMCSVQxDTALBgNVBAgMBFJvbWExDTALBgNVBAcMBFJvbWExGDAWBgNVBAoMD0lu
+Zm9DZXJ0IFMucC5BLjBSpFAwTjELMAkGA1UEBhMCSVQxDTALBgNVBAgMBEJhcmkx
+EjAQBgNVBAcMCVZhbGVuemFubzEcMBoGA1UECgwTSW5ub3ZhUHVnbGlhIFMucC5B
+LjBRpE8wTTELMAkGA1UEBhMCSVQxDzANBgNVBAgMBkFuY29uYTETMBEGA1UEBwwK
+U2VuaWdhbGxpYTEYMBYGA1UECgwPTmFtaXJpYWwgUy5wLkEuME+kTTBLMQswCQYD
+VQQGEwJJVDENMAsGA1UECAwEUm9tYTENMAsGA1UEBwwEUm9tYTEeMBwGA1UECgwV
+UG9zdGUgSXRhbGlhbmUgUy5wLkEuMFKkUDBOMQswCQYDVQQGEwJJVDEQMA4GA1UE
+CAwHUG90ZW56YTEQMA4GA1UEBwwHUG90ZW56YTEbMBkGA1UECgwSUmVnaW9uZSBC
+YXNpbGljYXRhMEykSjBIMQswCQYDVQQGEwJJVDEPMA0GA1UECAwGQW5jb25hMQ8w
+DQYDVQQHDAZBbmNvbmExFzAVBgNVBAoMDlJlZ2lvbmUgTWFyY2hlME+kTTBLMQsw
+CQYDVQQGEwJJVDEQMA4GA1UECAwHRmlyZW56ZTEQMA4GA1UEBwwHRmlyZW56ZTEY
+MBYGA1UECgwPUmVnaXN0ZXIgUy5wLkEuMEakRDBCMQswCQYDVQQGEwJJVDENMAsG
+A1UECAwEUm9tYTENMAsGA1UEBwwEUm9tYTEVMBMGA1UECgwMU29nZWkgUy5wLkEu
+MEikRjBEMQswCQYDVQQGEwJJVDEPMA0GA1UECAwGTWlsYW5vMQ8wDQYDVQQHDAZN
+aWxhbm8xEzARBgNVBAoMClRXVCBTLnAuQS4wZaRjMGExCzAJBgNVBAYTAklUMQ0w
+CwYDVQQIDARSb21hMRAwDgYDVQQHDAdQb21lemlhMTEwLwYDVQQKDChUZWxlY29t
+IEl0YWxpYSBUcnVzdCBUZWNobm9sb2dpZXMgUy5yLmwuMGqkaDBmMQswCQYDVQQG
+EwJJVDEPMA0GA1UECAwGTmFwb2xpMQ8wDQYDVQQHDAZOYXBvbGkxNTAzBgNVBAoM
+LFVOSVZFUlNJVEEgREVHTEkgU1RVREkgREkgTkFQT0xJIEZFREVSSUNPIElJMEqk
+SDBGMQswCQYDVQQGEwJJVDENMAsGA1UECAwETG9kaTENMAsGA1UEBwwETG9kaTEZ
+MBcGA1UECgwQWnVjY2hldHRpIFMucC5BLjBUpFIwUDELMAkGA1UEBhMCSVQxDzAN
+BgNVBAgMBk1pbGFubzEPMA0GA1UEBwwGTWlsYW5vMR8wHQYDVQQKDBZLUE5RV0VT
+VCBJVEFMSUEgUy5yLmwuMEykSjBIMQswCQYDVQQGEwJJVDEPMA0GA1UECAwGTWls
+YW5vMQ8wDQYDVQQHDAZNaWxhbm8xFzAVBgNVBAoMDklSSURFT1MgUy5wLkEuMEmk
+RzBFMQswCQYDVQQGEwJJVDENMAsGA1UECAwEUm9tYTENMAsGA1UEBwwEUm9tYTEY
+MBYGA1UECgwPTm90YXJ0ZWwgUy5wLkEuoTAwCocIAAAAAAAAAAAwIocgAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwQQYIKwYBBQUHAQEENTAzMDEGCCsG
+AQUFBzABhiVodHRwOi8vb2NzcDA3LmFjdGFsaXMuaXQvVkEvQVVUSC1ST09UMB0G
+A1UdDgQWBBSl/YUFDsPx1mVKIGzi201gkyuKoDASBgNVHRMBAf8ECDAGAQH/AgEA
+MB8GA1UdIwQYMBaAFFLYiDrIn3hm7YnzezhwlMkCAjbQME4GA1UdIARHMEUwQwYF
+K0wQAwEwOjA4BggrBgEFBQcCARYsaHR0cDovL3d3dy5hZ2lkLmdvdi5pdC9jZXJ0
+aWZpY2F0aS1maXJtYS1wZWMwgeMGA1UdHwSB2zCB2DCBlqCBk6CBkIaBjWxkYXA6
+Ly9sZGFwMDcuYWN0YWxpcy5pdC9jbiUzZEFjdGFsaXMlMjBBdXRoZW50aWNhdGlv
+biUyMFJvb3QlMjBDQSxvJTNkQWN0YWxpcyUyMFMucC5BLiUyZjAzMzU4NTIwOTY3
+LGMlM2RJVD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0O2JpbmFyeTA9oDugOYY3
+aHR0cDovL2NybDA3LmFjdGFsaXMuaXQvUmVwb3NpdG9yeS9BVVRILVJPT1QvZ2V0
+TGFzdENSTDAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG
+AQUFBwMEMA0GCSqGSIb3DQEBCwUAA4ICAQAInLD/Nl6k9fMhVS3df3nb/IpdsgeT
+EFsUA1I4o7VvhL03S+fk3QhFYOtL1dHNgJS1zlFu3EMYy7C6YDE2a8DQLvKJx3Uk
+yeyBHoMQRCHVSg+lQJQxFOuGn/28zZYNvJN1DvgOgEdEsYOipAAL5TBu8Oz7ixDd
+Wgxipd44wW0AGkhvow4amL5qp7VLxqawXlCE9PdLXzfP0j3OHqUcNCTBCXEAZrPP
+5I3QmbHwRhncviAcFNrPYqzNKul9EUrYaYR0BquS9YHVjlhJr+n/NL56tX7YqrwB
+gHHGa7XpgmVRhdlvDO5sKhIvIM1Pc13aQowkG6g6uLkG1PYBJjt8nFxwUsHSbLdW
+9QEaQctP2UC6FzvU/LH3WVI7mPRq7+bXKDQNdhT7KOElE/FLWbPl2yYk8uKe5Ok3
+YlbyjGVC+h7kehPgv5Y1iasUpZjVte2etEcSI1s7lbprKYt+UdaxiE7qvp/ilaO4
+P1ZHiZUXCbg3wjks00A1WOaxAKsmx9KF8JWKsU6arBT3kDCsoXksBb0KvYG/d0sa
+X3c9UeTthGTN8TyHaHuwTJ7Z3LljOJNsOyYbwvk57LybrFgY3WpcTHaztoL+3c9N
+/odBXgJeM1DKlLZMQ5r1HiRiwnQOaK3htK+B41EaLeu7WXZpN/t4xqA8RxYyYlWd
+vJe1SacGDfVcCw==
+-----END CERTIFICATE-----
diff --git a/src/tests/data/x509/misc/name_constraint_ci/leaf.pem b/src/tests/data/x509/misc/name_constraint_ci/leaf.pem
new file mode 100644
index 000000000..8dbba412e
--- /dev/null
+++ b/src/tests/data/x509/misc/name_constraint_ci/leaf.pem
@@ -0,0 +1,45 @@
+-----BEGIN CERTIFICATE-----
+MIIH8TCCBtmgAwIBAgIQQD1ha3ZylOCFLxKULwH9ojANBgkqhkiG9w0BAQsFADCB
+kDELMAkGA1UEBhMCSVQxDTALBgNVBAcMBFJvbWExJjAkBgNVBAoMHUFnZW56aWEg
+cGVyIGwnSXRhbGlhIERpZ2l0YWxlMTcwNQYDVQQLDC5BcmVhIFNvbHV6aW9uaSBw
+ZXIgbGEgUHViYmxpY2EgQW1taW5pc3RyYXppb25lMREwDwYDVQQDDAhBZ0lEIENB
+MTAeFw0yMDAxMjIwODE2MDFaFw0yMjAxMjEwODE2MDFaMIGSMQswCQYDVQQGEwJJ
+VDENMAsGA1UECAwEUm9tYTENMAsGA1UEBwwEUm9tYTEmMCQGA1UECgwdQWdlbnpp
+YSBwZXIgbCdJdGFsaWEgRGlnaXRhbGUxGjAYBgNVBAsMEUFNQklFTlRJIENPTExB
+VURPMSEwHwYDVQQDDBhJTkRJQ0VQQS1DT0xMQVVETy5HT1YuSVQwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1Rv8z5xQ2pMEI3m17bIaDPgpBCNCdxXL7
+LtWSDM2KjHP1NVjuPSA4ASLuPsk6AkB8m0ZJgJKFntzww0IK65cTQPXK51aQZtX9
+Vc7SYykAw5/xpfPR5H/VJfN3xwsN8uasTAiFT0wzZCRtDIpkc2vrdhn0ktndoxUp
+Zm5GT0pRw+8AmhZ+hO+C7xgDZ5CimwHRskJf3UE8HOFhHtIottA9kx1pYVv9iojo
+F+e/H3LGGuHl63p9/2gyjf3/3ZPaA9gtZpN6tnbiv0KOOEMVSvHXnmwtcg/JX3Sr
+Yg2W/93zcSH8IFQks2MuN1rbCv1/ckGXK0F496UPxOqYYA3PiddXAgMBAAGjggRB
+MIIEPTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9jYTEuYWdp
+ZC5nb3YuaXQvT0NTUDAdBgNVHQ4EFgQUqwTNv2lZ57PeXI/MXinOPUX808owHwYD
+VR0jBBgwFoAUpf2FBQ7D8dZlSiBs4ttNYJMriqAwWQYDVR0gBFIwUDAIBgZngQwB
+AgIwRAYGK0wQAwEDMDowOAYIKwYBBQUHAgEWLGh0dHA6Ly93d3cuYWdpZC5nb3Yu
+aXQvY2VydGlmaWNhdGktZmlybWEtcGVjMIHgBgNVHR8EgdgwgdUwgbCgga2ggaqG
+gadsZGFwOi8vY2ExLmFnaWQuZ292Lml0L2NuPUFnSUQlMjBDQTEsb3U9QXJlYSUy
+MFNvbHV6aW9uaSUyMHBlciUyMGxhJTIwUHViYmxpY2ElMjBBbW1pbmlzdHJhemlv
+bmUsbz1BZ2VuemlhJTIwcGVyJTIwbCUyN0l0YWxpYSUyMERpZ2l0YWxlLEM9SVQ/
+Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDAgoB6gHIYaaHR0cDovL2NhMS5hZ2lk
+Lmdvdi5pdC9DUkwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMC
+BggrBgEFBQcDATCB0gYDVR0RBIHKMIHHghtjYS5pbmRpY2VwYS1jb2xsYXVkby5n
+b3YuaXSCHHd3dy5pbmRpY2VwYS1jb2xsYXVkby5nb3YuaXSCG3d3dy5nZW9kYXRp
+LWNvbGxhdWRvLmdvdi5pdIIgZ292ZXJuYW5jZS1jb2xsYXVkby5pY3NwYy5nb3Yu
+aXSCF2dlb2RhdGktY29sbGF1ZG8uZ292Lml0ghhJTkRJQ0VQQS1DT0xMQVVETy5H
+T1YuSVSCGGluZGljZXBhLWNvbGxhdWRvLmdvdi5pdDCCAX4GCisGAQQB1nkCBAIE
+ggFuBIIBagFoAHYA7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/csAAAFv
+zFu92gAABAMARzBFAiA5SwL52cTLwjeFcNEbES5LE1wA260wvnPPeVF9zQEa/gIh
+AOS8weXMlVrkJ4rZgFmf9H7cF6OHiSANl/QDMGr4JJLGAHUAQcjKsd8iRkoQxqE6
+CUKHXk4xixsD6+tLx2jwkGKWBvYAAAFvzFu/GgAABAMARjBEAiBqxfN3vRyoxsmT
+4H2f1x+h5902T2bpYlLI2Kk7eTC6nwIgYUGSvmOtlPOuK62g6rvZoNvXLTVZ5DjX
+VlYSeGHvgs4AdwAiRUUHWVUkVpY/oS/x922G4CMmY63AS39dxoNcbuIPAgAAAW/M
+W8BMAAAEAwBIMEYCIQDqnpR2rF1G64aUHtSFSCOV/Mpo0pVwGw7UFskxeFigQwIh
+AMSJFNXBWNzJ1BAYzeJ4BsjGm+pspA3It3fitblscotrMA0GCSqGSIb3DQEBCwUA
+A4IBAQC+6qFPoMSejF6LC4iqJEFtzzLCzM8TDYEliHEtwj7fU8+rIDUSp9MgeCkl
+IB2iDXhW7rzTMfAMEc0MhuFmMgr8q7hH0GtdodSGIbJv41nZSXbDUIfLWZYO2u/v
+qbG8d0a5tU07KmZy7Q0mAlFOAA3OhXD9kHuLutMcvJf6XpFqHHXkDy88G/8hYhRr
+aMlXhP/uoyZ2dm5N/vMzo4pmOhuu5JF7Zjc97N/cHsmpixTgICjCXCehwby4nzEG
+ExJmdpxW2LD9UGduWYMVU5SARR2Atq+6UKaHmiehoUFWmm5Gkb18OfTFsQPTT2Y2
+tN5L9MD1jWDYoR1Yexg4LBV7gs/P
+-----END CERTIFICATE-----
diff --git a/src/tests/data/x509/misc/name_constraint_ci/root.pem b/src/tests/data/x509/misc/name_constraint_ci/root.pem
new file mode 100644
index 000000000..5762f37e6
--- /dev/null
+++ b/src/tests/data/x509/misc/name_constraint_ci/root.pem
@@ -0,0 +1,33 @@
+-----BEGIN CERTIFICATE-----
+MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE
+BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w
+MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
+IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC
+SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1
+ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv
+UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX
+4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9
+KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/
+gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb
+rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ
+51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F
+be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe
+KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F
+v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn
+fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7
+jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz
+ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt
+ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL
+e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70
+jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz
+WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V
+SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j
+pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX
+X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok
+fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R
+K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU
+ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU
+LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT
+LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
+-----END CERTIFICATE-----
diff --git a/src/tests/test_x509_path.cpp b/src/tests/test_x509_path.cpp
index bd113a6f4..ef6be2219 100644
--- a/src/tests/test_x509_path.cpp
+++ b/src/tests/test_x509_path.cpp
@@ -643,6 +643,52 @@ std::vector<Test::Result> Validate_Name_Constraint_SAN_Test::run()
BOTAN_REGISTER_TEST("x509", "x509_name_constraint_san", Validate_Name_Constraint_SAN_Test);
+class Validate_Name_Constraint_CaseInsensitive final : public Test
+ {
+ public:
+ std::vector<Test::Result> run() override;
+ };
+
+std::vector<Test::Result> Validate_Name_Constraint_CaseInsensitive::run()
+ {
+ if(Botan::has_filesystem_impl() == false)
+ {
+ return {Test::Result::Note("Path validation",
+ "Skipping due to missing filesystem access")};
+ }
+
+ std::vector<Test::Result> results;
+
+ const std::string root_crt = Test::data_file("/x509/misc/name_constraint_ci/root.pem");
+ const std::string int_crt = Test::data_file("/x509/misc/name_constraint_ci/int.pem");
+ const std::string ee_crt = Test::data_file("/x509/misc/name_constraint_ci/leaf.pem");
+
+ auto validation_time =
+ Botan::calendar_point(2021, 5, 8, 1, 0, 0).to_std_timepoint();
+
+ Botan::X509_Certificate root(root_crt);
+ Botan::X509_Certificate intermediate(int_crt);
+ Botan::X509_Certificate ee_cert(ee_crt);
+
+ Botan::Certificate_Store_In_Memory trusted;
+ trusted.add_certificate(root);
+
+ std::vector<Botan::X509_Certificate> chain = { ee_cert, intermediate };
+
+ Botan::Path_Validation_Restrictions restrictions;
+ Botan::Path_Validation_Result validation_result =
+ Botan::x509_path_validate(chain, restrictions, trusted, "",
+ Botan::Usage_Type::UNSPECIFIED, validation_time);
+
+ Test::Result result("DNS name constraints are case insensitive");
+ result.test_eq("Path validation succeeded",
+ validation_result.successful_validation(), true);
+
+ return {result};
+ }
+
+BOTAN_REGISTER_TEST("x509", "x509_name_constraint_ci", Validate_Name_Constraint_CaseInsensitive);
+
class BSI_Path_Validation_Tests final : public Test
{