diff options
author | Presubmit Automerger Backend <android-build-presubmit-automerger-backend@system.gserviceaccount.com> | 2022-03-25 05:28:56 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-03-25 05:28:56 +0000 |
commit | cd5eb94cfe014142d8ff7668bfc5c13871a2f4e7 (patch) | |
tree | dbcb1494b9b07eb4e40c0114864783b0aede0257 | |
parent | a280eaba3c661506d1067f6e52125934ea8fb862 (diff) | |
parent | 1159a80f83a7b41b34048d8c7908c2b694e1d32b (diff) | |
download | boringssl-cd5eb94cfe014142d8ff7668bfc5c13871a2f4e7.tar.gz |
[conflict] Ignore duplicates in |X509_STORE_add_*| 2p: 847f79794d am: 1159a80f83
Original change: https://googleplex-android-review.googlesource.com/c/platform/external/boringssl/+/17343103
Change-Id: I25a76de8a1845c9a56a3f5057b8468a4b8a6417b
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r-- | src/crypto/x509/x509_test.cc | 636 |
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, ¶m_type, ¶m_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(), ¶m_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)); |