1 // Copyright 2016 The Chromium Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef BSSL_PKI_CERT_ISSUER_SOURCE_SYNC_UNITTEST_H_
16 #define BSSL_PKI_CERT_ISSUER_SOURCE_SYNC_UNITTEST_H_
17 
18 #include <algorithm>
19 
20 #include <gtest/gtest.h>
21 #include <openssl/pool.h>
22 #include "cert_errors.h"
23 #include "cert_issuer_source.h"
24 #include "test_helpers.h"
25 
26 BSSL_NAMESPACE_BEGIN
27 
28 namespace {
29 
ReadTestPem(const std::string & file_name,const std::string & block_name,std::string * result)30 ::testing::AssertionResult ReadTestPem(const std::string &file_name,
31                                        const std::string &block_name,
32                                        std::string *result) {
33   const PemBlockMapping mappings[] = {
34       {block_name.c_str(), result},
35   };
36 
37   return ReadTestDataFromPemFile(file_name, mappings);
38 }
39 
ReadTestCert(const std::string & file_name,std::shared_ptr<const ParsedCertificate> * result)40 ::testing::AssertionResult ReadTestCert(
41     const std::string &file_name,
42     std::shared_ptr<const ParsedCertificate> *result) {
43   std::string der;
44   ::testing::AssertionResult r =
45       ReadTestPem("testdata/cert_issuer_source_static_unittest/" + file_name,
46                   "CERTIFICATE", &der);
47   if (!r) {
48     return r;
49   }
50   CertErrors errors;
51   *result = ParsedCertificate::Create(
52       bssl::UniquePtr<CRYPTO_BUFFER>(CRYPTO_BUFFER_new(
53           reinterpret_cast<const uint8_t *>(der.data()), der.size(), nullptr)),
54       {}, &errors);
55   if (!*result) {
56     return ::testing::AssertionFailure()
57            << "ParsedCertificate::Create() failed:\n"
58            << errors.ToDebugString();
59   }
60   return ::testing::AssertionSuccess();
61 }
62 
63 }  // namespace
64 
65 template <typename TestDelegate>
66 class CertIssuerSourceSyncTest : public ::testing::Test {
67  public:
SetUp()68   void SetUp() override {
69     ASSERT_TRUE(ReadTestCert("root.pem", &root_));
70     ASSERT_TRUE(ReadTestCert("i1_1.pem", &i1_1_));
71     ASSERT_TRUE(ReadTestCert("i1_2.pem", &i1_2_));
72     ASSERT_TRUE(ReadTestCert("i2.pem", &i2_));
73     ASSERT_TRUE(ReadTestCert("i3_1.pem", &i3_1_));
74     ASSERT_TRUE(ReadTestCert("i3_2.pem", &i3_2_));
75     ASSERT_TRUE(ReadTestCert("c1.pem", &c1_));
76     ASSERT_TRUE(ReadTestCert("c2.pem", &c2_));
77     ASSERT_TRUE(ReadTestCert("d.pem", &d_));
78     ASSERT_TRUE(ReadTestCert("e1.pem", &e1_));
79     ASSERT_TRUE(ReadTestCert("e2.pem", &e2_));
80   }
81 
AddCert(std::shared_ptr<const ParsedCertificate> cert)82   void AddCert(std::shared_ptr<const ParsedCertificate> cert) {
83     delegate_.AddCert(std::move(cert));
84   }
85 
AddAllCerts()86   void AddAllCerts() {
87     AddCert(root_);
88     AddCert(i1_1_);
89     AddCert(i1_2_);
90     AddCert(i2_);
91     AddCert(i3_1_);
92     AddCert(i3_2_);
93     AddCert(c1_);
94     AddCert(c2_);
95     AddCert(d_);
96     AddCert(e1_);
97     AddCert(e2_);
98   }
99 
source()100   CertIssuerSource &source() { return delegate_.source(); }
101 
102  protected:
IssuersMatch(std::shared_ptr<const ParsedCertificate> cert,ParsedCertificateList expected_matches)103   bool IssuersMatch(std::shared_ptr<const ParsedCertificate> cert,
104                     ParsedCertificateList expected_matches) {
105     ParsedCertificateList matches;
106     source().SyncGetIssuersOf(cert.get(), &matches);
107 
108     std::vector<der::Input> der_result_matches;
109     for (const auto &it : matches) {
110       der_result_matches.push_back(it->der_cert());
111     }
112     std::sort(der_result_matches.begin(), der_result_matches.end());
113 
114     std::vector<der::Input> der_expected_matches;
115     for (const auto &it : expected_matches) {
116       der_expected_matches.push_back(it->der_cert());
117     }
118     std::sort(der_expected_matches.begin(), der_expected_matches.end());
119 
120     if (der_expected_matches == der_result_matches) {
121       return true;
122     }
123 
124     // Print some extra information for debugging.
125     EXPECT_EQ(der_expected_matches, der_result_matches);
126     return false;
127   }
128 
129   TestDelegate delegate_;
130   std::shared_ptr<const ParsedCertificate> root_;
131   std::shared_ptr<const ParsedCertificate> i1_1_;
132   std::shared_ptr<const ParsedCertificate> i1_2_;
133   std::shared_ptr<const ParsedCertificate> i2_;
134   std::shared_ptr<const ParsedCertificate> i3_1_;
135   std::shared_ptr<const ParsedCertificate> i3_2_;
136   std::shared_ptr<const ParsedCertificate> c1_;
137   std::shared_ptr<const ParsedCertificate> c2_;
138   std::shared_ptr<const ParsedCertificate> d_;
139   std::shared_ptr<const ParsedCertificate> e1_;
140   std::shared_ptr<const ParsedCertificate> e2_;
141 };
142 
143 TYPED_TEST_SUITE_P(CertIssuerSourceSyncTest);
144 
TYPED_TEST_P(CertIssuerSourceSyncTest,NoMatch)145 TYPED_TEST_P(CertIssuerSourceSyncTest, NoMatch) {
146   this->AddCert(this->root_);
147 
148   EXPECT_TRUE(this->IssuersMatch(this->c1_, ParsedCertificateList()));
149 }
150 
TYPED_TEST_P(CertIssuerSourceSyncTest,OneMatch)151 TYPED_TEST_P(CertIssuerSourceSyncTest, OneMatch) {
152   this->AddAllCerts();
153 
154   EXPECT_TRUE(this->IssuersMatch(this->i1_1_, {this->root_}));
155   EXPECT_TRUE(this->IssuersMatch(this->d_, {this->i2_}));
156 }
157 
TYPED_TEST_P(CertIssuerSourceSyncTest,MultipleMatches)158 TYPED_TEST_P(CertIssuerSourceSyncTest, MultipleMatches) {
159   this->AddAllCerts();
160 
161   EXPECT_TRUE(this->IssuersMatch(this->e1_, {this->i3_1_, this->i3_2_}));
162   EXPECT_TRUE(this->IssuersMatch(this->e2_, {this->i3_1_, this->i3_2_}));
163 }
164 
165 // Searching for the issuer of a self-issued cert returns the same cert if it
166 // happens to be in the CertIssuerSourceStatic.
167 // Conceptually this makes sense, though probably not very useful in practice.
168 // Doesn't hurt anything though.
TYPED_TEST_P(CertIssuerSourceSyncTest,SelfIssued)169 TYPED_TEST_P(CertIssuerSourceSyncTest, SelfIssued) {
170   this->AddAllCerts();
171 
172   EXPECT_TRUE(this->IssuersMatch(this->root_, {this->root_}));
173 }
174 
175 // CertIssuerSourceStatic never returns results asynchronously.
TYPED_TEST_P(CertIssuerSourceSyncTest,IsNotAsync)176 TYPED_TEST_P(CertIssuerSourceSyncTest, IsNotAsync) {
177   this->AddCert(this->i1_1_);
178   std::unique_ptr<CertIssuerSource::Request> request;
179   this->source().AsyncGetIssuersOf(this->c1_.get(), &request);
180   EXPECT_EQ(nullptr, request);
181 }
182 
183 // These are all the tests that should have the same result with or without
184 // normalization.
185 REGISTER_TYPED_TEST_SUITE_P(CertIssuerSourceSyncTest, NoMatch, OneMatch,
186                             MultipleMatches, SelfIssued, IsNotAsync);
187 
188 template <typename TestDelegate>
189 class CertIssuerSourceSyncNormalizationTest
190     : public CertIssuerSourceSyncTest<TestDelegate> {};
191 TYPED_TEST_SUITE_P(CertIssuerSourceSyncNormalizationTest);
192 
TYPED_TEST_P(CertIssuerSourceSyncNormalizationTest,MultipleMatchesAfterNormalization)193 TYPED_TEST_P(CertIssuerSourceSyncNormalizationTest,
194              MultipleMatchesAfterNormalization) {
195   this->AddAllCerts();
196 
197   EXPECT_TRUE(this->IssuersMatch(this->c1_, {this->i1_1_, this->i1_2_}));
198   EXPECT_TRUE(this->IssuersMatch(this->c2_, {this->i1_1_, this->i1_2_}));
199 }
200 
201 // These tests require (utf8) normalization.
202 REGISTER_TYPED_TEST_SUITE_P(CertIssuerSourceSyncNormalizationTest,
203                             MultipleMatchesAfterNormalization);
204 
205 template <typename TestDelegate>
206 class CertIssuerSourceSyncNotNormalizedTest
207     : public CertIssuerSourceSyncTest<TestDelegate> {};
208 TYPED_TEST_SUITE_P(CertIssuerSourceSyncNotNormalizedTest);
209 
TYPED_TEST_P(CertIssuerSourceSyncNotNormalizedTest,OneMatchWithoutNormalization)210 TYPED_TEST_P(CertIssuerSourceSyncNotNormalizedTest,
211              OneMatchWithoutNormalization) {
212   this->AddAllCerts();
213 
214   // Without normalization c1 and c2 should at least be able to find their
215   // exact matching issuer. (c1 should match i1_1, and c2 should match i1_2.)
216   EXPECT_TRUE(this->IssuersMatch(this->c1_, {this->i1_1_}));
217   EXPECT_TRUE(this->IssuersMatch(this->c2_, {this->i1_2_}));
218 }
219 
220 // These tests are for implementations which do not do utf8 normalization.
221 REGISTER_TYPED_TEST_SUITE_P(CertIssuerSourceSyncNotNormalizedTest,
222                             OneMatchWithoutNormalization);
223 
224 BSSL_NAMESPACE_END
225 
226 #endif  // BSSL_PKI_CERT_ISSUER_SOURCE_SYNC_UNITTEST_H_
227