| // Copyright 2018 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/trial_comparison_cert_verifier.h" |
| |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/functional/bind.h" |
| #include "base/logging.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/test/bind.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "build/build_config.h" |
| #include "crypto/sha2.h" |
| #include "net/base/test_completion_callback.h" |
| #include "net/cert/cert_verify_proc.h" |
| #include "net/cert/cert_verify_result.h" |
| #include "net/cert/crl_set.h" |
| #include "net/cert/ev_root_ca_metadata.h" |
| #include "net/cert/mock_cert_verifier.h" |
| #include "net/cert/trial_comparison_cert_verifier_util.h" |
| #include "net/cert/x509_certificate.h" |
| #include "net/cert/x509_util.h" |
| #include "net/log/net_log_with_source.h" |
| #include "net/test/cert_test_util.h" |
| #include "net/test/gtest_util.h" |
| #include "net/test/test_data_directory.h" |
| #include "net/test/test_with_task_environment.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using net::test::IsError; |
| using net::test::IsOk; |
| using testing::_; |
| using testing::DoAll; |
| using testing::Return; |
| using testing::SetArgPointee; |
| |
| namespace net { |
| |
| namespace { |
| |
| MATCHER_P(CertChainMatches, expected_cert, "") { |
| CertificateList actual_certs = |
| X509Certificate::CreateCertificateListFromBytes( |
| base::as_bytes(base::make_span(arg)), |
| X509Certificate::FORMAT_PEM_CERT_SEQUENCE); |
| if (actual_certs.empty()) { |
| *result_listener << "failed to parse arg"; |
| return false; |
| } |
| std::vector<std::string> actual_der_certs; |
| for (const auto& cert : actual_certs) { |
| actual_der_certs.emplace_back( |
| x509_util::CryptoBufferAsStringPiece(cert->cert_buffer())); |
| } |
| |
| std::vector<std::string> expected_der_certs; |
| expected_der_certs.emplace_back( |
| x509_util::CryptoBufferAsStringPiece(expected_cert->cert_buffer())); |
| for (const auto& buffer : expected_cert->intermediate_buffers()) { |
| expected_der_certs.emplace_back( |
| x509_util::CryptoBufferAsStringPiece(buffer.get())); |
| } |
| |
| return actual_der_certs == expected_der_certs; |
| } |
| |
| // Like TestClosure, but handles multiple closure.Run()/WaitForResult() |
| // calls correctly regardless of ordering. |
| class RepeatedTestClosure { |
| public: |
| RepeatedTestClosure() |
| : closure_(base::BindRepeating(&RepeatedTestClosure::DidSetResult, |
| base::Unretained(this))) {} |
| |
| const base::RepeatingClosure& closure() const { return closure_; } |
| |
| void WaitForResult() { |
| DCHECK(!run_loop_); |
| if (!have_result_) { |
| run_loop_ = std::make_unique<base::RunLoop>(); |
| run_loop_->Run(); |
| run_loop_.reset(); |
| DCHECK(have_result_); |
| } |
| have_result_--; // Auto-reset for next callback. |
| } |
| |
| private: |
| void DidSetResult() { |
| have_result_++; |
| if (run_loop_) |
| run_loop_->Quit(); |
| } |
| |
| // RunLoop. Only non-NULL during the call to WaitForResult, so the class is |
| // reusable. |
| std::unique_ptr<base::RunLoop> run_loop_; |
| |
| unsigned int have_result_ = 0; |
| |
| base::RepeatingClosure closure_; |
| }; |
| |
| // Fake CertVerifyProc that sets the CertVerifyResult to a given value for |
| // all certificates that are Verify()'d |
| class FakeCertVerifyProc : public CertVerifyProc { |
| public: |
| FakeCertVerifyProc(const int result_error, const CertVerifyResult& result) |
| : CertVerifyProc(CRLSet::BuiltinCRLSet()), |
| result_error_(result_error), |
| result_(result), |
| main_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {} |
| |
| FakeCertVerifyProc(const FakeCertVerifyProc&) = delete; |
| FakeCertVerifyProc& operator=(const FakeCertVerifyProc&) = delete; |
| |
| void WaitForVerifyCall() { verify_called_.WaitForResult(); } |
| int num_verifications() const { return num_verifications_; } |
| |
| // CertVerifyProc implementation: |
| bool SupportsAdditionalTrustAnchors() const override { return false; } |
| |
| protected: |
| ~FakeCertVerifyProc() override = default; |
| |
| private: |
| int VerifyInternal(X509Certificate* cert, |
| const std::string& hostname, |
| const std::string& ocsp_response, |
| const std::string& sct_list, |
| int flags, |
| const CertificateList& additional_trust_anchors, |
| CertVerifyResult* verify_result, |
| const NetLogWithSource& net_log) override; |
| |
| // Runs on the main thread |
| void VerifyCalled(); |
| |
| const int result_error_; |
| const CertVerifyResult result_; |
| int num_verifications_ = 0; |
| RepeatedTestClosure verify_called_; |
| scoped_refptr<base::TaskRunner> main_task_runner_; |
| }; |
| |
| int FakeCertVerifyProc::VerifyInternal( |
| X509Certificate* cert, |
| const std::string& hostname, |
| const std::string& ocsp_response, |
| const std::string& sct_list, |
| int flags, |
| const CertificateList& additional_trust_anchors, |
| CertVerifyResult* verify_result, |
| const NetLogWithSource& net_log) { |
| *verify_result = result_; |
| main_task_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&FakeCertVerifyProc::VerifyCalled, this)); |
| return result_error_; |
| } |
| |
| void FakeCertVerifyProc::VerifyCalled() { |
| ++num_verifications_; |
| verify_called_.closure().Run(); |
| } |
| |
| // Fake CertVerifyProc that causes a failure if it is called. |
| class NotCalledCertVerifyProc : public CertVerifyProc { |
| public: |
| NotCalledCertVerifyProc() : CertVerifyProc(CRLSet::BuiltinCRLSet()) {} |
| NotCalledCertVerifyProc(const NotCalledCertVerifyProc&) = delete; |
| NotCalledCertVerifyProc& operator=(const NotCalledCertVerifyProc&) = delete; |
| |
| // CertVerifyProc implementation: |
| bool SupportsAdditionalTrustAnchors() const override { return false; } |
| |
| protected: |
| ~NotCalledCertVerifyProc() override = default; |
| |
| private: |
| int VerifyInternal(X509Certificate* cert, |
| const std::string& hostname, |
| const std::string& ocsp_response, |
| const std::string& sct_list, |
| int flags, |
| const CertificateList& additional_trust_anchors, |
| CertVerifyResult* verify_result, |
| const NetLogWithSource& net_log) override; |
| }; |
| |
| int NotCalledCertVerifyProc::VerifyInternal( |
| X509Certificate* cert, |
| const std::string& hostname, |
| const std::string& ocsp_response, |
| const std::string& sct_list, |
| int flags, |
| const CertificateList& additional_trust_anchors, |
| CertVerifyResult* verify_result, |
| const NetLogWithSource& net_log) { |
| ADD_FAILURE() << "NotCalledCertVerifyProc was called!"; |
| return ERR_UNEXPECTED; |
| } |
| |
| scoped_refptr<CertVerifyProc> MakeNotCalledProc() { |
| return base::MakeRefCounted<NotCalledCertVerifyProc>(); |
| } |
| |
| void NotCalledCallback(int error) { |
| ADD_FAILURE() << "NotCalledCallback was called with error code " << error; |
| } |
| |
| class MockCertVerifyProc : public CertVerifyProc { |
| public: |
| MockCertVerifyProc() : CertVerifyProc(CRLSet::BuiltinCRLSet()) {} |
| |
| MockCertVerifyProc(const MockCertVerifyProc&) = delete; |
| MockCertVerifyProc& operator=(const MockCertVerifyProc&) = delete; |
| |
| // CertVerifyProc implementation: |
| bool SupportsAdditionalTrustAnchors() const override { return false; } |
| MOCK_METHOD8(VerifyInternal, |
| int(X509Certificate* cert, |
| const std::string& hostname, |
| const std::string& ocsp_response, |
| const std::string& sct_list, |
| int flags, |
| const CertificateList& additional_trust_anchors, |
| CertVerifyResult* verify_result, |
| const NetLogWithSource& net_log)); |
| |
| protected: |
| ~MockCertVerifyProc() override = default; |
| }; |
| |
| class TestProcFactory : public CertVerifyProcFactory { |
| public: |
| explicit TestProcFactory( |
| std::deque<scoped_refptr<CertVerifyProc>> primary_verify_procs, |
| std::deque<scoped_refptr<CertVerifyProc>> trial_verify_procs) |
| : primary_verify_procs_(std::move(primary_verify_procs)), |
| trial_verify_procs_(std::move(trial_verify_procs)) {} |
| |
| scoped_refptr<net::CertVerifyProc> CreateCertVerifyProc( |
| scoped_refptr<CertNetFetcher> cert_net_fetcher, |
| const ImplParams& impl_params) override { |
| std::deque<scoped_refptr<CertVerifyProc>>* procs = |
| impl_params.use_chrome_root_store ? &trial_verify_procs_ |
| : &primary_verify_procs_; |
| if (procs->empty()) { |
| ADD_FAILURE() << "procs is empty for crs=" |
| << impl_params.use_chrome_root_store; |
| return MakeNotCalledProc(); |
| } |
| scoped_refptr<CertVerifyProc> r = procs->front(); |
| procs->pop_front(); |
| return r; |
| } |
| |
| protected: |
| ~TestProcFactory() override = default; |
| |
| std::deque<scoped_refptr<CertVerifyProc>> primary_verify_procs_; |
| std::deque<scoped_refptr<CertVerifyProc>> trial_verify_procs_; |
| }; |
| |
| scoped_refptr<CertVerifyProcFactory> ProcFactory( |
| std::deque<scoped_refptr<CertVerifyProc>> primary_verify_procs, |
| std::deque<scoped_refptr<CertVerifyProc>> trial_verify_procs) { |
| return base::MakeRefCounted<TestProcFactory>(std::move(primary_verify_procs), |
| std::move(trial_verify_procs)); |
| } |
| |
| struct TrialReportInfo { |
| TrialReportInfo(const std::string& hostname, |
| const scoped_refptr<X509Certificate>& unverified_cert, |
| bool enable_rev_checking, |
| bool require_rev_checking_local_anchors, |
| bool enable_sha1_local_anchors, |
| bool disable_symantec_enforcement, |
| const std::string& stapled_ocsp, |
| const std::string& sct_list, |
| const CertVerifyResult& primary_result, |
| const CertVerifyResult& trial_result) |
| : hostname(hostname), |
| unverified_cert(unverified_cert), |
| enable_rev_checking(enable_rev_checking), |
| require_rev_checking_local_anchors(require_rev_checking_local_anchors), |
| enable_sha1_local_anchors(enable_sha1_local_anchors), |
| disable_symantec_enforcement(disable_symantec_enforcement), |
| stapled_ocsp(stapled_ocsp), |
| sct_list(sct_list), |
| primary_result(primary_result), |
| trial_result(trial_result) {} |
| |
| std::string hostname; |
| scoped_refptr<X509Certificate> unverified_cert; |
| bool enable_rev_checking; |
| bool require_rev_checking_local_anchors; |
| bool enable_sha1_local_anchors; |
| bool disable_symantec_enforcement; |
| std::string stapled_ocsp; |
| std::string sct_list; |
| CertVerifyResult primary_result; |
| CertVerifyResult trial_result; |
| }; |
| |
| void RecordTrialReport(std::vector<TrialReportInfo>* reports, |
| const std::string& hostname, |
| const scoped_refptr<X509Certificate>& unverified_cert, |
| bool enable_rev_checking, |
| bool require_rev_checking_local_anchors, |
| bool enable_sha1_local_anchors, |
| bool disable_symantec_enforcement, |
| const std::string& stapled_ocsp, |
| const std::string& sct_list, |
| const CertVerifyResult& primary_result, |
| const CertVerifyResult& trial_result) { |
| TrialReportInfo report(hostname, unverified_cert, enable_rev_checking, |
| require_rev_checking_local_anchors, |
| enable_sha1_local_anchors, |
| disable_symantec_enforcement, stapled_ocsp, sct_list, |
| primary_result, trial_result); |
| reports->push_back(report); |
| } |
| |
| } // namespace |
| |
| class TrialComparisonCertVerifierTest : public TestWithTaskEnvironment { |
| void SetUp() override { |
| cert_chain_1_ = CreateCertificateChainFromFile( |
| GetTestCertsDirectory(), "multi-root-chain1.pem", |
| X509Certificate::FORMAT_AUTO); |
| ASSERT_TRUE(cert_chain_1_); |
| leaf_cert_1_ = X509Certificate::CreateFromBuffer( |
| bssl::UpRef(cert_chain_1_->cert_buffer()), {}); |
| ASSERT_TRUE(leaf_cert_1_); |
| cert_chain_2_ = CreateCertificateChainFromFile( |
| GetTestCertsDirectory(), "multi-root-chain2.pem", |
| X509Certificate::FORMAT_AUTO); |
| ASSERT_TRUE(cert_chain_2_); |
| |
| lets_encrypt_dst_x3_ = CreateCertificateChainFromFile( |
| GetTestCertsDirectory(), "lets-encrypt-dst-x3-root.pem", |
| X509Certificate::FORMAT_AUTO); |
| ASSERT_TRUE(lets_encrypt_dst_x3_); |
| lets_encrypt_isrg_x1_ = CreateCertificateChainFromFile( |
| GetTestCertsDirectory(), "lets-encrypt-isrg-x1-root.pem", |
| X509Certificate::FORMAT_AUTO); |
| ASSERT_TRUE(lets_encrypt_isrg_x1_); |
| |
| no_crs_impl_params_.use_chrome_root_store = false; |
| yes_crs_impl_params_.use_chrome_root_store = true; |
| } |
| |
| protected: |
| scoped_refptr<X509Certificate> cert_chain_1_; |
| scoped_refptr<X509Certificate> cert_chain_2_; |
| scoped_refptr<X509Certificate> leaf_cert_1_; |
| scoped_refptr<X509Certificate> lets_encrypt_dst_x3_; |
| scoped_refptr<X509Certificate> lets_encrypt_isrg_x1_; |
| net::CertVerifyProcFactory::ImplParams no_crs_impl_params_; |
| net::CertVerifyProcFactory::ImplParams yes_crs_impl_params_; |
| base::HistogramTester histograms_; |
| }; |
| |
| TEST_F(TrialComparisonCertVerifierTest, ObserverIsCalledOnVerifierUpdate) { |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({MakeNotCalledProc(), MakeNotCalledProc(), |
| MakeNotCalledProc(), MakeNotCalledProc()}, |
| {MakeNotCalledProc(), MakeNotCalledProc()}), |
| nullptr, no_crs_impl_params_, |
| base::BindRepeating(&RecordTrialReport, &reports)); |
| |
| CertVerifierObserverCounter observer_(&verifier); |
| EXPECT_EQ(observer_.change_count(), 0u); |
| verifier.UpdateVerifyProcData(nullptr, no_crs_impl_params_); |
| // Observer is called twice since the TrialComparisonCertVerifier currently |
| // forwards notifications from both the primary and secondary verifiers. |
| EXPECT_EQ(observer_.change_count(), 2u); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, InitiallyDisallowed) { |
| CertVerifyResult dummy_result; |
| dummy_result.verified_cert = cert_chain_1_; |
| |
| auto verify_proc = base::MakeRefCounted<FakeCertVerifyProc>(OK, dummy_result); |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc, MakeNotCalledProc()}, {MakeNotCalledProc()}), |
| nullptr, no_crs_impl_params_, |
| base::BindRepeating(&RecordTrialReport, &reports)); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| RunUntilIdle(); |
| |
| // Expect no report. |
| EXPECT_TRUE(reports.empty()); |
| |
| // Primary verifier should have ran, trial verifier should not have. |
| EXPECT_EQ(1, verify_proc->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 0); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 0); |
| histograms_.ExpectTotalCount("Net.CertVerifier_TrialComparisonResult", 0); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, InitiallyDisallowedThenAllowed) { |
| // Certificate that has multiple subjectAltName entries. This allows easily |
| // confirming which verification attempt the report was generated for without |
| // having to mock different CertVerifyProc results for each. |
| base::FilePath certs_dir = |
| GetTestNetDataDirectory() |
| .AppendASCII("verify_certificate_chain_unittest") |
| .AppendASCII("many-names"); |
| scoped_refptr<X509Certificate> cert_chain = CreateCertificateChainFromFile( |
| certs_dir, "ok-all-types.pem", X509Certificate::FORMAT_AUTO); |
| ASSERT_TRUE(cert_chain); |
| ASSERT_EQ(2U, cert_chain->intermediate_buffers().size()); |
| |
| scoped_refptr<X509Certificate> leaf = X509Certificate::CreateFromBuffer( |
| bssl::UpRef(cert_chain->cert_buffer()), {}); |
| ASSERT_TRUE(leaf); |
| |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, primary_result); |
| |
| // Trial verifier returns an error status. |
| CertVerifyResult secondary_result; |
| secondary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| secondary_result.verified_cert = cert_chain; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID, |
| secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| |
| CertVerifier::RequestParams params(leaf, "t0.test", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| // Enable the trial and do another verification. |
| verifier.set_trial_allowed(true); |
| CertVerifier::RequestParams params2(leaf, "t1.test", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result2; |
| TestCompletionCallback callback2; |
| std::unique_ptr<CertVerifier::Request> request2; |
| error = verifier.Verify(params2, &result2, callback2.callback(), &request2, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request2); |
| |
| error = callback2.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Primary verifier should have run twice, trial verifier should run once. |
| EXPECT_EQ(2, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kPrimaryValidSecondaryError, 1); |
| |
| // Expect a report from the second verification. |
| ASSERT_EQ(1U, reports.size()); |
| const TrialReportInfo& report = reports[0]; |
| EXPECT_EQ("t1.test", report.hostname); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, InitiallyAllowedThenDisallowed) { |
| // Certificate that has multiple subjectAltName entries. This allows easily |
| // confirming which verification attempt the report was generated for without |
| // having to mock different CertVerifyProc results for each. |
| base::FilePath certs_dir = |
| GetTestNetDataDirectory() |
| .AppendASCII("verify_certificate_chain_unittest") |
| .AppendASCII("many-names"); |
| scoped_refptr<X509Certificate> cert_chain = CreateCertificateChainFromFile( |
| certs_dir, "ok-all-types.pem", X509Certificate::FORMAT_AUTO); |
| ASSERT_TRUE(cert_chain); |
| ASSERT_EQ(2U, cert_chain->intermediate_buffers().size()); |
| |
| scoped_refptr<X509Certificate> leaf = X509Certificate::CreateFromBuffer( |
| bssl::UpRef(cert_chain->cert_buffer()), {}); |
| ASSERT_TRUE(leaf); |
| |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, primary_result); |
| |
| // Trial verifier returns an error status. |
| CertVerifyResult secondary_result; |
| secondary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| secondary_result.verified_cert = cert_chain; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID, |
| secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf, "t0.test", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| // Disable the trial and do another verification. |
| verifier.set_trial_allowed(false); |
| CertVerifier::RequestParams params2(leaf, "t1.test", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result2; |
| TestCompletionCallback callback2; |
| std::unique_ptr<CertVerifier::Request> request2; |
| error = verifier.Verify(params2, &result2, callback2.callback(), &request2, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request2); |
| |
| error = callback2.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Primary verifier should have run twice, trial verifier should run once. |
| EXPECT_EQ(2, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kPrimaryValidSecondaryError, 1); |
| |
| // Expect a report from the first verification. |
| ASSERT_EQ(1U, reports.size()); |
| const TrialReportInfo& report = reports[0]; |
| EXPECT_EQ("t0.test", report.hostname); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, InitiallyCRSEnabledThenDisabled) { |
| // Certificate that has multiple subjectAltName entries. This allows easily |
| // confirming which verification attempt the report was generated for without |
| // having to mock different CertVerifyProc results for each. |
| base::FilePath certs_dir = |
| GetTestNetDataDirectory() |
| .AppendASCII("verify_certificate_chain_unittest") |
| .AppendASCII("many-names"); |
| scoped_refptr<X509Certificate> cert_chain = CreateCertificateChainFromFile( |
| certs_dir, "ok-all-types.pem", X509Certificate::FORMAT_AUTO); |
| ASSERT_TRUE(cert_chain); |
| ASSERT_EQ(2U, cert_chain->intermediate_buffers().size()); |
| |
| scoped_refptr<X509Certificate> leaf = X509Certificate::CreateFromBuffer( |
| bssl::UpRef(cert_chain->cert_buffer()), {}); |
| ASSERT_TRUE(leaf); |
| |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, primary_result); |
| |
| // Trial verifier returns an error status. |
| CertVerifyResult secondary_result; |
| secondary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| secondary_result.verified_cert = cert_chain; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID, |
| secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| // Verifier created with ImplParams that have use_chrome_root_store=true. |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc(), verify_proc1, |
| MakeNotCalledProc()}, |
| {verify_proc2, verify_proc2}), |
| nullptr, yes_crs_impl_params_, |
| base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf, "t0.test", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| error = callback.WaitForResult(); |
| // The actual result returned should be from the secondary verifier. |
| EXPECT_THAT(error, IsError(ERR_CERT_DATE_INVALID)); |
| |
| // Turn chrome root store off and verify again. |
| verifier.UpdateVerifyProcData(nullptr, no_crs_impl_params_); |
| CertVerifier::RequestParams params2(leaf, "t1.test", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result2; |
| TestCompletionCallback callback2; |
| std::unique_ptr<CertVerifier::Request> request2; |
| error = verifier.Verify(params2, &result2, callback2.callback(), &request2, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request2); |
| |
| // The actual result returned should now be from the primary verifier. |
| error = callback2.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Primary verifier should have run once, secondary verifier should run twice. |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(2, verify_proc2->num_verifications()); |
| // Trial comparison was only run once. |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kPrimaryValidSecondaryError, 1); |
| |
| // Expect a report from the second verification. |
| ASSERT_EQ(1U, reports.size()); |
| const TrialReportInfo& report = reports[0]; |
| EXPECT_EQ("t1.test", report.hostname); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, InitiallyAllowedThenCRSEnabled) { |
| // Certificate that has multiple subjectAltName entries. This allows easily |
| // confirming which verification attempt the report was generated for without |
| // having to mock different CertVerifyProc results for each. |
| base::FilePath certs_dir = |
| GetTestNetDataDirectory() |
| .AppendASCII("verify_certificate_chain_unittest") |
| .AppendASCII("many-names"); |
| scoped_refptr<X509Certificate> cert_chain = CreateCertificateChainFromFile( |
| certs_dir, "ok-all-types.pem", X509Certificate::FORMAT_AUTO); |
| ASSERT_TRUE(cert_chain); |
| ASSERT_EQ(2U, cert_chain->intermediate_buffers().size()); |
| |
| scoped_refptr<X509Certificate> leaf = X509Certificate::CreateFromBuffer( |
| bssl::UpRef(cert_chain->cert_buffer()), {}); |
| ASSERT_TRUE(leaf); |
| |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, primary_result); |
| |
| // Trial verifier returns an error status. |
| CertVerifyResult secondary_result; |
| secondary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| secondary_result.verified_cert = cert_chain; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID, |
| secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc(), verify_proc1, |
| MakeNotCalledProc()}, |
| {verify_proc2, verify_proc2}), |
| nullptr, no_crs_impl_params_, |
| base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf, "t0.test", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| // Turn chrome root store on and verify again. |
| verifier.UpdateVerifyProcData(nullptr, yes_crs_impl_params_); |
| CertVerifier::RequestParams params2(leaf, "t1.test", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result2; |
| TestCompletionCallback callback2; |
| std::unique_ptr<CertVerifier::Request> request2; |
| error = verifier.Verify(params2, &result2, callback2.callback(), &request2, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request2); |
| |
| // The actual result returned should now be from the secondary verifier. |
| error = callback2.WaitForResult(); |
| EXPECT_THAT(error, IsError(ERR_CERT_DATE_INVALID)); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Primary verifier should have run once, secondary verifier should run twice. |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(2, verify_proc2->num_verifications()); |
| // Trial comparison was only run once. |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kPrimaryValidSecondaryError, 1); |
| |
| // Expect a report from the first verification. |
| ASSERT_EQ(1U, reports.size()); |
| const TrialReportInfo& report = reports[0]; |
| EXPECT_EQ("t0.test", report.hostname); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, |
| ConfigChangedDuringPrimaryVerification) { |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, primary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {MakeNotCalledProc()}), |
| nullptr, no_crs_impl_params_, |
| base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| // Change the verifier config before the primary verification finishes. |
| CertVerifier::Config config; |
| config.enable_sha1_local_anchors = true; |
| verifier.SetConfig(config); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| RunUntilIdle(); |
| |
| // Since the config changed, trial verifier should not run. |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 0); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 0); |
| histograms_.ExpectTotalCount("Net.CertVerifier_TrialComparisonResult", 0); |
| |
| // Expect no report. |
| EXPECT_TRUE(reports.empty()); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, ConfigChangedBeforeVerification) { |
| // Primary verifier returns an error status. |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| primary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID, |
| primary_result); |
| |
| CertVerifyResult secondary_result; |
| secondary_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| // Both verifiers are initially NotCalledCertVerifyProc, but should swap to |
| // verify_proc1 and verify_proc2 when UpdateVerifyProcData is called. |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({MakeNotCalledProc(), MakeNotCalledProc(), verify_proc1, |
| MakeNotCalledProc()}, |
| {MakeNotCalledProc(), verify_proc2}), |
| nullptr, no_crs_impl_params_, |
| base::BindRepeating(&RecordTrialReport, &reports)); |
| |
| verifier.set_trial_allowed(true); |
| |
| // Change the verifier Chrome Root Store data before verification, so the |
| // Verify should call the verifiers that were swapped in by the factories |
| // instead of the initial ones. |
| verifier.UpdateVerifyProcData(nullptr, no_crs_impl_params_); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsError(ERR_CERT_DATE_INVALID)); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect a report. |
| ASSERT_EQ(1U, reports.size()); |
| const TrialReportInfo& report = reports[0]; |
| |
| EXPECT_EQ(CERT_STATUS_DATE_INVALID, report.primary_result.cert_status); |
| EXPECT_EQ(0U, report.trial_result.cert_status); |
| |
| EXPECT_TRUE(report.primary_result.verified_cert->EqualsIncludingChain( |
| cert_chain_1_.get())); |
| EXPECT_TRUE(report.trial_result.verified_cert->EqualsIncludingChain( |
| cert_chain_1_.get())); |
| EXPECT_TRUE(report.unverified_cert->EqualsIncludingChain(leaf_cert_1_.get())); |
| |
| EXPECT_FALSE(report.enable_rev_checking); |
| EXPECT_FALSE(report.require_rev_checking_local_anchors); |
| EXPECT_FALSE(report.enable_sha1_local_anchors); |
| EXPECT_FALSE(report.disable_symantec_enforcement); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kPrimaryErrorSecondaryValid, 1); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, |
| CertVerifyProcChangedDuringPrimaryVerification) { |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, primary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc(), MakeNotCalledProc(), |
| MakeNotCalledProc()}, |
| {MakeNotCalledProc(), MakeNotCalledProc()}), |
| nullptr, no_crs_impl_params_, |
| base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| // Change the verifier Chrome Root Store data before the primary verification |
| // finishes. |
| verifier.UpdateVerifyProcData(nullptr, no_crs_impl_params_); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| RunUntilIdle(); |
| |
| // Since the config changed, trial verifier should not run. |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 0); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 0); |
| histograms_.ExpectTotalCount("Net.CertVerifier_TrialComparisonResult", 0); |
| |
| // Expect no report. |
| EXPECT_TRUE(reports.empty()); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, ConfigChangedDuringTrialVerification) { |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, primary_result); |
| |
| // Trial verifier returns an error status. |
| CertVerifyResult secondary_result; |
| secondary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| secondary_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID, |
| secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| // Change the verifier config during the trial verification. |
| CertVerifier::Config config; |
| config.enable_sha1_local_anchors = true; |
| verifier.SetConfig(config); |
| |
| RunUntilIdle(); |
| |
| // Since the config was the same when both primary and trial verification |
| // started, the result should still be reported. |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kPrimaryValidSecondaryError, 1); |
| |
| // Expect a report. |
| ASSERT_EQ(1U, reports.size()); |
| const TrialReportInfo& report = reports[0]; |
| |
| EXPECT_EQ(0U, report.primary_result.cert_status); |
| EXPECT_EQ(CERT_STATUS_DATE_INVALID, report.trial_result.cert_status); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, |
| CertVerifyProcChangedDuringTrialVerification) { |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, primary_result); |
| |
| // Trial verifier returns an error status. |
| CertVerifyResult secondary_result; |
| secondary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| secondary_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID, |
| secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc(), MakeNotCalledProc(), |
| MakeNotCalledProc()}, |
| {verify_proc2, MakeNotCalledProc()}), |
| nullptr, no_crs_impl_params_, |
| base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| // Change the verifier Chrome Root Store data during the trial verification. |
| verifier.UpdateVerifyProcData(nullptr, no_crs_impl_params_); |
| |
| RunUntilIdle(); |
| |
| // Since the config was the same when both primary and trial verification |
| // started, the result should still be reported. |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kPrimaryValidSecondaryError, 1); |
| |
| // Expect a report. |
| ASSERT_EQ(1U, reports.size()); |
| const TrialReportInfo& report = reports[0]; |
| |
| EXPECT_EQ(0U, report.primary_result.cert_status); |
| EXPECT_EQ(CERT_STATUS_DATE_INVALID, report.trial_result.cert_status); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, SameResult) { |
| CertVerifyResult dummy_result; |
| dummy_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, dummy_result); |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, dummy_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect no report. |
| EXPECT_TRUE(reports.empty()); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample("Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kEqual, 1); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, PrimaryVerifierErrorSecondaryOk) { |
| // Primary verifier returns an error status. |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| primary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID, |
| primary_result); |
| |
| CertVerifyResult secondary_result; |
| secondary_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsError(ERR_CERT_DATE_INVALID)); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect a report. |
| ASSERT_EQ(1U, reports.size()); |
| const TrialReportInfo& report = reports[0]; |
| |
| EXPECT_EQ(CERT_STATUS_DATE_INVALID, report.primary_result.cert_status); |
| EXPECT_EQ(0U, report.trial_result.cert_status); |
| |
| EXPECT_TRUE(report.primary_result.verified_cert->EqualsIncludingChain( |
| cert_chain_1_.get())); |
| EXPECT_TRUE(report.trial_result.verified_cert->EqualsIncludingChain( |
| cert_chain_1_.get())); |
| EXPECT_TRUE(report.unverified_cert->EqualsIncludingChain(leaf_cert_1_.get())); |
| |
| EXPECT_FALSE(report.enable_rev_checking); |
| EXPECT_FALSE(report.require_rev_checking_local_anchors); |
| EXPECT_FALSE(report.enable_sha1_local_anchors); |
| EXPECT_FALSE(report.disable_symantec_enforcement); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kPrimaryErrorSecondaryValid, 1); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, PrimaryVerifierOkSecondaryError) { |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, primary_result); |
| |
| // Trial verifier returns an error status. |
| CertVerifyResult secondary_result; |
| secondary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| secondary_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID, |
| secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| "ocsp", "sct"); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect a report. |
| ASSERT_EQ(1U, reports.size()); |
| const TrialReportInfo& report = reports[0]; |
| |
| EXPECT_EQ(0U, report.primary_result.cert_status); |
| EXPECT_EQ(CERT_STATUS_DATE_INVALID, report.trial_result.cert_status); |
| |
| EXPECT_TRUE(report.primary_result.verified_cert->EqualsIncludingChain( |
| cert_chain_1_.get())); |
| EXPECT_TRUE(report.trial_result.verified_cert->EqualsIncludingChain( |
| cert_chain_1_.get())); |
| EXPECT_TRUE(report.unverified_cert->EqualsIncludingChain(leaf_cert_1_.get())); |
| EXPECT_EQ("ocsp", report.stapled_ocsp); |
| EXPECT_EQ("sct", report.sct_list); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kPrimaryValidSecondaryError, 1); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, BothVerifiersDifferentErrors) { |
| // Primary verifier returns an error status. |
| CertVerifyResult primary_result; |
| primary_result.cert_status = CERT_STATUS_VALIDITY_TOO_LONG; |
| primary_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_VALIDITY_TOO_LONG, |
| primary_result); |
| |
| // Trial verifier returns a different error status. |
| CertVerifyResult secondary_result; |
| secondary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| secondary_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID, |
| secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsError(ERR_CERT_VALIDITY_TOO_LONG)); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect a report. |
| ASSERT_EQ(1U, reports.size()); |
| const TrialReportInfo& report = reports[0]; |
| |
| EXPECT_EQ(CERT_STATUS_VALIDITY_TOO_LONG, report.primary_result.cert_status); |
| EXPECT_EQ(CERT_STATUS_DATE_INVALID, report.trial_result.cert_status); |
| |
| EXPECT_TRUE(report.primary_result.verified_cert->EqualsIncludingChain( |
| cert_chain_1_.get())); |
| EXPECT_TRUE(report.trial_result.verified_cert->EqualsIncludingChain( |
| cert_chain_1_.get())); |
| EXPECT_TRUE(report.unverified_cert->EqualsIncludingChain(leaf_cert_1_.get())); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kBothErrorDifferentDetails, 1); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, |
| BothVerifiersOkDifferentVerifiedChains) { |
| // Primary verifier returns chain1 regardless of arguments. |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, primary_result); |
| |
| // Trial verifier returns a different verified cert chain. |
| CertVerifyResult secondary_result; |
| secondary_result.verified_cert = cert_chain_2_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, verify_proc1}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect a report. |
| ASSERT_EQ(1U, reports.size()); |
| const TrialReportInfo& report = reports[0]; |
| |
| EXPECT_EQ(0U, report.primary_result.cert_status); |
| EXPECT_EQ(0U, report.trial_result.cert_status); |
| |
| EXPECT_TRUE(report.primary_result.verified_cert->EqualsIncludingChain( |
| cert_chain_1_.get())); |
| EXPECT_TRUE(report.trial_result.verified_cert->EqualsIncludingChain( |
| cert_chain_2_.get())); |
| EXPECT_TRUE(report.unverified_cert->EqualsIncludingChain(leaf_cert_1_.get())); |
| |
| // The primary verifier should be used twice (first with the initial chain, |
| // then with the results of the trial verifier). |
| EXPECT_EQ(2, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kBothValidDifferentDetails, 1); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, |
| DifferentVerifiedChainsAndConfigHasChanged) { |
| // Primary verifier returns chain1 regardless of arguments. |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_REVOKED, |
| primary_result); |
| |
| // Trial verifier returns a different verified cert chain. |
| CertVerifyResult secondary_result; |
| secondary_result.verified_cert = cert_chain_2_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsError(ERR_CERT_REVOKED)); |
| |
| // Change the configuration. The trial verification should complete, but |
| // the difference in verified chains should prevent a trial reverification. |
| CertVerifier::Config config; |
| config.enable_sha1_local_anchors = true; |
| verifier.SetConfig(config); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect no report, since the configuration changed and the primary |
| // verifier could not be used to retry. |
| ASSERT_EQ(0U, reports.size()); |
| |
| // The primary verifier should only be used once, as the configuration |
| // changes after the trial verification is started. |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kIgnoredConfigurationChanged, 1); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, |
| BothVerifiersOkDifferentVerifiedChainsEqualAfterReverification) { |
| CertVerifyResult chain1_result; |
| chain1_result.verified_cert = cert_chain_1_; |
| CertVerifyResult chain2_result; |
| chain2_result.verified_cert = cert_chain_2_; |
| |
| scoped_refptr<MockCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<MockCertVerifyProc>(); |
| // Primary verifier returns ok status and chain1 if verifying the leaf alone. |
| EXPECT_CALL(*verify_proc1, |
| VerifyInternal(leaf_cert_1_.get(), _, _, _, _, _, _, _)) |
| .WillOnce(DoAll(SetArgPointee<6>(chain1_result), Return(OK))); |
| // Primary verifier returns ok status and chain2 if verifying chain2. |
| EXPECT_CALL(*verify_proc1, |
| VerifyInternal(cert_chain_2_.get(), _, _, _, _, _, _, _)) |
| .WillOnce(DoAll(SetArgPointee<6>(chain2_result), Return(OK))); |
| |
| // Trial verifier returns ok status and chain2. |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, chain2_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, verify_proc1}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect no report. |
| EXPECT_TRUE(reports.empty()); |
| |
| testing::Mock::VerifyAndClear(verify_proc1.get()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kIgnoredDifferentPathReVerifiesEquivalent, 1); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, |
| DifferentVerifiedChainsIgnorableDifferenceAfterReverification) { |
| base::FilePath certs_dir = |
| GetTestNetDataDirectory() |
| .AppendASCII("trial_comparison_cert_verifier_unittest") |
| .AppendASCII("target-multiple-policies"); |
| scoped_refptr<X509Certificate> cert_chain = CreateCertificateChainFromFile( |
| certs_dir, "chain.pem", X509Certificate::FORMAT_AUTO); |
| ASSERT_TRUE(cert_chain); |
| ASSERT_EQ(2U, cert_chain->intermediate_buffers().size()); |
| |
| scoped_refptr<X509Certificate> leaf = X509Certificate::CreateFromBuffer( |
| bssl::UpRef(cert_chain->cert_buffer()), {}); |
| ASSERT_TRUE(leaf); |
| |
| // Chain with the same leaf and different root. This is not a valid chain, but |
| // doesn't matter for the unittest since this uses mock CertVerifyProcs. |
| std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; |
| intermediates.push_back( |
| bssl::UpRef(cert_chain_1_->intermediate_buffers().back().get())); |
| scoped_refptr<X509Certificate> different_chain = |
| X509Certificate::CreateFromBuffer(bssl::UpRef(cert_chain->cert_buffer()), |
| std::move(intermediates)); |
| ASSERT_TRUE(different_chain); |
| |
| CertVerifyResult different_chain_result_no_known_root; |
| different_chain_result_no_known_root.verified_cert = different_chain; |
| |
| CertVerifyResult different_chain_result_known_root; |
| different_chain_result_known_root.verified_cert = different_chain; |
| different_chain_result_known_root.is_issued_by_known_root = true; |
| |
| CertVerifyResult chain_result; |
| chain_result.verified_cert = cert_chain; |
| chain_result.is_issued_by_known_root = true; |
| |
| SHA256HashValue root_fingerprint; |
| crypto::SHA256HashString(x509_util::CryptoBufferAsStringPiece( |
| cert_chain->intermediate_buffers().back().get()), |
| root_fingerprint.data, |
| sizeof(root_fingerprint.data)); |
| |
| scoped_refptr<MockCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<MockCertVerifyProc>(); |
| // Primary verifier returns ok status and different_chain if verifying leaf |
| // alone, but not is_known_root. |
| EXPECT_CALL(*verify_proc1, VerifyInternal(leaf.get(), _, _, _, _, _, _, _)) |
| .WillOnce(DoAll(SetArgPointee<6>(different_chain_result_no_known_root), |
| Return(OK))); |
| // Primary verifier returns ok status and different_chain if verifying |
| // cert_chain and with is_known_root.. |
| EXPECT_CALL(*verify_proc1, |
| VerifyInternal(cert_chain.get(), _, _, _, _, _, _, _)) |
| .WillOnce(DoAll(SetArgPointee<6>(different_chain_result_known_root), |
| Return(OK))); |
| |
| // Trial verifier returns ok status and chain_result. |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, chain_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, verify_proc1}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf, "test.example", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect no report. |
| EXPECT_TRUE(reports.empty()); |
| |
| // Primary verifier should be used twice, the second time with the chain |
| // from the trial verifier. Even so, it only should be counted once in |
| // metrics. |
| testing::Mock::VerifyAndClear(verify_proc1.get()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kIgnoredDifferentPathReVerifiesEquivalent, 1); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, BothVerifiersOkDifferentCertStatus) { |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| primary_result.cert_status = |
| CERT_STATUS_IS_EV | CERT_STATUS_REV_CHECKING_ENABLED; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, primary_result); |
| |
| CertVerifyResult secondary_result; |
| secondary_result.verified_cert = cert_chain_1_; |
| secondary_result.cert_status = CERT_STATUS_CT_COMPLIANCE_FAILED; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::Config config; |
| config.enable_rev_checking = true; |
| config.enable_sha1_local_anchors = true; |
| verifier.SetConfig(config); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", 0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect a report. |
| ASSERT_EQ(1U, reports.size()); |
| const TrialReportInfo& report = reports[0]; |
| |
| EXPECT_EQ(CERT_STATUS_IS_EV | CERT_STATUS_REV_CHECKING_ENABLED, |
| report.primary_result.cert_status); |
| EXPECT_EQ(CERT_STATUS_CT_COMPLIANCE_FAILED, report.trial_result.cert_status); |
| |
| EXPECT_TRUE(report.enable_rev_checking); |
| EXPECT_FALSE(report.require_rev_checking_local_anchors); |
| EXPECT_TRUE(report.enable_sha1_local_anchors); |
| EXPECT_FALSE(report.disable_symantec_enforcement); |
| |
| EXPECT_TRUE(report.primary_result.verified_cert->EqualsIncludingChain( |
| cert_chain_1_.get())); |
| EXPECT_TRUE(report.trial_result.verified_cert->EqualsIncludingChain( |
| cert_chain_1_.get())); |
| EXPECT_TRUE(report.unverified_cert->EqualsIncludingChain(leaf_cert_1_.get())); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kBothValidDifferentDetails, 1); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, CancelledDuringPrimaryVerification) { |
| // Primary verifier returns an error status. |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| primary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID, |
| primary_result); |
| |
| // Trial verifier has ok status. |
| CertVerifyResult secondary_result; |
| secondary_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = |
| verifier.Verify(params, &result, base::BindOnce(&NotCalledCallback), |
| &request, NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| // Delete the request, cancelling it. |
| request.reset(); |
| |
| // The callback to the main verifier does not run. However, the verification |
| // still completes in the background and triggers the trial verification. |
| |
| // Trial verifier should still run. |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect a report. |
| ASSERT_EQ(1U, reports.size()); |
| const TrialReportInfo& report = reports[0]; |
| |
| EXPECT_EQ(CERT_STATUS_DATE_INVALID, report.primary_result.cert_status); |
| EXPECT_EQ(0U, report.trial_result.cert_status); |
| |
| EXPECT_TRUE(report.primary_result.verified_cert->EqualsIncludingChain( |
| cert_chain_1_.get())); |
| EXPECT_TRUE(report.trial_result.verified_cert->EqualsIncludingChain( |
| cert_chain_1_.get())); |
| EXPECT_TRUE(report.unverified_cert->EqualsIncludingChain(leaf_cert_1_.get())); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kPrimaryErrorSecondaryValid, 1); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, DeletedDuringPrimaryVerification) { |
| // Primary verifier returns an error status. |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| primary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID, |
| primary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| auto verifier = std::make_unique<TrialComparisonCertVerifier>( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {MakeNotCalledProc()}), |
| nullptr, no_crs_impl_params_, |
| base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier->set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = |
| verifier->Verify(params, &result, base::BindOnce(&NotCalledCallback), |
| &request, NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| // Delete the TrialComparisonCertVerifier. |
| verifier.reset(); |
| |
| // The callback to the main verifier does not run. The verification task |
| // still completes in the background, but since the CertVerifier has been |
| // deleted, the result is ignored. |
| |
| // Wait for any tasks to finish. |
| RunUntilIdle(); |
| |
| // Expect no report. |
| EXPECT_TRUE(reports.empty()); |
| |
| // The trial verifier should never be called, nor histograms recorded. |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 0); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 0); |
| histograms_.ExpectTotalCount("Net.CertVerifier_TrialComparisonResult", 0); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, DeletedDuringVerificationResult) { |
| // Primary verifier returns an error status. |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| primary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID, |
| primary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| auto verifier = std::make_unique<TrialComparisonCertVerifier>( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {MakeNotCalledProc()}), |
| nullptr, no_crs_impl_params_, |
| base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier->set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier->Verify( |
| params, &result, |
| base::BindLambdaForTesting([&callback, &verifier](int result) { |
| // Delete the verifier while processing the result. This should not |
| // start a trial verification. |
| verifier.reset(); |
| callback.callback().Run(result); |
| }), |
| &request, NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| // Wait for primary verifier to finish. |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsError(ERR_CERT_DATE_INVALID)); |
| |
| // The callback to the trial verifier does not run. No verification task |
| // should start, as the verifier was deleted before the trial verification |
| // was started. |
| |
| // Wait for any tasks to finish. |
| RunUntilIdle(); |
| |
| // Expect no report. |
| EXPECT_TRUE(reports.empty()); |
| |
| // Histograms for the primary or trial verification should not be recorded, |
| // as the trial verification was cancelled by deleting the verifier. |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 0); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 0); |
| histograms_.ExpectTotalCount("Net.CertVerifier_TrialComparisonResult", 0); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, DeletedDuringTrialReport) { |
| // Primary verifier returns an error status. |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| primary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID, |
| primary_result); |
| |
| // Trial verifier has ok status. |
| CertVerifyResult secondary_result; |
| secondary_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, secondary_result); |
| |
| bool was_report_callback_called = false; |
| std::unique_ptr<TrialComparisonCertVerifier> verifier; |
| verifier = std::make_unique<TrialComparisonCertVerifier>( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, |
| base::BindLambdaForTesting( |
| [&verifier, &was_report_callback_called]( |
| const std::string& hostname, |
| const scoped_refptr<X509Certificate>& unverified_cert, |
| bool enable_rev_checking, bool require_rev_checking_local_anchors, |
| bool enable_sha1_local_anchors, bool disable_symantec_enforcement, |
| const std::string& stapled_ocsp, const std::string& sct_list, |
| const net::CertVerifyResult& primary_result, |
| const net::CertVerifyResult& trial_result) { |
| // During processing of a report, delete the underlying verifier. |
| // This should not cause any issues. |
| was_report_callback_called = true; |
| verifier.reset(); |
| })); |
| verifier->set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier->Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| // The callback should be notified of the primary result. |
| ASSERT_THAT(callback.WaitForResult(), IsError(ERR_CERT_DATE_INVALID)); |
| |
| // Wait for the verification task to complete in the background. This |
| // should ultimately call the ReportCallback that will delete the |
| // verifier. |
| RunUntilIdle(); |
| |
| EXPECT_TRUE(was_report_callback_called); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kPrimaryErrorSecondaryValid, 1); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, DeletedAfterTrialVerificationStarted) { |
| // Primary verifier returns an error status. |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| primary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID, |
| primary_result); |
| |
| // Trial verifier has ok status. |
| CertVerifyResult secondary_result; |
| secondary_result.verified_cert = cert_chain_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| auto verifier = std::make_unique<TrialComparisonCertVerifier>( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier->set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier->Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| // Wait for primary verifier to finish. |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsError(ERR_CERT_DATE_INVALID)); |
| |
| // Delete the TrialComparisonCertVerifier. The trial verification is still |
| // running on the task scheduler (or, depending on timing, has posted back |
| // to the IO thread after the Quit event). |
| verifier.reset(); |
| |
| // The callback to the trial verifier does not run. The verification task |
| // still completes in the background, but since the CertVerifier has been |
| // deleted, the result is ignored. |
| |
| // Wait for any tasks to finish. |
| RunUntilIdle(); |
| |
| // Expect no report. |
| EXPECT_TRUE(reports.empty()); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| // Histograms for trial verifier should not be recorded. |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 0); |
| histograms_.ExpectTotalCount("Net.CertVerifier_TrialComparisonResult", 0); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, PrimaryRevokedSecondaryOk) { |
| CertVerifyResult revoked_result; |
| revoked_result.verified_cert = cert_chain_1_; |
| revoked_result.cert_status = CERT_STATUS_REVOKED; |
| |
| CertVerifyResult ok_result; |
| ok_result.verified_cert = cert_chain_1_; |
| |
| // Primary verifier returns an error status. |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_REVOKED, |
| revoked_result); |
| |
| // Secondary verifier returns ok status regardless of whether |
| // REV_CHECKING_ENABLED was passed. |
| scoped_refptr<MockCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<MockCertVerifyProc>(); |
| EXPECT_CALL(*verify_proc2, VerifyInternal(_, _, _, _, _, _, _, _)) |
| .Times(1) |
| .WillRepeatedly(DoAll(SetArgPointee<6>(ok_result), Return(OK))); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsError(ERR_CERT_REVOKED)); |
| |
| RunUntilIdle(); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| testing::Mock::VerifyAndClear(verify_proc2.get()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kPrimaryErrorSecondaryValid, 1); |
| |
| // Expect a report. |
| EXPECT_EQ(1U, reports.size()); |
| } |
| |
| #if defined(PLATFORM_USES_CHROMIUM_EV_METADATA) |
| TEST_F(TrialComparisonCertVerifierTest, MultipleEVPolicies) { |
| base::FilePath certs_dir = |
| GetTestNetDataDirectory() |
| .AppendASCII("trial_comparison_cert_verifier_unittest") |
| .AppendASCII("target-multiple-policies"); |
| scoped_refptr<X509Certificate> cert_chain = CreateCertificateChainFromFile( |
| certs_dir, "chain.pem", X509Certificate::FORMAT_AUTO); |
| ASSERT_TRUE(cert_chain); |
| ASSERT_EQ(2U, cert_chain->intermediate_buffers().size()); |
| |
| SHA256HashValue root_fingerprint; |
| crypto::SHA256HashString(x509_util::CryptoBufferAsStringPiece( |
| cert_chain->intermediate_buffers().back().get()), |
| root_fingerprint.data, |
| sizeof(root_fingerprint.data)); |
| |
| // Both policies in the target are EV policies, but only 1.2.6.7 is valid for |
| // the root in this chain. |
| ScopedTestEVPolicy scoped_ev_policy_1(EVRootCAMetadata::GetInstance(), |
| root_fingerprint, "1.2.6.7"); |
| ScopedTestEVPolicy scoped_ev_policy_2(EVRootCAMetadata::GetInstance(), |
| SHA256HashValue(), "1.2.3.4"); |
| |
| // Both verifiers return OK, but secondary returns EV status. |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, primary_result); |
| |
| CertVerifyResult secondary_result; |
| secondary_result.verified_cert = cert_chain; |
| secondary_result.cert_status = |
| CERT_STATUS_IS_EV | CERT_STATUS_REV_CHECKING_ENABLED; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect no report. |
| EXPECT_TRUE(reports.empty()); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kIgnoredMultipleEVPoliciesAndOneMatchesRoot, 1); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, MultipleEVPoliciesNoneValidForRoot) { |
| base::FilePath certs_dir = |
| GetTestNetDataDirectory() |
| .AppendASCII("trial_comparison_cert_verifier_unittest") |
| .AppendASCII("target-multiple-policies"); |
| scoped_refptr<X509Certificate> cert_chain = CreateCertificateChainFromFile( |
| certs_dir, "chain.pem", X509Certificate::FORMAT_AUTO); |
| ASSERT_TRUE(cert_chain); |
| |
| // Both policies in the target are EV policies, but neither is valid for the |
| // root in this chain. |
| ScopedTestEVPolicy scoped_ev_policy_1(EVRootCAMetadata::GetInstance(), {1}, |
| "1.2.6.7"); |
| ScopedTestEVPolicy scoped_ev_policy_2(EVRootCAMetadata::GetInstance(), {2}, |
| "1.2.3.4"); |
| |
| // Both verifiers return OK, but secondary returns EV status. |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, primary_result); |
| |
| CertVerifyResult secondary_result; |
| secondary_result.verified_cert = cert_chain; |
| secondary_result.cert_status = |
| CERT_STATUS_IS_EV | CERT_STATUS_REV_CHECKING_ENABLED; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect a report. |
| ASSERT_EQ(1U, reports.size()); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kBothValidDifferentDetails, 1); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, MultiplePoliciesOnlyOneIsEV) { |
| base::FilePath certs_dir = |
| GetTestNetDataDirectory() |
| .AppendASCII("trial_comparison_cert_verifier_unittest") |
| .AppendASCII("target-multiple-policies"); |
| scoped_refptr<X509Certificate> cert_chain = CreateCertificateChainFromFile( |
| certs_dir, "chain.pem", X509Certificate::FORMAT_AUTO); |
| ASSERT_TRUE(cert_chain); |
| ASSERT_EQ(2U, cert_chain->intermediate_buffers().size()); |
| |
| SHA256HashValue root_fingerprint; |
| crypto::SHA256HashString(x509_util::CryptoBufferAsStringPiece( |
| cert_chain->intermediate_buffers().back().get()), |
| root_fingerprint.data, |
| sizeof(root_fingerprint.data)); |
| |
| // One policy in the target is an EV policy and is valid for the root. |
| ScopedTestEVPolicy scoped_ev_policy_1(EVRootCAMetadata::GetInstance(), |
| root_fingerprint, "1.2.6.7"); |
| |
| // Both verifiers return OK, but secondary returns EV status. |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, primary_result); |
| |
| CertVerifyResult secondary_result; |
| secondary_result.verified_cert = cert_chain; |
| secondary_result.cert_status = |
| CERT_STATUS_IS_EV | CERT_STATUS_REV_CHECKING_ENABLED; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect a report. |
| ASSERT_EQ(1U, reports.size()); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kBothValidDifferentDetails, 1); |
| } |
| #endif |
| |
| TEST_F(TrialComparisonCertVerifierTest, LocallyTrustedLeaf) { |
| // Platform verifier verifies the leaf directly. |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = leaf_cert_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, primary_result); |
| |
| // Trial verifier does not support directly-trusted leaf certs. |
| CertVerifyResult secondary_result; |
| secondary_result.cert_status = CERT_STATUS_AUTHORITY_INVALID; |
| secondary_result.verified_cert = leaf_cert_1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_AUTHORITY_INVALID, |
| secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsOk()); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect a report. |
| EXPECT_EQ(1U, reports.size()); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kPrimaryValidSecondaryError, 1); |
| } |
| |
| // Ignore results where both primary and trial verifier report SHA-1 signatures. |
| TEST_F(TrialComparisonCertVerifierTest, SHA1Ignored) { |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| primary_result.cert_status = |
| CERT_STATUS_SHA1_SIGNATURE_PRESENT | CERT_STATUS_REV_CHECKING_ENABLED; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>( |
| ERR_CERT_WEAK_SIGNATURE_ALGORITHM, primary_result); |
| |
| CertVerifyResult secondary_result; |
| secondary_result.verified_cert = cert_chain_1_; |
| secondary_result.cert_status = CERT_STATUS_SHA1_SIGNATURE_PRESENT; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>( |
| ERR_CERT_WEAK_SIGNATURE_ALGORITHM, secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsError(ERR_CERT_WEAK_SIGNATURE_ALGORITHM)); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect no report. |
| EXPECT_TRUE(reports.empty()); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kIgnoredSHA1SignaturePresent, 1); |
| } |
| |
| // Ignore results where both primary and trial verifier report AUHORITY_INVALID |
| // errors. |
| TEST_F(TrialComparisonCertVerifierTest, BothAuthorityInvalidIgnored) { |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| primary_result.cert_status = |
| CERT_STATUS_SHA1_SIGNATURE_PRESENT | CERT_STATUS_AUTHORITY_INVALID; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_AUTHORITY_INVALID, |
| primary_result); |
| |
| CertVerifyResult secondary_result; |
| secondary_result.verified_cert = cert_chain_1_; |
| secondary_result.cert_status = CERT_STATUS_AUTHORITY_INVALID; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_AUTHORITY_INVALID, |
| secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID)); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect no report. |
| EXPECT_TRUE(reports.empty()); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kIgnoredBothAuthorityInvalid, 1); |
| } |
| |
| // Ignore results where both primary and trial verifier terminate in |
| // known roots (with the same error and status codes). |
| TEST_F(TrialComparisonCertVerifierTest, BothKnownRootsIgnored) { |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| primary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| primary_result.is_issued_by_known_root = true; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>( |
| ERR_CERT_WEAK_SIGNATURE_ALGORITHM, primary_result); |
| |
| CertVerifyResult secondary_result; |
| secondary_result.verified_cert = cert_chain_2_; |
| secondary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| secondary_result.is_issued_by_known_root = true; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>( |
| ERR_CERT_WEAK_SIGNATURE_ALGORITHM, secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsError(ERR_CERT_WEAK_SIGNATURE_ALGORITHM)); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect no report. |
| EXPECT_TRUE(reports.empty()); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample("Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kIgnoredBothKnownRoot, |
| 1); |
| } |
| |
| // Ignore results where trial reports ERR_CERT_AUTHORITY_INVALID and the primary |
| // reports any error with a cert status of CERT_STATUS_SYMANTEC_LEGACY |
| TEST_F(TrialComparisonCertVerifierTest, |
| IgnoreAuthInvalidBuiltinWhenPrimaryReportSymantec) { |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = cert_chain_1_; |
| primary_result.cert_status = |
| CERT_STATUS_DATE_INVALID | CERT_STATUS_SYMANTEC_LEGACY; |
| primary_result.is_issued_by_known_root = true; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_COMMON_NAME_INVALID, |
| primary_result); |
| |
| CertVerifyResult secondary_result; |
| secondary_result.verified_cert = cert_chain_2_; |
| secondary_result.cert_status = CERT_STATUS_AUTHORITY_INVALID; |
| secondary_result.is_issued_by_known_root = true; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_AUTHORITY_INVALID, |
| secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsError(ERR_CERT_COMMON_NAME_INVALID)); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect no report. |
| EXPECT_TRUE(reports.empty()); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kIgnoredBuiltinAuthorityInvalidPlatformSymantec, |
| 1); |
| } |
| |
| TEST_F(TrialComparisonCertVerifierTest, LetsEncryptSpecialCase) { |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = lets_encrypt_dst_x3_; |
| primary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID, |
| primary_result); |
| |
| CertVerifyResult secondary_result; |
| secondary_result.verified_cert = lets_encrypt_isrg_x1_; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(OK, secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsError(ERR_CERT_DATE_INVALID)); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect no report. |
| EXPECT_TRUE(reports.empty()); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kIgnoredLetsEncryptExpiredRoot, 1); |
| } |
| |
| #if BUILDFLAG(IS_ANDROID) |
| TEST_F(TrialComparisonCertVerifierTest, AndroidPreferDate) { |
| CertVerifyResult primary_result; |
| primary_result.verified_cert = lets_encrypt_dst_x3_; |
| primary_result.cert_status = CERT_STATUS_DATE_INVALID; |
| scoped_refptr<FakeCertVerifyProc> verify_proc1 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_DATE_INVALID, |
| primary_result); |
| |
| CertVerifyResult secondary_result; |
| secondary_result.verified_cert = lets_encrypt_isrg_x1_; |
| secondary_result.cert_status = CERT_STATUS_AUTHORITY_INVALID; |
| scoped_refptr<FakeCertVerifyProc> verify_proc2 = |
| base::MakeRefCounted<FakeCertVerifyProc>(ERR_CERT_AUTHORITY_INVALID, |
| secondary_result); |
| |
| std::vector<TrialReportInfo> reports; |
| TrialComparisonCertVerifier verifier( |
| ProcFactory({verify_proc1, MakeNotCalledProc()}, {verify_proc2}), nullptr, |
| no_crs_impl_params_, base::BindRepeating(&RecordTrialReport, &reports)); |
| verifier.set_trial_allowed(true); |
| |
| CertVerifier::RequestParams params(leaf_cert_1_, "127.0.0.1", /*flags=*/0, |
| /*ocsp_response=*/std::string(), |
| /*sct_list=*/std::string()); |
| CertVerifyResult result; |
| TestCompletionCallback callback; |
| std::unique_ptr<CertVerifier::Request> request; |
| int error = verifier.Verify(params, &result, callback.callback(), &request, |
| NetLogWithSource()); |
| ASSERT_THAT(error, IsError(ERR_IO_PENDING)); |
| EXPECT_TRUE(request); |
| |
| error = callback.WaitForResult(); |
| EXPECT_THAT(error, IsError(ERR_CERT_DATE_INVALID)); |
| |
| verify_proc2->WaitForVerifyCall(); |
| RunUntilIdle(); |
| |
| // Expect no report. |
| EXPECT_TRUE(reports.empty()); |
| |
| EXPECT_EQ(1, verify_proc1->num_verifications()); |
| EXPECT_EQ(1, verify_proc2->num_verifications()); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1); |
| histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary", |
| 1); |
| histograms_.ExpectUniqueSample( |
| "Net.CertVerifier_TrialComparisonResult", |
| TrialComparisonResult::kIgnoredAndroidErrorDatePriority, 1); |
| } |
| #endif |
| |
| } // namespace net |