Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / net / cert / multi_threaded_cert_verifier_unittest.cc
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/cert/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/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"
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.get());
83
84   int error;
85   CertVerifyResult verify_result;
86   TestCompletionCallback callback;
87   CertVerifier::RequestHandle request_handle;
88
89   error = verifier_.Verify(test_cert.get(),
90                            "www.example.com",
91                            0,
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());
105
106   error = verifier_.Verify(test_cert.get(),
107                            "www.example.com",
108                            0,
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());
122 }
123
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();
129
130   scoped_refptr<X509Certificate> server_cert =
131       ImportCertFromFile(certs_dir, "salesforce_com_test.pem");
132   ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert.get());
133
134   scoped_refptr<X509Certificate> intermediate_cert1 =
135       ImportCertFromFile(certs_dir, "verisign_intermediate_ca_2011.pem");
136   ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert1.get());
137
138   scoped_refptr<X509Certificate> intermediate_cert2 =
139       ImportCertFromFile(certs_dir, "verisign_intermediate_ca_2016.pem");
140   ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert2.get());
141
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);
147
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);
153
154   int error;
155   CertVerifyResult verify_result;
156   TestCompletionCallback callback;
157   CertVerifier::RequestHandle request_handle;
158
159   error = verifier_.Verify(cert_chain1.get(),
160                            "www.example.com",
161                            0,
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());
175
176   error = verifier_.Verify(cert_chain2.get(),
177                            "www.example.com",
178                            0,
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());
192 }
193
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.get());
200
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;
208
209   error = verifier_.Verify(test_cert.get(),
210                            "www.example.com",
211                            0,
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",
221                            0,
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());
236 }
237
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.get());
244
245   int error;
246   CertVerifyResult verify_result;
247   CertVerifier::RequestHandle request_handle;
248
249   error = verifier_.Verify(test_cert.get(),
250                            "www.example.com",
251                            0,
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);
260
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",
268                              0,
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();
278   }
279 }
280
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.get());
293
294   int error;
295   CertVerifyResult verify_result;
296   TestCompletionCallback callback;
297   CertVerifier::RequestHandle request_handle;
298
299   error = verifier_.Verify(test_cert.get(),
300                            "www.example.com",
301                            0,
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.
311 }
312
313 TEST_F(MultiThreadedCertVerifierTest, RequestParamsComparators) {
314   SHA1HashValue a_key;
315   memset(a_key.data, 'a', sizeof(a_key.data));
316
317   SHA1HashValue z_key;
318   memset(z_key.data, 'z', sizeof(z_key.data));
319
320   const CertificateList empty_list;
321   CertificateList test_list;
322   test_list.push_back(
323       ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
324
325   struct {
326     // Keys to test
327     MultiThreadedCertVerifier::RequestParams key1;
328     MultiThreadedCertVerifier::RequestParams key2;
329
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),
341       0,
342     },
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),
349       -1,
350     },
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),
357       1,
358     },
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),
367       -1,
368     },
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),
376       1,
377     },
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),
383       -1,
384     },
385   };
386   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
387     SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
388
389     const MultiThreadedCertVerifier::RequestParams& key1 = tests[i].key1;
390     const MultiThreadedCertVerifier::RequestParams& key2 = tests[i].key2;
391
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";
407     }
408   }
409 }
410
411 TEST_F(MultiThreadedCertVerifierTest, CertTrustAnchorProvider) {
412   MockCertTrustAnchorProvider trust_provider;
413   verifier_.SetCertTrustAnchorProvider(&trust_provider);
414
415   scoped_refptr<X509Certificate> test_cert(
416       ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
417   ASSERT_TRUE(test_cert.get());
418
419   const CertificateList empty_cert_list;
420   CertificateList cert_list;
421   cert_list.push_back(test_cert);
422
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",
433                            0,
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());
446
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",
452                            0,
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());
463
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",
470                            0,
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());
483 }
484
485 }  // namespace net