• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/cert/multi_threaded_cert_verifier.h"
6 
7 #include <memory>
8 
9 #include "base/debug/leak_annotations.h"
10 #include "base/files/file_path.h"
11 #include "base/format_macros.h"
12 #include "base/functional/bind.h"
13 #include "net/base/net_errors.h"
14 #include "net/base/test_completion_callback.h"
15 #include "net/cert/cert_verify_proc.h"
16 #include "net/cert/cert_verify_result.h"
17 #include "net/cert/crl_set.h"
18 #include "net/cert/mock_cert_verifier.h"
19 #include "net/cert/x509_certificate.h"
20 #include "net/log/net_log_with_source.h"
21 #include "net/test/cert_test_util.h"
22 #include "net/test/gtest_util.h"
23 #include "net/test/test_data_directory.h"
24 #include "net/test/test_with_task_environment.h"
25 #include "testing/gmock/include/gmock/gmock.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 
28 using net::test::IsError;
29 using net::test::IsOk;
30 using testing::_;
31 using testing::DoAll;
32 using testing::Return;
33 
34 namespace net {
35 
36 class ChromeRootStoreData;
37 class CertNetFetcher;
38 
39 namespace {
40 
FailTest(int)41 void FailTest(int /* result */) {
42   FAIL();
43 }
44 
45 class MockCertVerifyProc : public CertVerifyProc {
46  public:
MockCertVerifyProc()47   MockCertVerifyProc() : CertVerifyProc(CRLSet::BuiltinCRLSet()) {}
48   MOCK_METHOD7(VerifyInternal,
49                int(X509Certificate*,
50                    const std::string&,
51                    const std::string&,
52                    const std::string&,
53                    int,
54                    CertVerifyResult*,
55                    const NetLogWithSource&));
56   MOCK_CONST_METHOD0(SupportsAdditionalTrustAnchors, bool());
57 
58  private:
59   ~MockCertVerifyProc() override = default;
60 };
61 
ACTION(SetCertVerifyResult)62 ACTION(SetCertVerifyResult) {
63   X509Certificate* cert = arg0;
64   CertVerifyResult* result = arg5;
65   result->Reset();
66   result->verified_cert = cert;
67   result->cert_status = CERT_STATUS_COMMON_NAME_INVALID;
68 }
69 
ACTION(SetCertVerifyRevokedResult)70 ACTION(SetCertVerifyRevokedResult) {
71   X509Certificate* cert = arg0;
72   CertVerifyResult* result = arg5;
73   result->Reset();
74   result->verified_cert = cert;
75   result->cert_status = CERT_STATUS_REVOKED;
76 }
77 
78 class SwapWithNewProcFactory : public CertVerifyProcFactory {
79  public:
SwapWithNewProcFactory(scoped_refptr<CertVerifyProc> new_mock_proc)80   explicit SwapWithNewProcFactory(scoped_refptr<CertVerifyProc> new_mock_proc)
81       : mock_verify_proc_(std::move(new_mock_proc)) {}
82 
CreateCertVerifyProc(scoped_refptr<CertNetFetcher> cert_net_fetcher,const CertVerifyProc::ImplParams & impl_params,const CertVerifyProc::InstanceParams & instance_params)83   scoped_refptr<net::CertVerifyProc> CreateCertVerifyProc(
84       scoped_refptr<CertNetFetcher> cert_net_fetcher,
85       const CertVerifyProc::ImplParams& impl_params,
86       const CertVerifyProc::InstanceParams& instance_params) override {
87     return mock_verify_proc_;
88   }
89 
90  protected:
91   ~SwapWithNewProcFactory() override = default;
92   scoped_refptr<CertVerifyProc> mock_verify_proc_;
93 };
94 
95 }  // namespace
96 
97 class MultiThreadedCertVerifierTest : public TestWithTaskEnvironment {
98  public:
MultiThreadedCertVerifierTest()99   MultiThreadedCertVerifierTest()
100       : mock_verify_proc_(base::MakeRefCounted<MockCertVerifyProc>()),
101         mock_new_verify_proc_(base::MakeRefCounted<MockCertVerifyProc>()),
102         verifier_(std::make_unique<MultiThreadedCertVerifier>(
103             mock_verify_proc_,
104             base::MakeRefCounted<SwapWithNewProcFactory>(
105                 mock_new_verify_proc_))) {
106     EXPECT_CALL(*mock_verify_proc_, SupportsAdditionalTrustAnchors())
107         .WillRepeatedly(Return(true));
108     EXPECT_CALL(*mock_verify_proc_, VerifyInternal(_, _, _, _, _, _, _))
109         .WillRepeatedly(
110             DoAll(SetCertVerifyResult(), Return(ERR_CERT_COMMON_NAME_INVALID)));
111   }
112   ~MultiThreadedCertVerifierTest() override = default;
113 
114  protected:
115   scoped_refptr<MockCertVerifyProc> mock_verify_proc_;
116   // The new verify_proc_ swapped in if the proc is updated.
117   scoped_refptr<MockCertVerifyProc> mock_new_verify_proc_;
118   std::unique_ptr<MultiThreadedCertVerifier> verifier_;
119 };
120 
121 // Tests that the callback of a canceled request is never made.
TEST_F(MultiThreadedCertVerifierTest,CancelRequest)122 TEST_F(MultiThreadedCertVerifierTest, CancelRequest) {
123   base::FilePath certs_dir = GetTestCertsDirectory();
124   scoped_refptr<X509Certificate> test_cert(
125       ImportCertFromFile(certs_dir, "ok_cert.pem"));
126   ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
127 
128   int error;
129   CertVerifyResult verify_result;
130   std::unique_ptr<CertVerifier::Request> request;
131 
132   error = verifier_->Verify(
133       CertVerifier::RequestParams(test_cert, "www.example.com", 0,
134                                   /*ocsp_response=*/std::string(),
135                                   /*sct_list=*/std::string()),
136       &verify_result, base::BindOnce(&FailTest), &request, NetLogWithSource());
137   ASSERT_THAT(error, IsError(ERR_IO_PENDING));
138   ASSERT_TRUE(request);
139   request.reset();
140 
141   // Issue a few more requests to the worker pool and wait for their
142   // completion, so that the task of the canceled request (which runs on a
143   // worker thread) is likely to complete by the end of this test.
144   TestCompletionCallback callback;
145   for (int i = 0; i < 5; ++i) {
146     error = verifier_->Verify(
147         CertVerifier::RequestParams(test_cert, "www2.example.com", 0,
148                                     /*ocsp_response=*/std::string(),
149                                     /*sct_list=*/std::string()),
150         &verify_result, callback.callback(), &request, NetLogWithSource());
151     ASSERT_THAT(error, IsError(ERR_IO_PENDING));
152     EXPECT_TRUE(request);
153     error = callback.WaitForResult();
154   }
155 }
156 
157 // Tests that the callback of a request is never made if the |verifier_| itself
158 // is deleted.
TEST_F(MultiThreadedCertVerifierTest,DeleteVerifier)159 TEST_F(MultiThreadedCertVerifierTest, DeleteVerifier) {
160   base::FilePath certs_dir = GetTestCertsDirectory();
161   scoped_refptr<X509Certificate> test_cert(
162       ImportCertFromFile(certs_dir, "ok_cert.pem"));
163   ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
164 
165   int error;
166   CertVerifyResult verify_result;
167   std::unique_ptr<CertVerifier::Request> request;
168 
169   error = verifier_->Verify(
170       CertVerifier::RequestParams(test_cert, "www.example.com", 0,
171                                   /*ocsp_response=*/std::string(),
172                                   /*sct_list=*/std::string()),
173       &verify_result, base::BindOnce(&FailTest), &request, NetLogWithSource());
174   ASSERT_THAT(error, IsError(ERR_IO_PENDING));
175   ASSERT_TRUE(request);
176   verifier_.reset();
177 
178   RunUntilIdle();
179 }
180 
181 namespace {
182 
183 struct CertVerifyResultHelper {
FailTestnet::__anonfe15b6840211::CertVerifyResultHelper184   void FailTest(int /* result */) { FAIL(); }
185   std::unique_ptr<CertVerifier::Request> request;
186 };
187 
188 }  // namespace
189 
190 // The same as the above "DeleteVerifier" test, except the callback provided
191 // will own the CertVerifier::Request as allowed by the CertVerifier contract.
192 // This is a regression test for https://crbug.com/1157562.
TEST_F(MultiThreadedCertVerifierTest,DeleteVerifierCallbackOwnsResult)193 TEST_F(MultiThreadedCertVerifierTest, DeleteVerifierCallbackOwnsResult) {
194   base::FilePath certs_dir = GetTestCertsDirectory();
195   scoped_refptr<X509Certificate> test_cert(
196       ImportCertFromFile(certs_dir, "ok_cert.pem"));
197   ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
198 
199   int error;
200   CertVerifyResult verify_result;
201   std::unique_ptr<CertVerifyResultHelper> result_helper =
202       std::make_unique<CertVerifyResultHelper>();
203   CertVerifyResultHelper* result_helper_ptr = result_helper.get();
204   CompletionOnceCallback callback = base::BindOnce(
205       &CertVerifyResultHelper::FailTest, std::move(result_helper));
206 
207   error = verifier_->Verify(
208       CertVerifier::RequestParams(test_cert, "www.example.com", 0,
209                                   /*ocsp_response=*/std::string(),
210                                   /*sct_list=*/std::string()),
211       &verify_result, std::move(callback), &result_helper_ptr->request,
212       NetLogWithSource());
213   ASSERT_THAT(error, IsError(ERR_IO_PENDING));
214   ASSERT_TRUE(result_helper_ptr->request);
215   verifier_.reset();
216 
217   RunUntilIdle();
218 }
219 
220 // Tests that a canceled request is not leaked.
TEST_F(MultiThreadedCertVerifierTest,CancelRequestThenQuit)221 TEST_F(MultiThreadedCertVerifierTest, CancelRequestThenQuit) {
222   base::FilePath certs_dir = GetTestCertsDirectory();
223   scoped_refptr<X509Certificate> test_cert(
224       ImportCertFromFile(certs_dir, "ok_cert.pem"));
225   ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
226 
227   int error;
228   CertVerifyResult verify_result;
229   TestCompletionCallback callback;
230   std::unique_ptr<CertVerifier::Request> request;
231 
232   {
233     // Because shutdown intentionally doesn't join worker threads, memory may
234     // be leaked if the main thread shuts down before the worker thread
235     // completes. In particular MultiThreadedCertVerifier calls
236     // base::WorkerPool::PostTaskAndReply(), which leaks its "relay" when it
237     // can't post the reply back to the origin thread. See
238     // https://crbug.com/522514
239     ANNOTATE_SCOPED_MEMORY_LEAK;
240     error = verifier_->Verify(
241         CertVerifier::RequestParams(test_cert, "www.example.com", 0,
242                                     /*ocsp_response=*/std::string(),
243                                     /*sct_list=*/std::string()),
244         &verify_result, callback.callback(), &request, NetLogWithSource());
245   }
246   ASSERT_THAT(error, IsError(ERR_IO_PENDING));
247   EXPECT_TRUE(request);
248   request.reset();
249   // Destroy |verifier_| by going out of scope.
250 }
251 
252 // Tests propagation of configuration options into CertVerifyProc flags
TEST_F(MultiThreadedCertVerifierTest,ConvertsConfigToFlags)253 TEST_F(MultiThreadedCertVerifierTest, ConvertsConfigToFlags) {
254   base::FilePath certs_dir = GetTestCertsDirectory();
255   scoped_refptr<X509Certificate> test_cert(
256       ImportCertFromFile(certs_dir, "ok_cert.pem"));
257   ASSERT_TRUE(test_cert);
258 
259   const struct TestConfig {
260     bool CertVerifier::Config::*config_ptr;
261     int expected_flag;
262   } kTestConfig[] = {
263       {&CertVerifier::Config::enable_rev_checking,
264        CertVerifyProc::VERIFY_REV_CHECKING_ENABLED},
265       {&CertVerifier::Config::require_rev_checking_local_anchors,
266        CertVerifyProc::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS},
267       {&CertVerifier::Config::enable_sha1_local_anchors,
268        CertVerifyProc::VERIFY_ENABLE_SHA1_LOCAL_ANCHORS},
269       {&CertVerifier::Config::disable_symantec_enforcement,
270        CertVerifyProc::VERIFY_DISABLE_SYMANTEC_ENFORCEMENT},
271   };
272   for (const auto& test_config : kTestConfig) {
273     CertVerifier::Config config;
274     config.*test_config.config_ptr = true;
275 
276     verifier_->SetConfig(config);
277 
278     EXPECT_CALL(*mock_verify_proc_,
279                 VerifyInternal(_, _, _, _, test_config.expected_flag, _, _))
280         .WillRepeatedly(
281             DoAll(SetCertVerifyRevokedResult(), Return(ERR_CERT_REVOKED)));
282 
283     CertVerifyResult verify_result;
284     TestCompletionCallback callback;
285     std::unique_ptr<CertVerifier::Request> request;
286     int error = verifier_->Verify(
287         CertVerifier::RequestParams(test_cert, "www.example.com", 0,
288                                     /*ocsp_response=*/std::string(),
289                                     /*sct_list=*/std::string()),
290         &verify_result, callback.callback(), &request, NetLogWithSource());
291     ASSERT_THAT(error, IsError(ERR_IO_PENDING));
292     EXPECT_TRUE(request);
293     error = callback.WaitForResult();
294     EXPECT_TRUE(IsCertificateError(error));
295     EXPECT_THAT(error, IsError(ERR_CERT_REVOKED));
296 
297     testing::Mock::VerifyAndClearExpectations(mock_verify_proc_.get());
298   }
299 }
300 
301 // Tests propagation of CertVerifier flags into CertVerifyProc flags
TEST_F(MultiThreadedCertVerifierTest,ConvertsFlagsToFlags)302 TEST_F(MultiThreadedCertVerifierTest, ConvertsFlagsToFlags) {
303   scoped_refptr<X509Certificate> test_cert(
304       ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
305   ASSERT_TRUE(test_cert);
306 
307   EXPECT_CALL(
308       *mock_verify_proc_,
309       VerifyInternal(_, _, _, _, CertVerifyProc::VERIFY_DISABLE_NETWORK_FETCHES,
310                      _, _))
311       .WillRepeatedly(
312           DoAll(SetCertVerifyRevokedResult(), Return(ERR_CERT_REVOKED)));
313 
314   CertVerifyResult verify_result;
315   TestCompletionCallback callback;
316   std::unique_ptr<CertVerifier::Request> request;
317   int error = verifier_->Verify(
318       CertVerifier::RequestParams(test_cert, "www.example.com",
319                                   CertVerifier::VERIFY_DISABLE_NETWORK_FETCHES,
320                                   /*ocsp_response=*/std::string(),
321                                   /*sct_list=*/std::string()),
322       &verify_result, callback.callback(), &request, NetLogWithSource());
323   ASSERT_THAT(error, IsError(ERR_IO_PENDING));
324   EXPECT_TRUE(request);
325   error = callback.WaitForResult();
326   EXPECT_TRUE(IsCertificateError(error));
327   EXPECT_THAT(error, IsError(ERR_CERT_REVOKED));
328 
329   testing::Mock::VerifyAndClearExpectations(mock_verify_proc_.get());
330 }
331 
332 // Tests swapping in new Chrome Root Store Data.
TEST_F(MultiThreadedCertVerifierTest,VerifyProcChangeChromeRootStore)333 TEST_F(MultiThreadedCertVerifierTest, VerifyProcChangeChromeRootStore) {
334   CertVerifierObserverCounter observer_counter(verifier_.get());
335 
336   base::FilePath certs_dir = GetTestCertsDirectory();
337   scoped_refptr<X509Certificate> test_cert(
338       ImportCertFromFile(certs_dir, "ok_cert.pem"));
339   ASSERT_TRUE(test_cert);
340 
341   EXPECT_EQ(observer_counter.change_count(), 0u);
342 
343   EXPECT_CALL(*mock_new_verify_proc_, VerifyInternal(_, _, _, _, _, _, _))
344       .WillRepeatedly(
345           DoAll(SetCertVerifyRevokedResult(), Return(ERR_CERT_REVOKED)));
346   verifier_->UpdateVerifyProcData(nullptr, {}, {});
347 
348   EXPECT_EQ(observer_counter.change_count(), 1u);
349 
350   CertVerifyResult verify_result;
351   TestCompletionCallback callback;
352   std::unique_ptr<CertVerifier::Request> request;
353   int error = verifier_->Verify(
354       CertVerifier::RequestParams(test_cert, "www.example.com", 0,
355                                   /*ocsp_response=*/std::string(),
356                                   /*sct_list=*/std::string()),
357       &verify_result, callback.callback(), &request, NetLogWithSource());
358   ASSERT_THAT(error, IsError(ERR_IO_PENDING));
359   EXPECT_TRUE(request);
360   error = callback.WaitForResult();
361   EXPECT_TRUE(IsCertificateError(error));
362   EXPECT_THAT(error, IsError(ERR_CERT_REVOKED));
363 
364   testing::Mock::VerifyAndClearExpectations(mock_verify_proc_.get());
365   testing::Mock::VerifyAndClearExpectations(mock_new_verify_proc_.get());
366 }
367 
368 // Tests swapping out a new proc while a request is pending still uses
369 // the old proc for the old request.
TEST_F(MultiThreadedCertVerifierTest,VerifyProcChangeRequest)370 TEST_F(MultiThreadedCertVerifierTest, VerifyProcChangeRequest) {
371   base::FilePath certs_dir = GetTestCertsDirectory();
372   scoped_refptr<X509Certificate> test_cert(
373       ImportCertFromFile(certs_dir, "ok_cert.pem"));
374   ASSERT_TRUE(test_cert);
375 
376   CertVerifyResult verify_result;
377   TestCompletionCallback callback;
378   std::unique_ptr<CertVerifier::Request> request;
379   int error = verifier_->Verify(
380       CertVerifier::RequestParams(test_cert, "www.example.com", 0,
381                                   /*ocsp_response=*/std::string(),
382                                   /*sct_list=*/std::string()),
383       &verify_result, callback.callback(), &request, NetLogWithSource());
384   ASSERT_THAT(error, IsError(ERR_IO_PENDING));
385   EXPECT_TRUE(request);
386   verifier_->UpdateVerifyProcData(nullptr, {}, {});
387   error = callback.WaitForResult();
388   EXPECT_TRUE(IsCertificateError(error));
389   EXPECT_THAT(error, IsError(ERR_CERT_COMMON_NAME_INVALID));
390 
391   testing::Mock::VerifyAndClearExpectations(mock_verify_proc_.get());
392   testing::Mock::VerifyAndClearExpectations(mock_new_verify_proc_.get());
393 }
394 
395 }  // namespace net
396