Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / cert / multi_threaded_cert_verifier_unittest.cc
bloba3db543f0d7b5db057af046a6361cb11fcc4b175
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, a
256 // CertVerifyWorker may be leaked if the main thread shuts down before the
257 // worker thread.
258 ANNOTATE_SCOPED_MEMORY_LEAK;
259 error = verifier_.Verify(test_cert.get(), "www.example.com", std::string(),
260 0, NULL, &verify_result, callback.callback(),
261 &request, BoundNetLog());
263 ASSERT_EQ(ERR_IO_PENDING, error);
264 EXPECT_TRUE(request);
265 request.reset();
266 // Destroy |verifier| by going out of scope.
269 TEST_F(MultiThreadedCertVerifierTest, RequestParamsComparators) {
270 SHA1HashValue a_key;
271 memset(a_key.data, 'a', sizeof(a_key.data));
273 SHA1HashValue z_key;
274 memset(z_key.data, 'z', sizeof(z_key.data));
276 const CertificateList empty_list;
277 CertificateList test_list;
278 test_list.push_back(
279 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
281 struct {
282 // Keys to test
283 MultiThreadedCertVerifier::RequestParams key1;
284 MultiThreadedCertVerifier::RequestParams key2;
286 // Expectation:
287 // -1 means key1 is less than key2
288 // 0 means key1 equals key2
289 // 1 means key1 is greater than key2
290 int expected_result;
291 } tests[] = {
293 // Test for basic equivalence.
294 MultiThreadedCertVerifier::RequestParams(
295 a_key, a_key, "www.example.test", std::string(), 0, test_list),
296 MultiThreadedCertVerifier::RequestParams(
297 a_key, a_key, "www.example.test", std::string(), 0, test_list),
301 // Test that different certificates but with the same CA and for
302 // the same host are different validation keys.
303 MultiThreadedCertVerifier::RequestParams(
304 a_key, a_key, "www.example.test", std::string(), 0, test_list),
305 MultiThreadedCertVerifier::RequestParams(
306 z_key, a_key, "www.example.test", std::string(), 0, test_list),
310 // Test that the same EE certificate for the same host, but with
311 // different chains are different validation keys.
312 MultiThreadedCertVerifier::RequestParams(
313 a_key, z_key, "www.example.test", std::string(), 0, test_list),
314 MultiThreadedCertVerifier::RequestParams(
315 a_key, a_key, "www.example.test", std::string(), 0, test_list),
319 // The same certificate, with the same chain, but for different
320 // hosts are different validation keys.
321 MultiThreadedCertVerifier::RequestParams(
322 a_key, a_key, "www1.example.test", std::string(), 0, test_list),
323 MultiThreadedCertVerifier::RequestParams(
324 a_key, a_key, "www2.example.test", std::string(), 0, test_list),
328 // The same certificate, chain, and host, but with different flags
329 // are different validation keys.
330 MultiThreadedCertVerifier::RequestParams(
331 a_key, a_key, "www.example.test", std::string(),
332 CertVerifier::VERIFY_EV_CERT, test_list),
333 MultiThreadedCertVerifier::RequestParams(
334 a_key, a_key, "www.example.test", std::string(), 0, test_list),
338 // Different additional_trust_anchors.
339 MultiThreadedCertVerifier::RequestParams(
340 a_key, a_key, "www.example.test", std::string(), 0, empty_list),
341 MultiThreadedCertVerifier::RequestParams(
342 a_key, a_key, "www.example.test", std::string(), 0, test_list),
346 // Different OCSP responses.
347 MultiThreadedCertVerifier::RequestParams(
348 a_key, a_key, "www.example.test", "ocsp response", 0, test_list),
349 MultiThreadedCertVerifier::RequestParams(
350 a_key, a_key, "www.example.test", std::string(), 0, test_list),
354 for (size_t i = 0; i < arraysize(tests); ++i) {
355 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
357 const MultiThreadedCertVerifier::RequestParams& key1 = tests[i].key1;
358 const MultiThreadedCertVerifier::RequestParams& key2 = tests[i].key2;
360 switch (tests[i].expected_result) {
361 case -1:
362 EXPECT_TRUE(key1 < key2);
363 EXPECT_FALSE(key2 < key1);
364 break;
365 case 0:
366 EXPECT_FALSE(key1 < key2);
367 EXPECT_FALSE(key2 < key1);
368 break;
369 case 1:
370 EXPECT_FALSE(key1 < key2);
371 EXPECT_TRUE(key2 < key1);
372 break;
373 default:
374 FAIL() << "Invalid expectation. Can be only -1, 0, 1";
379 TEST_F(MultiThreadedCertVerifierTest, CertTrustAnchorProvider) {
380 MockCertTrustAnchorProvider trust_provider;
381 verifier_.SetCertTrustAnchorProvider(&trust_provider);
383 scoped_refptr<X509Certificate> test_cert(
384 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
385 ASSERT_TRUE(test_cert.get());
387 const CertificateList empty_cert_list;
388 CertificateList cert_list;
389 cert_list.push_back(test_cert);
391 // Check that Verify() asks the |trust_provider| for the current list of
392 // additional trust anchors.
393 int error;
394 CertVerifyResult verify_result;
395 TestCompletionCallback callback;
396 scoped_ptr<CertVerifier::Request> request;
397 EXPECT_CALL(trust_provider, GetAdditionalTrustAnchors())
398 .WillOnce(ReturnRef(empty_cert_list));
399 error = verifier_.Verify(test_cert.get(), "www.example.com", std::string(), 0,
400 NULL, &verify_result, callback.callback(), &request,
401 BoundNetLog());
402 Mock::VerifyAndClearExpectations(&trust_provider);
403 ASSERT_EQ(ERR_IO_PENDING, error);
404 EXPECT_TRUE(request);
405 error = callback.WaitForResult();
406 EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
407 ASSERT_EQ(1u, verifier_.requests());
408 ASSERT_EQ(0u, verifier_.cache_hits());
410 // The next Verify() uses the cached result.
411 EXPECT_CALL(trust_provider, GetAdditionalTrustAnchors())
412 .WillOnce(ReturnRef(empty_cert_list));
413 error = verifier_.Verify(test_cert.get(), "www.example.com", std::string(), 0,
414 NULL, &verify_result, callback.callback(), &request,
415 BoundNetLog());
416 Mock::VerifyAndClearExpectations(&trust_provider);
417 EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
418 EXPECT_FALSE(request);
419 ASSERT_EQ(2u, verifier_.requests());
420 ASSERT_EQ(1u, verifier_.cache_hits());
422 // Another Verify() for the same certificate but with a different list of
423 // trust anchors will not reuse the cache.
424 EXPECT_CALL(trust_provider, GetAdditionalTrustAnchors())
425 .WillOnce(ReturnRef(cert_list));
426 error = verifier_.Verify(test_cert.get(), "www.example.com", std::string(), 0,
427 NULL, &verify_result, callback.callback(), &request,
428 BoundNetLog());
429 Mock::VerifyAndClearExpectations(&trust_provider);
430 ASSERT_EQ(ERR_IO_PENDING, error);
431 EXPECT_TRUE(request);
432 error = callback.WaitForResult();
433 EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
434 ASSERT_EQ(3u, verifier_.requests());
435 ASSERT_EQ(1u, verifier_.cache_hits());
438 // Tests de-duplication of requests.
439 // Starts up 5 requests, of which 3 are unique.
440 TEST_F(MultiThreadedCertVerifierTest, MultipleInflightJoin) {
441 base::FilePath certs_dir = GetTestCertsDirectory();
442 scoped_refptr<X509Certificate> test_cert(
443 ImportCertFromFile(certs_dir, "ok_cert.pem"));
444 ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
446 int error;
447 CertVerifyResult verify_result1;
448 TestCompletionCallback callback1;
449 scoped_ptr<CertVerifier::Request> request1;
450 CertVerifyResult verify_result2;
451 TestCompletionCallback callback2;
452 scoped_ptr<CertVerifier::Request> request2;
453 CertVerifyResult verify_result3;
454 TestCompletionCallback callback3;
455 scoped_ptr<CertVerifier::Request> request3;
456 CertVerifyResult verify_result4;
457 TestCompletionCallback callback4;
458 scoped_ptr<CertVerifier::Request> request4;
459 CertVerifyResult verify_result5;
460 TestCompletionCallback callback5;
461 scoped_ptr<CertVerifier::Request> request5;
463 const char domain1[] = "www.example1.com";
464 const char domain2[] = "www.exampleB.com";
465 const char domain3[] = "www.example3.com";
467 // Start 3 unique requests.
468 error = verifier_.Verify(test_cert.get(), domain2, std::string(), 0, nullptr,
469 &verify_result1, callback1.callback(), &request1,
470 BoundNetLog());
471 ASSERT_EQ(ERR_IO_PENDING, error);
472 EXPECT_TRUE(request1);
474 error = verifier_.Verify(test_cert.get(), domain2, std::string(), 0, nullptr,
475 &verify_result2, callback2.callback(), &request2,
476 BoundNetLog());
477 EXPECT_EQ(ERR_IO_PENDING, error);
478 EXPECT_TRUE(request2);
480 error = verifier_.Verify(test_cert.get(), domain3, std::string(), 0, nullptr,
481 &verify_result3, callback3.callback(), &request3,
482 BoundNetLog());
483 EXPECT_EQ(ERR_IO_PENDING, error);
484 EXPECT_TRUE(request3);
486 // Start duplicate requests (which should join to existing jobs).
487 error = verifier_.Verify(test_cert.get(), domain1, std::string(), 0, nullptr,
488 &verify_result4, callback4.callback(), &request4,
489 BoundNetLog());
490 EXPECT_EQ(ERR_IO_PENDING, error);
491 EXPECT_TRUE(request4);
493 error = verifier_.Verify(test_cert.get(), domain2, std::string(), 0, nullptr,
494 &verify_result5, callback5.callback(), &request5,
495 BoundNetLog());
496 EXPECT_EQ(ERR_IO_PENDING, error);
497 EXPECT_TRUE(request5);
499 error = callback1.WaitForResult();
500 EXPECT_TRUE(IsCertificateError(error));
501 error = callback2.WaitForResult();
502 ASSERT_TRUE(IsCertificateError(error));
503 error = callback4.WaitForResult();
504 ASSERT_TRUE(IsCertificateError(error));
506 // Let the other requests automatically cancel.
507 ASSERT_EQ(5u, verifier_.requests());
508 ASSERT_EQ(0u, verifier_.cache_hits());
509 ASSERT_EQ(2u, verifier_.inflight_joins());
512 } // namespace net