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