Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / cert / multi_threaded_cert_verifier_unittest.cc
blobaa01511448fa48c2e70d093362d9121bc3c998bf
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/cert/multi_threaded_cert_verifier.h"
7 #include "base/bind.h"
8 #include "base/debug/leak_annotations.h"
9 #include "base/files/file_path.h"
10 #include "base/format_macros.h"
11 #include "base/strings/stringprintf.h"
12 #include "net/base/net_errors.h"
13 #include "net/base/test_completion_callback.h"
14 #include "net/base/test_data_directory.h"
15 #include "net/cert/cert_trust_anchor_provider.h"
16 #include "net/cert/cert_verify_proc.h"
17 #include "net/cert/cert_verify_result.h"
18 #include "net/cert/x509_certificate.h"
19 #include "net/log/net_log.h"
20 #include "net/test/cert_test_util.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 using testing::Mock;
25 using testing::ReturnRef;
27 namespace net {
29 namespace {
31 void FailTest(int /* result */) {
32 FAIL();
35 class MockCertVerifyProc : public CertVerifyProc {
36 public:
37 MockCertVerifyProc() {}
39 private:
40 ~MockCertVerifyProc() override {}
42 // CertVerifyProc implementation
43 bool SupportsAdditionalTrustAnchors() const override { return false; }
44 bool SupportsOCSPStapling() const override { return false; }
46 int VerifyInternal(X509Certificate* cert,
47 const std::string& hostname,
48 const std::string& ocsp_response,
49 int flags,
50 CRLSet* crl_set,
51 const CertificateList& additional_trust_anchors,
52 CertVerifyResult* verify_result) override {
53 verify_result->Reset();
54 verify_result->verified_cert = cert;
55 verify_result->cert_status = CERT_STATUS_COMMON_NAME_INVALID;
56 return ERR_CERT_COMMON_NAME_INVALID;
60 class MockCertTrustAnchorProvider : public CertTrustAnchorProvider {
61 public:
62 MockCertTrustAnchorProvider() {}
63 virtual ~MockCertTrustAnchorProvider() {}
65 MOCK_METHOD0(GetAdditionalTrustAnchors, const CertificateList&());
68 } // namespace
70 class MultiThreadedCertVerifierTest : public ::testing::Test {
71 public:
72 MultiThreadedCertVerifierTest() : verifier_(new MockCertVerifyProc()) {}
73 ~MultiThreadedCertVerifierTest() override {}
75 protected:
76 MultiThreadedCertVerifier verifier_;
79 TEST_F(MultiThreadedCertVerifierTest, CacheHit) {
80 base::FilePath certs_dir = GetTestCertsDirectory();
81 scoped_refptr<X509Certificate> test_cert(
82 ImportCertFromFile(certs_dir, "ok_cert.pem"));
83 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert.get());
85 int error;
86 CertVerifyResult verify_result;
87 TestCompletionCallback callback;
88 scoped_ptr<CertVerifier::Request> request;
90 error = verifier_.Verify(test_cert.get(), "www.example.com", std::string(), 0,
91 NULL, &verify_result, callback.callback(), &request,
92 BoundNetLog());
93 ASSERT_EQ(ERR_IO_PENDING, error);
94 EXPECT_TRUE(request);
95 error = callback.WaitForResult();
96 ASSERT_TRUE(IsCertificateError(error));
97 ASSERT_EQ(1u, verifier_.requests());
98 ASSERT_EQ(0u, verifier_.cache_hits());
99 ASSERT_EQ(0u, verifier_.inflight_joins());
100 ASSERT_EQ(1u, verifier_.GetCacheSize());
102 error = verifier_.Verify(test_cert.get(), "www.example.com", std::string(), 0,
103 NULL, &verify_result, callback.callback(), &request,
104 BoundNetLog());
105 // Synchronous completion.
106 ASSERT_NE(ERR_IO_PENDING, error);
107 ASSERT_TRUE(IsCertificateError(error));
108 ASSERT_FALSE(request);
109 ASSERT_EQ(2u, verifier_.requests());
110 ASSERT_EQ(1u, verifier_.cache_hits());
111 ASSERT_EQ(0u, verifier_.inflight_joins());
112 ASSERT_EQ(1u, verifier_.GetCacheSize());
115 // Tests the same server certificate with different intermediate CA
116 // certificates. These should be treated as different certificate chains even
117 // though the two X509Certificate objects contain the same server certificate.
118 TEST_F(MultiThreadedCertVerifierTest, DifferentCACerts) {
119 base::FilePath certs_dir = GetTestCertsDirectory();
121 scoped_refptr<X509Certificate> server_cert =
122 ImportCertFromFile(certs_dir, "salesforce_com_test.pem");
123 ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert.get());
125 scoped_refptr<X509Certificate> intermediate_cert1 =
126 ImportCertFromFile(certs_dir, "verisign_intermediate_ca_2011.pem");
127 ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert1.get());
129 scoped_refptr<X509Certificate> intermediate_cert2 =
130 ImportCertFromFile(certs_dir, "verisign_intermediate_ca_2016.pem");
131 ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert2.get());
133 X509Certificate::OSCertHandles intermediates;
134 intermediates.push_back(intermediate_cert1->os_cert_handle());
135 scoped_refptr<X509Certificate> cert_chain1 =
136 X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
137 intermediates);
139 intermediates.clear();
140 intermediates.push_back(intermediate_cert2->os_cert_handle());
141 scoped_refptr<X509Certificate> cert_chain2 =
142 X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
143 intermediates);
145 int error;
146 CertVerifyResult verify_result;
147 TestCompletionCallback callback;
148 scoped_ptr<CertVerifier::Request> request;
150 error = verifier_.Verify(cert_chain1.get(), "www.example.com", std::string(),
151 0, NULL, &verify_result, callback.callback(),
152 &request, BoundNetLog());
153 ASSERT_EQ(ERR_IO_PENDING, error);
154 EXPECT_TRUE(request);
155 error = callback.WaitForResult();
156 ASSERT_TRUE(IsCertificateError(error));
157 ASSERT_EQ(1u, verifier_.requests());
158 ASSERT_EQ(0u, verifier_.cache_hits());
159 ASSERT_EQ(0u, verifier_.inflight_joins());
160 ASSERT_EQ(1u, verifier_.GetCacheSize());
162 error = verifier_.Verify(cert_chain2.get(), "www.example.com", std::string(),
163 0, NULL, &verify_result, callback.callback(),
164 &request, BoundNetLog());
165 ASSERT_EQ(ERR_IO_PENDING, error);
166 EXPECT_TRUE(request);
167 error = callback.WaitForResult();
168 ASSERT_TRUE(IsCertificateError(error));
169 ASSERT_EQ(2u, verifier_.requests());
170 ASSERT_EQ(0u, verifier_.cache_hits());
171 ASSERT_EQ(0u, verifier_.inflight_joins());
172 ASSERT_EQ(2u, verifier_.GetCacheSize());
175 // Tests an inflight join.
176 TEST_F(MultiThreadedCertVerifierTest, InflightJoin) {
177 base::FilePath certs_dir = GetTestCertsDirectory();
178 scoped_refptr<X509Certificate> test_cert(
179 ImportCertFromFile(certs_dir, "ok_cert.pem"));
180 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert.get());
182 int error;
183 CertVerifyResult verify_result;
184 TestCompletionCallback callback;
185 scoped_ptr<CertVerifier::Request> request;
186 CertVerifyResult verify_result2;
187 TestCompletionCallback callback2;
188 scoped_ptr<CertVerifier::Request> request2;
190 error = verifier_.Verify(test_cert.get(), "www.example.com", std::string(), 0,
191 NULL, &verify_result, callback.callback(), &request,
192 BoundNetLog());
193 ASSERT_EQ(ERR_IO_PENDING, error);
194 EXPECT_TRUE(request);
195 error = verifier_.Verify(test_cert.get(), "www.example.com", std::string(), 0,
196 NULL, &verify_result2, callback2.callback(),
197 &request2, BoundNetLog());
198 EXPECT_EQ(ERR_IO_PENDING, error);
199 EXPECT_TRUE(request2);
200 error = callback.WaitForResult();
201 EXPECT_TRUE(IsCertificateError(error));
202 error = callback2.WaitForResult();
203 ASSERT_TRUE(IsCertificateError(error));
204 ASSERT_EQ(2u, verifier_.requests());
205 ASSERT_EQ(0u, verifier_.cache_hits());
206 ASSERT_EQ(1u, verifier_.inflight_joins());
209 // Tests that the callback of a canceled request is never made.
210 TEST_F(MultiThreadedCertVerifierTest, CancelRequest) {
211 base::FilePath certs_dir = GetTestCertsDirectory();
212 scoped_refptr<X509Certificate> test_cert(
213 ImportCertFromFile(certs_dir, "ok_cert.pem"));
214 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert.get());
216 int error;
217 CertVerifyResult verify_result;
218 scoped_ptr<CertVerifier::Request> request;
220 error = verifier_.Verify(test_cert.get(), "www.example.com", std::string(), 0,
221 NULL, &verify_result, base::Bind(&FailTest),
222 &request, BoundNetLog());
223 ASSERT_EQ(ERR_IO_PENDING, error);
224 ASSERT_TRUE(request);
225 request.reset();
227 // Issue a few more requests to the worker pool and wait for their
228 // completion, so that the task of the canceled request (which runs on a
229 // worker thread) is likely to complete by the end of this test.
230 TestCompletionCallback callback;
231 for (int i = 0; i < 5; ++i) {
232 error = verifier_.Verify(test_cert.get(), "www2.example.com", std::string(),
233 0, NULL, &verify_result, callback.callback(),
234 &request, BoundNetLog());
235 ASSERT_EQ(ERR_IO_PENDING, error);
236 EXPECT_TRUE(request);
237 error = callback.WaitForResult();
238 verifier_.ClearCache();
242 // Tests that a canceled request is not leaked.
243 TEST_F(MultiThreadedCertVerifierTest, CancelRequestThenQuit) {
244 base::FilePath certs_dir = GetTestCertsDirectory();
245 scoped_refptr<X509Certificate> test_cert(
246 ImportCertFromFile(certs_dir, "ok_cert.pem"));
247 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert.get());
249 int error;
250 CertVerifyResult verify_result;
251 TestCompletionCallback callback;
252 scoped_ptr<CertVerifier::Request> request;
255 // Because shutdown intentionally doesn't join worker threads, memory may
256 // be leaked if the main thread shuts down before the worker thread
257 // completes. In particular MultiThreadedCertVerifier calls
258 // base::WorkerPool::PostTaskAndReply(), which leaks its "relay" when it
259 // can't post the reply back to the origin thread. See
260 // https://crbug.com/522514
261 ANNOTATE_SCOPED_MEMORY_LEAK;
262 error = verifier_.Verify(test_cert.get(), "www.example.com", std::string(),
263 0, NULL, &verify_result, callback.callback(),
264 &request, BoundNetLog());
266 ASSERT_EQ(ERR_IO_PENDING, error);
267 EXPECT_TRUE(request);
268 request.reset();
269 // Destroy |verifier| by going out of scope.
272 TEST_F(MultiThreadedCertVerifierTest, RequestParamsComparators) {
273 SHA1HashValue a_key;
274 memset(a_key.data, 'a', sizeof(a_key.data));
276 SHA1HashValue z_key;
277 memset(z_key.data, 'z', sizeof(z_key.data));
279 const CertificateList empty_list;
280 CertificateList test_list;
281 test_list.push_back(
282 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
284 struct {
285 // Keys to test
286 MultiThreadedCertVerifier::RequestParams key1;
287 MultiThreadedCertVerifier::RequestParams key2;
289 // Expectation:
290 // -1 means key1 is less than key2
291 // 0 means key1 equals key2
292 // 1 means key1 is greater than key2
293 int expected_result;
294 } tests[] = {
296 // Test for basic equivalence.
297 MultiThreadedCertVerifier::RequestParams(
298 a_key, a_key, "www.example.test", std::string(), 0, test_list),
299 MultiThreadedCertVerifier::RequestParams(
300 a_key, a_key, "www.example.test", std::string(), 0, test_list),
304 // Test that different certificates but with the same CA and for
305 // the same host are different validation keys.
306 MultiThreadedCertVerifier::RequestParams(
307 a_key, a_key, "www.example.test", std::string(), 0, test_list),
308 MultiThreadedCertVerifier::RequestParams(
309 z_key, a_key, "www.example.test", std::string(), 0, test_list),
313 // Test that the same EE certificate for the same host, but with
314 // different chains are different validation keys.
315 MultiThreadedCertVerifier::RequestParams(
316 a_key, z_key, "www.example.test", std::string(), 0, test_list),
317 MultiThreadedCertVerifier::RequestParams(
318 a_key, a_key, "www.example.test", std::string(), 0, test_list),
322 // The same certificate, with the same chain, but for different
323 // hosts are different validation keys.
324 MultiThreadedCertVerifier::RequestParams(
325 a_key, a_key, "www1.example.test", std::string(), 0, test_list),
326 MultiThreadedCertVerifier::RequestParams(
327 a_key, a_key, "www2.example.test", std::string(), 0, test_list),
331 // The same certificate, chain, and host, but with different flags
332 // are different validation keys.
333 MultiThreadedCertVerifier::RequestParams(
334 a_key, a_key, "www.example.test", std::string(),
335 CertVerifier::VERIFY_EV_CERT, test_list),
336 MultiThreadedCertVerifier::RequestParams(
337 a_key, a_key, "www.example.test", std::string(), 0, test_list),
341 // Different additional_trust_anchors.
342 MultiThreadedCertVerifier::RequestParams(
343 a_key, a_key, "www.example.test", std::string(), 0, empty_list),
344 MultiThreadedCertVerifier::RequestParams(
345 a_key, a_key, "www.example.test", std::string(), 0, test_list),
349 // Different OCSP responses.
350 MultiThreadedCertVerifier::RequestParams(
351 a_key, a_key, "www.example.test", "ocsp response", 0, test_list),
352 MultiThreadedCertVerifier::RequestParams(
353 a_key, a_key, "www.example.test", std::string(), 0, test_list),
357 for (size_t i = 0; i < arraysize(tests); ++i) {
358 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
360 const MultiThreadedCertVerifier::RequestParams& key1 = tests[i].key1;
361 const MultiThreadedCertVerifier::RequestParams& key2 = tests[i].key2;
363 switch (tests[i].expected_result) {
364 case -1:
365 EXPECT_TRUE(key1 < key2);
366 EXPECT_FALSE(key2 < key1);
367 break;
368 case 0:
369 EXPECT_FALSE(key1 < key2);
370 EXPECT_FALSE(key2 < key1);
371 break;
372 case 1:
373 EXPECT_FALSE(key1 < key2);
374 EXPECT_TRUE(key2 < key1);
375 break;
376 default:
377 FAIL() << "Invalid expectation. Can be only -1, 0, 1";
382 TEST_F(MultiThreadedCertVerifierTest, CertTrustAnchorProvider) {
383 MockCertTrustAnchorProvider trust_provider;
384 verifier_.SetCertTrustAnchorProvider(&trust_provider);
386 scoped_refptr<X509Certificate> test_cert(
387 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
388 ASSERT_TRUE(test_cert.get());
390 const CertificateList empty_cert_list;
391 CertificateList cert_list;
392 cert_list.push_back(test_cert);
394 // Check that Verify() asks the |trust_provider| for the current list of
395 // additional trust anchors.
396 int error;
397 CertVerifyResult verify_result;
398 TestCompletionCallback callback;
399 scoped_ptr<CertVerifier::Request> request;
400 EXPECT_CALL(trust_provider, GetAdditionalTrustAnchors())
401 .WillOnce(ReturnRef(empty_cert_list));
402 error = verifier_.Verify(test_cert.get(), "www.example.com", std::string(), 0,
403 NULL, &verify_result, callback.callback(), &request,
404 BoundNetLog());
405 Mock::VerifyAndClearExpectations(&trust_provider);
406 ASSERT_EQ(ERR_IO_PENDING, error);
407 EXPECT_TRUE(request);
408 error = callback.WaitForResult();
409 EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
410 ASSERT_EQ(1u, verifier_.requests());
411 ASSERT_EQ(0u, verifier_.cache_hits());
413 // The next Verify() uses the cached result.
414 EXPECT_CALL(trust_provider, GetAdditionalTrustAnchors())
415 .WillOnce(ReturnRef(empty_cert_list));
416 error = verifier_.Verify(test_cert.get(), "www.example.com", std::string(), 0,
417 NULL, &verify_result, callback.callback(), &request,
418 BoundNetLog());
419 Mock::VerifyAndClearExpectations(&trust_provider);
420 EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
421 EXPECT_FALSE(request);
422 ASSERT_EQ(2u, verifier_.requests());
423 ASSERT_EQ(1u, verifier_.cache_hits());
425 // Another Verify() for the same certificate but with a different list of
426 // trust anchors will not reuse the cache.
427 EXPECT_CALL(trust_provider, GetAdditionalTrustAnchors())
428 .WillOnce(ReturnRef(cert_list));
429 error = verifier_.Verify(test_cert.get(), "www.example.com", std::string(), 0,
430 NULL, &verify_result, callback.callback(), &request,
431 BoundNetLog());
432 Mock::VerifyAndClearExpectations(&trust_provider);
433 ASSERT_EQ(ERR_IO_PENDING, error);
434 EXPECT_TRUE(request);
435 error = callback.WaitForResult();
436 EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
437 ASSERT_EQ(3u, verifier_.requests());
438 ASSERT_EQ(1u, verifier_.cache_hits());
441 // Tests de-duplication of requests.
442 // Starts up 5 requests, of which 3 are unique.
443 TEST_F(MultiThreadedCertVerifierTest, MultipleInflightJoin) {
444 base::FilePath certs_dir = GetTestCertsDirectory();
445 scoped_refptr<X509Certificate> test_cert(
446 ImportCertFromFile(certs_dir, "ok_cert.pem"));
447 ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
449 int error;
450 CertVerifyResult verify_result1;
451 TestCompletionCallback callback1;
452 scoped_ptr<CertVerifier::Request> request1;
453 CertVerifyResult verify_result2;
454 TestCompletionCallback callback2;
455 scoped_ptr<CertVerifier::Request> request2;
456 CertVerifyResult verify_result3;
457 TestCompletionCallback callback3;
458 scoped_ptr<CertVerifier::Request> request3;
459 CertVerifyResult verify_result4;
460 TestCompletionCallback callback4;
461 scoped_ptr<CertVerifier::Request> request4;
462 CertVerifyResult verify_result5;
463 TestCompletionCallback callback5;
464 scoped_ptr<CertVerifier::Request> request5;
466 const char domain1[] = "www.example1.com";
467 const char domain2[] = "www.exampleB.com";
468 const char domain3[] = "www.example3.com";
470 // Start 3 unique requests.
471 error = verifier_.Verify(test_cert.get(), domain2, std::string(), 0, nullptr,
472 &verify_result1, callback1.callback(), &request1,
473 BoundNetLog());
474 ASSERT_EQ(ERR_IO_PENDING, error);
475 EXPECT_TRUE(request1);
477 error = verifier_.Verify(test_cert.get(), domain2, std::string(), 0, nullptr,
478 &verify_result2, callback2.callback(), &request2,
479 BoundNetLog());
480 EXPECT_EQ(ERR_IO_PENDING, error);
481 EXPECT_TRUE(request2);
483 error = verifier_.Verify(test_cert.get(), domain3, std::string(), 0, nullptr,
484 &verify_result3, callback3.callback(), &request3,
485 BoundNetLog());
486 EXPECT_EQ(ERR_IO_PENDING, error);
487 EXPECT_TRUE(request3);
489 // Start duplicate requests (which should join to existing jobs).
490 error = verifier_.Verify(test_cert.get(), domain1, std::string(), 0, nullptr,
491 &verify_result4, callback4.callback(), &request4,
492 BoundNetLog());
493 EXPECT_EQ(ERR_IO_PENDING, error);
494 EXPECT_TRUE(request4);
496 error = verifier_.Verify(test_cert.get(), domain2, std::string(), 0, nullptr,
497 &verify_result5, callback5.callback(), &request5,
498 BoundNetLog());
499 EXPECT_EQ(ERR_IO_PENDING, error);
500 EXPECT_TRUE(request5);
502 error = callback1.WaitForResult();
503 EXPECT_TRUE(IsCertificateError(error));
504 error = callback2.WaitForResult();
505 ASSERT_TRUE(IsCertificateError(error));
506 error = callback4.WaitForResult();
507 ASSERT_TRUE(IsCertificateError(error));
509 // Let the other requests automatically cancel.
510 ASSERT_EQ(5u, verifier_.requests());
511 ASSERT_EQ(0u, verifier_.cache_hits());
512 ASSERT_EQ(2u, verifier_.inflight_joins());
515 } // namespace net