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
23using testing::Mock;
24using testing::ReturnRef;
25
26namespace net {
27
28namespace {
29
30void FailTest(int /* result */) {
31  FAIL();
32}
33
34class 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
59class MockCertTrustAnchorProvider : public CertTrustAnchorProvider {
60 public:
61  MockCertTrustAnchorProvider() {}
62  virtual ~MockCertTrustAnchorProvider() {}
63
64  MOCK_METHOD0(GetAdditionalTrustAnchors, const CertificateList&());
65};
66
67}  // namespace
68
69class MultiThreadedCertVerifierTest : public ::testing::Test {
70 public:
71  MultiThreadedCertVerifierTest() : verifier_(new MockCertVerifyProc()) {}
72  virtual ~MultiThreadedCertVerifierTest() {}
73
74 protected:
75  MultiThreadedCertVerifier verifier_;
76};
77
78TEST_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.
127TEST_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.
195TEST_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.
239TEST_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
288TEST_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
313TEST_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
411TEST_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
486