Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(27)

Side by Side Diff: net/base/multi_threaded_cert_verifier_unittest.cc

Issue 13006020: net: extract net/cert out of net/base (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/base/multi_threaded_cert_verifier.cc ('k') | net/base/nss_cert_database.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "net/base/multi_threaded_cert_verifier.h"
6
7 #include "base/bind.h"
8 #include "base/files/file_path.h"
9 #include "base/format_macros.h"
10 #include "base/stringprintf.h"
11 #include "net/base/cert_test_util.h"
12 #include "net/base/cert_trust_anchor_provider.h"
13 #include "net/base/cert_verify_proc.h"
14 #include "net/base/cert_verify_result.h"
15 #include "net/base/net_errors.h"
16 #include "net/base/net_log.h"
17 #include "net/base/test_completion_callback.h"
18 #include "net/base/test_data_directory.h"
19 #include "net/base/x509_certificate.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 using testing::Mock;
24 using testing::ReturnRef;
25
26 namespace net {
27
28 namespace {
29
30 void FailTest(int /* result */) {
31 FAIL();
32 }
33
34 class MockCertVerifyProc : public CertVerifyProc {
35 public:
36 MockCertVerifyProc() {}
37
38 private:
39 virtual ~MockCertVerifyProc() {}
40
41 // CertVerifyProc implementation
42 virtual bool SupportsAdditionalTrustAnchors() const OVERRIDE {
43 return false;
44 }
45
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;
56 }
57 };
58
59 class MockCertTrustAnchorProvider : public CertTrustAnchorProvider {
60 public:
61 MockCertTrustAnchorProvider() {}
62 virtual ~MockCertTrustAnchorProvider() {}
63
64 MOCK_METHOD0(GetAdditionalTrustAnchors, const CertificateList&());
65 };
66
67 } // namespace
68
69 class MultiThreadedCertVerifierTest : public ::testing::Test {
70 public:
71 MultiThreadedCertVerifierTest() : verifier_(new MockCertVerifyProc()) {}
72 virtual ~MultiThreadedCertVerifierTest() {}
73
74 protected:
75 MultiThreadedCertVerifier verifier_;
76 };
77
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);
83
84 int error;
85 CertVerifyResult verify_result;
86 TestCompletionCallback callback;
87 CertVerifier::RequestHandle request_handle;
88
89 error = verifier_.Verify(test_cert, "www.example.com", 0, NULL,
90 &verify_result, callback.callback(),
91 &request_handle, BoundNetLog());
92 ASSERT_EQ(ERR_IO_PENDING, error);
93 ASSERT_TRUE(request_handle != NULL);
94 error = callback.WaitForResult();
95 ASSERT_TRUE(IsCertificateError(error));
96 ASSERT_EQ(1u, verifier_.requests());
97 ASSERT_EQ(0u, verifier_.cache_hits());
98 ASSERT_EQ(0u, verifier_.inflight_joins());
99 ASSERT_EQ(1u, verifier_.GetCacheSize());
100
101 error = verifier_.Verify(test_cert, "www.example.com", 0, NULL,
102 &verify_result, callback.callback(),
103 &request_handle, BoundNetLog());
104 // Synchronous completion.
105 ASSERT_NE(ERR_IO_PENDING, error);
106 ASSERT_TRUE(IsCertificateError(error));
107 ASSERT_TRUE(request_handle == NULL);
108 ASSERT_EQ(2u, verifier_.requests());
109 ASSERT_EQ(1u, verifier_.cache_hits());
110 ASSERT_EQ(0u, verifier_.inflight_joins());
111 ASSERT_EQ(1u, verifier_.GetCacheSize());
112 }
113
114 // Tests the same server certificate with different intermediate CA
115 // certificates. These should be treated as different certificate chains even
116 // though the two X509Certificate objects contain the same server certificate.
117 TEST_F(MultiThreadedCertVerifierTest, DifferentCACerts) {
118 base::FilePath certs_dir = GetTestCertsDirectory();
119
120 scoped_refptr<X509Certificate> server_cert =
121 ImportCertFromFile(certs_dir, "salesforce_com_test.pem");
122 ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert);
123
124 scoped_refptr<X509Certificate> intermediate_cert1 =
125 ImportCertFromFile(certs_dir, "verisign_intermediate_ca_2011.pem");
126 ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert1);
127
128 scoped_refptr<X509Certificate> intermediate_cert2 =
129 ImportCertFromFile(certs_dir, "verisign_intermediate_ca_2016.pem");
130 ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert2);
131
132 X509Certificate::OSCertHandles intermediates;
133 intermediates.push_back(intermediate_cert1->os_cert_handle());
134 scoped_refptr<X509Certificate> cert_chain1 =
135 X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
136 intermediates);
137
138 intermediates.clear();
139 intermediates.push_back(intermediate_cert2->os_cert_handle());
140 scoped_refptr<X509Certificate> cert_chain2 =
141 X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
142 intermediates);
143
144 int error;
145 CertVerifyResult verify_result;
146 TestCompletionCallback callback;
147 CertVerifier::RequestHandle request_handle;
148
149 error = verifier_.Verify(cert_chain1, "www.example.com", 0, NULL,
150 &verify_result, callback.callback(),
151 &request_handle, BoundNetLog());
152 ASSERT_EQ(ERR_IO_PENDING, error);
153 ASSERT_TRUE(request_handle != NULL);
154 error = callback.WaitForResult();
155 ASSERT_TRUE(IsCertificateError(error));
156 ASSERT_EQ(1u, verifier_.requests());
157 ASSERT_EQ(0u, verifier_.cache_hits());
158 ASSERT_EQ(0u, verifier_.inflight_joins());
159 ASSERT_EQ(1u, verifier_.GetCacheSize());
160
161 error = verifier_.Verify(cert_chain2, "www.example.com", 0, NULL,
162 &verify_result, callback.callback(),
163 &request_handle, BoundNetLog());
164 ASSERT_EQ(ERR_IO_PENDING, error);
165 ASSERT_TRUE(request_handle != NULL);
166 error = callback.WaitForResult();
167 ASSERT_TRUE(IsCertificateError(error));
168 ASSERT_EQ(2u, verifier_.requests());
169 ASSERT_EQ(0u, verifier_.cache_hits());
170 ASSERT_EQ(0u, verifier_.inflight_joins());
171 ASSERT_EQ(2u, verifier_.GetCacheSize());
172 }
173
174 // Tests an inflight join.
175 TEST_F(MultiThreadedCertVerifierTest, InflightJoin) {
176 base::FilePath certs_dir = GetTestCertsDirectory();
177 scoped_refptr<X509Certificate> test_cert(
178 ImportCertFromFile(certs_dir, "ok_cert.pem"));
179 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert);
180
181 int error;
182 CertVerifyResult verify_result;
183 TestCompletionCallback callback;
184 CertVerifier::RequestHandle request_handle;
185 CertVerifyResult verify_result2;
186 TestCompletionCallback callback2;
187 CertVerifier::RequestHandle request_handle2;
188
189 error = verifier_.Verify(test_cert, "www.example.com", 0, NULL,
190 &verify_result, callback.callback(),
191 &request_handle, BoundNetLog());
192 ASSERT_EQ(ERR_IO_PENDING, error);
193 ASSERT_TRUE(request_handle != NULL);
194 error = verifier_.Verify(
195 test_cert, "www.example.com", 0, NULL, &verify_result2,
196 callback2.callback(), &request_handle2, BoundNetLog());
197 ASSERT_EQ(ERR_IO_PENDING, error);
198 ASSERT_TRUE(request_handle2 != NULL);
199 error = callback.WaitForResult();
200 ASSERT_TRUE(IsCertificateError(error));
201 error = callback2.WaitForResult();
202 ASSERT_TRUE(IsCertificateError(error));
203 ASSERT_EQ(2u, verifier_.requests());
204 ASSERT_EQ(0u, verifier_.cache_hits());
205 ASSERT_EQ(1u, verifier_.inflight_joins());
206 }
207
208 // Tests that the callback of a canceled request is never made.
209 TEST_F(MultiThreadedCertVerifierTest, CancelRequest) {
210 base::FilePath certs_dir = GetTestCertsDirectory();
211 scoped_refptr<X509Certificate> test_cert(
212 ImportCertFromFile(certs_dir, "ok_cert.pem"));
213 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert);
214
215 int error;
216 CertVerifyResult verify_result;
217 CertVerifier::RequestHandle request_handle;
218
219 error = verifier_.Verify(
220 test_cert, "www.example.com", 0, NULL, &verify_result,
221 base::Bind(&FailTest), &request_handle, BoundNetLog());
222 ASSERT_EQ(ERR_IO_PENDING, error);
223 ASSERT_TRUE(request_handle != NULL);
224 verifier_.CancelRequest(request_handle);
225
226 // Issue a few more requests to the worker pool and wait for their
227 // completion, so that the task of the canceled request (which runs on a
228 // worker thread) is likely to complete by the end of this test.
229 TestCompletionCallback callback;
230 for (int i = 0; i < 5; ++i) {
231 error = verifier_.Verify(
232 test_cert, "www2.example.com", 0, NULL, &verify_result,
233 callback.callback(), &request_handle, BoundNetLog());
234 ASSERT_EQ(ERR_IO_PENDING, error);
235 ASSERT_TRUE(request_handle != NULL);
236 error = callback.WaitForResult();
237 verifier_.ClearCache();
238 }
239 }
240
241 // Tests that a canceled request is not leaked.
242 TEST_F(MultiThreadedCertVerifierTest, CancelRequestThenQuit) {
243 base::FilePath certs_dir = GetTestCertsDirectory();
244 scoped_refptr<X509Certificate> test_cert(
245 ImportCertFromFile(certs_dir, "ok_cert.pem"));
246 ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert);
247
248 int error;
249 CertVerifyResult verify_result;
250 TestCompletionCallback callback;
251 CertVerifier::RequestHandle request_handle;
252
253 error = verifier_.Verify(test_cert, "www.example.com", 0, NULL,
254 &verify_result, callback.callback(),
255 &request_handle, BoundNetLog());
256 ASSERT_EQ(ERR_IO_PENDING, error);
257 ASSERT_TRUE(request_handle != NULL);
258 verifier_.CancelRequest(request_handle);
259 // Destroy |verifier| by going out of scope.
260 }
261
262 TEST_F(MultiThreadedCertVerifierTest, RequestParamsComparators) {
263 SHA1HashValue a_key;
264 memset(a_key.data, 'a', sizeof(a_key.data));
265
266 SHA1HashValue z_key;
267 memset(z_key.data, 'z', sizeof(z_key.data));
268
269 const CertificateList empty_list;
270 CertificateList test_list;
271 test_list.push_back(
272 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
273
274 struct {
275 // Keys to test
276 MultiThreadedCertVerifier::RequestParams key1;
277 MultiThreadedCertVerifier::RequestParams key2;
278
279 // Expectation:
280 // -1 means key1 is less than key2
281 // 0 means key1 equals key2
282 // 1 means key1 is greater than key2
283 int expected_result;
284 } tests[] = {
285 { // Test for basic equivalence.
286 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
287 0, test_list),
288 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
289 0, test_list),
290 0,
291 },
292 { // Test that different certificates but with the same CA and for
293 // the same host are different validation keys.
294 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
295 0, test_list),
296 MultiThreadedCertVerifier::RequestParams(z_key, a_key, "www.example.test",
297 0, test_list),
298 -1,
299 },
300 { // Test that the same EE certificate for the same host, but with
301 // different chains are different validation keys.
302 MultiThreadedCertVerifier::RequestParams(a_key, z_key, "www.example.test",
303 0, test_list),
304 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
305 0, test_list),
306 1,
307 },
308 { // The same certificate, with the same chain, but for different
309 // hosts are different validation keys.
310 MultiThreadedCertVerifier::RequestParams(a_key, a_key,
311 "www1.example.test", 0,
312 test_list),
313 MultiThreadedCertVerifier::RequestParams(a_key, a_key,
314 "www2.example.test", 0,
315 test_list),
316 -1,
317 },
318 { // The same certificate, chain, and host, but with different flags
319 // are different validation keys.
320 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
321 CertVerifier::VERIFY_EV_CERT,
322 test_list),
323 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
324 0, test_list),
325 1,
326 },
327 { // Different additional_trust_anchors.
328 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
329 0, empty_list),
330 MultiThreadedCertVerifier::RequestParams(a_key, a_key, "www.example.test",
331 0, test_list),
332 -1,
333 },
334 };
335 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
336 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
337
338 const MultiThreadedCertVerifier::RequestParams& key1 = tests[i].key1;
339 const MultiThreadedCertVerifier::RequestParams& key2 = tests[i].key2;
340
341 switch (tests[i].expected_result) {
342 case -1:
343 EXPECT_TRUE(key1 < key2);
344 EXPECT_FALSE(key2 < key1);
345 break;
346 case 0:
347 EXPECT_FALSE(key1 < key2);
348 EXPECT_FALSE(key2 < key1);
349 break;
350 case 1:
351 EXPECT_FALSE(key1 < key2);
352 EXPECT_TRUE(key2 < key1);
353 break;
354 default:
355 FAIL() << "Invalid expectation. Can be only -1, 0, 1";
356 }
357 }
358 }
359
360 TEST_F(MultiThreadedCertVerifierTest, CertTrustAnchorProvider) {
361 MockCertTrustAnchorProvider trust_provider;
362 verifier_.SetCertTrustAnchorProvider(&trust_provider);
363
364 scoped_refptr<X509Certificate> test_cert(
365 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
366 ASSERT_TRUE(test_cert);
367
368 const CertificateList empty_cert_list;
369 CertificateList cert_list;
370 cert_list.push_back(test_cert);
371
372 // Check that Verify() asks the |trust_provider| for the current list of
373 // additional trust anchors.
374 int error;
375 CertVerifyResult verify_result;
376 TestCompletionCallback callback;
377 CertVerifier::RequestHandle request_handle;
378 EXPECT_CALL(trust_provider, GetAdditionalTrustAnchors())
379 .WillOnce(ReturnRef(empty_cert_list));
380 error = verifier_.Verify(test_cert, "www.example.com", 0, NULL,
381 &verify_result, callback.callback(),
382 &request_handle, BoundNetLog());
383 Mock::VerifyAndClearExpectations(&trust_provider);
384 ASSERT_EQ(ERR_IO_PENDING, error);
385 ASSERT_TRUE(request_handle);
386 error = callback.WaitForResult();
387 EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
388 ASSERT_EQ(1u, verifier_.requests());
389 ASSERT_EQ(0u, verifier_.cache_hits());
390
391 // The next Verify() uses the cached result.
392 EXPECT_CALL(trust_provider, GetAdditionalTrustAnchors())
393 .WillOnce(ReturnRef(empty_cert_list));
394 error = verifier_.Verify(test_cert, "www.example.com", 0, NULL,
395 &verify_result, callback.callback(),
396 &request_handle, BoundNetLog());
397 Mock::VerifyAndClearExpectations(&trust_provider);
398 EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
399 EXPECT_FALSE(request_handle);
400 ASSERT_EQ(2u, verifier_.requests());
401 ASSERT_EQ(1u, verifier_.cache_hits());
402
403 // Another Verify() for the same certificate but with a different list of
404 // trust anchors will not reuse the cache.
405 EXPECT_CALL(trust_provider, GetAdditionalTrustAnchors())
406 .WillOnce(ReturnRef(cert_list));
407 error = verifier_.Verify(test_cert, "www.example.com", 0, NULL,
408 &verify_result, callback.callback(),
409 &request_handle, BoundNetLog());
410 Mock::VerifyAndClearExpectations(&trust_provider);
411 ASSERT_EQ(ERR_IO_PENDING, error);
412 ASSERT_TRUE(request_handle != NULL);
413 error = callback.WaitForResult();
414 EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
415 ASSERT_EQ(3u, verifier_.requests());
416 ASSERT_EQ(1u, verifier_.cache_hits());
417 }
418
419 } // namespace net
OLDNEW
« no previous file with comments | « net/base/multi_threaded_cert_verifier.cc ('k') | net/base/nss_cert_database.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698