Home | History | Annotate | Download | only in cert
      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);
     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);
    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);
    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);
    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);
    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);
    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);
    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
    486