1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/cert/internal/trust_store_chrome.h"
6
7 #include "base/containers/span.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_util.h"
10 #include "crypto/sha2.h"
11 #include "net/cert/x509_certificate.h"
12 #include "net/cert/x509_util.h"
13 #include "net/test/cert_builder.h"
14 #include "net/test/cert_test_util.h"
15 #include "net/test/test_data_directory.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "third_party/boringssl/src/pki/cert_errors.h"
19 #include "third_party/boringssl/src/pki/parsed_certificate.h"
20
21 namespace net {
22 namespace {
23
24 #include "net/data/ssl/chrome_root_store/chrome-root-store-test-data-inc.cc"
25
ToParsedCertificate(const X509Certificate & cert)26 std::shared_ptr<const bssl::ParsedCertificate> ToParsedCertificate(
27 const X509Certificate& cert) {
28 bssl::CertErrors errors;
29 std::shared_ptr<const bssl::ParsedCertificate> parsed =
30 bssl::ParsedCertificate::Create(
31 bssl::UpRef(cert.cert_buffer()),
32 x509_util::DefaultParseCertificateOptions(), &errors);
33 EXPECT_TRUE(parsed) << errors.ToDebugString();
34 return parsed;
35 }
36
MakeTestRoot()37 scoped_refptr<X509Certificate> MakeTestRoot() {
38 auto builder = std::make_unique<CertBuilder>(nullptr, nullptr);
39 auto now = base::Time::Now();
40 builder->SetValidity(now - base::Days(1), now + base::Days(1));
41 builder->SetBasicConstraints(/*is_ca=*/true, /*path_len=*/-1);
42 builder->SetKeyUsages(
43 {bssl::KEY_USAGE_BIT_KEY_CERT_SIGN, bssl::KEY_USAGE_BIT_CRL_SIGN});
44 return builder->GetX509Certificate();
45 }
46
TEST(TrustStoreChromeTestNoFixture,ContainsCert)47 TEST(TrustStoreChromeTestNoFixture, ContainsCert) {
48 std::unique_ptr<TrustStoreChrome> trust_store_chrome =
49 TrustStoreChrome::CreateTrustStoreForTesting(
50 base::span<const ChromeRootCertInfo>(kChromeRootCertList),
51 /*version=*/1);
52
53 // Check every certificate in test_store.certs is included.
54 CertificateList certs = CreateCertificateListFromFile(
55 GetTestNetDataDirectory().AppendASCII("ssl/chrome_root_store"),
56 "test_store.certs", X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
57 ASSERT_EQ(certs.size(), 2u);
58
59 for (const auto& cert : certs) {
60 std::shared_ptr<const bssl::ParsedCertificate> parsed =
61 ToParsedCertificate(*cert);
62 ASSERT_TRUE(trust_store_chrome->Contains(parsed.get()));
63 bssl::CertificateTrust trust = trust_store_chrome->GetTrust(parsed.get());
64 EXPECT_EQ(bssl::CertificateTrust::ForTrustAnchor().ToDebugString(),
65 trust.ToDebugString());
66 }
67
68 // Other certificates should not be included. Which test cert used here isn't
69 // important as long as it isn't one of the certificates in the
70 // chrome_root_store/test_store.certs.
71 scoped_refptr<X509Certificate> other_cert =
72 ImportCertFromFile(GetTestCertsDirectory(), "root_ca_cert.pem");
73 ASSERT_TRUE(other_cert);
74 std::shared_ptr<const bssl::ParsedCertificate> other_parsed =
75 ToParsedCertificate(*other_cert);
76 ASSERT_FALSE(trust_store_chrome->Contains(other_parsed.get()));
77 bssl::CertificateTrust trust =
78 trust_store_chrome->GetTrust(other_parsed.get());
79 EXPECT_EQ(bssl::CertificateTrust::ForUnspecified().ToDebugString(),
80 trust.ToDebugString());
81 }
82
TEST(TrustStoreChromeTestNoFixture,Constraints)83 TEST(TrustStoreChromeTestNoFixture, Constraints) {
84 std::unique_ptr<TrustStoreChrome> trust_store_chrome =
85 TrustStoreChrome::CreateTrustStoreForTesting(
86 base::span<const ChromeRootCertInfo>(kChromeRootCertList),
87 /*version=*/1);
88
89 const std::string kUnconstrainedCertHash =
90 "568d6905a2c88708a4b3025190edcfedb1974a606a13c6e5290fcb2ae63edab5";
91 const std::string kConstrainedCertHash =
92 "6b9c08e86eb0f767cfad65cd98b62149e5494a67f5845e7bd1ed019f27b86bd6";
93
94 std::shared_ptr<const bssl::ParsedCertificate> constrained_cert;
95 std::shared_ptr<const bssl::ParsedCertificate> unconstrained_cert;
96
97 CertificateList certs = CreateCertificateListFromFile(
98 GetTestNetDataDirectory().AppendASCII("ssl/chrome_root_store"),
99 "test_store.certs", X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
100 ASSERT_EQ(certs.size(), 2u);
101 for (const auto& cert : certs) {
102 std::shared_ptr<const bssl::ParsedCertificate> parsed =
103 ToParsedCertificate(*cert);
104 std::string sha256_hex = base::ToLowerASCII(
105 base::HexEncode(crypto::SHA256Hash(parsed->der_cert())));
106 if (sha256_hex == kConstrainedCertHash) {
107 constrained_cert = parsed;
108 } else if (sha256_hex == kUnconstrainedCertHash) {
109 unconstrained_cert = parsed;
110 }
111 }
112
113 ASSERT_TRUE(unconstrained_cert);
114 EXPECT_TRUE(
115 trust_store_chrome->GetConstraintsForCert(unconstrained_cert.get())
116 .empty());
117
118 ASSERT_TRUE(constrained_cert);
119 base::span<const ChromeRootCertConstraints> constraints =
120 trust_store_chrome->GetConstraintsForCert(constrained_cert.get());
121 ASSERT_EQ(constraints.size(), 3U);
122
123 EXPECT_FALSE(constraints[0].sct_all_after.has_value());
124 ASSERT_TRUE(constraints[0].sct_not_after.has_value());
125 EXPECT_EQ(
126 constraints[0].sct_not_after.value().InMillisecondsSinceUnixEpoch() /
127 1000,
128 0x5af);
129 EXPECT_FALSE(constraints[0].min_version.has_value());
130 ASSERT_TRUE(constraints[0].max_version_exclusive.has_value());
131 EXPECT_EQ(constraints[0].max_version_exclusive.value().components(),
132 std::vector<uint32_t>({125, 0, 6368, 2}));
133 EXPECT_THAT(constraints[0].permitted_dns_names,
134 testing::ElementsAre("foo.example.com", "bar.example.com"));
135
136 EXPECT_FALSE(constraints[1].sct_not_after.has_value());
137 ASSERT_TRUE(constraints[1].sct_all_after.has_value());
138 EXPECT_EQ(
139 constraints[1].sct_all_after.value().InMillisecondsSinceUnixEpoch() /
140 1000,
141 0x2579);
142 ASSERT_TRUE(constraints[1].min_version.has_value());
143 EXPECT_FALSE(constraints[1].max_version_exclusive.has_value());
144 EXPECT_EQ(constraints[1].min_version.value().components(),
145 std::vector<uint32_t>({128}));
146 EXPECT_TRUE(constraints[1].permitted_dns_names.empty());
147
148 EXPECT_THAT(constraints[2].permitted_dns_names,
149 testing::ElementsAre("baz.example.com"));
150
151 // Other certificates should return nullptr if they are queried for CRS
152 // constraints. Which test cert used here isn't important as long as it isn't
153 // one of the certificates in the chrome_root_store/test_store.certs.
154 scoped_refptr<X509Certificate> other_cert =
155 ImportCertFromFile(GetTestCertsDirectory(), "root_ca_cert.pem");
156 ASSERT_TRUE(other_cert);
157 std::shared_ptr<const bssl::ParsedCertificate> other_parsed =
158 ToParsedCertificate(*other_cert);
159 ASSERT_TRUE(other_parsed);
160 EXPECT_FALSE(trust_store_chrome->Contains(other_parsed.get()));
161 EXPECT_TRUE(
162 trust_store_chrome->GetConstraintsForCert(other_parsed.get()).empty());
163 }
164
TEST(TrustStoreChromeTestNoFixture,OverrideConstraints)165 TEST(TrustStoreChromeTestNoFixture, OverrideConstraints) {
166 // Root1: has no constraints and no override constraints
167 // Root2: has constraints and no override constraints
168 // Root3: has no constraints and has override constraints
169 // Root4: has constraints and has override constraints
170 // Root5: not present in CRS and no override constraints
171 // Root6: not present in CRS but has override constraints
172 scoped_refptr<X509Certificate> root1 = MakeTestRoot();
173 scoped_refptr<X509Certificate> root2 = MakeTestRoot();
174 scoped_refptr<X509Certificate> root3 = MakeTestRoot();
175 scoped_refptr<X509Certificate> root4 = MakeTestRoot();
176 scoped_refptr<X509Certificate> root5 = MakeTestRoot();
177 scoped_refptr<X509Certificate> root6 = MakeTestRoot();
178
179 std::vector<StaticChromeRootCertConstraints> c2 = {{.min_version = "20"}};
180 std::vector<StaticChromeRootCertConstraints> c4 = {{.min_version = "40"}};
181 std::vector<ChromeRootCertInfo> root_cert_info = {
182 {root1->cert_span(), {}},
183 {root2->cert_span(), c2},
184 {root3->cert_span(), {}},
185 {root4->cert_span(), c4},
186 };
187
188 base::flat_map<std::array<uint8_t, crypto::kSHA256Length>,
189 std::vector<ChromeRootCertConstraints>>
190 override_constraints;
191
192 override_constraints[crypto::SHA256Hash(root3->cert_span())] = {
193 {std::nullopt,
194 std::nullopt,
195 std::nullopt,
196 /*max_version_exclusive=*/std::make_optional(base::Version("31")),
197 {}}};
198
199 override_constraints[crypto::SHA256Hash(root4->cert_span())] = {
200 {std::nullopt,
201 std::nullopt,
202 std::nullopt,
203 /*max_version_exclusive=*/std::make_optional(base::Version("41")),
204 {}}};
205
206 override_constraints[crypto::SHA256Hash(root6->cert_span())] = {
207 {std::nullopt,
208 std::nullopt,
209 std::nullopt,
210 /*max_version_exclusive=*/std::make_optional(base::Version("61")),
211 {}}};
212
213 std::unique_ptr<TrustStoreChrome> trust_store_chrome =
214 TrustStoreChrome::CreateTrustStoreForTesting(
215 std::move(root_cert_info),
216 /*version=*/1, std::move(override_constraints));
217
218 {
219 std::shared_ptr<const bssl::ParsedCertificate> parsed =
220 ToParsedCertificate(*root1);
221 ASSERT_TRUE(parsed);
222 EXPECT_TRUE(trust_store_chrome->Contains(parsed.get()));
223 EXPECT_TRUE(
224 trust_store_chrome->GetConstraintsForCert(parsed.get()).empty());
225 }
226
227 {
228 std::shared_ptr<const bssl::ParsedCertificate> parsed =
229 ToParsedCertificate(*root2);
230 ASSERT_TRUE(parsed);
231 EXPECT_TRUE(trust_store_chrome->Contains(parsed.get()));
232
233 base::span<const ChromeRootCertConstraints> constraints =
234 trust_store_chrome->GetConstraintsForCert(parsed.get());
235 ASSERT_EQ(constraints.size(), 1U);
236 EXPECT_EQ(constraints[0].min_version.value().components(),
237 std::vector<uint32_t>({20}));
238 EXPECT_FALSE(constraints[0].max_version_exclusive.has_value());
239 }
240
241 {
242 std::shared_ptr<const bssl::ParsedCertificate> parsed =
243 ToParsedCertificate(*root3);
244 ASSERT_TRUE(parsed);
245 EXPECT_TRUE(trust_store_chrome->Contains(parsed.get()));
246
247 base::span<const ChromeRootCertConstraints> constraints =
248 trust_store_chrome->GetConstraintsForCert(parsed.get());
249 ASSERT_EQ(constraints.size(), 1U);
250 EXPECT_FALSE(constraints[0].min_version.has_value());
251 EXPECT_EQ(constraints[0].max_version_exclusive.value().components(),
252 std::vector<uint32_t>({31}));
253 }
254
255 {
256 std::shared_ptr<const bssl::ParsedCertificate> parsed =
257 ToParsedCertificate(*root4);
258 ASSERT_TRUE(parsed);
259 EXPECT_TRUE(trust_store_chrome->Contains(parsed.get()));
260
261 base::span<const ChromeRootCertConstraints> constraints =
262 trust_store_chrome->GetConstraintsForCert(parsed.get());
263 ASSERT_EQ(constraints.size(), 1U);
264 EXPECT_FALSE(constraints[0].min_version.has_value());
265 EXPECT_EQ(constraints[0].max_version_exclusive.value().components(),
266 std::vector<uint32_t>({41}));
267 }
268
269 {
270 std::shared_ptr<const bssl::ParsedCertificate> parsed =
271 ToParsedCertificate(*root5);
272 ASSERT_TRUE(parsed);
273 EXPECT_FALSE(trust_store_chrome->Contains(parsed.get()));
274 EXPECT_TRUE(
275 trust_store_chrome->GetConstraintsForCert(parsed.get()).empty());
276 }
277
278 {
279 std::shared_ptr<const bssl::ParsedCertificate> parsed =
280 ToParsedCertificate(*root6);
281 ASSERT_TRUE(parsed);
282 EXPECT_FALSE(trust_store_chrome->Contains(parsed.get()));
283
284 base::span<const ChromeRootCertConstraints> constraints =
285 trust_store_chrome->GetConstraintsForCert(parsed.get());
286 ASSERT_EQ(constraints.size(), 1U);
287 EXPECT_FALSE(constraints[0].min_version.has_value());
288 EXPECT_EQ(constraints[0].max_version_exclusive.value().components(),
289 std::vector<uint32_t>({61}));
290 }
291 }
292
TEST(TrustStoreChromeTestNoFixture,ParseCommandLineConstraintsEmpty)293 TEST(TrustStoreChromeTestNoFixture, ParseCommandLineConstraintsEmpty) {
294 EXPECT_TRUE(TrustStoreChrome::ParseCrsConstraintsSwitch("").empty());
295 EXPECT_TRUE(TrustStoreChrome::ParseCrsConstraintsSwitch("invalid").empty());
296 EXPECT_TRUE(TrustStoreChrome::ParseCrsConstraintsSwitch(
297 "invalidhash:sctnotafter=123456")
298 .empty());
299 }
300
TEST(TrustStoreChromeTestNoFixture,ParseCommandLineConstraintsErrorHandling)301 TEST(TrustStoreChromeTestNoFixture, ParseCommandLineConstraintsErrorHandling) {
302 auto constraints = TrustStoreChrome::ParseCrsConstraintsSwitch(
303 // Valid hash and valid constraint name with invalid value (missing `,`
304 // between constraints, so sctallafter value will not be parsable as an
305 // integer). Should result in a constraintset with every constraint
306 // being nullopt.
307 "568c8ef6b526d1394bca052ba3e4d1f4d7a8d9c88c55a1a9ab7ca0fae2dc5473:"
308 "sctallafter=9876543sctnotafter=1234567890+"
309 // Invalid hash (valid hex, but too short).
310 "37a9761b69457987abbc8636182d8273498719659716397401f98e019b20a9:"
311 "sctallafter=9876543+"
312 // Invalid hash (valid hex, but too long).
313 "37a9761b69457987abbc8636182d8273498719659716397401f98e019b20a91111:"
314 "sctallafter=9876543+"
315 // Invalid constraint mapping (missing `:` between hash and constraint).
316 "737a9761b69457987abbc8636182d8273498719659716397401f98e019b20a98"
317 "sctallafter=9876543+"
318 // Invalid and valid hashes with both invalid and valid constraints.
319 "11,a7e0c75d7f772fccf26a6ac1f7b0a86a482e2f3d326bc911c95d56ff3d4906d5,22:"
320 "invalidconstraint=hello,sctnotafter=789012345+"
321 // Missing `+` between constraint mappings.
322 // This will parse the next hash and minversion all as an invalid
323 // sctallafter value and then the maxversionexclusive will apply to the
324 // previous root hash.
325 "65ee41e8a8c27b71b6bfcf44653c8e8370ec5e106e272592c2fbcbadf8dc5763:"
326 "sctnotafter=123456,sctallafter=54321"
327 "3333333333333333333333333333333333333333333333333333333333333333:"
328 "minversion=1,maxversionexclusive=2.3");
329 EXPECT_EQ(constraints.size(), 3U);
330
331 {
332 constexpr uint8_t hash[] = {0x56, 0x8c, 0x8e, 0xf6, 0xb5, 0x26, 0xd1, 0x39,
333 0x4b, 0xca, 0x05, 0x2b, 0xa3, 0xe4, 0xd1, 0xf4,
334 0xd7, 0xa8, 0xd9, 0xc8, 0x8c, 0x55, 0xa1, 0xa9,
335 0xab, 0x7c, 0xa0, 0xfa, 0xe2, 0xdc, 0x54, 0x73};
336 auto it = constraints.find(base::span(hash));
337 ASSERT_NE(it, constraints.end());
338 ASSERT_EQ(it->second.size(), 1U);
339 const auto& constraint1 = it->second[0];
340 EXPECT_FALSE(constraint1.sct_not_after.has_value());
341 EXPECT_FALSE(constraint1.sct_all_after.has_value());
342 EXPECT_FALSE(constraint1.min_version.has_value());
343 EXPECT_FALSE(constraint1.max_version_exclusive.has_value());
344 EXPECT_THAT(constraint1.permitted_dns_names, testing::IsEmpty());
345 }
346 {
347 constexpr uint8_t hash[] = {0xa7, 0xe0, 0xc7, 0x5d, 0x7f, 0x77, 0x2f, 0xcc,
348 0xf2, 0x6a, 0x6a, 0xc1, 0xf7, 0xb0, 0xa8, 0x6a,
349 0x48, 0x2e, 0x2f, 0x3d, 0x32, 0x6b, 0xc9, 0x11,
350 0xc9, 0x5d, 0x56, 0xff, 0x3d, 0x49, 0x06, 0xd5};
351 auto it = constraints.find(base::span(hash));
352 ASSERT_NE(it, constraints.end());
353 ASSERT_EQ(it->second.size(), 1U);
354
355 const auto& constraint1 = it->second[0];
356 ASSERT_TRUE(constraint1.sct_not_after.has_value());
357 EXPECT_EQ(constraint1.sct_not_after->InMillisecondsSinceUnixEpoch() / 1000,
358 789012345);
359 EXPECT_FALSE(constraint1.sct_all_after.has_value());
360 EXPECT_FALSE(constraint1.min_version.has_value());
361 EXPECT_FALSE(constraint1.max_version_exclusive.has_value());
362 EXPECT_THAT(constraint1.permitted_dns_names, testing::IsEmpty());
363 }
364
365 {
366 unsigned char hash[] = {0x65, 0xee, 0x41, 0xe8, 0xa8, 0xc2, 0x7b, 0x71,
367 0xb6, 0xbf, 0xcf, 0x44, 0x65, 0x3c, 0x8e, 0x83,
368 0x70, 0xec, 0x5e, 0x10, 0x6e, 0x27, 0x25, 0x92,
369 0xc2, 0xfb, 0xcb, 0xad, 0xf8, 0xdc, 0x57, 0x63};
370
371 auto it = constraints.find(base::span(hash));
372 ASSERT_NE(it, constraints.end());
373 ASSERT_EQ(it->second.size(), 1U);
374 const auto& constraint = it->second[0];
375 ASSERT_TRUE(constraint.sct_not_after.has_value());
376 EXPECT_EQ(constraint.sct_not_after->InMillisecondsSinceUnixEpoch() / 1000,
377 123456);
378 EXPECT_FALSE(constraint.sct_all_after.has_value());
379 EXPECT_FALSE(constraint.min_version.has_value());
380 EXPECT_EQ(constraint.max_version_exclusive, base::Version({2, 3}));
381 EXPECT_THAT(constraint.permitted_dns_names, testing::IsEmpty());
382 }
383 }
384
TEST(TrustStoreChromeTestNoFixture,ParseCommandLineConstraintsOneRootOneConstraint)385 TEST(TrustStoreChromeTestNoFixture,
386 ParseCommandLineConstraintsOneRootOneConstraint) {
387 auto constraints = TrustStoreChrome::ParseCrsConstraintsSwitch(
388 "65ee41e8a8c27b71b6bfcf44653c8e8370ec5e106e272592c2fbcbadf8dc5763:"
389 "sctnotafter=123456");
390 EXPECT_EQ(constraints.size(), 1U);
391 unsigned char hash[] = {0x65, 0xee, 0x41, 0xe8, 0xa8, 0xc2, 0x7b, 0x71,
392 0xb6, 0xbf, 0xcf, 0x44, 0x65, 0x3c, 0x8e, 0x83,
393 0x70, 0xec, 0x5e, 0x10, 0x6e, 0x27, 0x25, 0x92,
394 0xc2, 0xfb, 0xcb, 0xad, 0xf8, 0xdc, 0x57, 0x63};
395
396 auto it = constraints.find(base::span(hash));
397 ASSERT_NE(it, constraints.end());
398 ASSERT_EQ(it->second.size(), 1U);
399 const auto& constraint = it->second[0];
400 ASSERT_TRUE(constraint.sct_not_after.has_value());
401 EXPECT_EQ(constraint.sct_not_after->InMillisecondsSinceUnixEpoch() / 1000,
402 123456);
403 EXPECT_FALSE(constraint.sct_all_after.has_value());
404 EXPECT_FALSE(constraint.min_version.has_value());
405 EXPECT_FALSE(constraint.max_version_exclusive.has_value());
406 }
407
TEST(TrustStoreChromeTestNoFixture,ParseCommandLineConstraintsMultipleRootsMultipleConstraints)408 TEST(TrustStoreChromeTestNoFixture,
409 ParseCommandLineConstraintsMultipleRootsMultipleConstraints) {
410 auto constraints = TrustStoreChrome::ParseCrsConstraintsSwitch(
411 "784ecaa8b9dfcc826547f806f759abd6b4481582fc7e377dc3e6a0a959025126,"
412 "a7e0c75d7f772fccf26a6ac1f7b0a86a482e2f3d326bc911c95d56ff3d4906d5:"
413 "sctnotafter=123456,sctallafter=7689,"
414 "minversion=1.2.3.4,maxversionexclusive=10,"
415 "dns=foo.com,dns=bar.com+"
416 "a7e0c75d7f772fccf26a6ac1f7b0a86a482e2f3d326bc911c95d56ff3d4906d5,"
417 "568c8ef6b526d1394bca052ba3e4d1f4d7a8d9c88c55a1a9ab7ca0fae2dc5473:"
418 "sctallafter=9876543,sctnotafter=1234567890");
419 EXPECT_EQ(constraints.size(), 3U);
420
421 {
422 constexpr uint8_t hash1[] = {
423 0x78, 0x4e, 0xca, 0xa8, 0xb9, 0xdf, 0xcc, 0x82, 0x65, 0x47, 0xf8,
424 0x06, 0xf7, 0x59, 0xab, 0xd6, 0xb4, 0x48, 0x15, 0x82, 0xfc, 0x7e,
425 0x37, 0x7d, 0xc3, 0xe6, 0xa0, 0xa9, 0x59, 0x02, 0x51, 0x26};
426 auto it = constraints.find(base::span(hash1));
427 ASSERT_NE(it, constraints.end());
428 ASSERT_EQ(it->second.size(), 1U);
429 const auto& constraint1 = it->second[0];
430 ASSERT_TRUE(constraint1.sct_not_after.has_value());
431 EXPECT_EQ(constraint1.sct_not_after->InMillisecondsSinceUnixEpoch() / 1000,
432 123456);
433 ASSERT_TRUE(constraint1.sct_all_after.has_value());
434 EXPECT_EQ(constraint1.sct_all_after->InMillisecondsSinceUnixEpoch() / 1000,
435 7689);
436 EXPECT_EQ(constraint1.min_version, base::Version({1, 2, 3, 4}));
437 EXPECT_EQ(constraint1.max_version_exclusive, base::Version({10}));
438 EXPECT_THAT(constraint1.permitted_dns_names,
439 testing::ElementsAre("foo.com", "bar.com"));
440 }
441
442 {
443 constexpr uint8_t hash2[] = {
444 0xa7, 0xe0, 0xc7, 0x5d, 0x7f, 0x77, 0x2f, 0xcc, 0xf2, 0x6a, 0x6a,
445 0xc1, 0xf7, 0xb0, 0xa8, 0x6a, 0x48, 0x2e, 0x2f, 0x3d, 0x32, 0x6b,
446 0xc9, 0x11, 0xc9, 0x5d, 0x56, 0xff, 0x3d, 0x49, 0x06, 0xd5};
447 auto it = constraints.find(base::span(hash2));
448 ASSERT_NE(it, constraints.end());
449 ASSERT_EQ(it->second.size(), 2U);
450
451 const auto& constraint1 = it->second[0];
452 ASSERT_TRUE(constraint1.sct_not_after.has_value());
453 EXPECT_EQ(constraint1.sct_not_after->InMillisecondsSinceUnixEpoch() / 1000,
454 123456);
455 ASSERT_TRUE(constraint1.sct_all_after.has_value());
456 EXPECT_EQ(constraint1.sct_all_after->InMillisecondsSinceUnixEpoch() / 1000,
457 7689);
458 EXPECT_EQ(constraint1.min_version, base::Version({1, 2, 3, 4}));
459 EXPECT_EQ(constraint1.max_version_exclusive, base::Version({10}));
460 EXPECT_THAT(constraint1.permitted_dns_names,
461 testing::ElementsAre("foo.com", "bar.com"));
462
463 const auto& constraint2 = it->second[1];
464 ASSERT_TRUE(constraint2.sct_not_after.has_value());
465 EXPECT_EQ(constraint2.sct_not_after->InMillisecondsSinceUnixEpoch() / 1000,
466 1234567890);
467 ASSERT_TRUE(constraint2.sct_all_after.has_value());
468 EXPECT_EQ(constraint2.sct_all_after->InMillisecondsSinceUnixEpoch() / 1000,
469 9876543);
470 EXPECT_FALSE(constraint2.min_version.has_value());
471 EXPECT_FALSE(constraint2.max_version_exclusive.has_value());
472 EXPECT_THAT(constraint2.permitted_dns_names, testing::IsEmpty());
473 }
474
475 {
476 constexpr uint8_t hash3[] = {
477 0x56, 0x8c, 0x8e, 0xf6, 0xb5, 0x26, 0xd1, 0x39, 0x4b, 0xca, 0x05,
478 0x2b, 0xa3, 0xe4, 0xd1, 0xf4, 0xd7, 0xa8, 0xd9, 0xc8, 0x8c, 0x55,
479 0xa1, 0xa9, 0xab, 0x7c, 0xa0, 0xfa, 0xe2, 0xdc, 0x54, 0x73};
480 auto it = constraints.find(base::span(hash3));
481 ASSERT_NE(it, constraints.end());
482 ASSERT_EQ(it->second.size(), 1U);
483 const auto& constraint1 = it->second[0];
484 ASSERT_TRUE(constraint1.sct_not_after.has_value());
485 EXPECT_EQ(constraint1.sct_not_after->InMillisecondsSinceUnixEpoch() / 1000,
486 1234567890);
487 ASSERT_TRUE(constraint1.sct_all_after.has_value());
488 EXPECT_EQ(constraint1.sct_all_after->InMillisecondsSinceUnixEpoch() / 1000,
489 9876543);
490 EXPECT_FALSE(constraint1.min_version.has_value());
491 EXPECT_FALSE(constraint1.max_version_exclusive.has_value());
492 EXPECT_THAT(constraint1.permitted_dns_names, testing::IsEmpty());
493 }
494 }
495
496 } // namespace
497 } // namespace net
498