• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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