• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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/cert_and_ct_verifier.h"
6 
7 #include <memory>
8 
9 #include "base/files/file_path.h"
10 #include "base/memory/ref_counted.h"
11 #include "net/base/completion_once_callback.h"
12 #include "net/base/net_errors.h"
13 #include "net/base/test_completion_callback.h"
14 #include "net/cert/cert_verifier.h"
15 #include "net/cert/cert_verify_result.h"
16 #include "net/cert/ct_verifier.h"
17 #include "net/cert/mock_cert_verifier.h"
18 #include "net/cert/sct_status_flags.h"
19 #include "net/cert/signed_certificate_timestamp_and_status.h"
20 #include "net/cert/x509_certificate.h"
21 #include "net/cert/x509_util.h"
22 #include "net/log/net_log_with_source.h"
23 #include "net/test/cert_test_util.h"
24 #include "net/test/ct_test_util.h"
25 #include "net/test/gtest_util.h"
26 #include "net/test/test_data_directory.h"
27 #include "net/test/test_with_task_environment.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29 
30 using net::test::IsError;
31 using net::test::IsOk;
32 
33 namespace net {
34 
35 namespace {
36 
37 // Callback that allows a test to check that the callback was canceled. The
38 // FailTest() callback can own the CallbackHelper while the test keeps a WeakPtr
39 // to check whether it has been deleted. The callback itself will fail the test
40 // if it is run.
41 struct CallbackHelper {
42   base::WeakPtrFactory<CallbackHelper> factory{this};
43 };
FailTest(std::unique_ptr<CallbackHelper> helper,int result)44 void FailTest(std::unique_ptr<CallbackHelper> helper, int result) {
45   FAIL();
46 }
47 
48 class FakeCTVerifier : public CTVerifier {
49  public:
50   // CTVerifier implementation:
Verify(X509Certificate * cert,base::StringPiece stapled_ocsp_response,base::StringPiece sct_list_from_tls_extension,SignedCertificateTimestampAndStatusList * output_scts,const NetLogWithSource & net_log)51   void Verify(X509Certificate* cert,
52               base::StringPiece stapled_ocsp_response,
53               base::StringPiece sct_list_from_tls_extension,
54               SignedCertificateTimestampAndStatusList* output_scts,
55               const NetLogWithSource& net_log) override {
56     *output_scts = scts_;
57   }
58 
59   // Test setup interface:
set_scts(const SignedCertificateTimestampAndStatusList & scts)60   void set_scts(const SignedCertificateTimestampAndStatusList& scts) {
61     scts_ = scts;
62   }
63 
64  private:
65   SignedCertificateTimestampAndStatusList scts_;
66 };
67 
68 }  // namespace
69 
70 class CertAndCTVerifierTest : public TestWithTaskEnvironment {
71  public:
72   CertAndCTVerifierTest() = default;
73   ~CertAndCTVerifierTest() override = default;
74 };
75 
76 // Tests that both certificate and certificate transparency details in the
77 // CertVerifyResult are filled by the CertAndCTVerifier, when completion occurs
78 // synchronously.
TEST_F(CertAndCTVerifierTest,CertAndCTDetailsFilled_Sync)79 TEST_F(CertAndCTVerifierTest, CertAndCTDetailsFilled_Sync) {
80   base::FilePath certs_dir = GetTestCertsDirectory();
81   scoped_refptr<X509Certificate> test_cert(
82       ImportCertFromFile(certs_dir, "ok_cert.pem"));
83   ASSERT_TRUE(test_cert.get());
84 
85   // Mock the cert verification and CT verification results.
86   CertVerifyResult mock_result;
87   mock_result.cert_status = OK;
88   mock_result.verified_cert = test_cert;
89   auto cert_verifier = std::make_unique<MockCertVerifier>();
90   cert_verifier->AddResultForCert(test_cert, mock_result, OK);
91   cert_verifier->set_async(false);
92 
93   scoped_refptr<ct::SignedCertificateTimestamp> sct;
94   ct::GetX509CertSCT(&sct);
95   SignedCertificateTimestampAndStatus sct_and_status(sct, ct::SCT_STATUS_OK);
96   SignedCertificateTimestampAndStatusList sct_list{sct_and_status};
97   auto ct_verifier = std::make_unique<FakeCTVerifier>();
98   ct_verifier->set_scts(sct_list);
99 
100   CertAndCTVerifier cert_and_ct_verifier(std::move(cert_verifier),
101                                          std::move(ct_verifier));
102 
103   CertVerifyResult verify_result;
104   TestCompletionCallback callback;
105   std::unique_ptr<CertVerifier::Request> request;
106 
107   int result = callback.GetResult(cert_and_ct_verifier.Verify(
108       CertVerifier::RequestParams(test_cert, "www.example.com", 0,
109                                   /*ocsp_response=*/std::string(),
110                                   /*sct_list=*/std::string()),
111       &verify_result, callback.callback(), &request, NetLogWithSource()));
112   EXPECT_THAT(result, IsOk());
113   ASSERT_EQ(1u, verify_result.scts.size());
114   EXPECT_EQ(ct::SCT_STATUS_OK, verify_result.scts[0].status);
115 }
116 
117 // Tests that both certificate and certificate transparency details in the
118 // CertVerifyResult are filled by the CertAndCTVerifier, when completion occurs
119 // asynchronously.
TEST_F(CertAndCTVerifierTest,CertAndCTDetailsFilled_Async)120 TEST_F(CertAndCTVerifierTest, CertAndCTDetailsFilled_Async) {
121   base::FilePath certs_dir = GetTestCertsDirectory();
122   scoped_refptr<X509Certificate> test_cert(
123       ImportCertFromFile(certs_dir, "ok_cert.pem"));
124   ASSERT_TRUE(test_cert.get());
125 
126   // Mock the cert verification and CT verification results.
127   CertVerifyResult mock_result;
128   mock_result.cert_status = OK;
129   mock_result.verified_cert = test_cert;
130   auto cert_verifier = std::make_unique<MockCertVerifier>();
131   cert_verifier->AddResultForCert(test_cert, mock_result, OK);
132   cert_verifier->set_async(true);
133 
134   scoped_refptr<ct::SignedCertificateTimestamp> sct;
135   ct::GetX509CertSCT(&sct);
136   SignedCertificateTimestampAndStatus sct_and_status(sct, ct::SCT_STATUS_OK);
137   SignedCertificateTimestampAndStatusList sct_list{sct_and_status};
138   auto ct_verifier = std::make_unique<FakeCTVerifier>();
139   ct_verifier->set_scts(sct_list);
140 
141   CertAndCTVerifier cert_and_ct_verifier(std::move(cert_verifier),
142                                          std::move(ct_verifier));
143 
144   CertVerifyResult verify_result;
145   TestCompletionCallback callback;
146   std::unique_ptr<CertVerifier::Request> request;
147 
148   int result = callback.GetResult(cert_and_ct_verifier.Verify(
149       CertVerifier::RequestParams(test_cert, "www.example.com", 0,
150                                   /*ocsp_response=*/std::string(),
151                                   /*sct_list=*/std::string()),
152       &verify_result, callback.callback(), &request, NetLogWithSource()));
153   EXPECT_THAT(result, IsOk());
154   ASSERT_EQ(1u, verify_result.scts.size());
155   EXPECT_EQ(ct::SCT_STATUS_OK, verify_result.scts[0].status);
156 }
157 
158 // Tests that the callback of a canceled request is never run.
TEST_F(CertAndCTVerifierTest,CancelRequest)159 TEST_F(CertAndCTVerifierTest, CancelRequest) {
160   base::FilePath certs_dir = GetTestCertsDirectory();
161   scoped_refptr<X509Certificate> test_cert(
162       ImportCertFromFile(certs_dir, "ok_cert.pem"));
163   ASSERT_TRUE(test_cert.get());
164 
165   // Mock the cert verification and CT verification results.
166   CertVerifyResult mock_result;
167   mock_result.cert_status = OK;
168   mock_result.verified_cert = test_cert;
169   auto cert_verifier = std::make_unique<MockCertVerifier>();
170   cert_verifier->AddResultForCert(test_cert, mock_result, OK);
171   cert_verifier->set_async(true);
172 
173   scoped_refptr<ct::SignedCertificateTimestamp> sct;
174   ct::GetX509CertSCT(&sct);
175   SignedCertificateTimestampAndStatus sct_and_status(sct, ct::SCT_STATUS_OK);
176   SignedCertificateTimestampAndStatusList sct_list{sct_and_status};
177   auto ct_verifier = std::make_unique<FakeCTVerifier>();
178   ct_verifier->set_scts(sct_list);
179 
180   CertAndCTVerifier cert_and_ct_verifier(std::move(cert_verifier),
181                                          std::move(ct_verifier));
182 
183   CertVerifyResult verify_result;
184   std::unique_ptr<CertVerifier::Request> request;
185 
186   auto helper = std::make_unique<CallbackHelper>();
187   base::WeakPtr<CallbackHelper> weak_helper = helper->factory.GetWeakPtr();
188 
189   int result = cert_and_ct_verifier.Verify(
190       CertVerifier::RequestParams(test_cert, "www.example.com", 0,
191                                   /*ocsp_response=*/std::string(),
192                                   /*sct_list=*/std::string()),
193       &verify_result, base::BindOnce(&FailTest, std::move(helper)), &request,
194       NetLogWithSource());
195   ASSERT_THAT(result, IsError(ERR_IO_PENDING));
196   ASSERT_TRUE(request);
197   request.reset();
198 
199   // Check that the callback was reset when the request was reset.
200   ASSERT_TRUE(weak_helper.WasInvalidated());
201 
202   RunUntilIdle();
203 }
204 
205 // Tests that the callback of a request is never run if the CertAndCTVerifier is
206 // deleted.
TEST_F(CertAndCTVerifierTest,DeleteVerifier)207 TEST_F(CertAndCTVerifierTest, DeleteVerifier) {
208   base::FilePath certs_dir = GetTestCertsDirectory();
209   scoped_refptr<X509Certificate> test_cert(
210       ImportCertFromFile(certs_dir, "ok_cert.pem"));
211   ASSERT_TRUE(test_cert.get());
212 
213   // Mock the cert verification and CT verification results.
214   CertVerifyResult mock_result;
215   mock_result.cert_status = OK;
216   mock_result.verified_cert = test_cert;
217   auto cert_verifier = std::make_unique<MockCertVerifier>();
218   cert_verifier->AddResultForCert(test_cert, mock_result, OK);
219   cert_verifier->set_async(true);
220 
221   scoped_refptr<ct::SignedCertificateTimestamp> sct;
222   ct::GetX509CertSCT(&sct);
223   SignedCertificateTimestampAndStatus sct_and_status(sct, ct::SCT_STATUS_OK);
224   SignedCertificateTimestampAndStatusList sct_list{sct_and_status};
225   auto ct_verifier = std::make_unique<FakeCTVerifier>();
226   ct_verifier->set_scts(sct_list);
227 
228   auto cert_and_ct_verifier = std::make_unique<CertAndCTVerifier>(
229       std::move(cert_verifier), std::move(ct_verifier));
230 
231   CertVerifyResult verify_result;
232   std::unique_ptr<CertVerifier::Request> request;
233 
234   auto helper = std::make_unique<CallbackHelper>();
235   base::WeakPtr<CallbackHelper> weak_helper = helper->factory.GetWeakPtr();
236 
237   int result = cert_and_ct_verifier->Verify(
238       CertVerifier::RequestParams(test_cert, "www.example.com", 0,
239                                   /*ocsp_response=*/std::string(),
240                                   /*sct_list=*/std::string()),
241       &verify_result, base::BindOnce(&FailTest, std::move(helper)), &request,
242       NetLogWithSource());
243   ASSERT_THAT(result, IsError(ERR_IO_PENDING));
244   ASSERT_TRUE(request);
245   cert_and_ct_verifier.reset();
246 
247   // Check that the callback was reset when the verifier was deleted.
248   ASSERT_TRUE(weak_helper.WasInvalidated());
249 
250   RunUntilIdle();
251 }
252 
253 // Tests that cancelling the request and stopping without ever running anything
254 // works as expected.
TEST_F(CertAndCTVerifierTest,CancelRequestThenQuit)255 TEST_F(CertAndCTVerifierTest, CancelRequestThenQuit) {
256   base::FilePath certs_dir = GetTestCertsDirectory();
257   scoped_refptr<X509Certificate> test_cert(
258       ImportCertFromFile(certs_dir, "ok_cert.pem"));
259   ASSERT_TRUE(test_cert.get());
260 
261   // Mock the cert verification and CT verification results.
262   CertVerifyResult mock_result;
263   mock_result.cert_status = OK;
264   mock_result.verified_cert = test_cert;
265   auto cert_verifier = std::make_unique<MockCertVerifier>();
266   cert_verifier->AddResultForCert(test_cert, mock_result, OK);
267   cert_verifier->set_async(true);
268 
269   scoped_refptr<ct::SignedCertificateTimestamp> sct;
270   ct::GetX509CertSCT(&sct);
271   SignedCertificateTimestampAndStatus sct_and_status(sct, ct::SCT_STATUS_OK);
272   SignedCertificateTimestampAndStatusList sct_list{sct_and_status};
273   auto ct_verifier = std::make_unique<FakeCTVerifier>();
274   ct_verifier->set_scts(sct_list);
275 
276   auto cert_and_ct_verifier = std::make_unique<CertAndCTVerifier>(
277       std::move(cert_verifier), std::move(ct_verifier));
278 
279   CertVerifyResult verify_result;
280   std::unique_ptr<CertVerifier::Request> request;
281 
282   auto helper = std::make_unique<CallbackHelper>();
283   base::WeakPtr<CallbackHelper> weak_helper = helper->factory.GetWeakPtr();
284 
285   int result = cert_and_ct_verifier->Verify(
286       CertVerifier::RequestParams(test_cert, "www.example.com", 0,
287                                   /*ocsp_response=*/std::string(),
288                                   /*sct_list=*/std::string()),
289       &verify_result, base::BindOnce(&FailTest, std::move(helper)), &request,
290       NetLogWithSource());
291   ASSERT_THAT(result, IsError(ERR_IO_PENDING));
292   EXPECT_TRUE(request);
293   request.reset();
294 
295   // Check that the callback was reset when the request was reset.
296   ASSERT_TRUE(weak_helper.WasInvalidated());
297 
298   // Destroy |cert_and_ct_verifier| by going out of scope.
299 }
300 
301 // Regression test for crbug.com/1153484: If the CertVerifier aborts, the
302 // CT verification step should be skipped.
TEST_F(CertAndCTVerifierTest,CertVerifierErrorShouldSkipCT)303 TEST_F(CertAndCTVerifierTest, CertVerifierErrorShouldSkipCT) {
304   base::FilePath certs_dir = GetTestCertsDirectory();
305   scoped_refptr<X509Certificate> test_cert(
306       ImportCertFromFile(certs_dir, "ok_cert.pem"));
307   ASSERT_TRUE(test_cert.get());
308 
309   // Mock the cert verification result as aborted (like what happens if the
310   // MojoCertVerifier gets disconnected).
311   CertVerifyResult mock_result;
312   mock_result.cert_status = CERT_STATUS_INVALID;
313   mock_result.verified_cert = test_cert;
314   auto cert_verifier = std::make_unique<MockCertVerifier>();
315   cert_verifier->AddResultForCert(test_cert, mock_result, ERR_ABORTED);
316   cert_verifier->set_async(true);
317 
318   // Mock valid SCTs.
319   scoped_refptr<ct::SignedCertificateTimestamp> sct;
320   ct::GetX509CertSCT(&sct);
321   SignedCertificateTimestampAndStatus sct_and_status(sct, ct::SCT_STATUS_OK);
322   SignedCertificateTimestampAndStatusList sct_list{sct_and_status};
323   auto ct_verifier = std::make_unique<FakeCTVerifier>();
324   ct_verifier->set_scts(sct_list);
325 
326   CertAndCTVerifier cert_and_ct_verifier(std::move(cert_verifier),
327                                          std::move(ct_verifier));
328 
329   CertVerifyResult verify_result;
330   TestCompletionCallback callback;
331   std::unique_ptr<CertVerifier::Request> request;
332 
333   int result = callback.GetResult(cert_and_ct_verifier.Verify(
334       CertVerifier::RequestParams(test_cert, "www.example.com", 0,
335                                   /*ocsp_response=*/std::string(),
336                                   /*sct_list=*/std::string()),
337       &verify_result, callback.callback(), &request, NetLogWithSource()));
338   EXPECT_THAT(result, IsError(ERR_ABORTED));
339   // SCTs should not be filled in because CTVerifier::Verify() should not be
340   // called.
341   ASSERT_EQ(0u, verify_result.scts.size());
342 }
343 
TEST_F(CertAndCTVerifierTest,ObserverIsForwarded)344 TEST_F(CertAndCTVerifierTest, ObserverIsForwarded) {
345   auto mock_cert_verifier_owner = std::make_unique<MockCertVerifier>();
346   MockCertVerifier* mock_cert_verifier = mock_cert_verifier_owner.get();
347 
348   CertAndCTVerifier cert_and_ct_verifier(std::move(mock_cert_verifier_owner),
349                                          std::make_unique<FakeCTVerifier>());
350 
351   CertVerifierObserverCounter observer(&cert_and_ct_verifier);
352   EXPECT_EQ(observer.change_count(), 0u);
353   // A CertVerifierChanged event on the wrapped verifier should be forwarded to
354   // observers registered on CertAndCTVerifier.
355   mock_cert_verifier->SimulateOnCertVerifierChanged();
356   EXPECT_EQ(observer.change_count(), 1u);
357 }
358 
359 }  // namespace net
360