summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPresubmit Automerger Backend <android-build-presubmit-automerger-backend@system.gserviceaccount.com>2022-03-23 15:13:15 +0000
committerJimmy Chen <jimmycmchen@google.com>2022-03-23 15:23:07 +0000
commit1159a80f83a7b41b34048d8c7908c2b694e1d32b (patch)
treedbcb1494b9b07eb4e40c0114864783b0aede0257
parente9b77e9827648f629530ce8257c14278ecfcfd62 (diff)
parent847f79794d9e7877a78a3cfe0ba1c08a36c056f9 (diff)
downloadboringssl-1159a80f83a7b41b34048d8c7908c2b694e1d32b.tar.gz
[conflict] Ignore duplicates in |X509_STORE_add_*| 2p: 847f79794d
Original change: https://googleplex-android-review.googlesource.com/c/platform/external/boringssl/+/17342543 Bug: 226230302 Change-Id: Ic67ad4214f6feb67a9e95410b16cf3e096cc0627
-rw-r--r--src/crypto/x509/x509_test.cc636
1 files changed, 0 insertions, 636 deletions
diff --git a/src/crypto/x509/x509_test.cc b/src/crypto/x509/x509_test.cc
index 38414e99..007fc62c 100644
--- a/src/crypto/x509/x509_test.cc
+++ b/src/crypto/x509/x509_test.cc
@@ -3220,642 +3220,6 @@ TEST(X509Test, GeneralName) {
}
}
-// Test that extracting fields of an |X509_ALGOR| works correctly.
-TEST(X509Test, X509AlgorExtract) {
- static const char kTestOID[] = "1.2.840.113554.4.1.72585.2";
- const struct {
- int param_type;
- std::vector<uint8_t> param_der;
- } kTests[] = {
- // No parameter.
- {V_ASN1_UNDEF, {}},
- // BOOLEAN { TRUE }
- {V_ASN1_BOOLEAN, {0x01, 0x01, 0xff}},
- // BOOLEAN { FALSE }
- {V_ASN1_BOOLEAN, {0x01, 0x01, 0x00}},
- // OCTET_STRING { "a" }
- {V_ASN1_OCTET_STRING, {0x04, 0x01, 0x61}},
- // BIT_STRING { `01` `00` }
- {V_ASN1_BIT_STRING, {0x03, 0x02, 0x01, 0x00}},
- // INTEGER { -1 }
- {V_ASN1_INTEGER, {0x02, 0x01, 0xff}},
- // OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2 }
- {V_ASN1_OBJECT,
- {0x06, 0x0c, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7,
- 0x09, 0x02}},
- // NULL {}
- {V_ASN1_NULL, {0x05, 0x00}},
- // SEQUENCE {}
- {V_ASN1_SEQUENCE, {0x30, 0x00}},
- // SET {}
- {V_ASN1_SET, {0x31, 0x00}},
- // [0] { UTF8String { "a" } }
- {V_ASN1_OTHER, {0xa0, 0x03, 0x0c, 0x01, 0x61}},
- };
- for (const auto &t : kTests) {
- SCOPED_TRACE(Bytes(t.param_der));
-
- // Assemble an AlgorithmIdentifier with the parameter.
- bssl::ScopedCBB cbb;
- CBB seq, oid;
- ASSERT_TRUE(CBB_init(cbb.get(), 64));
- ASSERT_TRUE(CBB_add_asn1(cbb.get(), &seq, CBS_ASN1_SEQUENCE));
- ASSERT_TRUE(CBB_add_asn1(&seq, &oid, CBS_ASN1_OBJECT));
- ASSERT_TRUE(CBB_add_asn1_oid_from_text(&oid, kTestOID, strlen(kTestOID)));
- ASSERT_TRUE(CBB_add_bytes(&seq, t.param_der.data(), t.param_der.size()));
- ASSERT_TRUE(CBB_flush(cbb.get()));
-
- const uint8_t *ptr = CBB_data(cbb.get());
- bssl::UniquePtr<X509_ALGOR> alg(
- d2i_X509_ALGOR(nullptr, &ptr, CBB_len(cbb.get())));
- ASSERT_TRUE(alg);
-
- const ASN1_OBJECT *obj;
- int param_type;
- const void *param_value;
- X509_ALGOR_get0(&obj, &param_type, &param_value, alg.get());
-
- EXPECT_EQ(param_type, t.param_type);
- char oid_buf[sizeof(kTestOID)];
- ASSERT_EQ(int(sizeof(oid_buf) - 1),
- OBJ_obj2txt(oid_buf, sizeof(oid_buf), obj,
- /*always_return_oid=*/1));
- EXPECT_STREQ(oid_buf, kTestOID);
-
- // |param_type| and |param_value| must be consistent with |ASN1_TYPE|.
- if (param_type == V_ASN1_UNDEF) {
- EXPECT_EQ(nullptr, param_value);
- } else {
- bssl::UniquePtr<ASN1_TYPE> param(ASN1_TYPE_new());
- ASSERT_TRUE(param);
- ASSERT_TRUE(ASN1_TYPE_set1(param.get(), param_type, param_value));
-
- uint8_t *param_der = nullptr;
- int param_len = i2d_ASN1_TYPE(param.get(), &param_der);
- ASSERT_GE(param_len, 0);
- bssl::UniquePtr<uint8_t> free_param_der(param_der);
-
- EXPECT_EQ(Bytes(param_der, param_len), Bytes(t.param_der));
- }
- }
-}
-
-// Test the various |X509_ATTRIBUTE| creation functions.
-TEST(X509Test, Attribute) {
- // The friendlyName attribute has a BMPString value. See RFC 2985,
- // section 5.5.1.
- static const uint8_t kTest1[] = {0x26, 0x03}; // U+2603 SNOWMAN
- static const uint8_t kTest1UTF8[] = {0xe2, 0x98, 0x83};
- static const uint8_t kTest2[] = {0, 't', 0, 'e', 0, 's', 0, 't'};
-
- auto check_attribute = [&](X509_ATTRIBUTE *attr, bool has_test2) {
- EXPECT_EQ(NID_friendlyName, OBJ_obj2nid(X509_ATTRIBUTE_get0_object(attr)));
-
- EXPECT_EQ(has_test2 ? 2 : 1, X509_ATTRIBUTE_count(attr));
-
- // The first attribute should contain |kTest1|.
- const ASN1_TYPE *value = X509_ATTRIBUTE_get0_type(attr, 0);
- ASSERT_TRUE(value);
- EXPECT_EQ(V_ASN1_BMPSTRING, value->type);
- EXPECT_EQ(Bytes(kTest1),
- Bytes(ASN1_STRING_get0_data(value->value.bmpstring),
- ASN1_STRING_length(value->value.bmpstring)));
-
- // |X509_ATTRIBUTE_get0_data| requires the type match.
- EXPECT_FALSE(
- X509_ATTRIBUTE_get0_data(attr, 0, V_ASN1_OCTET_STRING, nullptr));
- const ASN1_BMPSTRING *bmpstring = static_cast<const ASN1_BMPSTRING *>(
- X509_ATTRIBUTE_get0_data(attr, 0, V_ASN1_BMPSTRING, nullptr));
- ASSERT_TRUE(bmpstring);
- EXPECT_EQ(Bytes(kTest1), Bytes(ASN1_STRING_get0_data(bmpstring),
- ASN1_STRING_length(bmpstring)));
-
- if (has_test2) {
- value = X509_ATTRIBUTE_get0_type(attr, 1);
- ASSERT_TRUE(value);
- EXPECT_EQ(V_ASN1_BMPSTRING, value->type);
- EXPECT_EQ(Bytes(kTest2),
- Bytes(ASN1_STRING_get0_data(value->value.bmpstring),
- ASN1_STRING_length(value->value.bmpstring)));
- } else {
- EXPECT_FALSE(X509_ATTRIBUTE_get0_type(attr, 1));
- }
-
- EXPECT_FALSE(X509_ATTRIBUTE_get0_type(attr, 2));
- };
-
- bssl::UniquePtr<ASN1_STRING> str(ASN1_STRING_type_new(V_ASN1_BMPSTRING));
- ASSERT_TRUE(str);
- ASSERT_TRUE(ASN1_STRING_set(str.get(), kTest1, sizeof(kTest1)));
-
- // Test |X509_ATTRIBUTE_create|.
- bssl::UniquePtr<X509_ATTRIBUTE> attr(
- X509_ATTRIBUTE_create(NID_friendlyName, V_ASN1_BMPSTRING, str.get()));
- ASSERT_TRUE(attr);
- str.release(); // |X509_ATTRIBUTE_create| takes ownership on success.
- check_attribute(attr.get(), /*has_test2=*/false);
-
- // Test the |MBSTRING_*| form of |X509_ATTRIBUTE_set1_data|.
- attr.reset(X509_ATTRIBUTE_new());
- ASSERT_TRUE(attr);
- ASSERT_TRUE(
- X509_ATTRIBUTE_set1_object(attr.get(), OBJ_nid2obj(NID_friendlyName)));
- ASSERT_TRUE(X509_ATTRIBUTE_set1_data(attr.get(), MBSTRING_UTF8, kTest1UTF8,
- sizeof(kTest1UTF8)));
- check_attribute(attr.get(), /*has_test2=*/false);
-
- // Test the |ASN1_STRING| form of |X509_ATTRIBUTE_set1_data|.
- ASSERT_TRUE(X509_ATTRIBUTE_set1_data(attr.get(), V_ASN1_BMPSTRING, kTest2,
- sizeof(kTest2)));
- check_attribute(attr.get(), /*has_test2=*/true);
-
- // Test the |ASN1_TYPE| form of |X509_ATTRIBUTE_set1_data|.
- attr.reset(X509_ATTRIBUTE_new());
- ASSERT_TRUE(attr);
- ASSERT_TRUE(
- X509_ATTRIBUTE_set1_object(attr.get(), OBJ_nid2obj(NID_friendlyName)));
- str.reset(ASN1_STRING_type_new(V_ASN1_BMPSTRING));
- ASSERT_TRUE(str);
- ASSERT_TRUE(ASN1_STRING_set(str.get(), kTest1, sizeof(kTest1)));
- ASSERT_TRUE(
- X509_ATTRIBUTE_set1_data(attr.get(), V_ASN1_BMPSTRING, str.get(), -1));
- check_attribute(attr.get(), /*has_test2=*/false);
-}
-
-// Test that, by default, |X509_V_FLAG_TRUSTED_FIRST| is set, which means we'll
-// skip over server-sent expired intermediates when there is a local trust
-// anchor that works better.
-TEST(X509Test, TrustedFirst) {
- // Generate the following certificates:
- //
- // Root 2 (in store, expired)
- // |
- // Root 1 (in store) Root 1 (cross-sign)
- // \ /
- // Intermediate
- // |
- // Leaf
- bssl::UniquePtr<EVP_PKEY> key = PrivateKeyFromPEM(kP256Key);
- ASSERT_TRUE(key);
-
- bssl::UniquePtr<X509> root2 =
- MakeTestCert("Root 2", "Root 2", key.get(), /*is_ca=*/true);
- ASSERT_TRUE(root2);
- ASSERT_TRUE(ASN1_TIME_adj(X509_getm_notAfter(root2.get()), kReferenceTime,
- /*offset_day=*/0,
- /*offset_sec=*/-1));
- ASSERT_TRUE(X509_sign(root2.get(), key.get(), EVP_sha256()));
-
- bssl::UniquePtr<X509> root1 =
- MakeTestCert("Root 1", "Root 1", key.get(), /*is_ca=*/true);
- ASSERT_TRUE(root1);
- ASSERT_TRUE(X509_sign(root1.get(), key.get(), EVP_sha256()));
-
- bssl::UniquePtr<X509> root1_cross =
- MakeTestCert("Root 2", "Root 1", key.get(), /*is_ca=*/true);
- ASSERT_TRUE(root1_cross);
- ASSERT_TRUE(X509_sign(root1_cross.get(), key.get(), EVP_sha256()));
-
- bssl::UniquePtr<X509> intermediate =
- MakeTestCert("Root 1", "Intermediate", key.get(), /*is_ca=*/true);
- ASSERT_TRUE(intermediate);
- ASSERT_TRUE(X509_sign(intermediate.get(), key.get(), EVP_sha256()));
-
- bssl::UniquePtr<X509> leaf =
- MakeTestCert("Intermediate", "Leaf", key.get(), /*is_ca=*/false);
- ASSERT_TRUE(leaf);
- ASSERT_TRUE(X509_sign(leaf.get(), key.get(), EVP_sha256()));
-
- // As a control, confirm that |leaf| -> |intermediate| -> |root1| is valid,
- // but the path through |root1_cross| is expired.
- EXPECT_EQ(X509_V_OK,
- Verify(leaf.get(), {root1.get()}, {intermediate.get()}, {}));
- EXPECT_EQ(X509_V_ERR_CERT_HAS_EXPIRED,
- Verify(leaf.get(), {root2.get()},
- {intermediate.get(), root1_cross.get()}, {}));
-
- // By default, we should find the |leaf| -> |intermediate| -> |root2| chain,
- // skipping |root1_cross|.
- EXPECT_EQ(X509_V_OK, Verify(leaf.get(), {root1.get(), root2.get()},
- {intermediate.get(), root1_cross.get()}, {}));
-
- // When |X509_V_FLAG_TRUSTED_FIRST| is disabled, we get stuck on the expired
- // intermediate. Note we need the callback to clear the flag. Setting |flags|
- // to zero only skips setting new flags.
- //
- // This test exists to confirm our current behavior, but these modes are just
- // workarounds for not having an actual path-building verifier. If we fix it,
- // this test can be removed.
- EXPECT_EQ(X509_V_ERR_CERT_HAS_EXPIRED,
- Verify(leaf.get(), {root1.get(), root2.get()},
- {intermediate.get(), root1_cross.get()}, {}, /*flags=*/0,
- [&](X509_VERIFY_PARAM *param) {
- X509_VERIFY_PARAM_clear_flags(param,
- X509_V_FLAG_TRUSTED_FIRST);
- }));
-
- // Even when |X509_V_FLAG_TRUSTED_FIRST| is disabled, if |root2| is not
- // trusted, the alt chains logic recovers the path.
- EXPECT_EQ(
- X509_V_OK,
- Verify(leaf.get(), {root1.get()}, {intermediate.get(), root1_cross.get()},
- {}, /*flags=*/0, [&](X509_VERIFY_PARAM *param) {
- X509_VERIFY_PARAM_clear_flags(param, X509_V_FLAG_TRUSTED_FIRST);
- }));
-}
-
-// kConstructedBitString is an X.509 certificate where the signature is encoded
-// as a BER constructed BIT STRING. Note that, while OpenSSL's parser accepts
-// this input, it interprets the value incorrectly.
-static const char kConstructedBitString[] = R"(
------BEGIN CERTIFICATE-----
-MIIBJTCBxqADAgECAgIE0jAKBggqhkjOPQQDAjAPMQ0wCwYDVQQDEwRUZXN0MCAX
-DTAwMDEwMTAwMDAwMFoYDzIxMDAwMTAxMDAwMDAwWjAPMQ0wCwYDVQQDEwRUZXN0
-MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5itp4r9ln5e+Lx4NlIpM1Zdrt6ke
-DUb73ampHp3culoB59aXqAoY+cPEox5W4nyDSNsWGhz1HX7xlC1Lz3IiwaMQMA4w
-DAYDVR0TBAUwAwEB/zAKBggqhkjOPQQDAiNOAyQAMEYCIQCp0iIX5s30KXjihR4g
-KnJpd3seqGlVRqCVgrD0KGYDJgA1QAIhAKkx0vR82QU0NtHDD11KX/LuQF2T+2nX
-oeKp5LKAbMVi
------END CERTIFICATE-----
-)";
-
-// kConstructedOctetString is an X.509 certificate where an extension is encoded
-// as a BER constructed OCTET STRING.
-static const char kConstructedOctetString[] = R"(
------BEGIN CERTIFICATE-----
-MIIBJDCByqADAgECAgIE0jAKBggqhkjOPQQDAjAPMQ0wCwYDVQQDEwRUZXN0MCAX
-DTAwMDEwMTAwMDAwMFoYDzIxMDAwMTAxMDAwMDAwWjAPMQ0wCwYDVQQDEwRUZXN0
-MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5itp4r9ln5e+Lx4NlIpM1Zdrt6ke
-DUb73ampHp3culoB59aXqAoY+cPEox5W4nyDSNsWGhz1HX7xlC1Lz3IiwaMUMBIw
-EAYDVR0TJAkEAzADAQQCAf8wCgYIKoZIzj0EAwIDSQAwRgIhAKnSIhfmzfQpeOKF
-HiAqcml3ex6oaVVGoJWCsPQoZjVAAiEAqTHS9HzZBTQ20cMPXUpf8u5AXZP7adeh
-4qnksoBsxWI=
------END CERTIFICATE-----
-)";
-
-// kIndefiniteLength is an X.509 certificate where the outermost SEQUENCE uses
-// BER indefinite-length encoding.
-static const char kIndefiniteLength[] = R"(
------BEGIN CERTIFICATE-----
-MIAwgcagAwIBAgICBNIwCgYIKoZIzj0EAwIwDzENMAsGA1UEAxMEVGVzdDAgFw0w
-MDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowDzENMAsGA1UEAxMEVGVzdDBZ
-MBMGByqGSM49AgEGCCqGSM49AwEHA0IABOYraeK/ZZ+Xvi8eDZSKTNWXa7epHg1G
-+92pqR6d3LpaAefWl6gKGPnDxKMeVuJ8g0jbFhoc9R1+8ZQtS89yIsGjEDAOMAwG
-A1UdEwQFMAMBAf8wCgYIKoZIzj0EAwIDSQAwRgIhAKnSIhfmzfQpeOKFHiAqcml3
-ex6oaVVGoJWCsPQoZjVAAiEAqTHS9HzZBTQ20cMPXUpf8u5AXZP7adeh4qnksoBs
-xWIAAA==
------END CERTIFICATE-----
-)";
-
-// kNonZeroPadding is an X.09 certificate where the BIT STRING signature field
-// has non-zero padding values.
-static const char kNonZeroPadding[] = R"(
------BEGIN CERTIFICATE-----
-MIIB0DCCAXagAwIBAgIJANlMBNpJfb/rMAkGByqGSM49BAEwRTELMAkGA1UEBhMC
-QVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdp
-dHMgUHR5IEx0ZDAeFw0xNDA0MjMyMzIxNTdaFw0xNDA1MjMyMzIxNTdaMEUxCzAJ
-BgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5l
-dCBXaWRnaXRzIFB0eSBMdGQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATmK2ni
-v2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI2xYa
-HPUdfvGULUvPciLBo1AwTjAdBgNVHQ4EFgQUq4TSrKuV8IJOFngHVVdf5CaNgtEw
-HwYDVR0jBBgwFoAUq4TSrKuV8IJOFngHVVdf5CaNgtEwDAYDVR0TBAUwAwEB/zAJ
-BgcqhkjOPQQBA0kBMEUCIQDyoDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13E
-BwIgfB55FGohg/B6dGh5XxSZmmi08cueFV7mHzJSYV51yRQB
------END CERTIFICATE-----
-)";
-
-TEST(X509Test, BER) {
- // Constructed strings are forbidden in DER.
- EXPECT_FALSE(CertFromPEM(kConstructedBitString));
- EXPECT_FALSE(CertFromPEM(kConstructedOctetString));
- // Indefinite lengths are forbidden in DER.
- EXPECT_FALSE(CertFromPEM(kIndefiniteLength));
- // Padding bits in BIT STRINGs must be zero in BER.
- EXPECT_FALSE(CertFromPEM(kNonZeroPadding));
-}
-
-TEST(X509Test, Names) {
- bssl::UniquePtr<EVP_PKEY> key = PrivateKeyFromPEM(kP256Key);
- ASSERT_TRUE(key);
- bssl::UniquePtr<X509> root =
- MakeTestCert("Root", "Root", key.get(), /*is_ca=*/true);
- ASSERT_TRUE(root);
- ASSERT_TRUE(X509_sign(root.get(), key.get(), EVP_sha256()));
-
- struct {
- std::vector<std::pair<int, std::string>> cert_subject;
- std::vector<std::string> cert_dns_names;
- std::vector<std::string> cert_emails;
- std::vector<std::string> valid_dns_names;
- std::vector<std::string> invalid_dns_names;
- std::vector<std::string> valid_emails;
- std::vector<std::string> invalid_emails;
- unsigned flags;
- } kTests[] = {
- // DNS names only match DNS names and do so case-insensitively.
- {
- /*cert_subject=*/{},
- /*cert_dns_names=*/{"example.com", "WWW.EXAMPLE.COM"},
- /*cert_emails=*/{},
- /*valid_dns_names=*/
- {"example.com", "EXAMPLE.COM", "www.example.com", "WWW.EXAMPLE.COM"},
- /*invalid_dns_names=*/{"test.example.com", "example.org"},
- /*valid_emails=*/{},
- /*invalid_emails=*/{"test@example.com", "example.com"},
- /*flags=*/0,
- },
-
- // DNS wildcards match exactly one component.
- {
- /*cert_subject=*/{},
- /*cert_dns_names=*/{"*.example.com", "*.EXAMPLE.ORG"},
- /*cert_emails=*/{},
- /*valid_dns_names=*/
- {"www.example.com", "WWW.EXAMPLE.COM", "www.example.org",
- "WWW.EXAMPLE.ORG"},
- /*invalid_dns_names=*/{"example.com", "test.www.example.com"},
- /*valid_emails=*/{},
- /*invalid_emails=*/{"test@example.com", "www.example.com"},
- /*flags=*/0,
- },
-
- // DNS wildcards can be disabled.
- // TODO(davidben): Can we remove this feature? Does anyone use it?
- {
- /*cert_subject=*/{},
- /*cert_dns_names=*/{"example.com", "*.example.com"},
- /*cert_emails=*/{},
- /*valid_dns_names=*/{"example.com"},
- /*invalid_dns_names=*/{"www.example.com"},
- /*valid_emails=*/{},
- /*invalid_emails=*/{},
- /*flags=*/X509_CHECK_FLAG_NO_WILDCARDS,
- },
-
- // Invalid DNS wildcards do not match.
- {
- /*cert_subject=*/{},
- /*cert_dns_names=*/
- {"a.*", "**.b.example", "*c.example", "d*.example", "e*e.example",
- "*", ".", "..", "*."},
- /*cert_emails=*/{},
- /*valid_dns_names=*/{},
- /*invalid_dns_names=*/
- {"a.example", "test.b.example", "cc.example", "dd.example",
- "eee.example", "f", "g."},
- /*valid_emails=*/{},
- /*invalid_emails=*/{},
- /*flags=*/0,
- },
-
- // IDNs match like any other DNS labels.
- {
- /*cert_subject=*/{},
- /*cert_dns_names=*/
- {"xn--rger-koa.a.example", "*.xn--rger-koa.b.example",
- "www.xn--rger-koa.c.example"},
- /*cert_emails=*/{},
- /*valid_dns_names=*/
- {"xn--rger-koa.a.example", "www.xn--rger-koa.b.example",
- "www.xn--rger-koa.c.example"},
- /*invalid_dns_names=*/
- {"www.xn--rger-koa.a.example", "xn--rger-koa.b.example",
- "www.xn--rger-koa.d.example"},
- /*valid_emails=*/{},
- /*invalid_emails=*/{},
- /*flags=*/0,
- },
-
- // For now, DNS names are also extracted out of the common name, but only
- // there is no SAN list.
- // TODO(https://crbug.com/boringssl/464): Remove this.
- {
- /*cert_subject=*/{{NID_commonName, "a.example"},
- {NID_commonName, "*.b.example"}},
- /*cert_dns_names=*/{},
- /*cert_emails=*/{},
- /*valid_dns_names=*/
- {"a.example", "A.EXAMPLE", "test.b.example", "TEST.B.EXAMPLE"},
- /*invalid_dns_names=*/{},
- /*valid_emails=*/{},
- /*invalid_emails=*/{},
- /*flags=*/0,
- },
- {
- /*cert_subject=*/{{NID_commonName, "a.example"},
- {NID_commonName, "*.b.example"}},
- /*cert_dns_names=*/{"example.com"},
- /*cert_emails=*/{},
- /*valid_dns_names=*/{},
- /*invalid_dns_names=*/
- {"a.example", "A.EXAMPLE", "test.b.example", "TEST.B.EXAMPLE"},
- /*valid_emails=*/{},
- /*invalid_emails=*/{},
- /*flags=*/0,
- },
-
- // Other subject RDNs do not provide DNS names.
- {
- /*cert_subject=*/{{NID_organizationName, "example.com"}},
- /*cert_dns_names=*/{},
- /*cert_emails=*/{},
- /*valid_dns_names=*/{},
- /*invalid_dns_names=*/{"example.com"},
- /*valid_emails=*/{},
- /*invalid_emails=*/{},
- /*flags=*/0,
- },
-
- // Input DNS names cannot have wildcards.
- {
- /*cert_subject=*/{},
- /*cert_dns_names=*/{"www.example.com"},
- /*cert_emails=*/{},
- /*valid_dns_names=*/{},
- /*invalid_dns_names=*/{"*.example.com"},
- /*valid_emails=*/{},
- /*invalid_emails=*/{},
- /*flags=*/0,
- },
-
- // OpenSSL has some non-standard wildcard syntax for input DNS names. We
- // do not support this.
- {
- /*cert_subject=*/{},
- /*cert_dns_names=*/{"www.a.example", "*.b.test"},
- /*cert_emails=*/{},
- /*valid_dns_names=*/{},
- /*invalid_dns_names=*/
- {".www.a.example", ".www.b.test", ".a.example", ".b.test", ".example",
- ".test"},
- /*valid_emails=*/{},
- /*invalid_emails=*/{},
- /*flags=*/0,
- },
-
- // Emails match case-sensitively before the '@' and case-insensitively
- // after. They do not match DNS names.
- {
- /*cert_subject=*/{},
- /*cert_dns_names=*/{},
- /*cert_emails=*/{"test@a.example", "TEST@B.EXAMPLE"},
- /*valid_dns_names=*/{},
- /*invalid_dns_names=*/{"a.example", "b.example"},
- /*valid_emails=*/
- {"test@a.example", "test@A.EXAMPLE", "TEST@b.example",
- "TEST@B.EXAMPLE"},
- /*invalid_emails=*/
- {"TEST@a.example", "test@B.EXAMPLE", "another-test@a.example",
- "est@a.example"},
- /*flags=*/0,
- },
-
- // Emails may also be found in the subject.
- {
- /*cert_subject=*/{{NID_pkcs9_emailAddress, "test@a.example"},
- {NID_pkcs9_emailAddress, "TEST@B.EXAMPLE"}},
- /*cert_dns_names=*/{},
- /*cert_emails=*/{},
- /*valid_dns_names=*/{},
- /*invalid_dns_names=*/{"a.example", "b.example"},
- /*valid_emails=*/
- {"test@a.example", "test@A.EXAMPLE", "TEST@b.example",
- "TEST@B.EXAMPLE"},
- /*invalid_emails=*/
- {"TEST@a.example", "test@B.EXAMPLE", "another-test@a.example",
- "est@a.example"},
- /*flags=*/0,
- },
-
- // There are no email wildcard names.
- {
- /*cert_subject=*/{},
- /*cert_dns_names=*/{},
- /*cert_emails=*/{"test@*.a.example", "@b.example", "*@c.example"},
- /*valid_dns_names=*/{},
- /*invalid_dns_names=*/{},
- /*valid_emails=*/{},
- /*invalid_emails=*/
- {"test@test.a.example", "test@b.example", "test@c.example"},
- /*flags=*/0,
- },
-
- // Unrelated RDNs can be skipped when looking in the subject.
- {
- /*cert_subject=*/{{NID_organizationName, "Acme Corporation"},
- {NID_commonName, "a.example"},
- {NID_pkcs9_emailAddress, "test@b.example"},
- {NID_countryName, "US"}},
- /*cert_dns_names=*/{},
- /*cert_emails=*/{},
- /*valid_dns_names=*/{"a.example"},
- /*invalid_dns_names=*/{},
- /*valid_emails=*/{"test@b.example"},
- /*invalid_emails=*/{},
- /*flags=*/0,
- },
- };
-
- size_t i = 0;
- for (const auto &t : kTests) {
- SCOPED_TRACE(i++);
-
- // Issue a test certificate.
- bssl::UniquePtr<X509> cert =
- MakeTestCert("Root", "Leaf", key.get(), /*is_ca=*/false);
- ASSERT_TRUE(cert);
- if (!t.cert_subject.empty()) {
- bssl::UniquePtr<X509_NAME> subject(X509_NAME_new());
- ASSERT_TRUE(subject);
- for (const auto &entry : t.cert_subject) {
- ASSERT_TRUE(X509_NAME_add_entry_by_NID(
- subject.get(), entry.first, MBSTRING_ASC,
- reinterpret_cast<const unsigned char *>(entry.second.data()),
- entry.second.size(), /*loc=*/-1, /*set=*/0));
- }
- ASSERT_TRUE(X509_set_subject_name(cert.get(), subject.get()));
- }
- bssl::UniquePtr<GENERAL_NAMES> sans(sk_GENERAL_NAME_new_null());
- ASSERT_TRUE(sans);
- for (const auto &dns : t.cert_dns_names) {
- bssl::UniquePtr<GENERAL_NAME> name(GENERAL_NAME_new());
- ASSERT_TRUE(name);
- name->type = GEN_DNS;
- name->d.dNSName = ASN1_IA5STRING_new();
- ASSERT_TRUE(name->d.dNSName);
- ASSERT_TRUE(ASN1_STRING_set(name->d.dNSName, dns.data(), dns.size()));
- ASSERT_TRUE(bssl::PushToStack(sans.get(), std::move(name)));
- }
- for (const auto &email : t.cert_emails) {
- bssl::UniquePtr<GENERAL_NAME> name(GENERAL_NAME_new());
- ASSERT_TRUE(name);
- name->type = GEN_EMAIL;
- name->d.rfc822Name = ASN1_IA5STRING_new();
- ASSERT_TRUE(name->d.rfc822Name);
- ASSERT_TRUE(
- ASN1_STRING_set(name->d.rfc822Name, email.data(), email.size()));
- ASSERT_TRUE(bssl::PushToStack(sans.get(), std::move(name)));
- }
- if (sk_GENERAL_NAME_num(sans.get()) != 0) {
- ASSERT_TRUE(X509_add1_ext_i2d(cert.get(), NID_subject_alt_name,
- sans.get(), /*crit=*/0, /*flags=*/0));
- }
- ASSERT_TRUE(X509_sign(cert.get(), key.get(), EVP_sha256()));
-
- for (const auto &dns : t.valid_dns_names) {
- SCOPED_TRACE(dns);
- EXPECT_EQ(1, X509_check_host(cert.get(), dns.data(), dns.size(), t.flags,
- /*peername=*/nullptr));
- EXPECT_EQ(X509_V_OK,
- Verify(cert.get(), {root.get()}, /*intermediates=*/{},
- /*crls=*/{}, /*flags=*/0, [&](X509_VERIFY_PARAM *param) {
- ASSERT_TRUE(X509_VERIFY_PARAM_set1_host(
- param, dns.data(), dns.size()));
- X509_VERIFY_PARAM_set_hostflags(param, t.flags);
- }));
- }
-
- for (const auto &dns : t.invalid_dns_names) {
- SCOPED_TRACE(dns);
- EXPECT_EQ(0, X509_check_host(cert.get(), dns.data(), dns.size(), t.flags,
- /*peername=*/nullptr));
- EXPECT_EQ(X509_V_ERR_HOSTNAME_MISMATCH,
- Verify(cert.get(), {root.get()}, /*intermediates=*/{},
- /*crls=*/{}, /*flags=*/0, [&](X509_VERIFY_PARAM *param) {
- ASSERT_TRUE(X509_VERIFY_PARAM_set1_host(
- param, dns.data(), dns.size()));
- X509_VERIFY_PARAM_set_hostflags(param, t.flags);
- }));
- }
-
- for (const auto &email : t.valid_emails) {
- SCOPED_TRACE(email);
- EXPECT_EQ(
- 1, X509_check_email(cert.get(), email.data(), email.size(), t.flags));
- EXPECT_EQ(X509_V_OK,
- Verify(cert.get(), {root.get()}, /*intermediates=*/{},
- /*crls=*/{}, /*flags=*/0, [&](X509_VERIFY_PARAM *param) {
- ASSERT_TRUE(X509_VERIFY_PARAM_set1_email(
- param, email.data(), email.size()));
- X509_VERIFY_PARAM_set_hostflags(param, t.flags);
- }));
- }
-
- for (const auto &email : t.invalid_emails) {
- SCOPED_TRACE(email);
- EXPECT_EQ(
- 0, X509_check_email(cert.get(), email.data(), email.size(), t.flags));
- EXPECT_EQ(X509_V_ERR_EMAIL_MISMATCH,
- Verify(cert.get(), {root.get()}, /*intermediates=*/{},
- /*crls=*/{}, /*flags=*/0, [&](X509_VERIFY_PARAM *param) {
- ASSERT_TRUE(X509_VERIFY_PARAM_set1_email(
- param, email.data(), email.size()));
- X509_VERIFY_PARAM_set_hostflags(param, t.flags);
- }));
- }
- }
-}
-
TEST(X509Test, AddDuplicates) {
bssl::UniquePtr<X509_STORE> store(X509_STORE_new());
bssl::UniquePtr<X509> a(CertFromPEM(kCrossSigningRootPEM));