blob: c9e25c11acda74850ea9b11d61b068f5f0fc9c5a [file] [log] [blame]
// 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 <algorithm>
#include <gtest/gtest.h>
#include <openssl/pool.h>
#include "cert_errors.h"
#include "cert_issuer_source.h"
#include "test_helpers.h"
namespace bssl {
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<const ParsedCertificate> *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>(CRYPTO_BUFFER_new(
reinterpret_cast<const uint8_t *>(der.data()), der.size(), nullptr)),
{}, &errors);
if (!*result) {
return ::testing::AssertionFailure()
<< "ParsedCertificate::Create() failed:\n"
<< errors.ToDebugString();
}
return ::testing::AssertionSuccess();
}
} // namespace
template <typename TestDelegate>
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<const ParsedCertificate> 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<const ParsedCertificate> cert,
ParsedCertificateList expected_matches) {
ParsedCertificateList matches;
source().SyncGetIssuersOf(cert.get(), &matches);
std::vector<der::Input> 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::Input> 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<const ParsedCertificate> root_;
std::shared_ptr<const ParsedCertificate> i1_1_;
std::shared_ptr<const ParsedCertificate> i1_2_;
std::shared_ptr<const ParsedCertificate> i2_;
std::shared_ptr<const ParsedCertificate> i3_1_;
std::shared_ptr<const ParsedCertificate> i3_2_;
std::shared_ptr<const ParsedCertificate> c1_;
std::shared_ptr<const ParsedCertificate> c2_;
std::shared_ptr<const ParsedCertificate> d_;
std::shared_ptr<const ParsedCertificate> e1_;
std::shared_ptr<const ParsedCertificate> 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<CertIssuerSource::Request> 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 <typename TestDelegate>
class CertIssuerSourceSyncNormalizationTest
: public CertIssuerSourceSyncTest<TestDelegate> {};
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 <typename TestDelegate>
class CertIssuerSourceSyncNotNormalizedTest
: public CertIssuerSourceSyncTest<TestDelegate> {};
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);
} // namespace bssl
#endif // BSSL_PKI_CERT_ISSUER_SOURCE_SYNC_UNITTEST_H_