/* -*- 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.
¤ 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.0.30Bemerkung:
(vorverarbeitet)
¤
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.