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