We started redesigning GpuMemoryBuffer interface to handle multiple buffers [0].
[chromium-blink-merge.git] / net / cert / multi_threaded_cert_verifier_unittest.cc
blobc7c143f3902b463b135264ed8c3c41a6560190a9
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; }
45 int VerifyInternal(X509Certificate* cert,
46 const std::string& hostname,
47 int flags,
48 CRLSet* crl_set,
49 const CertificateList& additional_trust_anchors,
50 CertVerifyResult* verify_result) override {
51 verify_result->Reset();
52 verify_result->verified_cert = cert;
53 verify_result->cert_status = CERT_STATUS_COMMON_NAME_INVALID;
54 return ERR_CERT_COMMON_NAME_INVALID;
58 class MockCertTrustAnchorProvider : public CertTrustAnchorProvider {
59 public:
60 MockCertTrustAnchorProvider() {}
61 virtual ~MockCertTrustAnchorProvider() {}
63 MOCK_METHOD0(GetAdditionalTrustAnchors, const CertificateList&());
66 } // namespace
68 class MultiThreadedCertVerifierTest : public ::testing::Test {
69 public:
70 MultiThreadedCertVerifierTest() : verifier_(new MockCertVerifyProc()) {}
71 ~MultiThreadedCertVerifierTest() override {}
73 protected:
74 MultiThreadedCertVerifier verifier_;
77 TEST_F(MultiThreadedCertVerifierTest, CacheHit) {
78 base::FilePath certs_dir = GetTestCertsDirectory();
79 scoped_refptr<X509Certificate> test_cert(
80 ImportCertFromFile(certs_dir, "ok_cert.pem"));
81 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert.get());
83 int error;
84 CertVerifyResult verify_result;
85 TestCompletionCallback callback;
86 CertVerifier::RequestHandle request_handle;
88 error = verifier_.Verify(test_cert.get(),
89 "www.example.com",
91 NULL,
92 &verify_result,
93 callback.callback(),
94 &request_handle,
95 BoundNetLog());
96 ASSERT_EQ(ERR_IO_PENDING, error);
97 EXPECT_TRUE(request_handle);
98 error = callback.WaitForResult();
99 ASSERT_TRUE(IsCertificateError(error));
100 ASSERT_EQ(1u, verifier_.requests());
101 ASSERT_EQ(0u, verifier_.cache_hits());
102 ASSERT_EQ(0u, verifier_.inflight_joins());
103 ASSERT_EQ(1u, verifier_.GetCacheSize());
105 error = verifier_.Verify(test_cert.get(),
106 "www.example.com",
108 NULL,
109 &verify_result,
110 callback.callback(),
111 &request_handle,
112 BoundNetLog());
113 // Synchronous completion.
114 ASSERT_NE(ERR_IO_PENDING, error);
115 ASSERT_TRUE(IsCertificateError(error));
116 ASSERT_TRUE(request_handle == NULL);
117 ASSERT_EQ(2u, verifier_.requests());
118 ASSERT_EQ(1u, verifier_.cache_hits());
119 ASSERT_EQ(0u, verifier_.inflight_joins());
120 ASSERT_EQ(1u, verifier_.GetCacheSize());
123 // Tests the same server certificate with different intermediate CA
124 // certificates. These should be treated as different certificate chains even
125 // though the two X509Certificate objects contain the same server certificate.
126 TEST_F(MultiThreadedCertVerifierTest, DifferentCACerts) {
127 base::FilePath certs_dir = GetTestCertsDirectory();
129 scoped_refptr<X509Certificate> server_cert =
130 ImportCertFromFile(certs_dir, "salesforce_com_test.pem");
131 ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert.get());
133 scoped_refptr<X509Certificate> intermediate_cert1 =
134 ImportCertFromFile(certs_dir, "verisign_intermediate_ca_2011.pem");
135 ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert1.get());
137 scoped_refptr<X509Certificate> intermediate_cert2 =
138 ImportCertFromFile(certs_dir, "verisign_intermediate_ca_2016.pem");
139 ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert2.get());
141 X509Certificate::OSCertHandles intermediates;
142 intermediates.push_back(intermediate_cert1->os_cert_handle());
143 scoped_refptr<X509Certificate> cert_chain1 =
144 X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
145 intermediates);
147 intermediates.clear();
148 intermediates.push_back(intermediate_cert2->os_cert_handle());
149 scoped_refptr<X509Certificate> cert_chain2 =
150 X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
151 intermediates);
153 int error;
154 CertVerifyResult verify_result;
155 TestCompletionCallback callback;
156 CertVerifier::RequestHandle request_handle;
158 error = verifier_.Verify(cert_chain1.get(),
159 "www.example.com",
161 NULL,
162 &verify_result,
163 callback.callback(),
164 &request_handle,
165 BoundNetLog());
166 ASSERT_EQ(ERR_IO_PENDING, error);
167 EXPECT_TRUE(request_handle);
168 error = callback.WaitForResult();
169 ASSERT_TRUE(IsCertificateError(error));
170 ASSERT_EQ(1u, verifier_.requests());
171 ASSERT_EQ(0u, verifier_.cache_hits());
172 ASSERT_EQ(0u, verifier_.inflight_joins());
173 ASSERT_EQ(1u, verifier_.GetCacheSize());
175 error = verifier_.Verify(cert_chain2.get(),
176 "www.example.com",
178 NULL,
179 &verify_result,
180 callback.callback(),
181 &request_handle,
182 BoundNetLog());
183 ASSERT_EQ(ERR_IO_PENDING, error);
184 EXPECT_TRUE(request_handle);
185 error = callback.WaitForResult();
186 ASSERT_TRUE(IsCertificateError(error));
187 ASSERT_EQ(2u, verifier_.requests());
188 ASSERT_EQ(0u, verifier_.cache_hits());
189 ASSERT_EQ(0u, verifier_.inflight_joins());
190 ASSERT_EQ(2u, verifier_.GetCacheSize());
193 // Tests an inflight join.
194 TEST_F(MultiThreadedCertVerifierTest, InflightJoin) {
195 base::FilePath certs_dir = GetTestCertsDirectory();
196 scoped_refptr<X509Certificate> test_cert(
197 ImportCertFromFile(certs_dir, "ok_cert.pem"));
198 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert.get());
200 int error;
201 CertVerifyResult verify_result;
202 TestCompletionCallback callback;
203 CertVerifier::RequestHandle request_handle;
204 CertVerifyResult verify_result2;
205 TestCompletionCallback callback2;
206 CertVerifier::RequestHandle request_handle2;
208 error = verifier_.Verify(test_cert.get(),
209 "www.example.com",
211 NULL,
212 &verify_result,
213 callback.callback(),
214 &request_handle,
215 BoundNetLog());
216 ASSERT_EQ(ERR_IO_PENDING, error);
217 EXPECT_TRUE(request_handle);
218 error = verifier_.Verify(test_cert.get(),
219 "www.example.com",
221 NULL,
222 &verify_result2,
223 callback2.callback(),
224 &request_handle2,
225 BoundNetLog());
226 EXPECT_EQ(ERR_IO_PENDING, error);
227 EXPECT_TRUE(request_handle2 != NULL);
228 error = callback.WaitForResult();
229 EXPECT_TRUE(IsCertificateError(error));
230 error = callback2.WaitForResult();
231 ASSERT_TRUE(IsCertificateError(error));
232 ASSERT_EQ(2u, verifier_.requests());
233 ASSERT_EQ(0u, verifier_.cache_hits());
234 ASSERT_EQ(1u, verifier_.inflight_joins());
237 // Tests that the callback of a canceled request is never made.
238 TEST_F(MultiThreadedCertVerifierTest, CancelRequest) {
239 base::FilePath certs_dir = GetTestCertsDirectory();
240 scoped_refptr<X509Certificate> test_cert(
241 ImportCertFromFile(certs_dir, "ok_cert.pem"));
242 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert.get());
244 int error;
245 CertVerifyResult verify_result;
246 CertVerifier::RequestHandle request_handle;
248 error = verifier_.Verify(test_cert.get(),
249 "www.example.com",
251 NULL,
252 &verify_result,
253 base::Bind(&FailTest),
254 &request_handle,
255 BoundNetLog());
256 ASSERT_EQ(ERR_IO_PENDING, error);
257 ASSERT_TRUE(request_handle != NULL);
258 verifier_.CancelRequest(request_handle);
260 // Issue a few more requests to the worker pool and wait for their
261 // completion, so that the task of the canceled request (which runs on a
262 // worker thread) is likely to complete by the end of this test.
263 TestCompletionCallback callback;
264 for (int i = 0; i < 5; ++i) {
265 error = verifier_.Verify(test_cert.get(),
266 "www2.example.com",
268 NULL,
269 &verify_result,
270 callback.callback(),
271 &request_handle,
272 BoundNetLog());
273 ASSERT_EQ(ERR_IO_PENDING, error);
274 EXPECT_TRUE(request_handle);
275 error = callback.WaitForResult();
276 verifier_.ClearCache();
280 // Tests that a canceled request is not leaked.
281 TEST_F(MultiThreadedCertVerifierTest, CancelRequestThenQuit) {
282 base::FilePath certs_dir = GetTestCertsDirectory();
283 scoped_refptr<X509Certificate> test_cert(
284 ImportCertFromFile(certs_dir, "ok_cert.pem"));
285 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert.get());
287 int error;
288 CertVerifyResult verify_result;
289 TestCompletionCallback callback;
290 CertVerifier::RequestHandle request_handle;
293 // Because shutdown intentionally doesn't join worker threads, a
294 // CertVerifyWorker may be leaked if the main thread shuts down before the
295 // worker thread.
296 ANNOTATE_SCOPED_MEMORY_LEAK;
297 error = verifier_.Verify(test_cert.get(), "www.example.com", 0, NULL,
298 &verify_result, callback.callback(),
299 &request_handle, BoundNetLog());
301 ASSERT_EQ(ERR_IO_PENDING, error);
302 EXPECT_TRUE(request_handle);
303 verifier_.CancelRequest(request_handle);
304 // Destroy |verifier| by going out of scope.
307 TEST_F(MultiThreadedCertVerifierTest, RequestParamsComparators) {
308 SHA1HashValue a_key;
309 memset(a_key.data, 'a', sizeof(a_key.data));
311 SHA1HashValue z_key;
312 memset(z_key.data, 'z', sizeof(z_key.data));
314 const CertificateList empty_list;
315 CertificateList test_list;
316 test_list.push_back(
317 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
319 struct {
320 // Keys to test
321 MultiThreadedCertVerifier::RequestParams key1;
322 MultiThreadedCertVerifier::RequestParams key2;
324 // Expectation:
325 // -1 means key1 is less than key2
326 // 0 means key1 equals key2
327 // 1 means key1 is greater than key2
328 int expected_result;
329 } tests[] = {
330 { // Test for basic equivalence.
331 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
332 0, test_list),
333 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
334 0, test_list),
337 { // Test that different certificates but with the same CA and for
338 // the same host are different validation keys.
339 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
340 0, test_list),
341 MultiThreadedCertVerifier::RequestParams(z_key, a_key, "www.example.test",
342 0, test_list),
345 { // Test that the same EE certificate for the same host, but with
346 // different chains are different validation keys.
347 MultiThreadedCertVerifier::RequestParams(a_key, z_key, "www.example.test",
348 0, test_list),
349 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
350 0, test_list),
353 { // The same certificate, with the same chain, but for different
354 // hosts are different validation keys.
355 MultiThreadedCertVerifier::RequestParams(a_key, a_key,
356 "www1.example.test", 0,
357 test_list),
358 MultiThreadedCertVerifier::RequestParams(a_key, a_key,
359 "www2.example.test", 0,
360 test_list),
363 { // The same certificate, chain, and host, but with different flags
364 // are different validation keys.
365 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
366 CertVerifier::VERIFY_EV_CERT,
367 test_list),
368 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
369 0, test_list),
372 { // Different additional_trust_anchors.
373 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
374 0, empty_list),
375 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
376 0, test_list),
380 for (size_t i = 0; i < arraysize(tests); ++i) {
381 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
383 const MultiThreadedCertVerifier::RequestParams& key1 = tests[i].key1;
384 const MultiThreadedCertVerifier::RequestParams& key2 = tests[i].key2;
386 switch (tests[i].expected_result) {
387 case -1:
388 EXPECT_TRUE(key1 < key2);
389 EXPECT_FALSE(key2 < key1);
390 break;
391 case 0:
392 EXPECT_FALSE(key1 < key2);
393 EXPECT_FALSE(key2 < key1);
394 break;
395 case 1:
396 EXPECT_FALSE(key1 < key2);
397 EXPECT_TRUE(key2 < key1);
398 break;
399 default:
400 FAIL() << "Invalid expectation. Can be only -1, 0, 1";
405 TEST_F(MultiThreadedCertVerifierTest, CertTrustAnchorProvider) {
406 MockCertTrustAnchorProvider trust_provider;
407 verifier_.SetCertTrustAnchorProvider(&trust_provider);
409 scoped_refptr<X509Certificate> test_cert(
410 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
411 ASSERT_TRUE(test_cert.get());
413 const CertificateList empty_cert_list;
414 CertificateList cert_list;
415 cert_list.push_back(test_cert);
417 // Check that Verify() asks the |trust_provider| for the current list of
418 // additional trust anchors.
419 int error;
420 CertVerifyResult verify_result;
421 TestCompletionCallback callback;
422 CertVerifier::RequestHandle request_handle;
423 EXPECT_CALL(trust_provider, GetAdditionalTrustAnchors())
424 .WillOnce(ReturnRef(empty_cert_list));
425 error = verifier_.Verify(test_cert.get(),
426 "www.example.com",
428 NULL,
429 &verify_result,
430 callback.callback(),
431 &request_handle,
432 BoundNetLog());
433 Mock::VerifyAndClearExpectations(&trust_provider);
434 ASSERT_EQ(ERR_IO_PENDING, error);
435 EXPECT_TRUE(request_handle);
436 error = callback.WaitForResult();
437 EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
438 ASSERT_EQ(1u, verifier_.requests());
439 ASSERT_EQ(0u, verifier_.cache_hits());
441 // The next Verify() uses the cached result.
442 EXPECT_CALL(trust_provider, GetAdditionalTrustAnchors())
443 .WillOnce(ReturnRef(empty_cert_list));
444 error = verifier_.Verify(test_cert.get(),
445 "www.example.com",
447 NULL,
448 &verify_result,
449 callback.callback(),
450 &request_handle,
451 BoundNetLog());
452 Mock::VerifyAndClearExpectations(&trust_provider);
453 EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
454 EXPECT_FALSE(request_handle);
455 ASSERT_EQ(2u, verifier_.requests());
456 ASSERT_EQ(1u, verifier_.cache_hits());
458 // Another Verify() for the same certificate but with a different list of
459 // trust anchors will not reuse the cache.
460 EXPECT_CALL(trust_provider, GetAdditionalTrustAnchors())
461 .WillOnce(ReturnRef(cert_list));
462 error = verifier_.Verify(test_cert.get(),
463 "www.example.com",
465 NULL,
466 &verify_result,
467 callback.callback(),
468 &request_handle,
469 BoundNetLog());
470 Mock::VerifyAndClearExpectations(&trust_provider);
471 ASSERT_EQ(ERR_IO_PENDING, error);
472 EXPECT_TRUE(request_handle);
473 error = callback.WaitForResult();
474 EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
475 ASSERT_EQ(3u, verifier_.requests());
476 ASSERT_EQ(1u, verifier_.cache_hits());
479 } // namespace net