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