/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This code is made available to you under your choice of the following sets * of licensing terms:
*/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ /* Copyright 2014 Mozilla Contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License.
*/ #include"pkixgtest.h"
// We allow underscores for compatibility with existing practices.
DNS_ID_MATCH("a_b", "a_b"),
DNS_ID_MATCH("*.example.com", "uses_underscore.example.com"),
DNS_ID_MATCH("*.uses_underscore.example.com", "a.uses_underscore.example.com"),
// We allow reference ID labels to start and end with hyphens for // compatibility.
DNS_ID_MATCH("*.example.com", "-.example.com"),
DNS_ID_MATCH("*.example.com", "-hyphenstart.example.com"),
DNS_ID_MATCH("*.example.com", "hyphenend-.example.com"), // Presented ID labels may not start or end with hyphens.
DNS_ID_BAD_DER("-.example.com", "-.example.com"),
DNS_ID_BAD_DER("-hyphenstart.example.com", "-hyphenstart.example.com"),
DNS_ID_BAD_DER("hyphenend-.example.com", "hyphenend-.example.com"),
// See bug 1139039 // A DNS-ID must not end in an all-numeric label. We don't consider // underscores to be numeric.
DNS_ID_MATCH("_1", "_1"),
DNS_ID_MATCH("example._1", "example._1"),
DNS_ID_MATCH("example.1_", "example.1_"),
// Wildcard not in leftmost label
DNS_ID_MATCH("d.c.b.a", "d.c.b.a"),
DNS_ID_BAD_DER("d.*.b.a", "d.c.b.a"),
DNS_ID_BAD_DER("d.c*.b.a", "d.c.b.a"),
DNS_ID_BAD_DER("d.c*.b.a", "d.cc.b.a"),
// case sensitivity
DNS_ID_MATCH("abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
DNS_ID_MATCH("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz"),
DNS_ID_MATCH("aBc", "Abc"),
// digits
DNS_ID_MATCH("a1", "a1"),
// A trailing dot indicates an absolute name. Absolute presented names are // not allowed, but absolute reference names are allowed.
DNS_ID_MATCH("example", "example"),
DNS_ID_BAD_DER("example.", "example."),
DNS_ID_MATCH("example", "example."),
DNS_ID_BAD_DER("example.", "example"),
DNS_ID_MATCH("example.com", "example.com"),
DNS_ID_BAD_DER("example.com.", "example.com."),
DNS_ID_MATCH("example.com", "example.com."),
DNS_ID_BAD_DER("example.com.", "example.com"),
DNS_ID_BAD_DER("example.com..", "example.com."),
DNS_ID_BAD_DER("example.com..", "example.com"),
DNS_ID_BAD_DER("example.com...", "example.com."),
// "*" cannot expand to nothing.
DNS_ID_BAD_DER("c*.b.a", "c.b.a"),
///////////////////////////////////////////////////////////////////////////// // These are test cases adapted from Chromium's x509_certificate_unittest.cc. // The parameter order is the opposite in Chromium's tests. Also, some tests // were modified to fit into this framework or due to intentional differences // between mozilla::pkix and Chromium.
// '*' must be the only character in the wildcard label
DNS_ID_BAD_DER("wa*.bar.foo.com", "WALLY.bar.foo.com"),
// We require "*" to be the last character in a wildcard label, but // Chromium does not.
DNS_ID_BAD_DER("*Ly.bar.foo.com", "wally.bar.foo.com"),
// Chromium does URL decoding of the reference ID, but we don't, and we also // require that the reference ID is valid, so we can't test these two. // DNS_ID_MATCH("www.foo.com", "ww%57.foo.com"), // DNS_ID_MATCH("www&.foo.com", "www%26.foo.com"),
// Our matcher requires the reference ID to be a valid DNS name, so we cannot // test this case. //DNS_ID_BAD_DER("*.*.bar.foo.com", "*..bar.foo.com"),
DNS_ID_MATCH("www.bath.org", "www.bath.org"),
// Our matcher requires the reference ID to be a valid DNS name, so we cannot // test these cases. // DNS_ID_BAD_DER("www.bath.org", ""), // DNS_ID_BAD_DER("www.bath.org", "20.30.40.50"), // DNS_ID_BAD_DER("www.bath.org", "66.77.88.99"),
// The following are adapted from the examples quoted from // http://tools.ietf.org/html/rfc6125#section-6.4.3 // (e.g., *.example.com would match foo.example.com but // not bar.foo.example.com or example.com).
DNS_ID_MATCH("*.example.com", "foo.example.com"),
DNS_ID_MISMATCH("*.example.com", "bar.foo.example.com"),
DNS_ID_MISMATCH("*.example.com", "example.com"), // (e.g., baz*.example.net and *baz.example.net and b*z.example.net would // be taken to match baz1.example.net and foobaz.example.net and // buzz.example.net, respectively. However, we don't allow any characters // other than '*' in the wildcard label.
DNS_ID_BAD_DER("baz*.example.net", "baz1.example.net"),
// Both of these are different from Chromium, but match NSS, becaues the // wildcard character "*" is not the last character of the label.
DNS_ID_BAD_DER("*baz.example.net", "foobaz.example.net"),
DNS_ID_BAD_DER("b*z.example.net", "buzz.example.net"),
// Wildcards should not be valid for public registry controlled domains, // and unknown/unrecognized domains, at least three domain components must // be present. For mozilla::pkix and NSS, there must always be at least two // labels after the wildcard label.
DNS_ID_MATCH("*.test.example", "www.test.example"),
DNS_ID_MATCH("*.example.co.uk", "test.example.co.uk"),
DNS_ID_BAD_DER("*.exmaple", "test.example"),
// The result is different than Chromium, because Chromium takes into account // the additional knowledge it has that "co.uk" is a TLD. mozilla::pkix does // not know that.
DNS_ID_MATCH("*.co.uk", "example.co.uk"),
// IDN variants of wildcards and registry controlled domains.
DNS_ID_MATCH("*.xn--poema-9qae5a.com.br", "www.xn--poema-9qae5a.com.br"),
DNS_ID_MATCH("*.example.xn--mgbaam7a8h", "test.example.xn--mgbaam7a8h"),
// RFC6126 allows this, and NSS accepts it, but Chromium disallows it. // TODO: File bug against Chromium.
DNS_ID_MATCH("*.com.br", "xn--poema-9qae5a.com.br"),
DNS_ID_BAD_DER("*.xn--mgbaam7a8h", "example.xn--mgbaam7a8h"), // Wildcards should be permissible for 'private' registry-controlled // domains. (In mozilla::pkix, we do not know if it is a private registry- // controlled domain or not.)
DNS_ID_MATCH("*.appspot.com", "www.appspot.com"),
DNS_ID_MATCH("*.s3.amazonaws.com", "foo.s3.amazonaws.com"),
// Multiple wildcards are not valid.
DNS_ID_BAD_DER("*.*.com", "foo.example.com"),
DNS_ID_BAD_DER("*.bar.*.com", "foo.bar.example.com"),
// Absolute vs relative DNS name tests. Although not explicitly specified // in RFC 6125, absolute reference names (those ending in a .) should // match either absolute or relative presented names. We don't allow // absolute presented names. // TODO: File errata against RFC 6125 about this.
DNS_ID_BAD_DER("foo.com.", "foo.com"),
DNS_ID_MATCH("foo.com", "foo.com."),
DNS_ID_BAD_DER("foo.com.", "foo.com."),
DNS_ID_BAD_DER("f.", "f"),
DNS_ID_MATCH("f", "f."),
DNS_ID_BAD_DER("f.", "f."),
DNS_ID_BAD_DER("*.bar.foo.com.", "www-3.bar.foo.com"),
DNS_ID_MATCH("*.bar.foo.com", "www-3.bar.foo.com."),
DNS_ID_BAD_DER("*.bar.foo.com.", "www-3.bar.foo.com."),
// We require the reference ID to be a valid DNS name, so we cannot test this // case. // DNS_ID_MISMATCH(".", "."),
// The result is different than Chromium because we don't know that co.uk is // a TLD.
DNS_ID_MATCH("*.co.uk", "foo.co.uk"),
DNS_ID_MATCH("*.co.uk", "foo.co.uk."),
DNS_ID_BAD_DER("*.co.uk.", "foo.co.uk"),
DNS_ID_BAD_DER("*.co.uk.", "foo.co.uk."),
DNS_ID_MISMATCH("*.example.com", "localhost"),
DNS_ID_MISMATCH("*.example.com", "localhost."), // Note that we already have the testcase DNS_ID_BAD_DER("*", "foo") above
};
// Allowed character set
I("a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z", true, true),
I("A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z", true, true),
I("0.1.2.3.4.5.6.7.8.9.a", true, true), // "a" needed to avoid numeric last label
I("a-b", true, true), // hyphen (presented ID labels cannot start or end with a hyphen)
// Wildcard specifications are not valid reference names, but are valid // presented names if there are enough labels and if '*' is the only // character in the wildcard label.
I("*.a", false, false),
I("a*", false, false),
I("a*.", false, false),
I("a*.a", false, false),
I("a*.a.", false, false),
I("*.a.b", false, true),
I("*.a.b.", false, false),
I("a*.b.c", false, false),
I("*.a.b.c", false, true),
I("a*.b.c.d", false, false),
// Multiple wildcards are not allowed.
I("a**.b.c", false, false),
I("a*b*.c.d", false, false),
I("a*.b*.c", false, false),
// Wildcards are only allowed in the first label.
I("a.*", false, false),
I("a.*.b", false, false),
I("a.b.*", false, false),
I("a.b*.c", false, false),
I("*.b*.c", false, false),
I(".*.a.b", false, false),
I(".a*.b.c", false, false),
// Wildcards must be at the *end* of the first label.
I("*a.b.c", false, false),
I("a*b.c.d", false, false),
// maximum label length is 63 characters
I("1234567890""1234567890""1234567890" "1234567890""1234567890""1234567890""abc", true, true),
I("1234567890""1234567890""1234567890" "1234567890""1234567890""1234567890""abcd", false, false),
// maximum total length is 253 characters
I("1234567890""1234567890""1234567890""1234567890""1234567890""." "1234567890""1234567890""1234567890""1234567890""1234567890""." "1234567890""1234567890""1234567890""1234567890""1234567890""." "1234567890""1234567890""1234567890""1234567890""1234567890""." "1234567890""1234567890""1234567890""1234567890""12345678""a", true, true),
I("1234567890""1234567890""1234567890""1234567890""1234567890""." "1234567890""1234567890""1234567890""1234567890""1234567890""." "1234567890""1234567890""1234567890""1234567890""1234567890""." "1234567890""1234567890""1234567890""1234567890""1234567890""." "1234567890""1234567890""1234567890""1234567890""123456789""a", false, false),
};
staticconst InputValidity DNSNAMES_VALIDITY_TURKISH_I[] =
{ // http://en.wikipedia.org/wiki/Dotted_and_dotless_I#In_computing // IDN registration rules disallow "latin capital letter i with dot above," // but our checks aren't intended to enforce those rules.
I("I", true, true), // ASCII capital I
I("i", true, true), // ASCII lowercase i
I("\xC4\xB0", false, false), // latin capital letter i with dot above
I("\xC4\xB1", false, false), // latin small letter dotless i
I("xn--i-9bb", true, true), // latin capital letter i with dot above, in punycode
I("xn--cfa", true, true), // latin small letter dotless i, in punycode
I("xn--\xC4\xB0", false, false), // latin capital letter i with dot above, mashup
I("xn--\xC4\xB1", false, false), // latin small letter dotless i, mashup
};
#define IPV4_VALID(str, a, b, c, d) \
{ \
ByteString(reinterpret_cast<const uint8_t*>(str), sizeof(str) - 1), \ true, \
{ a, b, c, d } \
}
// The value of expectedValueIfValid must be ignored for invalid IP addresses. // The value { 73, 73, 73, 73 } is used because it is unlikely to result in an // accidental match, unlike { 0, 0, 0, 0 }, which is a value we actually test. #define IPV4_INVALID(str) \
{ \
ByteString(reinterpret_cast<const uint8_t*>(str), sizeof(str) - 1), \ false, \
{ 73, 73, 73, 73 } \
}
#define IPV6_VALID(str, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \
{ \
ByteString(reinterpret_cast<const uint8_t*>(str), sizeof(str) - 1), \ true, \
{ a, b, c, d, \
e, f, g, h, \
i, j, k, l, \
m, n, o, p } \
}
// Contraction in full IPv6 addresses not allowed
IPV6_INVALID("::1234:5678:9abc:def0:1234:5678:9abc:def0"), // start
IPV6_INVALID("1234:5678:9abc:def0:1234:5678:9abc:def0::"), // end
IPV6_INVALID("1234:5678::9abc:def0:1234:5678:9abc:def0"), // interior
// Multiple contractions not allowed
IPV6_INVALID("::1::"),
IPV6_INVALID("::1::2"),
IPV6_INVALID("1::2::"),
class pkixnames_MatchPresentedDNSIDWithReferenceDNSID
: public ::testing::Test
, public ::testing::WithParamInterface<PresentedMatchesReference>
{ public:
DefaultNameMatchingPolicy mNameMatchingPolicy;
};
class pkixnames_Turkish_I_Comparison
: public ::testing::Test
, public ::testing::WithParamInterface<InputValidity>
{ public:
DefaultNameMatchingPolicy mNameMatchingPolicy;
};
TEST_P(pkixnames_Turkish_I_Comparison, MatchPresentedDNSIDWithReferenceDNSID)
{ // Make sure we don't have the similar problems that strcasecmp and others // have with the other kinds of "i" and "I" commonly used in Turkish locales.
class pkixnames_IsValidReferenceDNSID
: public ::testing::Test
, public ::testing::WithParamInterface<InputValidity>
{ public:
DefaultNameMatchingPolicy mNameMatchingPolicy;
};
class pkixnames_ParseIPv4Address
: public ::testing::Test
, public ::testing::WithParamInterface<IPAddressParams<4>>
{ public:
DefaultNameMatchingPolicy mNameMatchingPolicy;
};
TEST_P(pkixnames_ParseIPv4Address, ParseIPv4Address)
{ const IPAddressParams<4>& param(GetParam());
SCOPED_TRACE(param.input.c_str());
Input input;
ASSERT_EQ(Success, input.Init(param.input.data(),
param.input.length()));
uint8_t ipAddress[4];
ASSERT_EQ(param.isValid, ParseIPv4Address(input, ipAddress)); if (param.isValid) { for (size_t i = 0; i < sizeof(ipAddress); ++i) {
ASSERT_EQ(param.expectedValueIfValid[i], ipAddress[i]);
}
}
}
class pkixnames_ParseIPv6Address
: public ::testing::Test
, public ::testing::WithParamInterface<IPAddressParams<16>>
{ public:
DefaultNameMatchingPolicy mNameMatchingPolicy;
};
TEST_P(pkixnames_ParseIPv6Address, ParseIPv6Address)
{ const IPAddressParams<16>& param(GetParam());
SCOPED_TRACE(param.input.c_str());
Input input;
ASSERT_EQ(Success, input.Init(param.input.data(),
param.input.length()));
uint8_t ipAddress[16];
ASSERT_EQ(param.isValid, ParseIPv6Address(input, ipAddress)); if (param.isValid) { for (size_t i = 0; i < sizeof(ipAddress); ++i) {
ASSERT_EQ(param.expectedValueIfValid[i], ipAddress[i]);
}
}
}
// This is an arbitrary string that is used to indicate that no SAN extension // should be put into the generated certificate. It needs to be different from // "" or any other subjectAltName value that we actually want to test, but its // actual value does not matter. Note that this isn't a correctly-encoded SAN // extension value! staticconst ByteString
NO_SAN(reinterpret_cast<const uint8_t*>("I'm a bad, bad, certificate"));
class pkixnames_CheckCertHostname
: public ::testing::Test
, public ::testing::WithParamInterface<CheckCertHostnameParams>
{ public:
DefaultNameMatchingPolicy mNameMatchingPolicy;
};
// The subnet is 1.2.0.0/16 but it is specified as 1.2.3.0/16 staticconst uint8_t ipv4_constraint_CIDR_16_bad_addr_bytes[] = {
1, 2, 3, 0, 0xff, 0xff, 0, 0
};
// Masks are supposed to be of the form <ones><zeros>, but this one is of the // form <ones><zeros><ones><zeros>. staticconst uint8_t ipv4_constraint_bad_mask_bytes[] = {
1, 2, 3, 0, 0xff, 0, 0xff, 0
};
// The subnet is 1122::/16 but it is specified as 1122:3344::/16 staticconst uint8_t ipv6_constraint_CIDR_16_bad_addr_bytes[] = {
0x11, 0x22, 0x33, 0x44, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0xff, 0xff, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
// Masks are supposed to be of the form <ones><zeros>, but this one is of the // form <ones><zeros><ones><zeros>. staticconst uint8_t ipv6_constraint_bad_mask_bytes[] = {
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
};
// Note that, for DNSNames, these test cases in CHECK_CERT_HOSTNAME_PARAMS are // mostly about testing different scenerios regarding the structure of entries // in the subjectAltName and subject of the certificate, than about the how // specific presented identifier values are matched against the reference // identifier values. This is because we also use the test cases in // DNSNAMES_VALIDITY to test CheckCertHostname. Consequently, tests about // whether specific presented DNSNames (including wildcards, in particular) are // matched against a reference DNSName only need to be added to // DNSNAMES_VALIDITY, and not here. staticconst CheckCertHostnameParams CHECK_CERT_HOSTNAME_PARAMS[] =
{ // This is technically illegal. PrintableString is defined in such a way that // '*' is not an allowed character, but there are many real-world certificates // that are encoded this way.
WITHOUT_SAN("foo.example.com", RDN(CN("*.example.com", der::PrintableString)),
Success),
WITHOUT_SAN("foo.example.com", RDN(CN("*.example.com", der::UTF8String)),
Success),
// Many certificates use TeletexString when encoding wildcards in CN-IDs // because PrintableString is defined as not allowing '*' and UTF8String was, // at one point in history, considered too new to depend on for compatibility. // We accept TeletexString-encoded CN-IDs when they don't contain any escape // sequences. The reference I used for the escape codes was // https://tools.ietf.org/html/rfc1468. The escaping mechanism is actually // pretty complex and these tests don't even come close to testing all the // possibilities.
WITHOUT_SAN("foo.example.com", RDN(CN("*.example.com", der::TeletexString)),
Success), // "ESC ( B" ({0x1B,0x50,0x42}) is the escape code to switch to ASCII, which // is redundant because it already the default.
WITHOUT_SAN("foo.example.com",
RDN(CN("\x1B(B*.example.com", der::TeletexString)),
Result::ERROR_BAD_CERT_DOMAIN),
WITHOUT_SAN("foo.example.com",
RDN(CN("*.example\x1B(B.com", der::TeletexString)),
Result::ERROR_BAD_CERT_DOMAIN),
WITHOUT_SAN("foo.example.com",
RDN(CN("*.example.com\x1B(B", der::TeletexString)),
Result::ERROR_BAD_CERT_DOMAIN), // "ESC $ B" ({0x1B,0x24,0x42}) is the escape code to switch to // JIS X 0208-1983 (a Japanese character set).
WITHOUT_SAN("foo.example.com",
RDN(CN("\x1B$B*.example.com", der::TeletexString)),
Result::ERROR_BAD_CERT_DOMAIN),
WITHOUT_SAN("foo.example.com",
RDN(CN("*.example.com\x1B$B", der::TeletexString)),
Result::ERROR_BAD_CERT_DOMAIN),
// Match a DNSName SAN entry with a redundant (ignored) matching CN-ID.
WITH_SAN("a", RDN(CN("a")), DNSName("a"), Success), // Match a DNSName SAN entry when there is an CN-ID that doesn't match.
WITH_SAN("b", RDN(CN("a")), DNSName("b"), Success), // Do not match a CN-ID when there is a valid DNSName SAN Entry.
WITH_SAN("a", RDN(CN("a")), DNSName("b"), Result::ERROR_BAD_CERT_DOMAIN), // Do not match a CN-ID when there is a malformed DNSName SAN Entry.
WITH_SAN("a", RDN(CN("a")), DNSName("!"), Result::ERROR_BAD_DER), // Do not match a matching CN-ID when there is a valid IPAddress SAN entry.
WITH_SAN("a", RDN(CN("a")), IPAddress(ipv4_addr_bytes),
Result::ERROR_BAD_CERT_DOMAIN), // Do not match a matching CN-ID when there is a malformed IPAddress SAN entry.
WITH_SAN("a", RDN(CN("a")), IPAddress(example_com),
Result::ERROR_BAD_CERT_DOMAIN), // Match a DNSName against a matching CN-ID when there is a SAN, but the SAN // does not contain an DNSName or IPAddress entry.
WITH_SAN("a", RDN(CN("a")), RFC822Name("foo@example.com"), Success), // Match a matching CN-ID when there is no SAN.
WITHOUT_SAN("a", RDN(CN("a")), Success), // Do not match a mismatching CN-ID when there is no SAN.
WITHOUT_SAN("a", RDN(CN("b")), Result::ERROR_BAD_CERT_DOMAIN),
// The first DNSName matches.
WITH_SAN("a", RDN(CN("foo")), DNSName("a") + DNSName("b"), Success), // The last DNSName matches.
WITH_SAN("b", RDN(CN("foo")), DNSName("a") + DNSName("b"), Success), // The middle DNSName matches.
WITH_SAN("b", RDN(CN("foo")),
DNSName("a") + DNSName("b") + DNSName("c"), Success), // After an IP address.
WITH_SAN("b", RDN(CN("foo")),
IPAddress(ipv4_addr_bytes) + DNSName("b"), Success), // Before an IP address.
WITH_SAN("a", RDN(CN("foo")),
DNSName("a") + IPAddress(ipv4_addr_bytes), Success), // Between an RFC822Name and an IP address.
WITH_SAN("b", RDN(CN("foo")),
RFC822Name("foo@example.com") + DNSName("b") +
IPAddress(ipv4_addr_bytes),
Success), // Duplicate DNSName.
WITH_SAN("a", RDN(CN("foo")), DNSName("a") + DNSName("a"), Success), // After an invalid DNSName.
WITH_SAN("b", RDN(CN("foo")), DNSName("!") + DNSName("b"),
Result::ERROR_BAD_DER),
// http://tools.ietf.org/html/rfc5280#section-4.2.1.6: "If the subjectAltName // extension is present, the sequence MUST contain at least one entry." // However, for compatibility reasons, this is not enforced. See bug 1143085. // This case is treated as if the extension is not present (i.e. name // matching falls back to the subject CN).
WITH_SAN("a", RDN(CN("a")), ByteString(), Success),
WITH_SAN("a", RDN(CN("b")), ByteString(), Result::ERROR_BAD_CERT_DOMAIN),
// http://tools.ietf.org/html/rfc5280#section-4.1.2.6 says "If subject naming // information is present only in the subjectAltName extension (e.g., a key // bound only to an email address or URI), then the subject name MUST be an // empty sequence and the subjectAltName extension MUST be critical." So, we // have to support an empty subject. We don't enforce that the SAN must be // critical or even that there is a SAN when the subject is empty, though.
WITH_SAN("a", ByteString(), DNSName("a"), Success), // Make sure we return ERROR_BAD_CERT_DOMAIN and not ERROR_BAD_DER.
WITHOUT_SAN("a", ByteString(), Result::ERROR_BAD_CERT_DOMAIN),
// Two CNs in the same RDN, both match.
WITHOUT_SAN("a", RDN(CN("a") + CN("a")), Success), // Two CNs in the same RDN, both DNSNames, first one matches.
WITHOUT_SAN("a", RDN(CN("a") + CN("b")),
Result::ERROR_BAD_CERT_DOMAIN), // Two CNs in the same RDN, both DNSNames, last one matches.
WITHOUT_SAN("b", RDN(CN("a") + CN("b")), Success), // Two CNs in the same RDN, first one matches, second isn't a DNSName.
WITHOUT_SAN("a", RDN(CN("a") + CN("Not a DNSName")),
Result::ERROR_BAD_CERT_DOMAIN), // Two CNs in the same RDN, first one not a DNSName, second matches.
WITHOUT_SAN("b", RDN(CN("Not a DNSName") + CN("b")), Success),
// Two CNs in separate RDNs, both match.
WITHOUT_SAN("a", RDN(CN("a")) + RDN(CN("a")), Success), // Two CNs in separate RDNs, both DNSNames, first one matches.
WITHOUT_SAN("a", RDN(CN("a")) + RDN(CN("b")),
Result::ERROR_BAD_CERT_DOMAIN), // Two CNs in separate RDNs, both DNSNames, last one matches.
WITHOUT_SAN("b", RDN(CN("a")) + RDN(CN("b")), Success), // Two CNs in separate RDNs, first one matches, second isn't a DNSName.
WITHOUT_SAN("a", RDN(CN("a")) + RDN(CN("Not a DNSName")),
Result::ERROR_BAD_CERT_DOMAIN), // Two CNs in separate RDNs, first one not a DNSName, second matches.
WITHOUT_SAN("b", RDN(CN("Not a DNSName")) + RDN(CN("b")), Success),
// One CN, one RDN, CN is the first AVA in the RDN, CN matches.
WITHOUT_SAN("a", RDN(CN("a") + OU("b")), Success), // One CN, one RDN, CN is the first AVA in the RDN, CN does not match.
WITHOUT_SAN("b", RDN(CN("a") + OU("b")),
Result::ERROR_BAD_CERT_DOMAIN), // One CN, one RDN, CN is not the first AVA in the RDN, CN matches.
WITHOUT_SAN("b", RDN(OU("a") + CN("b")), Success), // One CN, one RDN, CN is not the first AVA in the RDN, CN does not match.
WITHOUT_SAN("a", RDN(OU("a") + CN("b")),
Result::ERROR_BAD_CERT_DOMAIN),
// One CN, multiple RDNs, CN is in the first RDN, CN matches.
WITHOUT_SAN("a", RDN(CN("a")) + RDN(OU("b")), Success), // One CN, multiple RDNs, CN is in the first RDN, CN does not match.
WITHOUT_SAN("b", RDN(CN("a")) + RDN(OU("b")), Result::ERROR_BAD_CERT_DOMAIN), // One CN, multiple RDNs, CN is not in the first RDN, CN matches.
WITHOUT_SAN("b", RDN(OU("a")) + RDN(CN("b")), Success), // One CN, multiple RDNs, CN is not in the first RDN, CN does not match.
WITHOUT_SAN("a", RDN(OU("a")) + RDN(CN("b")), Result::ERROR_BAD_CERT_DOMAIN),
// One CN, one RDN, CN is not in the first or last AVA, CN matches.
WITHOUT_SAN("b", RDN(OU("a") + CN("b") + OU("c")), Success), // One CN, multiple RDNs, CN is not in the first or last RDN, CN matches.
WITHOUT_SAN("b", RDN(OU("a")) + RDN(CN("b")) + RDN(OU("c")), Success),
// Empty CN does not match.
WITHOUT_SAN("example.com", RDN(CN("")), Result::ERROR_BAD_CERT_DOMAIN),
// Do not match a DNSName that is encoded in a malformed IPAddress.
WITH_SAN("example.com", RDN(CN("foo")), IPAddress(example_com),
Result::ERROR_BAD_CERT_DOMAIN),
// We skip over the malformed IPAddress and match the DNSName entry because // we've heard reports of real-world certificates that have malformed // IPAddress SANs.
WITH_SAN("example.org", RDN(CN("foo")),
IPAddress(example_com) + DNSName("example.org"), Success),
// Match a matching IPv4 address SAN entry.
WITH_SAN(ipv4_addr_str, RDN(CN("foo")), IPAddress(ipv4_addr_bytes),
Success), // Match a matching IPv4 addresses in the CN when there is no SAN
WITHOUT_SAN(ipv4_addr_str, RDN(CN(ipv4_addr_str)), Success), // Do not match a matching IPv4 address in the CN when there is a SAN with // a DNSName entry.
WITH_SAN(ipv4_addr_str, RDN(CN(ipv4_addr_str)),
DNSName("example.com"), Result::ERROR_BAD_CERT_DOMAIN), // Do not match a matching IPv4 address in the CN when there is a SAN with // a non-matching IPAddress entry.
WITH_SAN(ipv4_addr_str, RDN(CN(ipv4_addr_str)),
IPAddress(ipv6_addr_bytes), Result::ERROR_BAD_CERT_DOMAIN), // Match a matching IPv4 address in the CN when there is a SAN with a // non-IPAddress, non-DNSName entry.
WITH_SAN(ipv4_addr_str, RDN(CN(ipv4_addr_str)),
RFC822Name("foo@example.com"), Success), // Do not match a matching IPv4 address in the CN when there is a SAN with a // malformed IPAddress entry.
WITH_SAN(ipv4_addr_str, RDN(CN(ipv4_addr_str)),
IPAddress(example_com), Result::ERROR_BAD_CERT_DOMAIN), // Do not match a matching IPv4 address in the CN when there is a SAN with a // malformed DNSName entry.
WITH_SAN(ipv4_addr_str, RDN(CN(ipv4_addr_str)),
DNSName("!"), Result::ERROR_BAD_CERT_DOMAIN),
// We don't match IPv6 addresses in the CN, regardless of whether there is // a SAN.
WITHOUT_SAN(ipv6_addr_str, RDN(CN(ipv6_addr_str)),
Result::ERROR_BAD_CERT_DOMAIN),
WITH_SAN(ipv6_addr_str, RDN(CN(ipv6_addr_str)),
DNSName("example.com"), Result::ERROR_BAD_CERT_DOMAIN),
WITH_SAN(ipv6_addr_str, RDN(CN(ipv6_addr_str)),
IPAddress(ipv6_addr_bytes), Success),
WITH_SAN(ipv6_addr_str, RDN(CN("foo")), IPAddress(ipv6_addr_bytes),
Success),
// We don't match the binary encoding of the bytes of IP addresses in the // CN.
WITHOUT_SAN(ipv4_addr_str, RDN(CN(ipv4_addr_bytes_as_str)),
Result::ERROR_BAD_CERT_DOMAIN),
WITHOUT_SAN(ipv6_addr_str, RDN(CN(ipv6_addr_bytes_as_str)),
Result::ERROR_BAD_CERT_DOMAIN),
// We don't match IP addresses with DNSName SANs.
WITH_SAN(ipv4_addr_str, RDN(CN("foo")),
DNSName(ipv4_addr_bytes_as_str), Result::ERROR_BAD_CERT_DOMAIN),
WITH_SAN(ipv4_addr_str, RDN(CN("foo")), DNSName(ipv4_addr_str),
Result::ERROR_BAD_CERT_DOMAIN),
WITH_SAN(ipv6_addr_str, RDN(CN("foo")),
DNSName(ipv6_addr_bytes_as_str), Result::ERROR_BAD_CERT_DOMAIN),
WITH_SAN(ipv6_addr_str, RDN(CN("foo")), DNSName(ipv6_addr_str),
Result::ERROR_BAD_CERT_DOMAIN),
// Do not match an IPv4 reference ID against the equivalent IPv4-compatible // IPv6 SAN entry.
WITH_SAN(ipv4_addr_str, RDN(CN("foo")),
IPAddress(ipv4_compatible_ipv6_addr_bytes),
Result::ERROR_BAD_CERT_DOMAIN), // Do not match an IPv4 reference ID against the equivalent IPv4-mapped IPv6 // SAN entry.
WITH_SAN(ipv4_addr_str, RDN(CN("foo")),
IPAddress(ipv4_mapped_ipv6_addr_bytes),
Result::ERROR_BAD_CERT_DOMAIN), // Do not match an IPv4-compatible IPv6 reference ID against the equivalent // IPv4 SAN entry.
WITH_SAN(ipv4_compatible_ipv6_addr_str, RDN(CN("foo")),
IPAddress(ipv4_addr_bytes), Result::ERROR_BAD_CERT_DOMAIN), // Do not match an IPv4 reference ID against the equivalent IPv4-mapped IPv6 // SAN entry.
WITH_SAN(ipv4_mapped_ipv6_addr_str, RDN(CN("foo")),
IPAddress(ipv4_addr_bytes),
Result::ERROR_BAD_CERT_DOMAIN),
// Test that the presence of an otherName entry is handled appropriately. // (The actual value of the otherName entry isn't important - that's not what // we're testing here.)
WITH_SAN("example.com", ByteString(), // The tag for otherName is CONTEXT_SPECIFIC | CONSTRUCTED | 0
TLV((2 << 6) | (1 << 5) | 0, ByteString()) + DNSName("example.com"),
Success),
WITH_SAN("example.com", ByteString(),
TLV((2 << 6) | (1 << 5) | 0, ByteString()),
Result::ERROR_BAD_CERT_DOMAIN),
};
ByteString extensions[2]; if (subjectAltName != NO_SAN) {
extensions[0] = CreateEncodedSubjectAltName(subjectAltName);
EXPECT_FALSE(ENCODING_FAILED(extensions[0]));
} if (endEntityOrCA == EndEntityOrCA::MustBeCA) { // Currently, these tests assume that if we're creating a CA certificate, it // will not have a subjectAlternativeName extension. If that assumption // changes, this code will have to be updated. Ideally this would be // ASSERT_EQ, but that inserts a 'return;', which doesn't match this // function's return type.
EXPECT_EQ(subjectAltName, NO_SAN);
extensions[0] = CreateEncodedBasicConstraints(true, nullptr,
Critical::Yes);
EXPECT_FALSE(ENCODING_FAILED(extensions[0]));
}
TEST_F(pkixnames_CheckCertHostname, SANWithoutSequence)
{ // A certificate with a truly empty SAN extension (one that doesn't even // contain a SEQUENCE at all) is malformed. If we didn't treat this as // malformed then we'd have to treat it like the CN_EmptySAN cases.
// The default name matching policy halts on invalid SAN entries.
ASSERT_EQ(Result::ERROR_BAD_DER,
CheckCertHostname(certInput, hostnameInput, mNameMatchingPolicy));
SkipInvalidSubjectAlternativeNamesNameMatchingPolicy nameMatchingPolicy; // A policy that skips invalid SAN entries should result in a domain mismatch // error.
ASSERT_EQ(Result::ERROR_BAD_CERT_DOMAIN,
CheckCertHostname(certInput, hostnameInput, nameMatchingPolicy));
}
class pkixnames_CheckCertHostname_PresentedMatchesReference
: public ::testing::Test
, public ::testing::WithParamInterface<PresentedMatchesReference>
{ public:
DefaultNameMatchingPolicy mNameMatchingPolicy;
};
TEST_P(pkixnames_CheckCertHostname_PresentedMatchesReference, CN_NoSAN)
{ // Since there is no SAN, a valid presented DNS ID in the subject CN field // should result in a match.
TEST_P(pkixnames_CheckCertHostname_PresentedMatchesReference,
SubjectAltName_CNNotDNSName)
{ // A DNSName SAN entry should match, regardless of the contents of the // subject CN.
TEST_P(pkixnames_Turkish_I_Comparison, CheckCertHostname_CN_NoSAN)
{ // Make sure we don't have the similar problems that strcasecmp and others // have with the other kinds of "i" and "I" commonly used in Turkish locales, // when we're matching a CN due to lack of subjectAltName.
TEST_P(pkixnames_Turkish_I_Comparison, CheckCertHostname_SAN)
{ // Make sure we don't have the similar problems that strcasecmp and others // have with the other kinds of "i" and "I" commonly used in Turkish locales, // when we're matching a dNSName in the SAN.
class pkixnames_CheckCertHostname_IPV4_Addresses
: public ::testing::Test
, public ::testing::WithParamInterface<IPAddressParams<4>>
{ public:
DefaultNameMatchingPolicy mNameMatchingPolicy;
};
TEST_P(pkixnames_CheckCertHostname_IPV4_Addresses,
ValidIPv4AddressInIPAddressSAN)
{ // When the reference hostname is a valid IPv4 address, a correctly-formed // IPv4 Address SAN matches it.
TEST_P(pkixnames_CheckCertHostname_IPV4_Addresses,
ValidIPv4AddressInCN_NoSAN)
{ // When the reference hostname is a valid IPv4 address, a correctly-formed // IPv4 Address in the CN matches it when there is no SAN.
// Some of the invalid IPv4 addresses are valid DNS names!
Result expectedResult = (param.isValid || IsValidReferenceDNSID(hostnameInput))
? Success
: Result::ERROR_BAD_CERT_DOMAIN;
// Does not encode min or max. static ByteString
GeneralSubtree(const ByteString& base)
{ return TLV(der::SEQUENCE, base);
}
staticconst NameConstraintParams NAME_CONSTRAINT_PARAMS[] =
{ ///////////////////////////////////////////////////////////////////////////// // XXX: Malformed name constraints for supported types of names are ignored // when there are no names of that type to constrain.
{ ByteString(), NO_SAN,
GeneralSubtree(DNSName("!")),
Success, Success
},
{ // DirectoryName constraints are an exception, because *every* certificate // has at least one DirectoryName (tbsCertificate.subject).
ByteString(), NO_SAN,
GeneralSubtree(Name(ByteString(reinterpret_cast<const uint8_t*>("!"), 1))),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
{ ByteString(), NO_SAN,
GeneralSubtree(IPAddress(ipv4_constraint_truncated_bytes)),
Success, Success
},
{ ByteString(), NO_SAN,
GeneralSubtree(IPAddress(ipv4_constraint_overlong_bytes)),
Success, Success
},
{ ByteString(), NO_SAN,
GeneralSubtree(IPAddress(ipv6_constraint_truncated_bytes)),
Success, Success
},
{ ByteString(), NO_SAN,
GeneralSubtree(IPAddress(ipv6_constraint_overlong_bytes)),
Success, Success
},
{ ByteString(), NO_SAN,
GeneralSubtree(RFC822Name("!")),
Success, Success
},
///////////////////////////////////////////////////////////////////////////// // Edge cases of name constraint absolute vs. relative and subdomain matching // that are not clearly explained in RFC 5280. (See the long comment above // MatchPresentedDNSIDWithReferenceDNSID.)
// Q: Does a presented identifier equal (case insensitive) to the name // constraint match the constraint? For example, does the presented // ID "host.example.com" match a "host.example.com" constraint?
{ ByteString(), DNSName("host.example.com"),
GeneralSubtree(DNSName("host.example.com")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // This test case is an example from RFC 5280.
ByteString(), DNSName("host1.example.com"),
GeneralSubtree(DNSName("host.example.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
{ ByteString(), RFC822Name("a@host.example.com"),
GeneralSubtree(RFC822Name("host.example.com")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // This test case is an example from RFC 5280.
ByteString(), RFC822Name("a@host1.example.com"),
GeneralSubtree(RFC822Name("host.example.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
// Q: When the name constraint does not start with ".", do subdomain // presented identifiers match it? For example, does the presented // ID "www.host.example.com" match a "host.example.com" constraint?
{ // This test case is an example from RFC 5280.
ByteString(), DNSName("www.host.example.com"),
GeneralSubtree(DNSName( "host.example.com")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // The subdomain matching rule for host names that do not start with "." is // different for RFC822Names than for DNSNames!
ByteString(), RFC822Name("a@www.host.example.com"),
GeneralSubtree(RFC822Name( "host.example.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE,
Success
},
// Q: When the name constraint does not start with ".", does a // non-subdomain prefix match it? For example, does "bigfoo.bar.com" // match "foo.bar.com"?
{ ByteString(), DNSName("bigfoo.bar.com"),
GeneralSubtree(DNSName( "foo.bar.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
{ ByteString(), RFC822Name("a@bigfoo.bar.com"),
GeneralSubtree(RFC822Name( "foo.bar.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
// Q: Is a name constraint that starts with "." valid, and if so, what // semantics does it have? For example, does a presented ID of // "www.example.com" match a constraint of ".example.com"? Does a // presented ID of "example.com" match a constraint of ".example.com"?
{ ByteString(), DNSName("www.example.com"),
GeneralSubtree(DNSName( ".example.com")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // When there is no Local-part, an RFC822 name constraint's domain may // start with '.', and the semantics are the same as for DNSNames.
ByteString(), RFC822Name("a@www.example.com"),
GeneralSubtree(RFC822Name( ".example.com")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // When there is a Local-part, an RFC822 name constraint's domain must not // start with '.'.
ByteString(), RFC822Name("a@www.example.com"),
GeneralSubtree(RFC822Name( "a@.example.com")),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
{ // Check that we only allow subdomains to match.
ByteString(), DNSName( "example.com"),
GeneralSubtree(DNSName(".example.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
{ // Check that we only allow subdomains to match.
ByteString(), RFC822Name("a@example.com"),
GeneralSubtree(RFC822Name(".example.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
{ // Check that we don't get confused and consider "b" == "."
ByteString(), DNSName("bexample.com"),
GeneralSubtree(DNSName(".example.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
{ // Check that we don't get confused and consider "b" == "."
ByteString(), RFC822Name("a@bexample.com"),
GeneralSubtree(RFC822Name( ".example.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
// Q: Is there a way to prevent subdomain matches? // (This is tested in a different set of tests because it requires a // combination of permittedSubtrees and excludedSubtrees.)
// Q: Are name constraints allowed to be specified as absolute names? // For example, does a presented ID of "example.com" match a name // constraint of "example.com." and vice versa? //
{ // The DNSName in the constraint is not valid because constraint DNS IDs // are not allowed to be absolute.
ByteString(), DNSName("example.com"),
GeneralSubtree(DNSName("example.com.")),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER,
},
{ ByteString(), RFC822Name("a@example.com"),
GeneralSubtree(RFC822Name( "example.com.")),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER,
},
{ // The DNSName in the SAN is not valid because presented DNS IDs are not // allowed to be absolute.
ByteString(), DNSName("example.com."),
GeneralSubtree(DNSName("example.com")),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER,
},
{ ByteString(), RFC822Name("a@example.com."),
GeneralSubtree(RFC822Name( "example.com")),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER,
},
{ // The presented DNSName is the same length as the constraint, because the // subdomain is only one character long and because the constraint both // begins and ends with ".". But, it doesn't matter because absolute names // are not allowed for DNSName constraints.
ByteString(), DNSName("p.example.com"),
GeneralSubtree(DNSName(".example.com.")),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER,
},
{ // The presented DNSName is the same length as the constraint, because the // subdomain is only one character long and because the constraint both // begins and ends with ".".
ByteString(), RFC822Name("a@p.example.com"),
GeneralSubtree(RFC822Name( ".example.com.")),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER,
},
{ // Same as previous test case, but using a wildcard presented ID.
ByteString(), DNSName("*.example.com"),
GeneralSubtree(DNSName(".example.com.")),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
{ // Same as previous test case, but using a wildcard presented ID, which is // invalid in an RFC822Name.
ByteString(), RFC822Name("a@*.example.com"),
GeneralSubtree(RFC822Name( ".example.com.")),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
// Q: Are "" and "." valid DNSName constraints? If so, what do they mean?
{ ByteString(), DNSName("example.com"),
GeneralSubtree(DNSName("")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ ByteString(), RFC822Name("a@example.com"),
GeneralSubtree(RFC822Name("")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // The malformed (absolute) presented ID does not match.
ByteString(), DNSName("example.com."),
GeneralSubtree(DNSName("")),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
{ ByteString(), RFC822Name("a@example.com."),
GeneralSubtree(RFC822Name("")),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
{ // Invalid syntax in name constraint
ByteString(), DNSName("example.com"),
GeneralSubtree(DNSName(".")),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER,
},
{ // Invalid syntax in name constraint
ByteString(), RFC822Name("a@example.com"),
GeneralSubtree(RFC822Name(".")),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER,
},
{ ByteString(), DNSName("example.com."),
GeneralSubtree(DNSName(".")),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
{ ByteString(), RFC822Name("a@example.com."),
GeneralSubtree(RFC822Name(".")),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
///////////////////////////////////////////////////////////////////////////// // Basic IP Address constraints (non-CN-ID)
// The Mozilla CA Policy says this means "no IPv4 addresses allowed."
{ ByteString(), IPAddress(ipv4_addr_bytes),
GeneralSubtree(IPAddress(ipv4_constraint_all_zeros_bytes)),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ ByteString(), IPAddress(ipv4_addr_00000000_bytes),
GeneralSubtree(IPAddress(ipv4_constraint_all_zeros_bytes)),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ ByteString(), IPAddress(ipv4_addr_FFFFFFFF_bytes),
GeneralSubtree(IPAddress(ipv4_constraint_all_zeros_bytes)),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
// The Mozilla CA Policy says this means "no IPv6 addresses allowed."
{ ByteString(), IPAddress(ipv6_addr_bytes),
GeneralSubtree(IPAddress(ipv6_constraint_all_zeros_bytes)),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ ByteString(), IPAddress(ipv6_addr_all_zeros_bytes),
GeneralSubtree(IPAddress(ipv6_constraint_all_zeros_bytes)),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
// RFC 5280 doesn't partition IP address constraints into separate IPv4 and // IPv6 categories, so a IPv4 permittedSubtrees constraint excludes all IPv6 // addresses, and vice versa.
{ ByteString(), IPAddress(ipv4_addr_bytes),
GeneralSubtree(IPAddress(ipv6_constraint_all_zeros_bytes)),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
{ ByteString(), IPAddress(ipv6_addr_bytes),
GeneralSubtree(IPAddress(ipv4_constraint_all_zeros_bytes)),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
// IPv4 Subnets
{ ByteString(), IPAddress(ipv4_addr_bytes),
GeneralSubtree(IPAddress(ipv4_constraint_CIDR_16_bytes)),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ ByteString(), IPAddress(ipv4_addr_bytes),
GeneralSubtree(IPAddress(ipv4_constraint_CIDR_17_bytes)),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ ByteString(), IPAddress(ipv4_other_addr_bytes),
GeneralSubtree(IPAddress(ipv4_constraint_CIDR_16_bytes)),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
{ // XXX(bug 1089430): We don't reject this even though it is weird.
ByteString(), IPAddress(ipv4_addr_bytes),
GeneralSubtree(IPAddress(ipv4_constraint_CIDR_16_bad_addr_bytes)),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // XXX(bug 1089430): We don't reject this even though it is weird.
ByteString(), IPAddress(ipv4_other_addr_bytes),
GeneralSubtree(IPAddress(ipv4_constraint_bad_mask_bytes)),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
// IPv6 Subnets
{ ByteString(), IPAddress(ipv6_addr_bytes),
GeneralSubtree(IPAddress(ipv6_constraint_CIDR_16_bytes)),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ ByteString(), IPAddress(ipv6_other_addr_bytes),
GeneralSubtree(IPAddress(ipv6_constraint_CIDR_16_bytes)),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
{ // XXX(bug 1089430): We don't reject this even though it is weird.
ByteString(), IPAddress(ipv6_addr_bytes),
GeneralSubtree(IPAddress(ipv6_constraint_CIDR_16_bad_addr_bytes)),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // XXX(bug 1089430): We don't reject this even though it is weird.
ByteString(), IPAddress(ipv6_other_addr_bytes),
GeneralSubtree(IPAddress(ipv6_constraint_bad_mask_bytes)),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
// Malformed presented IP addresses and constraints
{ // The presented IPv4 address is empty
ByteString(), IPAddress(),
GeneralSubtree(IPAddress(ipv4_constraint_all_zeros_bytes)),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
{ // The presented IPv4 address is truncated
ByteString(), IPAddress(ipv4_addr_truncated_bytes),
GeneralSubtree(IPAddress(ipv4_constraint_all_zeros_bytes)),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
{ // The presented IPv4 address is too long
ByteString(), IPAddress(ipv4_addr_overlong_bytes),
GeneralSubtree(IPAddress(ipv4_constraint_all_zeros_bytes)),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
{ // The presented IPv4 constraint is empty
ByteString(), IPAddress(ipv4_addr_bytes),
GeneralSubtree(IPAddress()),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
{ // The presented IPv4 constraint is truncated
ByteString(), IPAddress(ipv4_addr_bytes),
GeneralSubtree(IPAddress(ipv4_constraint_truncated_bytes)),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
{ // The presented IPv4 constraint is too long
ByteString(), IPAddress(ipv4_addr_bytes),
GeneralSubtree(IPAddress(ipv4_constraint_overlong_bytes)),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
{ // The presented IPv6 address is empty
ByteString(), IPAddress(),
GeneralSubtree(IPAddress(ipv6_constraint_all_zeros_bytes)),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
{ // The presented IPv6 address is truncated
ByteString(), IPAddress(ipv6_addr_truncated_bytes),
GeneralSubtree(IPAddress(ipv6_constraint_all_zeros_bytes)),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
{ // The presented IPv6 address is too long
ByteString(), IPAddress(ipv6_addr_overlong_bytes),
GeneralSubtree(IPAddress(ipv6_constraint_all_zeros_bytes)),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
{ // The presented IPv6 constraint is empty
ByteString(), IPAddress(ipv6_addr_bytes),
GeneralSubtree(IPAddress()),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
{ // The presented IPv6 constraint is truncated
ByteString(), IPAddress(ipv6_addr_bytes),
GeneralSubtree(IPAddress(ipv6_constraint_truncated_bytes)),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
{ // The presented IPv6 constraint is too long
ByteString(), IPAddress(ipv6_addr_bytes),
GeneralSubtree(IPAddress(ipv6_constraint_overlong_bytes)),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
///////////////////////////////////////////////////////////////////////////// // XXX: We don't reject malformed name constraints when there are no names of // that type.
{ ByteString(), NO_SAN, GeneralSubtree(DNSName("!")),
Success, Success
},
{ ByteString(), NO_SAN, GeneralSubtree(IPAddress(ipv4_addr_overlong_bytes)),
Success, Success
},
{ ByteString(), NO_SAN, GeneralSubtree(IPAddress(ipv6_addr_overlong_bytes)),
Success, Success
},
{ ByteString(), NO_SAN, GeneralSubtree(RFC822Name("\0")),
Success, Success
},
{ // Empty Name is ignored for DNSName constraints.
ByteString(), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
Success, Success
},
{ // Empty CN is ignored for DNSName constraints because it isn't a // syntactically-valid DNSName. // // NSS gives different results.
RDN(CN("")), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
Success, Success
},
{ // IP Address is ignored for DNSName constraints. // // NSS gives different results.
RDN(CN("1.2.3.4")), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
Success, Success
},
{ // OU has something that looks like a dNSName that matches.
RDN(OU("a.example.com")), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
Success, Success
},
{ // OU has something that looks like a dNSName that does not match.
RDN(OU("b.example.com")), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
Success, Success
},
{ // NSS gives different results.
RDN(CN("Not a DNSName")), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
Success, Success
},
{ RDN(CN("a.example.com")), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ RDN(CN("b.example.com")), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
{ // DNSName CN-ID match is detected when there is a SAN w/o any DNSName or // IPAddress
RDN(CN("a.example.com")), RFC822Name("foo@example.com"),
GeneralSubtree(DNSName("a.example.com")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // DNSName CN-ID mismatch is detected when there is a SAN w/o any DNSName // or IPAddress
RDN(CN("a.example.com")), RFC822Name("foo@example.com"),
GeneralSubtree(DNSName("b.example.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
{ // DNSName CN-ID match not reported when there is a DNSName SAN
RDN(CN("a.example.com")), DNSName("b.example.com"),
GeneralSubtree(DNSName("a.example.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
{ // DNSName CN-ID mismatch not reported when there is a DNSName SAN
RDN(CN("a.example.com")), DNSName("b.example.com"),
GeneralSubtree(DNSName("b.example.com")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE,
},
{ // DNSName CN-ID match not reported when there is an IPAddress SAN
RDN(CN("a.example.com")), IPAddress(ipv4_addr_bytes),
GeneralSubtree(DNSName("a.example.com")),
Success, Success
},
{ // DNSName CN-ID mismatch not reported when there is an IPAddress SAN
RDN(CN("a.example.com")), IPAddress(ipv4_addr_bytes),
GeneralSubtree(DNSName("b.example.com")),
Success, Success
},
{ // IPAddress CN-ID match is detected when there is a SAN w/o any DNSName or // IPAddress
RDN(CN(ipv4_addr_str)), RFC822Name("foo@example.com"),
GeneralSubtree(IPAddress(ipv4_addr_bytes_FFFFFFFF)),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // IPAddress CN-ID mismatch is detected when there is a SAN w/o any DNSName // or IPAddress
RDN(CN(ipv4_addr_str)), RFC822Name("foo@example.com"),
GeneralSubtree(IPAddress(ipv4_other_addr_bytes_FFFFFFFF)),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
{ // IPAddress CN-ID match not reported when there is a DNSName SAN
RDN(CN(ipv4_addr_str)), DNSName("b.example.com"),
GeneralSubtree(IPAddress(ipv4_addr_bytes_FFFFFFFF)),
Success, Success
},
{ // IPAddress CN-ID mismatch not reported when there is a DNSName SAN
RDN(CN(ipv4_addr_str)), DNSName("b.example.com"),
GeneralSubtree(IPAddress(ipv4_addr_bytes_FFFFFFFF)),
Success, Success
},
{ // IPAddress CN-ID match not reported when there is an IPAddress SAN
RDN(CN(ipv4_addr_str)), IPAddress(ipv4_other_addr_bytes),
GeneralSubtree(IPAddress(ipv4_addr_bytes_FFFFFFFF)),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
{ // IPAddress CN-ID mismatch not reported when there is an IPAddress SAN
RDN(CN(ipv4_addr_str)), IPAddress(ipv4_other_addr_bytes),
GeneralSubtree(IPAddress(ipv4_other_addr_bytes_FFFFFFFF)),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
///////////////////////////////////////////////////////////////////////////// // Test that constraints are applied to the most specific (last) CN, and only // that CN-ID.
{ // Name constraint only matches a.example.com, but the most specific CN // (i.e. the CN-ID) is b.example.com. (Two CNs in one RDN.)
RDN(CN("a.example.com") + CN("b.example.com")), NO_SAN,
GeneralSubtree(DNSName("a.example.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
{ // Name constraint only matches a.example.com, but the most specific CN // (i.e. the CN-ID) is b.example.com. (Two CNs in separate RDNs.)
RDN(CN("a.example.com")) + RDN(CN("b.example.com")), NO_SAN,
GeneralSubtree(DNSName("a.example.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
},
{ // Name constraint only permits b.example.com, and the most specific CN // (i.e. the CN-ID) is b.example.com. (Two CNs in one RDN.)
RDN(CN("a.example.com") + CN("b.example.com")), NO_SAN,
GeneralSubtree(DNSName("b.example.com")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // Name constraint only permits b.example.com, and the most specific CN // (i.e. the CN-ID) is b.example.com. (Two CNs in separate RDNs.)
RDN(CN("a.example.com")) + RDN(CN("b.example.com")), NO_SAN,
GeneralSubtree(DNSName("b.example.com")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
///////////////////////////////////////////////////////////////////////////// // Additional RFC822 name constraint tests. There are more tests regarding // the DNSName part of the constraint mixed into the DNSName constraint // tests.
///////////////////////////////////////////////////////////////////////////// // Name constraint tests that relate to having an empty SAN. According to RFC // 5280 this isn't valid, but we allow it for compatibility reasons (see bug // 1143085).
{ // For DNSNames, we fall back to the subject CN.
RDN(CN("a.example.com")), ByteString(),
GeneralSubtree(DNSName("a.example.com")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // For RFC822Names, we do not fall back to the subject emailAddress. // This new implementation seems to conform better to the standards for // RFC822 name constraints, by only applying the name constraints to // emailAddress names in the certificate subject if there is no // subjectAltName extension in the cert. // In this case, the presence of the (empty) SAN extension means that RFC822 // name constraints are not enforced on the emailAddress attributes of the // subject.
RDN(emailAddress("a@example.com")), ByteString(),
GeneralSubtree(RFC822Name("a@example.com")),
Success, Success
},
{ // Compare this to the case where there is no SAN (i.e. the name // constraints are enforced, because the extension is not present at all).
RDN(emailAddress("a@example.com")), NO_SAN,
GeneralSubtree(RFC822Name("a@example.com")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
///////////////////////////////////////////////////////////////////////////// // DirectoryName name constraint tests
{ // One AVA per RDN
RDN(OU("Example Organization")) + RDN(CN("example.com")), NO_SAN,
GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization")) +
RDN(CN("example.com"))))),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // RDNs can have multiple AVAs.
RDN(OU("Example Organization") + CN("example.com")), NO_SAN,
GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization") +
CN("example.com"))))),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // The constraint is a prefix of the subject DN.
RDN(OU("Example Organization")) + RDN(CN("example.com")), NO_SAN,
GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization"))))),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // The name constraint is not a prefix of the subject DN. // Note that for excludedSubtrees, we simply prohibit any non-empty // directoryName constraint to ensure we are not being too lenient.
RDN(OU("Other Example Organization")) + RDN(CN("example.com")), NO_SAN,
GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization")) +
RDN(CN("example.com"))))),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // Same as the previous one, but one RDN with multiple AVAs.
RDN(OU("Other Example Organization") + CN("example.com")), NO_SAN,
GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization") +
CN("example.com"))))),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // With multiple AVAs per RDN in the subject DN, the constraint is not a // prefix of the subject DN.
RDN(OU("Example Organization") + CN("example.com")), NO_SAN,
GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization"))))),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // The subject DN RDN has multiple AVAs, but the name constraint has only // one AVA per RDN.
RDN(OU("Example Organization") + CN("example.com")), NO_SAN,
GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization")) +
RDN(CN("example.com"))))),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // The name constraint RDN has multiple AVAs, but the subject DN has only // one AVA per RDN.
RDN(OU("Example Organization")) + RDN(CN("example.com")), NO_SAN,
GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization") +
CN("example.com"))))),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // In this case, the constraint uses a different encoding from the subject. // We consider them to match because we allow UTF8String and // PrintableString to compare equal when their contents are equal.
RDN(OU("Example Organization", der::UTF8String)) + RDN(CN("example.com")),
NO_SAN, GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization",
der::PrintableString)) +
RDN(CN("example.com"))))),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // Same as above, but with UTF8String/PrintableString switched.
RDN(OU("Example Organization", der::PrintableString)) + RDN(CN("example.com")),
NO_SAN, GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization",
der::UTF8String)) +
RDN(CN("example.com"))))),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // If the contents aren't the same, then they shouldn't match.
RDN(OU("Other Example Organization", der::UTF8String)) + RDN(CN("example.com")),
NO_SAN, GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization",
der::PrintableString)) +
RDN(CN("example.com"))))),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ // Only UTF8String and PrintableString are considered equivalent.
RDN(OU("Example Organization", der::PrintableString)) + RDN(CN("example.com")),
NO_SAN, GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization",
der::TeletexString)) +
RDN(CN("example.com"))))),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE
}, // Some additional tests for completeness: // Ensure that wildcards are handled:
{ RDN(CN("*.example.com")), NO_SAN, GeneralSubtree(DNSName("example.com")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ ByteString(), DNSName("*.example.com"),
GeneralSubtree(DNSName("example.com")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ ByteString(), DNSName("www.example.com"),
GeneralSubtree(DNSName("*.example.com")),
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
}, // Handle multiple name constraint entries:
{ RDN(CN("example.com")), NO_SAN,
GeneralSubtree(DNSName("example.org")) +
GeneralSubtree(DNSName("example.com")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ ByteString(), DNSName("example.com"),
GeneralSubtree(DNSName("example.org")) +
GeneralSubtree(DNSName("example.com")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
}, // Handle multiple names in subject alternative name extension:
{ ByteString(), DNSName("example.com") + DNSName("example.org"),
GeneralSubtree(DNSName("example.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE
}, // Handle a mix of DNSName and DirectoryName:
{ RDN(OU("Example Organization")), DNSName("example.com"),
GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization"))))) +
GeneralSubtree(DNSName("example.com")),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ RDN(OU("Other Example Organization")), DNSName("example.com"),
GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization"))))) +
GeneralSubtree(DNSName("example.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ RDN(OU("Example Organization")), DNSName("example.org"),
GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization"))))) +
GeneralSubtree(DNSName("example.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE
}, // Handle a certificate with no DirectoryName:
{ ByteString(), DNSName("example.com"),
GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization"))))),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
};
class pkixnames_CheckNameConstraints
: public ::testing::Test
, public ::testing::WithParamInterface<NameConstraintParams>
{ public:
DefaultNameMatchingPolicy mNameMatchingPolicy;
};
TEST_P(pkixnames_CheckNameConstraints,
NameConstraintsEnforcedForDirectlyIssuedEndEntity)
{ // Test that name constraints are enforced on a certificate directly issued by // a certificate with the given name constraints.
// The |subjectAltName| param is not used for these test cases (hence the use of // "NO_SAN"). staticconst NameConstraintParams NO_FALLBACK_NAME_CONSTRAINT_PARAMS[] =
{ // The only difference between end-entities being verified for serverAuth and // intermediates or end-entities being verified for other uses is that for // the latter cases, there is no fallback matching of DNSName entries to the // subject common name.
{ RDN(CN("Not a DNSName")), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
Success, Success
},
{ RDN(CN("a.example.com")), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
Success, Success
},
{ RDN(CN("b.example.com")), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
Success, Success
}, // Sanity-check that name constraints are in fact enforced in these cases.
{ RDN(CN("Example Name")), NO_SAN,
GeneralSubtree(DirectoryName(Name(RDN(CN("Example Name"))))),
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
}, // (In this implementation, if a DirectoryName is in excludedSubtrees, nothing // is considered to be in the name space.)
{ RDN(CN("Other Example Name")), NO_SAN,
GeneralSubtree(DirectoryName(Name(RDN(CN("Example Name"))))),
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
};
class pkixnames_CheckNameConstraintsOnIntermediate
: public ::testing::Test
, public ::testing::WithParamInterface<NameConstraintParams>
{
};
TEST_P(pkixnames_CheckNameConstraintsOnIntermediate,
NameConstraintsEnforcedOnIntermediate)
{ // Test that name constraints are enforced on an intermediate certificate // directly issued by a certificate with the given name constraints.
class pkixnames_CheckNameConstraintsForNonServerAuthUsage
: public ::testing::Test
, public ::testing::WithParamInterface<NameConstraintParams>
{
};
TEST_P(pkixnames_CheckNameConstraintsForNonServerAuthUsage,
NameConstraintsEnforcedForNonServerAuthUsage)
{ // Test that for key purposes other than serverAuth, fallback to the subject // common name does not occur.
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.