// Copyright 2016 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BSSL_PKI_CERT_ISSUER_SOURCE_SYNC_UNITTEST_H_ #define BSSL_PKI_CERT_ISSUER_SOURCE_SYNC_UNITTEST_H_ #include #include #include #include "cert_errors.h" #include "cert_issuer_source.h" #include "test_helpers.h" BSSL_NAMESPACE_BEGIN namespace { ::testing::AssertionResult ReadTestPem(const std::string &file_name, const std::string &block_name, std::string *result) { const PemBlockMapping mappings[] = { {block_name.c_str(), result}, }; return ReadTestDataFromPemFile(file_name, mappings); } ::testing::AssertionResult ReadTestCert( const std::string &file_name, std::shared_ptr *result) { std::string der; ::testing::AssertionResult r = ReadTestPem("testdata/cert_issuer_source_static_unittest/" + file_name, "CERTIFICATE", &der); if (!r) { return r; } CertErrors errors; *result = ParsedCertificate::Create( bssl::UniquePtr(CRYPTO_BUFFER_new( reinterpret_cast(der.data()), der.size(), nullptr)), {}, &errors); if (!*result) { return ::testing::AssertionFailure() << "ParsedCertificate::Create() failed:\n" << errors.ToDebugString(); } return ::testing::AssertionSuccess(); } } // namespace template class CertIssuerSourceSyncTest : public ::testing::Test { public: void SetUp() override { ASSERT_TRUE(ReadTestCert("root.pem", &root_)); ASSERT_TRUE(ReadTestCert("i1_1.pem", &i1_1_)); ASSERT_TRUE(ReadTestCert("i1_2.pem", &i1_2_)); ASSERT_TRUE(ReadTestCert("i2.pem", &i2_)); ASSERT_TRUE(ReadTestCert("i3_1.pem", &i3_1_)); ASSERT_TRUE(ReadTestCert("i3_2.pem", &i3_2_)); ASSERT_TRUE(ReadTestCert("c1.pem", &c1_)); ASSERT_TRUE(ReadTestCert("c2.pem", &c2_)); ASSERT_TRUE(ReadTestCert("d.pem", &d_)); ASSERT_TRUE(ReadTestCert("e1.pem", &e1_)); ASSERT_TRUE(ReadTestCert("e2.pem", &e2_)); } void AddCert(std::shared_ptr cert) { delegate_.AddCert(std::move(cert)); } void AddAllCerts() { AddCert(root_); AddCert(i1_1_); AddCert(i1_2_); AddCert(i2_); AddCert(i3_1_); AddCert(i3_2_); AddCert(c1_); AddCert(c2_); AddCert(d_); AddCert(e1_); AddCert(e2_); } CertIssuerSource &source() { return delegate_.source(); } protected: bool IssuersMatch(std::shared_ptr cert, ParsedCertificateList expected_matches) { ParsedCertificateList matches; source().SyncGetIssuersOf(cert.get(), &matches); std::vector der_result_matches; for (const auto &it : matches) { der_result_matches.push_back(it->der_cert()); } std::sort(der_result_matches.begin(), der_result_matches.end()); std::vector der_expected_matches; for (const auto &it : expected_matches) { der_expected_matches.push_back(it->der_cert()); } std::sort(der_expected_matches.begin(), der_expected_matches.end()); if (der_expected_matches == der_result_matches) { return true; } // Print some extra information for debugging. EXPECT_EQ(der_expected_matches, der_result_matches); return false; } TestDelegate delegate_; std::shared_ptr root_; std::shared_ptr i1_1_; std::shared_ptr i1_2_; std::shared_ptr i2_; std::shared_ptr i3_1_; std::shared_ptr i3_2_; std::shared_ptr c1_; std::shared_ptr c2_; std::shared_ptr d_; std::shared_ptr e1_; std::shared_ptr e2_; }; TYPED_TEST_SUITE_P(CertIssuerSourceSyncTest); TYPED_TEST_P(CertIssuerSourceSyncTest, NoMatch) { this->AddCert(this->root_); EXPECT_TRUE(this->IssuersMatch(this->c1_, ParsedCertificateList())); } TYPED_TEST_P(CertIssuerSourceSyncTest, OneMatch) { this->AddAllCerts(); EXPECT_TRUE(this->IssuersMatch(this->i1_1_, {this->root_})); EXPECT_TRUE(this->IssuersMatch(this->d_, {this->i2_})); } TYPED_TEST_P(CertIssuerSourceSyncTest, MultipleMatches) { this->AddAllCerts(); EXPECT_TRUE(this->IssuersMatch(this->e1_, {this->i3_1_, this->i3_2_})); EXPECT_TRUE(this->IssuersMatch(this->e2_, {this->i3_1_, this->i3_2_})); } // Searching for the issuer of a self-issued cert returns the same cert if it // happens to be in the CertIssuerSourceStatic. // Conceptually this makes sense, though probably not very useful in practice. // Doesn't hurt anything though. TYPED_TEST_P(CertIssuerSourceSyncTest, SelfIssued) { this->AddAllCerts(); EXPECT_TRUE(this->IssuersMatch(this->root_, {this->root_})); } // CertIssuerSourceStatic never returns results asynchronously. TYPED_TEST_P(CertIssuerSourceSyncTest, IsNotAsync) { this->AddCert(this->i1_1_); std::unique_ptr request; this->source().AsyncGetIssuersOf(this->c1_.get(), &request); EXPECT_EQ(nullptr, request); } // These are all the tests that should have the same result with or without // normalization. REGISTER_TYPED_TEST_SUITE_P(CertIssuerSourceSyncTest, NoMatch, OneMatch, MultipleMatches, SelfIssued, IsNotAsync); template class CertIssuerSourceSyncNormalizationTest : public CertIssuerSourceSyncTest {}; TYPED_TEST_SUITE_P(CertIssuerSourceSyncNormalizationTest); TYPED_TEST_P(CertIssuerSourceSyncNormalizationTest, MultipleMatchesAfterNormalization) { this->AddAllCerts(); EXPECT_TRUE(this->IssuersMatch(this->c1_, {this->i1_1_, this->i1_2_})); EXPECT_TRUE(this->IssuersMatch(this->c2_, {this->i1_1_, this->i1_2_})); } // These tests require (utf8) normalization. REGISTER_TYPED_TEST_SUITE_P(CertIssuerSourceSyncNormalizationTest, MultipleMatchesAfterNormalization); template class CertIssuerSourceSyncNotNormalizedTest : public CertIssuerSourceSyncTest {}; TYPED_TEST_SUITE_P(CertIssuerSourceSyncNotNormalizedTest); TYPED_TEST_P(CertIssuerSourceSyncNotNormalizedTest, OneMatchWithoutNormalization) { this->AddAllCerts(); // Without normalization c1 and c2 should at least be able to find their // exact matching issuer. (c1 should match i1_1, and c2 should match i1_2.) EXPECT_TRUE(this->IssuersMatch(this->c1_, {this->i1_1_})); EXPECT_TRUE(this->IssuersMatch(this->c2_, {this->i1_2_})); } // These tests are for implementations which do not do utf8 normalization. REGISTER_TYPED_TEST_SUITE_P(CertIssuerSourceSyncNotNormalizedTest, OneMatchWithoutNormalization); BSSL_NAMESPACE_END #endif // BSSL_PKI_CERT_ISSUER_SOURCE_SYNC_UNITTEST_H_