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