// Copyright 2019 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/cert_verify_proc_builtin.h" #include "base/memory/raw_ptr.h" #include "base/numerics/safe_conversions.h" #include "base/ranges/algorithm.h" #include "base/run_loop.h" #include "base/strings/stringprintf.h" #include "base/task/sequenced_task_runner.h" #include "base/task/thread_pool.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h" #include "base/time/time.h" #include "net/base/test_completion_callback.h" #include "net/cert/cert_verify_proc.h" #include "net/cert/crl_set.h" #include "net/cert/ev_root_ca_metadata.h" #include "net/cert/internal/system_trust_store.h" #include "net/cert/pki/trust_store.h" #include "net/cert/pki/trust_store_collection.h" #include "net/cert/pki/trust_store_in_memory.h" #include "net/cert_net/cert_net_fetcher_url_request.h" #include "net/der/encode_values.h" #include "net/log/net_log_with_source.h" #include "net/log/test_net_log.h" #include "net/test/cert_builder.h" #include "net/test/cert_test_util.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" #include "net/test/embedded_test_server/request_handler_util.h" #include "net/test/gtest_util.h" #include "net/test/revocation_builder.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_builder.h" #include "net/url_request/url_request_test_util.h" #include "testing/gtest/include/gtest/gtest.h" using net::test::IsError; using net::test::IsOk; namespace net { namespace { std::unique_ptr HangRequestAndCallback( base::OnceClosure callback, const test_server::HttpRequest& request) { std::move(callback).Run(); return std::make_unique(); } void FailTest(const std::string& message) { ADD_FAILURE() << message; } std::unique_ptr FailRequestAndFailTest( const std::string& message, scoped_refptr main_task_runner, const test_server::HttpRequest& request) { main_task_runner->PostTask(FROM_HERE, base::BindOnce(FailTest, message)); auto response = std::make_unique(); response->set_code(HTTP_NOT_ACCEPTABLE); return response; } std::unique_ptr ServeResponse( HttpStatusCode status_code, const std::string& content_type, const std::string& content, const test_server::HttpRequest& request) { auto http_response = std::make_unique(); http_response->set_code(status_code); http_response->set_content_type(content_type); http_response->set_content(content); return http_response; } std::string MakeRandomHexString(size_t num_bytes) { std::vector rand_bytes; rand_bytes.resize(num_bytes); base::RandBytes(rand_bytes.data(), rand_bytes.size()); return base::HexEncode(rand_bytes.data(), rand_bytes.size()); } static std::string MakeRandomPath(base::StringPiece suffix) { return "/" + MakeRandomHexString(12) + std::string(suffix); } int VerifyOnWorkerThread(const scoped_refptr& verify_proc, scoped_refptr cert, const std::string& hostname, int flags, const CertificateList& additional_trust_anchors, CertVerifyResult* verify_result, NetLogSource* out_source) { base::ScopedAllowBaseSyncPrimitivesForTesting scoped_allow_blocking; NetLogWithSource net_log(NetLogWithSource::Make( net::NetLog::Get(), net::NetLogSourceType::CERT_VERIFIER_TASK)); int error = verify_proc->Verify(cert.get(), hostname, /*ocsp_response=*/std::string(), /*sct_list=*/std::string(), flags, additional_trust_anchors, verify_result, net_log); verify_result->DetachFromSequence(); *out_source = net_log.source(); return error; } class MockSystemTrustStore : public SystemTrustStore { public: TrustStore* GetTrustStore() override { return &trust_store_; } bool UsesSystemTrustStore() const override { return false; } bool IsKnownRoot(const ParsedCertificate* trust_anchor) const override { return mock_is_known_root_; } void AddTrustStore(TrustStore* store) { trust_store_.AddTrustStore(store); } void SetMockIsKnownRoot(bool is_known_root) { mock_is_known_root_ = is_known_root; } #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) int64_t chrome_root_store_version() override { return 0; } #endif private: TrustStoreCollection trust_store_; bool mock_is_known_root_ = false; }; class BlockingTrustStore : public TrustStore { public: CertificateTrust GetTrust(const ParsedCertificate* cert, base::SupportsUserData* debug_data) override { return backing_trust_store_.GetTrust(cert, debug_data); } void SyncGetIssuersOf(const ParsedCertificate* cert, ParsedCertificateList* issuers) override { sync_get_issuer_started_event_.Signal(); sync_get_issuer_ok_to_finish_event_.Wait(); backing_trust_store_.SyncGetIssuersOf(cert, issuers); } base::WaitableEvent sync_get_issuer_started_event_; base::WaitableEvent sync_get_issuer_ok_to_finish_event_; TrustStoreInMemory backing_trust_store_; }; } // namespace class CertVerifyProcBuiltinTest : public ::testing::Test { public: // CertVerifyProcBuiltinTest() {} void SetUp() override { cert_net_fetcher_ = base::MakeRefCounted(); auto mock_system_trust_store = std::make_unique(); mock_system_trust_store_ = mock_system_trust_store.get(); verify_proc_ = CreateCertVerifyProcBuiltin( cert_net_fetcher_, CRLSet::EmptyCRLSetForTesting(), std::move(mock_system_trust_store)); context_ = CreateTestURLRequestContextBuilder()->Build(); cert_net_fetcher_->SetURLRequestContext(context_.get()); } void TearDown() override { cert_net_fetcher_->Shutdown(); } void Verify(scoped_refptr cert, const std::string& hostname, int flags, const CertificateList& additional_trust_anchors, CertVerifyResult* verify_result, NetLogSource* out_source, CompletionOnceCallback callback) { verify_result->DetachFromSequence(); base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, base::BindOnce(&VerifyOnWorkerThread, verify_proc_, std::move(cert), hostname, flags, additional_trust_anchors, verify_result, out_source), std::move(callback)); } base::test::TaskEnvironment& task_environment() { return task_environment_; } // Creates a CRL issued and signed by |crl_issuer|, marking |revoked_serials| // as revoked, and registers it to be served by the test server. // Returns the full URL to retrieve the CRL from the test server. GURL CreateAndServeCrl( EmbeddedTestServer* test_server, CertBuilder* crl_issuer, const std::vector& revoked_serials, absl::optional signature_algorithm = absl::nullopt) { std::string crl = BuildCrl(crl_issuer->GetSubject(), crl_issuer->GetKey(), revoked_serials, signature_algorithm); std::string crl_path = MakeRandomPath(".crl"); test_server->RegisterRequestHandler( base::BindRepeating(&test_server::HandlePrefixedRequest, crl_path, base::BindRepeating(ServeResponse, HTTP_OK, "application/pkix-crl", crl))); return test_server->GetURL(crl_path); } void AddTrustStore(TrustStore* store) { mock_system_trust_store_->AddTrustStore(store); } void SetMockIsKnownRoot(bool is_known_root) { mock_system_trust_store_->SetMockIsKnownRoot(is_known_root); } private: base::test::TaskEnvironment task_environment_{ base::test::TaskEnvironment::TimeSource::MOCK_TIME, base::test::TaskEnvironment::MainThreadType::IO, }; CertVerifier::Config config_; std::unique_ptr context_; // Must outlive `mock_system_trust_store_`. scoped_refptr verify_proc_; raw_ptr mock_system_trust_store_ = nullptr; scoped_refptr cert_net_fetcher_; }; TEST_F(CertVerifyProcBuiltinTest, SimpleSuccess) { auto [leaf, intermediate, root] = CertBuilder::CreateSimpleChain3(); scoped_refptr chain = leaf->GetX509CertificateChain(); ASSERT_TRUE(chain.get()); base::HistogramTester histogram_tester; CertVerifyResult verify_result; NetLogSource verify_net_log_source; TestCompletionCallback callback; Verify(chain.get(), "www.example.com", /*flags=*/0, /*additional_trust_anchors=*/{root->GetX509Certificate()}, &verify_result, &verify_net_log_source, callback.callback()); int error = callback.WaitForResult(); EXPECT_THAT(error, IsOk()); EXPECT_THAT(histogram_tester.GetAllSamples( "Net.CertVerifier.PathBuilderIterationCount"), testing::ElementsAre(base::Bucket(/*min=*/2, /*count=*/1))); } TEST_F(CertVerifyProcBuiltinTest, CRLNotCheckedForKnownRoots) { auto [leaf, root] = CertBuilder::CreateSimpleChain2(); EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTP); ASSERT_TRUE(test_server.InitializeAndListen()); // CRL that marks leaf as revoked. leaf->SetCrlDistributionPointUrl( CreateAndServeCrl(&test_server, root.get(), {leaf->GetSerialNumber()})); test_server.StartAcceptingConnections(); scoped_refptr chain = leaf->GetX509CertificateChain(); ASSERT_TRUE(chain.get()); NetLogSource verify_net_log_source; { CertVerifyResult verify_result; TestCompletionCallback verify_callback; Verify(chain.get(), "www.example.com", CertVerifyProc::VERIFY_REV_CHECKING_ENABLED, /*additional_trust_anchors=*/{root->GetX509Certificate()}, &verify_result, &verify_net_log_source, verify_callback.callback()); int error = verify_callback.WaitForResult(); EXPECT_THAT(error, IsError(ERR_CERT_REVOKED)); EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_REV_CHECKING_ENABLED); } { // Pretend the root is a known root. SetMockIsKnownRoot(true); base::HistogramTester histogram_tester; CertVerifyResult verify_result; TestCompletionCallback verify_callback; Verify(chain.get(), "www.example.com", CertVerifyProc::VERIFY_REV_CHECKING_ENABLED, /*additional_trust_anchors=*/{root->GetX509Certificate()}, &verify_result, &verify_net_log_source, verify_callback.callback()); int error = verify_callback.WaitForResult(); // CRLs are not checked for chains issued by known roots, so verification // should be successful. EXPECT_THAT(error, IsOk()); EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_REV_CHECKING_ENABLED); EXPECT_THAT(histogram_tester.GetAllSamples( "Net.CertVerifier.PathBuilderIterationCount"), testing::ElementsAre(base::Bucket(/*min=*/1, /*count=*/1))); } } // Tests that if the verification deadline is exceeded during revocation // checking, additional CRL fetches will not be attempted. TEST_F(CertVerifyProcBuiltinTest, RevocationCheckDeadlineCRL) { auto [leaf, intermediate, root] = CertBuilder::CreateSimpleChain3(); const base::TimeDelta timeout_increment = CertNetFetcherURLRequest::GetDefaultTimeoutForTesting() + base::Milliseconds(1); const int expected_request_count = base::ClampFloor(GetCertVerifyProcBuiltinTimeLimitForTesting() / timeout_increment) + 1; EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTP); ASSERT_TRUE(test_server.InitializeAndListen()); // Set up the test cert to have enough crlDistributionPoint urls that if the // first N-1 requests hang the deadline will be exceeded before the Nth // request is made. std::vector crl_urls; std::vector runloops(expected_request_count); for (int i = 0; i < expected_request_count; ++i) { std::string path = base::StringPrintf("/hung/%i", i); crl_urls.emplace_back(test_server.GetURL(path)); test_server.RegisterRequestHandler( base::BindRepeating(&test_server::HandlePrefixedRequest, path, base::BindRepeating(&HangRequestAndCallback, runloops[i].QuitClosure()))); } // Add CRL URLs and handlers that will add test failures if requested. for (int i = expected_request_count; i < expected_request_count + 1; ++i) { std::string path = base::StringPrintf("/failtest/%i", i); crl_urls.emplace_back(test_server.GetURL(path)); test_server.RegisterRequestHandler(base::BindRepeating( &test_server::HandlePrefixedRequest, path, base::BindRepeating(FailRequestAndFailTest, "additional request made after deadline exceeded", base::SequencedTaskRunner::GetCurrentDefault()))); } leaf->SetCrlDistributionPointUrls(crl_urls); test_server.StartAcceptingConnections(); scoped_refptr chain = leaf->GetX509CertificateChain(); ASSERT_TRUE(chain.get()); base::HistogramTester histogram_tester; CertVerifyResult verify_result; NetLogSource verify_net_log_source; TestCompletionCallback verify_callback; Verify(chain.get(), "www.example.com", CertVerifyProc::VERIFY_REV_CHECKING_ENABLED, /*additional_trust_anchors=*/{root->GetX509Certificate()}, &verify_result, &verify_net_log_source, verify_callback.callback()); for (int i = 0; i < expected_request_count; i++) { // Wait for request #|i| to be made. runloops[i].Run(); // Advance virtual time to cause the timeout task to become runnable. task_environment().AdvanceClock(timeout_increment); } // Once |expected_request_count| requests have been made and timed out, the // overall deadline should be reached, and no more requests should have been // made. (If they were, the test will fail due to the ADD_FAILURE callback in // the request handlers.) int error = verify_callback.WaitForResult(); // Soft-fail revocation checking was used, therefore verification result // should be OK even though none of the CRLs could be retrieved. EXPECT_THAT(error, IsOk()); EXPECT_THAT(histogram_tester.GetAllSamples( "Net.CertVerifier.PathBuilderIterationCount"), testing::ElementsAre(base::Bucket(/*min=*/2, /*count=*/1))); } // Tests that if the verification deadline is exceeded during revocation // checking, additional OCSP fetches will not be attempted. TEST_F(CertVerifyProcBuiltinTest, RevocationCheckDeadlineOCSP) { auto [leaf, intermediate, root] = CertBuilder::CreateSimpleChain3(); const base::TimeDelta timeout_increment = CertNetFetcherURLRequest::GetDefaultTimeoutForTesting() + base::Milliseconds(1); const int expected_request_count = base::ClampFloor(GetCertVerifyProcBuiltinTimeLimitForTesting() / timeout_increment) + 1; EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTP); ASSERT_TRUE(test_server.InitializeAndListen()); // Set up the test cert to have enough OCSP urls that if the // first N-1 requests hang the deadline will be exceeded before the Nth // request is made. std::vector ocsp_urls; std::vector runloops(expected_request_count); for (int i = 0; i < expected_request_count; ++i) { std::string path = base::StringPrintf("/hung/%i", i); ocsp_urls.emplace_back(test_server.GetURL(path)); test_server.RegisterRequestHandler( base::BindRepeating(&test_server::HandlePrefixedRequest, path, base::BindRepeating(&HangRequestAndCallback, runloops[i].QuitClosure()))); } // Add OCSP URLs and handlers that will add test failures if requested. for (int i = expected_request_count; i < expected_request_count + 1; ++i) { std::string path = base::StringPrintf("/failtest/%i", i); ocsp_urls.emplace_back(test_server.GetURL(path)); test_server.RegisterRequestHandler(base::BindRepeating( &test_server::HandlePrefixedRequest, path, base::BindRepeating(FailRequestAndFailTest, "additional request made after deadline exceeded", base::SequencedTaskRunner::GetCurrentDefault()))); } leaf->SetCaIssuersAndOCSPUrls({}, ocsp_urls); test_server.StartAcceptingConnections(); scoped_refptr chain = leaf->GetX509CertificateChain(); ASSERT_TRUE(chain.get()); CertVerifyResult verify_result; NetLogSource verify_net_log_source; TestCompletionCallback verify_callback; Verify(chain.get(), "www.example.com", CertVerifyProc::VERIFY_REV_CHECKING_ENABLED, /*additional_trust_anchors=*/{root->GetX509Certificate()}, &verify_result, &verify_net_log_source, verify_callback.callback()); for (int i = 0; i < expected_request_count; i++) { // Wait for request #|i| to be made. runloops[i].Run(); // Advance virtual time to cause the timeout task to become runnable. task_environment().AdvanceClock(timeout_increment); } // Once |expected_request_count| requests have been made and timed out, the // overall deadline should be reached, and no more requests should have been // made. (If they were, the test will fail due to the ADD_FAILURE callback in // the request handlers.) int error = verify_callback.WaitForResult(); // Soft-fail revocation checking was used, therefore verification result // should be OK even though none of the OCSP responses could be retrieved. EXPECT_THAT(error, IsOk()); } #if defined(PLATFORM_USES_CHROMIUM_EV_METADATA) // Tests that if we're doing EV verification, that no OCSP revocation checking // is done. TEST_F(CertVerifyProcBuiltinTest, EVNoOCSPRevocationChecks) { auto [leaf, intermediate, root] = CertBuilder::CreateSimpleChain3(); // Add test EV policy to leaf and intermediate. static const char kEVTestCertPolicy[] = "1.2.3.4"; leaf->SetCertificatePolicies({kEVTestCertPolicy}); intermediate->SetCertificatePolicies({kEVTestCertPolicy}); EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTP); ASSERT_TRUE(test_server.InitializeAndListen()); // Set up the test intermediate to have an OCSP url that fails the test if // called. std::vector ocsp_urls; std::string path = "/failtest"; ocsp_urls.emplace_back(test_server.GetURL(path)); test_server.RegisterRequestHandler(base::BindRepeating( &test_server::HandlePrefixedRequest, path, base::BindRepeating(FailRequestAndFailTest, "no OCSP requests should be sent", base::SequencedTaskRunner::GetCurrentDefault()))); intermediate->SetCaIssuersAndOCSPUrls({}, ocsp_urls); test_server.StartAcceptingConnections(); // Consider the root of the test chain a valid EV root for the test policy. ScopedTestEVPolicy scoped_test_ev_policy( EVRootCAMetadata::GetInstance(), X509Certificate::CalculateFingerprint256(root->GetCertBuffer()), kEVTestCertPolicy); scoped_refptr chain = leaf->GetX509CertificateChain(); ASSERT_TRUE(chain.get()); RecordingNetLogObserver net_log_observer(NetLogCaptureMode::kDefault); CertVerifyResult verify_result; NetLogSource verify_net_log_source; TestCompletionCallback verify_callback; Verify(chain.get(), "www.example.com", /*flags=*/0, /*additional_trust_anchors=*/{root->GetX509Certificate()}, &verify_result, &verify_net_log_source, verify_callback.callback()); // EV doesn't do revocation checking, therefore verification result // should be OK and EV. int error = verify_callback.WaitForResult(); EXPECT_THAT(error, IsOk()); EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_IS_EV); EXPECT_FALSE(verify_result.cert_status & CERT_STATUS_REV_CHECKING_ENABLED); auto events = net_log_observer.GetEntriesForSource(verify_net_log_source); auto event = base::ranges::find( events, NetLogEventType::CERT_VERIFY_PROC_PATH_BUILD_ATTEMPT, &NetLogEntry::type); ASSERT_NE(event, events.end()); EXPECT_EQ(net::NetLogEventPhase::BEGIN, event->phase); EXPECT_EQ(true, event->params.FindBool("is_ev_attempt")); event = base::ranges::find(++event, events.end(), NetLogEventType::CERT_VERIFY_PROC_PATH_BUILT, &NetLogEntry::type); ASSERT_NE(event, events.end()); EXPECT_EQ(net::NetLogEventPhase::NONE, event->phase); EXPECT_FALSE(event->params.FindString("errors")); event = base::ranges::find( ++event, events.end(), NetLogEventType::CERT_VERIFY_PROC_PATH_BUILD_ATTEMPT, &NetLogEntry::type); ASSERT_NE(event, events.end()); EXPECT_EQ(net::NetLogEventPhase::END, event->phase); EXPECT_EQ(true, event->params.FindBool("has_valid_path")); } #endif // defined(PLATFORM_USES_CHROMIUM_EV_METADATA) TEST_F(CertVerifyProcBuiltinTest, DeadlineExceededDuringSyncGetIssuers) { auto [leaf, intermediate, root] = CertBuilder::CreateSimpleChain3(); BlockingTrustStore trust_store; AddTrustStore(&trust_store); auto intermediate_parsed_cert = ParsedCertificate::Create(intermediate->DupCertBuffer(), {}, nullptr); ASSERT_TRUE(intermediate_parsed_cert); trust_store.backing_trust_store_.AddCertificateWithUnspecifiedTrust( intermediate_parsed_cert); scoped_refptr chain = leaf->GetX509Certificate(); ASSERT_TRUE(chain.get()); CertVerifyResult verify_result; NetLogSource verify_net_log_source; TestCompletionCallback verify_callback; Verify(chain.get(), "www.example.com", /*flags=*/0, /*additional_trust_anchors=*/{root->GetX509Certificate()}, &verify_result, &verify_net_log_source, verify_callback.callback()); // Wait for trust_store.SyncGetIssuersOf to be called. trust_store.sync_get_issuer_started_event_.Wait(); // Advance the clock past the verifier deadline. const base::TimeDelta timeout_increment = GetCertVerifyProcBuiltinTimeLimitForTesting() + base::Milliseconds(1); task_environment().AdvanceClock(timeout_increment); // Signal trust_store.SyncGetIssuersOf to finish. trust_store.sync_get_issuer_ok_to_finish_event_.Signal(); int error = verify_callback.WaitForResult(); // Because the deadline was reached while retrieving the intermediate, path // building should have stopped there and not found the root. The partial // path built up to that point should be returned, and the error should be // CERT_AUTHORITY_INVALID. EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID)); ASSERT_EQ(1u, verify_result.verified_cert->intermediate_buffers().size()); EXPECT_EQ(intermediate->GetCertBuffer(), verify_result.verified_cert->intermediate_buffers()[0].get()); } TEST_F(CertVerifyProcBuiltinTest, DebugData) { auto [leaf, intermediate, root] = CertBuilder::CreateSimpleChain3(); scoped_refptr chain = leaf->GetX509CertificateChain(); ASSERT_TRUE(chain.get()); base::Time time = base::Time::Now(); CertVerifyResult verify_result; NetLogSource verify_net_log_source; TestCompletionCallback callback; Verify(chain.get(), "www.example.com", /*flags=*/0, /*additional_trust_anchors=*/{root->GetX509Certificate()}, &verify_result, &verify_net_log_source, callback.callback()); int error = callback.WaitForResult(); EXPECT_THAT(error, IsOk()); auto* debug_data = CertVerifyProcBuiltinResultDebugData::Get(&verify_result); ASSERT_TRUE(debug_data); // No delayed tasks involved, so the mock time should not have advanced. EXPECT_EQ(time, debug_data->verification_time()); base::Time der_verification_time_converted_back_to_base_time; EXPECT_TRUE(net::der::GeneralizedTimeToTime( debug_data->der_verification_time(), &der_verification_time_converted_back_to_base_time)); // GeneralizedTime only has seconds precision. EXPECT_EQ( 0, (time - der_verification_time_converted_back_to_base_time).InSeconds()); } namespace { // Returns a TLV to use as an unknown signature algorithm when building a cert. // The specific contents are as follows (the OID is from // https://davidben.net/oid): // // SEQUENCE { // OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.0 } // NULL {} // } std::string UnknownSignatureAlgorithmTLV() { const uint8_t kInvalidSignatureAlgorithmTLV[] = { 0x30, 0x10, 0x06, 0x0c, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7, 0x09, 0x00, 0x05, 0x00}; return std::string(std::begin(kInvalidSignatureAlgorithmTLV), std::end(kInvalidSignatureAlgorithmTLV)); } // Returns a TLV to use as an invalid signature algorithm when building a cert. // This is a SEQUENCE so that it will pass the ParseCertificate code // and fail inside ParseSignatureAlgorithm. // SEQUENCE { // INTEGER { 42 } // } std::string InvalidSignatureAlgorithmTLV() { const uint8_t kInvalidSignatureAlgorithmTLV[] = {0x30, 0x03, 0x02, 0x01, 0x2a}; return std::string(std::begin(kInvalidSignatureAlgorithmTLV), std::end(kInvalidSignatureAlgorithmTLV)); } } // namespace TEST_F(CertVerifyProcBuiltinTest, UnknownSignatureAlgorithmTarget) { auto [leaf, intermediate, root] = CertBuilder::CreateSimpleChain3(); leaf->SetSignatureAlgorithmTLV(UnknownSignatureAlgorithmTLV()); // Trust the root and build a chain to verify that includes the intermediate. ScopedTestRoot scoped_root(root->GetX509Certificate().get()); scoped_refptr chain = leaf->GetX509CertificateChain(); ASSERT_TRUE(chain.get()); int flags = 0; CertVerifyResult verify_result; NetLogSource verify_net_log_source; TestCompletionCallback callback; Verify(chain.get(), "www.example.com", flags, CertificateList(), &verify_result, &verify_net_log_source, callback.callback()); int error = callback.WaitForResult(); // Unknown signature algorithm in the leaf cert should result in the cert // being invalid. EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_INVALID); EXPECT_THAT(error, IsError(ERR_CERT_INVALID)); } TEST_F(CertVerifyProcBuiltinTest, UnparsableMismatchedTBSSignatureAlgorithmTarget) { auto [leaf, root] = CertBuilder::CreateSimpleChain2(); // Set only the tbsCertificate signature to an invalid value. leaf->SetTBSSignatureAlgorithmTLV(InvalidSignatureAlgorithmTLV()); // Trust the root and build a chain to verify. ScopedTestRoot scoped_root(root->GetX509Certificate().get()); scoped_refptr chain = leaf->GetX509CertificateChain(); ASSERT_TRUE(chain.get()); int flags = 0; CertVerifyResult verify_result; NetLogSource verify_net_log_source; TestCompletionCallback callback; Verify(chain.get(), "www.example.com", flags, CertificateList(), &verify_result, &verify_net_log_source, callback.callback()); int error = callback.WaitForResult(); // Invalid signature algorithm in the leaf cert should result in the // cert being invalid. EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_INVALID); EXPECT_THAT(error, IsError(ERR_CERT_INVALID)); } TEST_F(CertVerifyProcBuiltinTest, UnknownSignatureAlgorithmIntermediate) { auto [leaf, intermediate, root] = CertBuilder::CreateSimpleChain3(); intermediate->SetSignatureAlgorithmTLV(UnknownSignatureAlgorithmTLV()); // Trust the root and build a chain to verify that includes the intermediate. ScopedTestRoot scoped_root(root->GetX509Certificate().get()); scoped_refptr chain = leaf->GetX509CertificateChain(); ASSERT_TRUE(chain.get()); int flags = 0; CertVerifyResult verify_result; NetLogSource verify_net_log_source; TestCompletionCallback callback; Verify(chain.get(), "www.example.com", flags, CertificateList(), &verify_result, &verify_net_log_source, callback.callback()); int error = callback.WaitForResult(); // Unknown signature algorithm in the intermediate cert should result in the // cert being invalid. EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_INVALID); EXPECT_THAT(error, IsError(ERR_CERT_INVALID)); } TEST_F(CertVerifyProcBuiltinTest, UnparsableMismatchedTBSSignatureAlgorithmIntermediate) { auto [leaf, intermediate, root] = CertBuilder::CreateSimpleChain3(); // Set only the tbsCertificate signature to an invalid value. intermediate->SetTBSSignatureAlgorithmTLV(InvalidSignatureAlgorithmTLV()); // Trust the root and build a chain to verify that includes the intermediate. ScopedTestRoot scoped_root(root->GetX509Certificate().get()); scoped_refptr chain = leaf->GetX509CertificateChain(); ASSERT_TRUE(chain.get()); ASSERT_EQ(chain->intermediate_buffers().size(), 1U); int flags = 0; CertVerifyResult verify_result; NetLogSource verify_net_log_source; TestCompletionCallback callback; Verify(chain.get(), "www.example.com", flags, CertificateList(), &verify_result, &verify_net_log_source, callback.callback()); int error = callback.WaitForResult(); // Invalid signature algorithm in the intermediate cert should result in the // cert being invalid. EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_INVALID); EXPECT_THAT(error, IsError(ERR_CERT_INVALID)); } TEST_F(CertVerifyProcBuiltinTest, UnknownSignatureAlgorithmRoot) { auto [leaf, intermediate, root] = CertBuilder::CreateSimpleChain3(); root->SetSignatureAlgorithmTLV(UnknownSignatureAlgorithmTLV()); // Trust the root and build a chain to verify that includes the intermediate. ScopedTestRoot scoped_root(root->GetX509Certificate().get()); scoped_refptr chain = leaf->GetX509CertificateChain(); ASSERT_TRUE(chain.get()); int flags = 0; CertVerifyResult verify_result; NetLogSource verify_net_log_source; TestCompletionCallback callback; Verify(chain.get(), "www.example.com", flags, CertificateList(), &verify_result, &verify_net_log_source, callback.callback()); int error = callback.WaitForResult(); // Unknown signature algorithm in the root cert should have no effect on // verification. EXPECT_THAT(error, IsOk()); } // This test is disabled on Android as adding the invalid root through // ScopedTestRoot causes it to be parsed by the Java X509 code which barfs. We // could re-enable if Chrome on Android has fully switched to the // builtin-verifier and ScopedTestRoot no longer has Android-specific code. #if BUILDFLAG(IS_ANDROID) #define MAYBE_UnparsableMismatchedTBSSignatureAlgorithmRoot \ DISABLED_UnparsableMismatchedTBSSignatureAlgorithmRoot #else #define MAYBE_UnparsableMismatchedTBSSignatureAlgorithmRoot \ UnparsableMismatchedTBSSignatureAlgorithmRoot #endif TEST_F(CertVerifyProcBuiltinTest, MAYBE_UnparsableMismatchedTBSSignatureAlgorithmRoot) { auto [leaf, intermediate, root] = CertBuilder::CreateSimpleChain3(); // Set only the tbsCertificate signature to an invalid value. root->SetTBSSignatureAlgorithmTLV(InvalidSignatureAlgorithmTLV()); // Trust the root and build a chain to verify that includes the intermediate. ScopedTestRoot scoped_root(root->GetX509Certificate().get()); scoped_refptr chain = leaf->GetX509CertificateChain(); ASSERT_TRUE(chain.get()); int flags = 0; CertVerifyResult verify_result; NetLogSource verify_net_log_source; TestCompletionCallback callback; Verify(chain.get(), "www.example.com", flags, CertificateList(), &verify_result, &verify_net_log_source, callback.callback()); int error = callback.WaitForResult(); // Invalid signature algorithm in the root cert should have no effect on // verification. EXPECT_THAT(error, IsOk()); } } // namespace net