Land Recent QUIC Changes.
[chromium-blink-merge.git] / net / cert / multi_threaded_cert_verifier_unittest.cc
blob3a0c765d2120969e1fb08b7ed808dc0cfe1953ae
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/files/file_path.h"
9 #include "base/format_macros.h"
10 #include "base/strings/stringprintf.h"
11 #include "net/base/net_errors.h"
12 #include "net/base/net_log.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/test/cert_test_util.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 using testing::Mock;
24 using testing::ReturnRef;
26 namespace net {
28 namespace {
30 void FailTest(int /* result */) {
31 FAIL();
34 class MockCertVerifyProc : public CertVerifyProc {
35 public:
36 MockCertVerifyProc() {}
38 private:
39 virtual ~MockCertVerifyProc() {}
41 // CertVerifyProc implementation
42 virtual bool SupportsAdditionalTrustAnchors() const OVERRIDE {
43 return false;
46 virtual int VerifyInternal(X509Certificate* cert,
47 const std::string& hostname,
48 int flags,
49 CRLSet* crl_set,
50 const CertificateList& additional_trust_anchors,
51 CertVerifyResult* verify_result) OVERRIDE {
52 verify_result->Reset();
53 verify_result->verified_cert = cert;
54 verify_result->cert_status = CERT_STATUS_COMMON_NAME_INVALID;
55 return ERR_CERT_COMMON_NAME_INVALID;
59 class MockCertTrustAnchorProvider : public CertTrustAnchorProvider {
60 public:
61 MockCertTrustAnchorProvider() {}
62 virtual ~MockCertTrustAnchorProvider() {}
64 MOCK_METHOD0(GetAdditionalTrustAnchors, const CertificateList&());
67 } // namespace
69 class MultiThreadedCertVerifierTest : public ::testing::Test {
70 public:
71 MultiThreadedCertVerifierTest() : verifier_(new MockCertVerifyProc()) {}
72 virtual ~MultiThreadedCertVerifierTest() {}
74 protected:
75 MultiThreadedCertVerifier verifier_;
78 TEST_F(MultiThreadedCertVerifierTest, CacheHit) {
79 base::FilePath certs_dir = GetTestCertsDirectory();
80 scoped_refptr<X509Certificate> test_cert(
81 ImportCertFromFile(certs_dir, "ok_cert.pem"));
82 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert);
84 int error;
85 CertVerifyResult verify_result;
86 TestCompletionCallback callback;
87 CertVerifier::RequestHandle request_handle;
89 error = verifier_.Verify(test_cert.get(),
90 "www.example.com",
92 NULL,
93 &verify_result,
94 callback.callback(),
95 &request_handle,
96 BoundNetLog());
97 ASSERT_EQ(ERR_IO_PENDING, error);
98 EXPECT_TRUE(request_handle);
99 error = callback.WaitForResult();
100 ASSERT_TRUE(IsCertificateError(error));
101 ASSERT_EQ(1u, verifier_.requests());
102 ASSERT_EQ(0u, verifier_.cache_hits());
103 ASSERT_EQ(0u, verifier_.inflight_joins());
104 ASSERT_EQ(1u, verifier_.GetCacheSize());
106 error = verifier_.Verify(test_cert.get(),
107 "www.example.com",
109 NULL,
110 &verify_result,
111 callback.callback(),
112 &request_handle,
113 BoundNetLog());
114 // Synchronous completion.
115 ASSERT_NE(ERR_IO_PENDING, error);
116 ASSERT_TRUE(IsCertificateError(error));
117 ASSERT_TRUE(request_handle == NULL);
118 ASSERT_EQ(2u, verifier_.requests());
119 ASSERT_EQ(1u, verifier_.cache_hits());
120 ASSERT_EQ(0u, verifier_.inflight_joins());
121 ASSERT_EQ(1u, verifier_.GetCacheSize());
124 // Tests the same server certificate with different intermediate CA
125 // certificates. These should be treated as different certificate chains even
126 // though the two X509Certificate objects contain the same server certificate.
127 TEST_F(MultiThreadedCertVerifierTest, DifferentCACerts) {
128 base::FilePath certs_dir = GetTestCertsDirectory();
130 scoped_refptr<X509Certificate> server_cert =
131 ImportCertFromFile(certs_dir, "salesforce_com_test.pem");
132 ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert);
134 scoped_refptr<X509Certificate> intermediate_cert1 =
135 ImportCertFromFile(certs_dir, "verisign_intermediate_ca_2011.pem");
136 ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert1);
138 scoped_refptr<X509Certificate> intermediate_cert2 =
139 ImportCertFromFile(certs_dir, "verisign_intermediate_ca_2016.pem");
140 ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert2);
142 X509Certificate::OSCertHandles intermediates;
143 intermediates.push_back(intermediate_cert1->os_cert_handle());
144 scoped_refptr<X509Certificate> cert_chain1 =
145 X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
146 intermediates);
148 intermediates.clear();
149 intermediates.push_back(intermediate_cert2->os_cert_handle());
150 scoped_refptr<X509Certificate> cert_chain2 =
151 X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
152 intermediates);
154 int error;
155 CertVerifyResult verify_result;
156 TestCompletionCallback callback;
157 CertVerifier::RequestHandle request_handle;
159 error = verifier_.Verify(cert_chain1.get(),
160 "www.example.com",
162 NULL,
163 &verify_result,
164 callback.callback(),
165 &request_handle,
166 BoundNetLog());
167 ASSERT_EQ(ERR_IO_PENDING, error);
168 EXPECT_TRUE(request_handle);
169 error = callback.WaitForResult();
170 ASSERT_TRUE(IsCertificateError(error));
171 ASSERT_EQ(1u, verifier_.requests());
172 ASSERT_EQ(0u, verifier_.cache_hits());
173 ASSERT_EQ(0u, verifier_.inflight_joins());
174 ASSERT_EQ(1u, verifier_.GetCacheSize());
176 error = verifier_.Verify(cert_chain2.get(),
177 "www.example.com",
179 NULL,
180 &verify_result,
181 callback.callback(),
182 &request_handle,
183 BoundNetLog());
184 ASSERT_EQ(ERR_IO_PENDING, error);
185 EXPECT_TRUE(request_handle);
186 error = callback.WaitForResult();
187 ASSERT_TRUE(IsCertificateError(error));
188 ASSERT_EQ(2u, verifier_.requests());
189 ASSERT_EQ(0u, verifier_.cache_hits());
190 ASSERT_EQ(0u, verifier_.inflight_joins());
191 ASSERT_EQ(2u, verifier_.GetCacheSize());
194 // Tests an inflight join.
195 TEST_F(MultiThreadedCertVerifierTest, InflightJoin) {
196 base::FilePath certs_dir = GetTestCertsDirectory();
197 scoped_refptr<X509Certificate> test_cert(
198 ImportCertFromFile(certs_dir, "ok_cert.pem"));
199 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert);
201 int error;
202 CertVerifyResult verify_result;
203 TestCompletionCallback callback;
204 CertVerifier::RequestHandle request_handle;
205 CertVerifyResult verify_result2;
206 TestCompletionCallback callback2;
207 CertVerifier::RequestHandle request_handle2;
209 error = verifier_.Verify(test_cert.get(),
210 "www.example.com",
212 NULL,
213 &verify_result,
214 callback.callback(),
215 &request_handle,
216 BoundNetLog());
217 ASSERT_EQ(ERR_IO_PENDING, error);
218 EXPECT_TRUE(request_handle);
219 error = verifier_.Verify(test_cert.get(),
220 "www.example.com",
222 NULL,
223 &verify_result2,
224 callback2.callback(),
225 &request_handle2,
226 BoundNetLog());
227 EXPECT_EQ(ERR_IO_PENDING, error);
228 EXPECT_TRUE(request_handle2 != NULL);
229 error = callback.WaitForResult();
230 EXPECT_TRUE(IsCertificateError(error));
231 error = callback2.WaitForResult();
232 ASSERT_TRUE(IsCertificateError(error));
233 ASSERT_EQ(2u, verifier_.requests());
234 ASSERT_EQ(0u, verifier_.cache_hits());
235 ASSERT_EQ(1u, verifier_.inflight_joins());
238 // Tests that the callback of a canceled request is never made.
239 TEST_F(MultiThreadedCertVerifierTest, CancelRequest) {
240 base::FilePath certs_dir = GetTestCertsDirectory();
241 scoped_refptr<X509Certificate> test_cert(
242 ImportCertFromFile(certs_dir, "ok_cert.pem"));
243 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert);
245 int error;
246 CertVerifyResult verify_result;
247 CertVerifier::RequestHandle request_handle;
249 error = verifier_.Verify(test_cert.get(),
250 "www.example.com",
252 NULL,
253 &verify_result,
254 base::Bind(&FailTest),
255 &request_handle,
256 BoundNetLog());
257 ASSERT_EQ(ERR_IO_PENDING, error);
258 ASSERT_TRUE(request_handle != NULL);
259 verifier_.CancelRequest(request_handle);
261 // Issue a few more requests to the worker pool and wait for their
262 // completion, so that the task of the canceled request (which runs on a
263 // worker thread) is likely to complete by the end of this test.
264 TestCompletionCallback callback;
265 for (int i = 0; i < 5; ++i) {
266 error = verifier_.Verify(test_cert.get(),
267 "www2.example.com",
269 NULL,
270 &verify_result,
271 callback.callback(),
272 &request_handle,
273 BoundNetLog());
274 ASSERT_EQ(ERR_IO_PENDING, error);
275 EXPECT_TRUE(request_handle);
276 error = callback.WaitForResult();
277 verifier_.ClearCache();
281 // Tests that a canceled request is not leaked.
282 #if !defined(LEAK_SANITIZER)
283 #define MAYBE_CancelRequestThenQuit CancelRequestThenQuit
284 #else
285 // See PR303886. LeakSanitizer flags a leak here.
286 #define MAYBE_CancelRequestThenQuit DISABLED_CancelRequestThenQuit
287 #endif
288 TEST_F(MultiThreadedCertVerifierTest, MAYBE_CancelRequestThenQuit) {
289 base::FilePath certs_dir = GetTestCertsDirectory();
290 scoped_refptr<X509Certificate> test_cert(
291 ImportCertFromFile(certs_dir, "ok_cert.pem"));
292 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert);
294 int error;
295 CertVerifyResult verify_result;
296 TestCompletionCallback callback;
297 CertVerifier::RequestHandle request_handle;
299 error = verifier_.Verify(test_cert.get(),
300 "www.example.com",
302 NULL,
303 &verify_result,
304 callback.callback(),
305 &request_handle,
306 BoundNetLog());
307 ASSERT_EQ(ERR_IO_PENDING, error);
308 EXPECT_TRUE(request_handle);
309 verifier_.CancelRequest(request_handle);
310 // Destroy |verifier| by going out of scope.
313 TEST_F(MultiThreadedCertVerifierTest, RequestParamsComparators) {
314 SHA1HashValue a_key;
315 memset(a_key.data, 'a', sizeof(a_key.data));
317 SHA1HashValue z_key;
318 memset(z_key.data, 'z', sizeof(z_key.data));
320 const CertificateList empty_list;
321 CertificateList test_list;
322 test_list.push_back(
323 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
325 struct {
326 // Keys to test
327 MultiThreadedCertVerifier::RequestParams key1;
328 MultiThreadedCertVerifier::RequestParams key2;
330 // Expectation:
331 // -1 means key1 is less than key2
332 // 0 means key1 equals key2
333 // 1 means key1 is greater than key2
334 int expected_result;
335 } tests[] = {
336 { // Test for basic equivalence.
337 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
338 0, test_list),
339 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
340 0, test_list),
343 { // Test that different certificates but with the same CA and for
344 // the same host are different validation keys.
345 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
346 0, test_list),
347 MultiThreadedCertVerifier::RequestParams(z_key, a_key, "www.example.test",
348 0, test_list),
351 { // Test that the same EE certificate for the same host, but with
352 // different chains are different validation keys.
353 MultiThreadedCertVerifier::RequestParams(a_key, z_key, "www.example.test",
354 0, test_list),
355 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
356 0, test_list),
359 { // The same certificate, with the same chain, but for different
360 // hosts are different validation keys.
361 MultiThreadedCertVerifier::RequestParams(a_key, a_key,
362 "www1.example.test", 0,
363 test_list),
364 MultiThreadedCertVerifier::RequestParams(a_key, a_key,
365 "www2.example.test", 0,
366 test_list),
369 { // The same certificate, chain, and host, but with different flags
370 // are different validation keys.
371 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
372 CertVerifier::VERIFY_EV_CERT,
373 test_list),
374 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
375 0, test_list),
378 { // Different additional_trust_anchors.
379 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
380 0, empty_list),
381 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
382 0, test_list),
386 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
387 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
389 const MultiThreadedCertVerifier::RequestParams& key1 = tests[i].key1;
390 const MultiThreadedCertVerifier::RequestParams& key2 = tests[i].key2;
392 switch (tests[i].expected_result) {
393 case -1:
394 EXPECT_TRUE(key1 < key2);
395 EXPECT_FALSE(key2 < key1);
396 break;
397 case 0:
398 EXPECT_FALSE(key1 < key2);
399 EXPECT_FALSE(key2 < key1);
400 break;
401 case 1:
402 EXPECT_FALSE(key1 < key2);
403 EXPECT_TRUE(key2 < key1);
404 break;
405 default:
406 FAIL() << "Invalid expectation. Can be only -1, 0, 1";
411 TEST_F(MultiThreadedCertVerifierTest, CertTrustAnchorProvider) {
412 MockCertTrustAnchorProvider trust_provider;
413 verifier_.SetCertTrustAnchorProvider(&trust_provider);
415 scoped_refptr<X509Certificate> test_cert(
416 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
417 ASSERT_TRUE(test_cert.get());
419 const CertificateList empty_cert_list;
420 CertificateList cert_list;
421 cert_list.push_back(test_cert);
423 // Check that Verify() asks the |trust_provider| for the current list of
424 // additional trust anchors.
425 int error;
426 CertVerifyResult verify_result;
427 TestCompletionCallback callback;
428 CertVerifier::RequestHandle request_handle;
429 EXPECT_CALL(trust_provider, GetAdditionalTrustAnchors())
430 .WillOnce(ReturnRef(empty_cert_list));
431 error = verifier_.Verify(test_cert.get(),
432 "www.example.com",
434 NULL,
435 &verify_result,
436 callback.callback(),
437 &request_handle,
438 BoundNetLog());
439 Mock::VerifyAndClearExpectations(&trust_provider);
440 ASSERT_EQ(ERR_IO_PENDING, error);
441 EXPECT_TRUE(request_handle);
442 error = callback.WaitForResult();
443 EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
444 ASSERT_EQ(1u, verifier_.requests());
445 ASSERT_EQ(0u, verifier_.cache_hits());
447 // The next Verify() uses the cached result.
448 EXPECT_CALL(trust_provider, GetAdditionalTrustAnchors())
449 .WillOnce(ReturnRef(empty_cert_list));
450 error = verifier_.Verify(test_cert.get(),
451 "www.example.com",
453 NULL,
454 &verify_result,
455 callback.callback(),
456 &request_handle,
457 BoundNetLog());
458 Mock::VerifyAndClearExpectations(&trust_provider);
459 EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
460 EXPECT_FALSE(request_handle);
461 ASSERT_EQ(2u, verifier_.requests());
462 ASSERT_EQ(1u, verifier_.cache_hits());
464 // Another Verify() for the same certificate but with a different list of
465 // trust anchors will not reuse the cache.
466 EXPECT_CALL(trust_provider, GetAdditionalTrustAnchors())
467 .WillOnce(ReturnRef(cert_list));
468 error = verifier_.Verify(test_cert.get(),
469 "www.example.com",
471 NULL,
472 &verify_result,
473 callback.callback(),
474 &request_handle,
475 BoundNetLog());
476 Mock::VerifyAndClearExpectations(&trust_provider);
477 ASSERT_EQ(ERR_IO_PENDING, error);
478 EXPECT_TRUE(request_handle);
479 error = callback.WaitForResult();
480 EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
481 ASSERT_EQ(3u, verifier_.requests());
482 ASSERT_EQ(1u, verifier_.cache_hits());
485 } // namespace net