1 // Copyright 2017 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/revocation_checker.h"
6
7 #include <string_view>
8
9 #include "base/time/time.h"
10 #include "net/cert/mock_cert_net_fetcher.h"
11 #include "net/test/cert_builder.h"
12 #include "net/test/revocation_builder.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "third_party/boringssl/src/pki/cert_errors.h"
16 #include "third_party/boringssl/src/pki/common_cert_errors.h"
17 #include "third_party/boringssl/src/pki/parse_certificate.h"
18 #include "third_party/boringssl/src/pki/parsed_certificate.h"
19 #include "url/gurl.h"
20
21 namespace net {
22
23 namespace {
24
25 using ::testing::_;
26 using ::testing::ByMove;
27 using ::testing::Mock;
28 using ::testing::Return;
29 using ::testing::StrictMock;
30
AddCertsToList(std::vector<CertBuilder * > builders,bssl::ParsedCertificateList * out_certs)31 bool AddCertsToList(std::vector<CertBuilder*> builders,
32 bssl::ParsedCertificateList* out_certs) {
33 for (auto* builder : builders) {
34 if (!bssl::ParsedCertificate::CreateAndAddToVector(
35 builder->DupCertBuffer(), {}, out_certs, /*errors=*/nullptr)) {
36 return false;
37 }
38 }
39 return true;
40 }
41
TEST(RevocationChecker,NoRevocationMechanism)42 TEST(RevocationChecker, NoRevocationMechanism) {
43 auto [leaf, root] = CertBuilder::CreateSimpleChain2();
44
45 bssl::ParsedCertificateList chain;
46 ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain));
47
48 RevocationPolicy policy;
49 policy.check_revocation = true;
50 policy.networking_allowed = true;
51 policy.crl_allowed = true;
52 policy.allow_unable_to_check = false;
53
54 {
55 // Require revocation methods to be presented.
56 policy.allow_missing_info = false;
57
58 // No methods on |mock_fetcher| should be called.
59 auto mock_fetcher = base::MakeRefCounted<StrictMock<MockCertNetFetcher>>();
60
61 bssl::CertPathErrors errors;
62 CheckValidatedChainRevocation(
63 chain, policy, /*deadline=*/base::TimeTicks(),
64 /*stapled_leaf_ocsp_response=*/std::string_view(), base::Time::Now(),
65 mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr);
66
67 EXPECT_TRUE(errors.ContainsHighSeverityErrors());
68 EXPECT_TRUE(
69 errors.ContainsError(bssl::cert_errors::kNoRevocationMechanism));
70 }
71
72 {
73 // Allow certs without revocation methods.
74 policy.allow_missing_info = true;
75
76 // No methods on |mock_fetcher| should be called.
77 auto mock_fetcher = base::MakeRefCounted<StrictMock<MockCertNetFetcher>>();
78
79 bssl::CertPathErrors errors;
80 CheckValidatedChainRevocation(
81 chain, policy, /*deadline=*/base::TimeTicks(),
82 /*stapled_leaf_ocsp_response=*/std::string_view(), base::Time::Now(),
83 mock_fetcher.get(), &errors,
84 /*stapled_ocsp_verify_result=*/nullptr);
85
86 EXPECT_FALSE(errors.ContainsHighSeverityErrors());
87 }
88
89 {
90 // Revocation checking disabled.
91 policy.check_revocation = false;
92 // Require revocation methods to be presented, but this does not matter if
93 // check_revocation is false.
94 policy.allow_missing_info = false;
95
96 // No methods on |mock_fetcher| should be called.
97 auto mock_fetcher = base::MakeRefCounted<StrictMock<MockCertNetFetcher>>();
98
99 bssl::CertPathErrors errors;
100 CheckValidatedChainRevocation(
101 chain, policy, /*deadline=*/base::TimeTicks(),
102 /*stapled_leaf_ocsp_response=*/std::string_view(), base::Time::Now(),
103 mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr);
104
105 EXPECT_FALSE(errors.ContainsHighSeverityErrors());
106 }
107 }
108
TEST(RevocationChecker,ValidCRL)109 TEST(RevocationChecker, ValidCRL) {
110 auto [leaf, root] = CertBuilder::CreateSimpleChain2();
111
112 const GURL kTestCrlUrl("http://example.com/crl1");
113 leaf->SetCrlDistributionPointUrl(kTestCrlUrl);
114
115 bssl::ParsedCertificateList chain;
116 ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain));
117
118 RevocationPolicy policy;
119 policy.check_revocation = true;
120 policy.allow_missing_info = false;
121 policy.allow_unable_to_check = false;
122
123 std::string crl_data_as_string_for_some_reason =
124 BuildCrl(root->GetSubject(), root->GetKey(),
125 /*revoked_serials=*/{});
126 std::vector<uint8_t> crl_data(crl_data_as_string_for_some_reason.begin(),
127 crl_data_as_string_for_some_reason.end());
128
129 {
130 policy.networking_allowed = true;
131 policy.crl_allowed = true;
132
133 auto mock_fetcher = base::MakeRefCounted<StrictMock<MockCertNetFetcher>>();
134 EXPECT_CALL(*mock_fetcher, FetchCrl(kTestCrlUrl, _, _))
135 .WillOnce(Return(ByMove(MockCertNetFetcherRequest::Create(crl_data))));
136
137 bssl::CertPathErrors errors;
138 CheckValidatedChainRevocation(
139 chain, policy, /*deadline=*/base::TimeTicks(),
140 /*stapled_leaf_ocsp_response=*/std::string_view(), base::Time::Now(),
141 mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr);
142
143 EXPECT_FALSE(errors.ContainsHighSeverityErrors());
144 }
145
146 {
147 policy.networking_allowed = false;
148 policy.crl_allowed = true;
149
150 // No methods on |mock_fetcher| should be called.
151 auto mock_fetcher = base::MakeRefCounted<StrictMock<MockCertNetFetcher>>();
152
153 bssl::CertPathErrors errors;
154 CheckValidatedChainRevocation(
155 chain, policy, /*deadline=*/base::TimeTicks(),
156 /*stapled_leaf_ocsp_response=*/std::string_view(), base::Time::Now(),
157 mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr);
158
159 EXPECT_TRUE(errors.ContainsHighSeverityErrors());
160 EXPECT_TRUE(
161 errors.ContainsError(bssl::cert_errors::kUnableToCheckRevocation));
162 }
163
164 {
165 policy.networking_allowed = true;
166 policy.crl_allowed = false;
167
168 // No methods on |mock_fetcher| should be called.
169 auto mock_fetcher = base::MakeRefCounted<StrictMock<MockCertNetFetcher>>();
170
171 bssl::CertPathErrors errors;
172 CheckValidatedChainRevocation(
173 chain, policy, /*deadline=*/base::TimeTicks(),
174 /*stapled_leaf_ocsp_response=*/std::string_view(), base::Time::Now(),
175 mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr);
176
177 EXPECT_TRUE(errors.ContainsHighSeverityErrors());
178 // Since CRLs were not considered, the error should be "no revocation
179 // mechanism".
180 EXPECT_TRUE(
181 errors.ContainsError(bssl::cert_errors::kNoRevocationMechanism));
182 }
183 }
184
TEST(RevocationChecker,RevokedCRL)185 TEST(RevocationChecker, RevokedCRL) {
186 auto [leaf, root] = CertBuilder::CreateSimpleChain2();
187
188 const GURL kTestCrlUrl("http://example.com/crl1");
189 leaf->SetCrlDistributionPointUrl(kTestCrlUrl);
190
191 bssl::ParsedCertificateList chain;
192 ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain));
193
194 RevocationPolicy policy;
195 policy.check_revocation = true;
196 policy.networking_allowed = true;
197 policy.crl_allowed = true;
198
199 std::string crl_data_as_string_for_some_reason =
200 BuildCrl(root->GetSubject(), root->GetKey(),
201 /*revoked_serials=*/{leaf->GetSerialNumber()});
202 std::vector<uint8_t> crl_data(crl_data_as_string_for_some_reason.begin(),
203 crl_data_as_string_for_some_reason.end());
204
205 {
206 // These should have no effect on an affirmatively revoked response.
207 policy.allow_missing_info = false;
208 policy.allow_unable_to_check = false;
209
210 auto mock_fetcher = base::MakeRefCounted<StrictMock<MockCertNetFetcher>>();
211 EXPECT_CALL(*mock_fetcher, FetchCrl(kTestCrlUrl, _, _))
212 .WillOnce(Return(ByMove(MockCertNetFetcherRequest::Create(crl_data))));
213
214 bssl::CertPathErrors errors;
215 CheckValidatedChainRevocation(
216 chain, policy, /*deadline=*/base::TimeTicks(),
217 /*stapled_leaf_ocsp_response=*/std::string_view(), base::Time::Now(),
218 mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr);
219
220 EXPECT_TRUE(errors.ContainsHighSeverityErrors());
221 EXPECT_TRUE(errors.ContainsError(bssl::cert_errors::kCertificateRevoked));
222 }
223
224 {
225 // These should have no effect on an affirmatively revoked response.
226 policy.allow_missing_info = true;
227 policy.allow_unable_to_check = true;
228
229 auto mock_fetcher = base::MakeRefCounted<StrictMock<MockCertNetFetcher>>();
230 EXPECT_CALL(*mock_fetcher, FetchCrl(kTestCrlUrl, _, _))
231 .WillOnce(Return(ByMove(MockCertNetFetcherRequest::Create(crl_data))));
232
233 bssl::CertPathErrors errors;
234 CheckValidatedChainRevocation(
235 chain, policy, /*deadline=*/base::TimeTicks(),
236 /*stapled_leaf_ocsp_response=*/std::string_view(), base::Time::Now(),
237 mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr);
238
239 EXPECT_TRUE(errors.ContainsHighSeverityErrors());
240 EXPECT_TRUE(errors.ContainsError(bssl::cert_errors::kCertificateRevoked));
241 }
242 }
243
TEST(RevocationChecker,CRLRequestFails)244 TEST(RevocationChecker, CRLRequestFails) {
245 auto [leaf, root] = CertBuilder::CreateSimpleChain2();
246
247 const GURL kTestCrlUrl("http://example.com/crl1");
248 leaf->SetCrlDistributionPointUrl(kTestCrlUrl);
249
250 bssl::ParsedCertificateList chain;
251 ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain));
252
253 RevocationPolicy policy;
254 policy.check_revocation = true;
255 policy.networking_allowed = true;
256 policy.crl_allowed = true;
257
258 {
259 policy.allow_unable_to_check = false;
260 policy.allow_missing_info = false;
261
262 auto mock_fetcher = base::MakeRefCounted<StrictMock<MockCertNetFetcher>>();
263 EXPECT_CALL(*mock_fetcher, FetchCrl(kTestCrlUrl, _, _))
264 .WillOnce(Return(
265 ByMove(MockCertNetFetcherRequest::Create(ERR_CONNECTION_FAILED))));
266
267 bssl::CertPathErrors errors;
268 CheckValidatedChainRevocation(
269 chain, policy, /*deadline=*/base::TimeTicks(),
270 /*stapled_leaf_ocsp_response=*/std::string_view(), base::Time::Now(),
271 mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr);
272
273 EXPECT_TRUE(errors.ContainsHighSeverityErrors());
274 EXPECT_TRUE(
275 errors.ContainsError(bssl::cert_errors::kUnableToCheckRevocation));
276 }
277
278 {
279 policy.allow_unable_to_check = false;
280 policy.allow_missing_info = true; // Should have no effect.
281
282 auto mock_fetcher = base::MakeRefCounted<StrictMock<MockCertNetFetcher>>();
283 EXPECT_CALL(*mock_fetcher, FetchCrl(kTestCrlUrl, _, _))
284 .WillOnce(Return(
285 ByMove(MockCertNetFetcherRequest::Create(ERR_CONNECTION_FAILED))));
286
287 bssl::CertPathErrors errors;
288 CheckValidatedChainRevocation(
289 chain, policy, /*deadline=*/base::TimeTicks(),
290 /*stapled_leaf_ocsp_response=*/std::string_view(), base::Time::Now(),
291 mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr);
292
293 EXPECT_TRUE(errors.ContainsHighSeverityErrors());
294 EXPECT_TRUE(
295 errors.ContainsError(bssl::cert_errors::kUnableToCheckRevocation));
296 }
297
298 {
299 policy.allow_unable_to_check = true;
300 policy.allow_missing_info = false;
301
302 auto mock_fetcher = base::MakeRefCounted<StrictMock<MockCertNetFetcher>>();
303 EXPECT_CALL(*mock_fetcher, FetchCrl(kTestCrlUrl, _, _))
304 .WillOnce(Return(
305 ByMove(MockCertNetFetcherRequest::Create(ERR_CONNECTION_FAILED))));
306
307 bssl::CertPathErrors errors;
308 CheckValidatedChainRevocation(
309 chain, policy, /*deadline=*/base::TimeTicks(),
310 /*stapled_leaf_ocsp_response=*/std::string_view(), base::Time::Now(),
311 mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr);
312
313 EXPECT_FALSE(errors.ContainsHighSeverityErrors());
314 }
315 }
316
TEST(RevocationChecker,CRLNonHttpUrl)317 TEST(RevocationChecker, CRLNonHttpUrl) {
318 auto [leaf, root] = CertBuilder::CreateSimpleChain2();
319
320 const GURL kTestCrlUrl("https://example.com/crl1");
321 leaf->SetCrlDistributionPointUrl(kTestCrlUrl);
322
323 bssl::ParsedCertificateList chain;
324 ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain));
325
326 RevocationPolicy policy;
327 policy.check_revocation = true;
328 policy.networking_allowed = true;
329 policy.crl_allowed = true;
330 policy.allow_unable_to_check = false;
331 policy.allow_missing_info = false;
332
333 // HTTPS CRL URLs should not be fetched.
334 auto mock_fetcher = base::MakeRefCounted<StrictMock<MockCertNetFetcher>>();
335
336 bssl::CertPathErrors errors;
337 CheckValidatedChainRevocation(
338 chain, policy, /*deadline=*/base::TimeTicks(),
339 /*stapled_leaf_ocsp_response=*/std::string_view(), base::Time::Now(),
340 mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr);
341
342 EXPECT_TRUE(errors.ContainsHighSeverityErrors());
343 EXPECT_TRUE(errors.ContainsError(bssl::cert_errors::kNoRevocationMechanism));
344 }
345
TEST(RevocationChecker,SkipEntireInvalidCRLDistributionPoints)346 TEST(RevocationChecker, SkipEntireInvalidCRLDistributionPoints) {
347 auto [leaf, root] = CertBuilder::CreateSimpleChain2();
348
349 const GURL kSecondCrlUrl("http://www.example.com/bar.crl");
350
351 // SEQUENCE {
352 // # First distribution point: this is invalid, thus the entire
353 // # crlDistributionPoints extension should be ignored and revocation
354 // # checking should fail.
355 // SEQUENCE {
356 // [0] {
357 // [0] {
358 // # [9] is not a valid tag in bssl::GeneralNames
359 // [9 PRIMITIVE] { "foo" }
360 // }
361 // }
362 // }
363 // # Second distribution point. Even though this is an acceptable
364 // # distributionPoint, it should not be used.
365 // SEQUENCE {
366 // [0] {
367 // [0] {
368 // [6 PRIMITIVE] { "http://www.example.com/bar.crl" }
369 // }
370 // }
371 // }
372 // }
373 const uint8_t crldp[] = {0x30, 0x31, 0x30, 0x09, 0xa0, 0x07, 0xa0, 0x05, 0x89,
374 0x03, 0x66, 0x6f, 0x6f, 0x30, 0x24, 0xa0, 0x22, 0xa0,
375 0x20, 0x86, 0x1e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
376 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d,
377 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62,
378 0x61, 0x72, 0x2e, 0x63, 0x72, 0x6c};
379 leaf->SetExtension(
380 bssl::der::Input(bssl::kCrlDistributionPointsOid),
381 std::string(reinterpret_cast<const char*>(crldp), std::size(crldp)));
382
383 bssl::ParsedCertificateList chain;
384 ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain));
385
386 RevocationPolicy policy;
387 policy.check_revocation = true;
388 policy.networking_allowed = true;
389 policy.crl_allowed = true;
390 policy.allow_unable_to_check = false;
391 policy.allow_missing_info = false;
392
393 std::string crl_data_as_string_for_some_reason =
394 BuildCrl(root->GetSubject(), root->GetKey(),
395 /*revoked_serials=*/{});
396 std::vector<uint8_t> crl_data(crl_data_as_string_for_some_reason.begin(),
397 crl_data_as_string_for_some_reason.end());
398
399 // No methods on |mock_fetcher| should be called.
400 auto mock_fetcher = base::MakeRefCounted<StrictMock<MockCertNetFetcher>>();
401
402 bssl::CertPathErrors errors;
403 CheckValidatedChainRevocation(
404 chain, policy, /*deadline=*/base::TimeTicks(),
405 /*stapled_leaf_ocsp_response=*/std::string_view(), base::Time::Now(),
406 mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr);
407
408 // Should fail since the entire cRLDistributionPoints extension was skipped
409 // and no other revocation method is present.
410 EXPECT_TRUE(errors.ContainsHighSeverityErrors());
411 EXPECT_TRUE(errors.ContainsError(bssl::cert_errors::kNoRevocationMechanism));
412 }
413
TEST(RevocationChecker,SkipUnsupportedCRLDistPointWithNonUriFullname)414 TEST(RevocationChecker, SkipUnsupportedCRLDistPointWithNonUriFullname) {
415 auto [leaf, root] = CertBuilder::CreateSimpleChain2();
416
417 const GURL kSecondCrlUrl("http://www.example.com/bar.crl");
418
419 // SEQUENCE {
420 // # First distribution point: this should be ignored since it has a non-URI
421 // # fullName field.
422 // SEQUENCE {
423 // [0] {
424 // [0] {
425 // [4] {
426 // SEQUENCE {
427 // SET {
428 // SEQUENCE {
429 // # countryName
430 // OBJECT_IDENTIFIER { 2.5.4.6 }
431 // PrintableString { "US" }
432 // }
433 // }
434 // SET {
435 // SEQUENCE {
436 // # commonName
437 // OBJECT_IDENTIFIER { 2.5.4.3 }
438 // PrintableString { "foo" }
439 // }
440 // }
441 // }
442 // }
443 // }
444 // }
445 // }
446 // # Second distribution point. This should be used since it only has a
447 // # fullName URI.
448 // SEQUENCE {
449 // [0] {
450 // [0] {
451 // [6 PRIMITIVE] { "http://www.example.com/bar.crl" }
452 // }
453 // }
454 // }
455 // }
456 const uint8_t crldp[] = {
457 0x30, 0x4b, 0x30, 0x23, 0xa0, 0x21, 0xa0, 0x1f, 0xa4, 0x1d, 0x30,
458 0x1b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
459 0x02, 0x55, 0x53, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04,
460 0x03, 0x13, 0x03, 0x66, 0x6f, 0x6f, 0x30, 0x24, 0xa0, 0x22, 0xa0,
461 0x20, 0x86, 0x1e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
462 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e,
463 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61, 0x72, 0x2e, 0x63, 0x72, 0x6c};
464 leaf->SetExtension(
465 bssl::der::Input(bssl::kCrlDistributionPointsOid),
466 std::string(reinterpret_cast<const char*>(crldp), std::size(crldp)));
467
468 bssl::ParsedCertificateList chain;
469 ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain));
470
471 RevocationPolicy policy;
472 policy.check_revocation = true;
473 policy.networking_allowed = true;
474 policy.crl_allowed = true;
475 policy.allow_unable_to_check = false;
476 policy.allow_missing_info = false;
477
478 std::string crl_data_as_string_for_some_reason =
479 BuildCrl(root->GetSubject(), root->GetKey(),
480 /*revoked_serials=*/{});
481 std::vector<uint8_t> crl_data(crl_data_as_string_for_some_reason.begin(),
482 crl_data_as_string_for_some_reason.end());
483
484 // The first crldp should be skipped, the second should be retrieved.
485 auto mock_fetcher = base::MakeRefCounted<StrictMock<MockCertNetFetcher>>();
486 EXPECT_CALL(*mock_fetcher, FetchCrl(kSecondCrlUrl, _, _))
487 .WillOnce(Return(ByMove(MockCertNetFetcherRequest::Create(crl_data))));
488
489 bssl::CertPathErrors errors;
490 CheckValidatedChainRevocation(
491 chain, policy, /*deadline=*/base::TimeTicks(),
492 /*stapled_leaf_ocsp_response=*/std::string_view(), base::Time::Now(),
493 mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr);
494
495 EXPECT_FALSE(errors.ContainsHighSeverityErrors());
496 }
497
TEST(RevocationChecker,SkipUnsupportedCRLDistPointWithReasons)498 TEST(RevocationChecker, SkipUnsupportedCRLDistPointWithReasons) {
499 auto [leaf, root] = CertBuilder::CreateSimpleChain2();
500
501 const GURL kSecondCrlUrl("http://www.example.com/bar.crl");
502
503 // SEQUENCE {
504 // # First distribution point: this should be ignored since it has a reasons
505 // # field.
506 // SEQUENCE {
507 // [0] {
508 // [0] {
509 // [6 PRIMITIVE] { "http://www.example.com/foo.crl" }
510 // }
511 // }
512 // # reasons
513 // [1 PRIMITIVE] { b`011` }
514 // }
515 // # Second distribution point. This should be used since it only has a
516 // # fullName URI.
517 // SEQUENCE {
518 // [0] {
519 // [0] {
520 // [6 PRIMITIVE] { "http://www.example.com/bar.crl" }
521 // }
522 // }
523 // }
524 // }
525 const uint8_t crldp[] = {
526 0x30, 0x50, 0x30, 0x28, 0xa0, 0x22, 0xa0, 0x20, 0x86, 0x1e, 0x68, 0x74,
527 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61,
528 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6f, 0x6f,
529 0x2e, 0x63, 0x72, 0x6c, 0x81, 0x02, 0x05, 0x60, 0x30, 0x24, 0xa0, 0x22,
530 0xa0, 0x20, 0x86, 0x1e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
531 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63,
532 0x6f, 0x6d, 0x2f, 0x62, 0x61, 0x72, 0x2e, 0x63, 0x72, 0x6c};
533 leaf->SetExtension(
534 bssl::der::Input(bssl::kCrlDistributionPointsOid),
535 std::string(reinterpret_cast<const char*>(crldp), std::size(crldp)));
536
537 bssl::ParsedCertificateList chain;
538 ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain));
539
540 RevocationPolicy policy;
541 policy.check_revocation = true;
542 policy.networking_allowed = true;
543 policy.crl_allowed = true;
544 policy.allow_unable_to_check = false;
545 policy.allow_missing_info = false;
546
547 std::string crl_data_as_string_for_some_reason =
548 BuildCrl(root->GetSubject(), root->GetKey(),
549 /*revoked_serials=*/{});
550 std::vector<uint8_t> crl_data(crl_data_as_string_for_some_reason.begin(),
551 crl_data_as_string_for_some_reason.end());
552
553 // The first crldp should be skipped, the second should be retrieved.
554 auto mock_fetcher = base::MakeRefCounted<StrictMock<MockCertNetFetcher>>();
555 EXPECT_CALL(*mock_fetcher, FetchCrl(kSecondCrlUrl, _, _))
556 .WillOnce(Return(ByMove(MockCertNetFetcherRequest::Create(crl_data))));
557
558 bssl::CertPathErrors errors;
559 CheckValidatedChainRevocation(
560 chain, policy, /*deadline=*/base::TimeTicks(),
561 /*stapled_leaf_ocsp_response=*/std::string_view(), base::Time::Now(),
562 mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr);
563
564 EXPECT_FALSE(errors.ContainsHighSeverityErrors());
565 }
566
TEST(RevocationChecker,SkipUnsupportedCRLDistPointWithCrlIssuer)567 TEST(RevocationChecker, SkipUnsupportedCRLDistPointWithCrlIssuer) {
568 auto [leaf, root] = CertBuilder::CreateSimpleChain2();
569
570 const GURL kSecondCrlUrl("http://www.example.com/bar.crl");
571
572 // SEQUENCE {
573 // # First distribution point: this should be ignored since it has a
574 // crlIssuer field.
575 // SEQUENCE {
576 // [0] {
577 // [0] {
578 // [6 PRIMITIVE] { "http://www.example.com/foo.crl" }
579 // }
580 // }
581 // [2] {
582 // [4] {
583 // SEQUENCE {
584 // SET {
585 // SEQUENCE {
586 // # countryName
587 // OBJECT_IDENTIFIER { 2.5.4.6 }
588 // PrintableString { "US" }
589 // }
590 // }
591 // SET {
592 // SEQUENCE {
593 // # organizationName
594 // OBJECT_IDENTIFIER { 2.5.4.10 }
595 // PrintableString { "Test Certificates 2011" }
596 // }
597 // }
598 // SET {
599 // SEQUENCE {
600 // # organizationUnitName
601 // OBJECT_IDENTIFIER { 2.5.4.11 }
602 // PrintableString { "indirectCRL CA3 cRLIssuer" }
603 // }
604 // }
605 // }
606 // }
607 // }
608 // }
609 // # Second distribution point. This should be used since it only has a
610 // # fullName URI.
611 // SEQUENCE {
612 // [0] {
613 // [0] {
614 // [6 PRIMITIVE] { "http://www.example.com/bar.crl" }
615 // }
616 // }
617 // }
618 // }
619 const uint8_t crldp[] = {
620 0x30, 0x81, 0xa4, 0x30, 0x7c, 0xa0, 0x22, 0xa0, 0x20, 0x86, 0x1e, 0x68,
621 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78,
622 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6f,
623 0x6f, 0x2e, 0x63, 0x72, 0x6c, 0xa2, 0x56, 0xa4, 0x54, 0x30, 0x52, 0x31,
624 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
625 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x16, 0x54,
626 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
627 0x61, 0x74, 0x65, 0x73, 0x20, 0x32, 0x30, 0x31, 0x31, 0x31, 0x22, 0x30,
628 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x19, 0x69, 0x6e, 0x64, 0x69,
629 0x72, 0x65, 0x63, 0x74, 0x43, 0x52, 0x4c, 0x20, 0x43, 0x41, 0x33, 0x20,
630 0x63, 0x52, 0x4c, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x30, 0x24, 0xa0,
631 0x22, 0xa0, 0x20, 0x86, 0x1e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
632 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e,
633 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61, 0x72, 0x2e, 0x63, 0x72, 0x6c};
634 leaf->SetExtension(
635 bssl::der::Input(bssl::kCrlDistributionPointsOid),
636 std::string(reinterpret_cast<const char*>(crldp), std::size(crldp)));
637
638 bssl::ParsedCertificateList chain;
639 ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain));
640
641 RevocationPolicy policy;
642 policy.check_revocation = true;
643 policy.networking_allowed = true;
644 policy.crl_allowed = true;
645 policy.allow_unable_to_check = false;
646 policy.allow_missing_info = false;
647
648 std::string crl_data_as_string_for_some_reason =
649 BuildCrl(root->GetSubject(), root->GetKey(),
650 /*revoked_serials=*/{});
651 std::vector<uint8_t> crl_data(crl_data_as_string_for_some_reason.begin(),
652 crl_data_as_string_for_some_reason.end());
653
654 // The first crldp should be skipped, the second should be retrieved.
655 auto mock_fetcher = base::MakeRefCounted<StrictMock<MockCertNetFetcher>>();
656 EXPECT_CALL(*mock_fetcher, FetchCrl(kSecondCrlUrl, _, _))
657 .WillOnce(Return(ByMove(MockCertNetFetcherRequest::Create(crl_data))));
658
659 bssl::CertPathErrors errors;
660 CheckValidatedChainRevocation(
661 chain, policy, /*deadline=*/base::TimeTicks(),
662 /*stapled_leaf_ocsp_response=*/std::string_view(), base::Time::Now(),
663 mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr);
664
665 EXPECT_FALSE(errors.ContainsHighSeverityErrors());
666 }
667
668 // TODO(mattm): Add more unittests (deadlines, OCSP, stapled OCSP, CRLSets).
669 // Currently those features are exercised indirectly through tests in
670 // url_request_unittest.cc, cert_verify_proc_unittest.cc, etc.
671
672 } // namespace
673
674 } // namespace net
675