// Copyright 2017 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/cert/internal/revocation_checker.h" #include #include "base/time/time.h" #include "net/cert/mock_cert_net_fetcher.h" #include "net/test/cert_builder.h" #include "net/test/revocation_builder.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/boringssl/src/pki/cert_errors.h" #include "third_party/boringssl/src/pki/common_cert_errors.h" #include "third_party/boringssl/src/pki/parse_certificate.h" #include "third_party/boringssl/src/pki/parsed_certificate.h" #include "url/gurl.h" namespace net { namespace { using ::testing::_; using ::testing::ByMove; using ::testing::Mock; using ::testing::Return; using ::testing::StrictMock; bool AddCertsToList(std::vector builders, bssl::ParsedCertificateList* out_certs) { for (auto* builder : builders) { if (!bssl::ParsedCertificate::CreateAndAddToVector( builder->DupCertBuffer(), {}, out_certs, /*errors=*/nullptr)) { return false; } } return true; } TEST(RevocationChecker, NoRevocationMechanism) { auto [leaf, root] = CertBuilder::CreateSimpleChain2(); bssl::ParsedCertificateList chain; ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain)); RevocationPolicy policy; policy.check_revocation = true; policy.networking_allowed = true; policy.crl_allowed = true; policy.allow_unable_to_check = false; { // Require revocation methods to be presented. policy.allow_missing_info = false; // No methods on |mock_fetcher| should be called. auto mock_fetcher = base::MakeRefCounted>(); bssl::CertPathErrors errors; CheckValidatedChainRevocation( chain, policy, /*deadline=*/base::TimeTicks(), /*stapled_leaf_ocsp_response=*/std::string_view(), mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr); EXPECT_TRUE(errors.ContainsHighSeverityErrors()); EXPECT_TRUE( errors.ContainsError(bssl::cert_errors::kNoRevocationMechanism)); } { // Allow certs without revocation methods. policy.allow_missing_info = true; // No methods on |mock_fetcher| should be called. auto mock_fetcher = base::MakeRefCounted>(); bssl::CertPathErrors errors; CheckValidatedChainRevocation( chain, policy, /*deadline=*/base::TimeTicks(), /*stapled_leaf_ocsp_response=*/std::string_view(), mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr); EXPECT_FALSE(errors.ContainsHighSeverityErrors()); } { // Revocation checking disabled. policy.check_revocation = false; // Require revocation methods to be presented, but this does not matter if // check_revocation is false. policy.allow_missing_info = false; // No methods on |mock_fetcher| should be called. auto mock_fetcher = base::MakeRefCounted>(); bssl::CertPathErrors errors; CheckValidatedChainRevocation( chain, policy, /*deadline=*/base::TimeTicks(), /*stapled_leaf_ocsp_response=*/std::string_view(), mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr); EXPECT_FALSE(errors.ContainsHighSeverityErrors()); } } TEST(RevocationChecker, ValidCRL) { auto [leaf, root] = CertBuilder::CreateSimpleChain2(); const GURL kTestCrlUrl("http://example.com/crl1"); leaf->SetCrlDistributionPointUrl(kTestCrlUrl); bssl::ParsedCertificateList chain; ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain)); RevocationPolicy policy; policy.check_revocation = true; policy.allow_missing_info = false; policy.allow_unable_to_check = false; std::string crl_data_as_string_for_some_reason = BuildCrl(root->GetSubject(), root->GetKey(), /*revoked_serials=*/{}); std::vector crl_data(crl_data_as_string_for_some_reason.begin(), crl_data_as_string_for_some_reason.end()); { policy.networking_allowed = true; policy.crl_allowed = true; auto mock_fetcher = base::MakeRefCounted>(); EXPECT_CALL(*mock_fetcher, FetchCrl(kTestCrlUrl, _, _)) .WillOnce(Return(ByMove(MockCertNetFetcherRequest::Create(crl_data)))); bssl::CertPathErrors errors; CheckValidatedChainRevocation( chain, policy, /*deadline=*/base::TimeTicks(), /*stapled_leaf_ocsp_response=*/std::string_view(), mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr); EXPECT_FALSE(errors.ContainsHighSeverityErrors()); } { policy.networking_allowed = false; policy.crl_allowed = true; // No methods on |mock_fetcher| should be called. auto mock_fetcher = base::MakeRefCounted>(); bssl::CertPathErrors errors; CheckValidatedChainRevocation( chain, policy, /*deadline=*/base::TimeTicks(), /*stapled_leaf_ocsp_response=*/std::string_view(), mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr); EXPECT_TRUE(errors.ContainsHighSeverityErrors()); EXPECT_TRUE( errors.ContainsError(bssl::cert_errors::kUnableToCheckRevocation)); } { policy.networking_allowed = true; policy.crl_allowed = false; // No methods on |mock_fetcher| should be called. auto mock_fetcher = base::MakeRefCounted>(); bssl::CertPathErrors errors; CheckValidatedChainRevocation( chain, policy, /*deadline=*/base::TimeTicks(), /*stapled_leaf_ocsp_response=*/std::string_view(), mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr); EXPECT_TRUE(errors.ContainsHighSeverityErrors()); // Since CRLs were not considered, the error should be "no revocation // mechanism". EXPECT_TRUE( errors.ContainsError(bssl::cert_errors::kNoRevocationMechanism)); } } TEST(RevocationChecker, RevokedCRL) { auto [leaf, root] = CertBuilder::CreateSimpleChain2(); const GURL kTestCrlUrl("http://example.com/crl1"); leaf->SetCrlDistributionPointUrl(kTestCrlUrl); bssl::ParsedCertificateList chain; ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain)); RevocationPolicy policy; policy.check_revocation = true; policy.networking_allowed = true; policy.crl_allowed = true; std::string crl_data_as_string_for_some_reason = BuildCrl(root->GetSubject(), root->GetKey(), /*revoked_serials=*/{leaf->GetSerialNumber()}); std::vector crl_data(crl_data_as_string_for_some_reason.begin(), crl_data_as_string_for_some_reason.end()); { // These should have no effect on an affirmatively revoked response. policy.allow_missing_info = false; policy.allow_unable_to_check = false; auto mock_fetcher = base::MakeRefCounted>(); EXPECT_CALL(*mock_fetcher, FetchCrl(kTestCrlUrl, _, _)) .WillOnce(Return(ByMove(MockCertNetFetcherRequest::Create(crl_data)))); bssl::CertPathErrors errors; CheckValidatedChainRevocation( chain, policy, /*deadline=*/base::TimeTicks(), /*stapled_leaf_ocsp_response=*/std::string_view(), mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr); EXPECT_TRUE(errors.ContainsHighSeverityErrors()); EXPECT_TRUE(errors.ContainsError(bssl::cert_errors::kCertificateRevoked)); } { // These should have no effect on an affirmatively revoked response. policy.allow_missing_info = true; policy.allow_unable_to_check = true; auto mock_fetcher = base::MakeRefCounted>(); EXPECT_CALL(*mock_fetcher, FetchCrl(kTestCrlUrl, _, _)) .WillOnce(Return(ByMove(MockCertNetFetcherRequest::Create(crl_data)))); bssl::CertPathErrors errors; CheckValidatedChainRevocation( chain, policy, /*deadline=*/base::TimeTicks(), /*stapled_leaf_ocsp_response=*/std::string_view(), mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr); EXPECT_TRUE(errors.ContainsHighSeverityErrors()); EXPECT_TRUE(errors.ContainsError(bssl::cert_errors::kCertificateRevoked)); } } TEST(RevocationChecker, CRLRequestFails) { auto [leaf, root] = CertBuilder::CreateSimpleChain2(); const GURL kTestCrlUrl("http://example.com/crl1"); leaf->SetCrlDistributionPointUrl(kTestCrlUrl); bssl::ParsedCertificateList chain; ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain)); RevocationPolicy policy; policy.check_revocation = true; policy.networking_allowed = true; policy.crl_allowed = true; { policy.allow_unable_to_check = false; policy.allow_missing_info = false; auto mock_fetcher = base::MakeRefCounted>(); EXPECT_CALL(*mock_fetcher, FetchCrl(kTestCrlUrl, _, _)) .WillOnce(Return( ByMove(MockCertNetFetcherRequest::Create(ERR_CONNECTION_FAILED)))); bssl::CertPathErrors errors; CheckValidatedChainRevocation( chain, policy, /*deadline=*/base::TimeTicks(), /*stapled_leaf_ocsp_response=*/std::string_view(), mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr); EXPECT_TRUE(errors.ContainsHighSeverityErrors()); EXPECT_TRUE( errors.ContainsError(bssl::cert_errors::kUnableToCheckRevocation)); } { policy.allow_unable_to_check = false; policy.allow_missing_info = true; // Should have no effect. auto mock_fetcher = base::MakeRefCounted>(); EXPECT_CALL(*mock_fetcher, FetchCrl(kTestCrlUrl, _, _)) .WillOnce(Return( ByMove(MockCertNetFetcherRequest::Create(ERR_CONNECTION_FAILED)))); bssl::CertPathErrors errors; CheckValidatedChainRevocation( chain, policy, /*deadline=*/base::TimeTicks(), /*stapled_leaf_ocsp_response=*/std::string_view(), mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr); EXPECT_TRUE(errors.ContainsHighSeverityErrors()); EXPECT_TRUE( errors.ContainsError(bssl::cert_errors::kUnableToCheckRevocation)); } { policy.allow_unable_to_check = true; policy.allow_missing_info = false; auto mock_fetcher = base::MakeRefCounted>(); EXPECT_CALL(*mock_fetcher, FetchCrl(kTestCrlUrl, _, _)) .WillOnce(Return( ByMove(MockCertNetFetcherRequest::Create(ERR_CONNECTION_FAILED)))); bssl::CertPathErrors errors; CheckValidatedChainRevocation( chain, policy, /*deadline=*/base::TimeTicks(), /*stapled_leaf_ocsp_response=*/std::string_view(), mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr); EXPECT_FALSE(errors.ContainsHighSeverityErrors()); } } TEST(RevocationChecker, CRLNonHttpUrl) { auto [leaf, root] = CertBuilder::CreateSimpleChain2(); const GURL kTestCrlUrl("https://example.com/crl1"); leaf->SetCrlDistributionPointUrl(kTestCrlUrl); bssl::ParsedCertificateList chain; ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain)); RevocationPolicy policy; policy.check_revocation = true; policy.networking_allowed = true; policy.crl_allowed = true; policy.allow_unable_to_check = false; policy.allow_missing_info = false; // HTTPS CRL URLs should not be fetched. auto mock_fetcher = base::MakeRefCounted>(); bssl::CertPathErrors errors; CheckValidatedChainRevocation( chain, policy, /*deadline=*/base::TimeTicks(), /*stapled_leaf_ocsp_response=*/std::string_view(), mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr); EXPECT_TRUE(errors.ContainsHighSeverityErrors()); EXPECT_TRUE(errors.ContainsError(bssl::cert_errors::kNoRevocationMechanism)); } TEST(RevocationChecker, SkipEntireInvalidCRLDistributionPoints) { auto [leaf, root] = CertBuilder::CreateSimpleChain2(); const GURL kSecondCrlUrl("http://www.example.com/bar.crl"); // SEQUENCE { // # First distribution point: this is invalid, thus the entire // # crlDistributionPoints extension should be ignored and revocation // # checking should fail. // SEQUENCE { // [0] { // [0] { // # [9] is not a valid tag in bssl::GeneralNames // [9 PRIMITIVE] { "foo" } // } // } // } // # Second distribution point. Even though this is an acceptable // # distributionPoint, it should not be used. // SEQUENCE { // [0] { // [0] { // [6 PRIMITIVE] { "http://www.example.com/bar.crl" } // } // } // } // } const uint8_t crldp[] = {0x30, 0x31, 0x30, 0x09, 0xa0, 0x07, 0xa0, 0x05, 0x89, 0x03, 0x66, 0x6f, 0x6f, 0x30, 0x24, 0xa0, 0x22, 0xa0, 0x20, 0x86, 0x1e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61, 0x72, 0x2e, 0x63, 0x72, 0x6c}; leaf->SetExtension( bssl::der::Input(bssl::kCrlDistributionPointsOid), std::string(reinterpret_cast(crldp), std::size(crldp))); bssl::ParsedCertificateList chain; ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain)); RevocationPolicy policy; policy.check_revocation = true; policy.networking_allowed = true; policy.crl_allowed = true; policy.allow_unable_to_check = false; policy.allow_missing_info = false; std::string crl_data_as_string_for_some_reason = BuildCrl(root->GetSubject(), root->GetKey(), /*revoked_serials=*/{}); std::vector crl_data(crl_data_as_string_for_some_reason.begin(), crl_data_as_string_for_some_reason.end()); // No methods on |mock_fetcher| should be called. auto mock_fetcher = base::MakeRefCounted>(); bssl::CertPathErrors errors; CheckValidatedChainRevocation( chain, policy, /*deadline=*/base::TimeTicks(), /*stapled_leaf_ocsp_response=*/std::string_view(), mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr); // Should fail since the entire cRLDistributionPoints extension was skipped // and no other revocation method is present. EXPECT_TRUE(errors.ContainsHighSeverityErrors()); EXPECT_TRUE(errors.ContainsError(bssl::cert_errors::kNoRevocationMechanism)); } TEST(RevocationChecker, SkipUnsupportedCRLDistPointWithNonUriFullname) { auto [leaf, root] = CertBuilder::CreateSimpleChain2(); const GURL kSecondCrlUrl("http://www.example.com/bar.crl"); // SEQUENCE { // # First distribution point: this should be ignored since it has a non-URI // # fullName field. // SEQUENCE { // [0] { // [0] { // [4] { // SEQUENCE { // SET { // SEQUENCE { // # countryName // OBJECT_IDENTIFIER { 2.5.4.6 } // PrintableString { "US" } // } // } // SET { // SEQUENCE { // # commonName // OBJECT_IDENTIFIER { 2.5.4.3 } // PrintableString { "foo" } // } // } // } // } // } // } // } // # Second distribution point. This should be used since it only has a // # fullName URI. // SEQUENCE { // [0] { // [0] { // [6 PRIMITIVE] { "http://www.example.com/bar.crl" } // } // } // } // } const uint8_t crldp[] = { 0x30, 0x4b, 0x30, 0x23, 0xa0, 0x21, 0xa0, 0x1f, 0xa4, 0x1d, 0x30, 0x1b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x03, 0x66, 0x6f, 0x6f, 0x30, 0x24, 0xa0, 0x22, 0xa0, 0x20, 0x86, 0x1e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61, 0x72, 0x2e, 0x63, 0x72, 0x6c}; leaf->SetExtension( bssl::der::Input(bssl::kCrlDistributionPointsOid), std::string(reinterpret_cast(crldp), std::size(crldp))); bssl::ParsedCertificateList chain; ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain)); RevocationPolicy policy; policy.check_revocation = true; policy.networking_allowed = true; policy.crl_allowed = true; policy.allow_unable_to_check = false; policy.allow_missing_info = false; std::string crl_data_as_string_for_some_reason = BuildCrl(root->GetSubject(), root->GetKey(), /*revoked_serials=*/{}); std::vector crl_data(crl_data_as_string_for_some_reason.begin(), crl_data_as_string_for_some_reason.end()); // The first crldp should be skipped, the second should be retrieved. auto mock_fetcher = base::MakeRefCounted>(); EXPECT_CALL(*mock_fetcher, FetchCrl(kSecondCrlUrl, _, _)) .WillOnce(Return(ByMove(MockCertNetFetcherRequest::Create(crl_data)))); bssl::CertPathErrors errors; CheckValidatedChainRevocation( chain, policy, /*deadline=*/base::TimeTicks(), /*stapled_leaf_ocsp_response=*/std::string_view(), mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr); EXPECT_FALSE(errors.ContainsHighSeverityErrors()); } TEST(RevocationChecker, SkipUnsupportedCRLDistPointWithReasons) { auto [leaf, root] = CertBuilder::CreateSimpleChain2(); const GURL kSecondCrlUrl("http://www.example.com/bar.crl"); // SEQUENCE { // # First distribution point: this should be ignored since it has a reasons // # field. // SEQUENCE { // [0] { // [0] { // [6 PRIMITIVE] { "http://www.example.com/foo.crl" } // } // } // # reasons // [1 PRIMITIVE] { b`011` } // } // # Second distribution point. This should be used since it only has a // # fullName URI. // SEQUENCE { // [0] { // [0] { // [6 PRIMITIVE] { "http://www.example.com/bar.crl" } // } // } // } // } const uint8_t crldp[] = { 0x30, 0x50, 0x30, 0x28, 0xa0, 0x22, 0xa0, 0x20, 0x86, 0x1e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6f, 0x6f, 0x2e, 0x63, 0x72, 0x6c, 0x81, 0x02, 0x05, 0x60, 0x30, 0x24, 0xa0, 0x22, 0xa0, 0x20, 0x86, 0x1e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61, 0x72, 0x2e, 0x63, 0x72, 0x6c}; leaf->SetExtension( bssl::der::Input(bssl::kCrlDistributionPointsOid), std::string(reinterpret_cast(crldp), std::size(crldp))); bssl::ParsedCertificateList chain; ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain)); RevocationPolicy policy; policy.check_revocation = true; policy.networking_allowed = true; policy.crl_allowed = true; policy.allow_unable_to_check = false; policy.allow_missing_info = false; std::string crl_data_as_string_for_some_reason = BuildCrl(root->GetSubject(), root->GetKey(), /*revoked_serials=*/{}); std::vector crl_data(crl_data_as_string_for_some_reason.begin(), crl_data_as_string_for_some_reason.end()); // The first crldp should be skipped, the second should be retrieved. auto mock_fetcher = base::MakeRefCounted>(); EXPECT_CALL(*mock_fetcher, FetchCrl(kSecondCrlUrl, _, _)) .WillOnce(Return(ByMove(MockCertNetFetcherRequest::Create(crl_data)))); bssl::CertPathErrors errors; CheckValidatedChainRevocation( chain, policy, /*deadline=*/base::TimeTicks(), /*stapled_leaf_ocsp_response=*/std::string_view(), mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr); EXPECT_FALSE(errors.ContainsHighSeverityErrors()); } TEST(RevocationChecker, SkipUnsupportedCRLDistPointWithCrlIssuer) { auto [leaf, root] = CertBuilder::CreateSimpleChain2(); const GURL kSecondCrlUrl("http://www.example.com/bar.crl"); // SEQUENCE { // # First distribution point: this should be ignored since it has a // crlIssuer field. // SEQUENCE { // [0] { // [0] { // [6 PRIMITIVE] { "http://www.example.com/foo.crl" } // } // } // [2] { // [4] { // SEQUENCE { // SET { // SEQUENCE { // # countryName // OBJECT_IDENTIFIER { 2.5.4.6 } // PrintableString { "US" } // } // } // SET { // SEQUENCE { // # organizationName // OBJECT_IDENTIFIER { 2.5.4.10 } // PrintableString { "Test Certificates 2011" } // } // } // SET { // SEQUENCE { // # organizationUnitName // OBJECT_IDENTIFIER { 2.5.4.11 } // PrintableString { "indirectCRL CA3 cRLIssuer" } // } // } // } // } // } // } // # Second distribution point. This should be used since it only has a // # fullName URI. // SEQUENCE { // [0] { // [0] { // [6 PRIMITIVE] { "http://www.example.com/bar.crl" } // } // } // } // } const uint8_t crldp[] = { 0x30, 0x81, 0xa4, 0x30, 0x7c, 0xa0, 0x22, 0xa0, 0x20, 0x86, 0x1e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6f, 0x6f, 0x2e, 0x63, 0x72, 0x6c, 0xa2, 0x56, 0xa4, 0x54, 0x30, 0x52, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x16, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x32, 0x30, 0x31, 0x31, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x19, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x43, 0x52, 0x4c, 0x20, 0x43, 0x41, 0x33, 0x20, 0x63, 0x52, 0x4c, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x30, 0x24, 0xa0, 0x22, 0xa0, 0x20, 0x86, 0x1e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61, 0x72, 0x2e, 0x63, 0x72, 0x6c}; leaf->SetExtension( bssl::der::Input(bssl::kCrlDistributionPointsOid), std::string(reinterpret_cast(crldp), std::size(crldp))); bssl::ParsedCertificateList chain; ASSERT_TRUE(AddCertsToList({leaf.get(), root.get()}, &chain)); RevocationPolicy policy; policy.check_revocation = true; policy.networking_allowed = true; policy.crl_allowed = true; policy.allow_unable_to_check = false; policy.allow_missing_info = false; std::string crl_data_as_string_for_some_reason = BuildCrl(root->GetSubject(), root->GetKey(), /*revoked_serials=*/{}); std::vector crl_data(crl_data_as_string_for_some_reason.begin(), crl_data_as_string_for_some_reason.end()); // The first crldp should be skipped, the second should be retrieved. auto mock_fetcher = base::MakeRefCounted>(); EXPECT_CALL(*mock_fetcher, FetchCrl(kSecondCrlUrl, _, _)) .WillOnce(Return(ByMove(MockCertNetFetcherRequest::Create(crl_data)))); bssl::CertPathErrors errors; CheckValidatedChainRevocation( chain, policy, /*deadline=*/base::TimeTicks(), /*stapled_leaf_ocsp_response=*/std::string_view(), mock_fetcher.get(), &errors, /*stapled_ocsp_verify_result=*/nullptr); EXPECT_FALSE(errors.ContainsHighSeverityErrors()); } // TODO(mattm): Add more unittests (deadlines, OCSP, stapled OCSP, CRLSets). // Currently those features are exercised indirectly through tests in // url_request_unittest.cc, cert_verify_proc_unittest.cc, etc. } // namespace } // namespace net