Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2010 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/cert_verifier.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/file_path.h"
      9 #include "base/stringprintf.h"
     10 #include "net/base/cert_test_util.h"
     11 #include "net/base/net_errors.h"
     12 #include "net/base/test_completion_callback.h"
     13 #include "net/base/x509_certificate.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 
     16 namespace net {
     17 
     18 class TestTimeService : public CertVerifier::TimeService {
     19  public:
     20   // CertVerifier::TimeService methods:
     21   virtual base::Time Now() { return current_time_; }
     22 
     23   void set_current_time(base::Time now) { current_time_ = now; }
     24 
     25  private:
     26   base::Time current_time_;
     27 };
     28 
     29 class CertVerifierTest : public testing::Test {
     30 };
     31 
     32 class ExplodingCallback : public CallbackRunner<Tuple1<int> > {
     33  public:
     34   virtual void RunWithParams(const Tuple1<int>& params) {
     35     FAIL();
     36   }
     37 };
     38 
     39 // Tests a cache hit, which should results in synchronous completion.
     40 TEST_F(CertVerifierTest, CacheHit) {
     41   TestTimeService* time_service = new TestTimeService;
     42   base::Time current_time = base::Time::Now();
     43   time_service->set_current_time(current_time);
     44   CertVerifier verifier(time_service);
     45 
     46   FilePath certs_dir = GetTestCertsDirectory();
     47   scoped_refptr<X509Certificate> google_cert(
     48       ImportCertFromFile(certs_dir, "google.single.der"));
     49   ASSERT_NE(static_cast<X509Certificate*>(NULL), google_cert);
     50 
     51   int error;
     52   CertVerifyResult verify_result;
     53   TestCompletionCallback callback;
     54   CertVerifier::RequestHandle request_handle;
     55 
     56   error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result,
     57                           &callback, &request_handle);
     58   ASSERT_EQ(ERR_IO_PENDING, error);
     59   ASSERT_TRUE(request_handle != NULL);
     60   error = callback.WaitForResult();
     61   ASSERT_TRUE(IsCertificateError(error));
     62   ASSERT_EQ(1u, verifier.requests());
     63   ASSERT_EQ(0u, verifier.cache_hits());
     64   ASSERT_EQ(0u, verifier.inflight_joins());
     65 
     66   error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result,
     67                           &callback, &request_handle);
     68   // Synchronous completion.
     69   ASSERT_NE(ERR_IO_PENDING, error);
     70   ASSERT_TRUE(IsCertificateError(error));
     71   ASSERT_TRUE(request_handle == NULL);
     72   ASSERT_EQ(2u, verifier.requests());
     73   ASSERT_EQ(1u, verifier.cache_hits());
     74   ASSERT_EQ(0u, verifier.inflight_joins());
     75 }
     76 
     77 // Tests an inflight join.
     78 TEST_F(CertVerifierTest, InflightJoin) {
     79   TestTimeService* time_service = new TestTimeService;
     80   base::Time current_time = base::Time::Now();
     81   time_service->set_current_time(current_time);
     82   CertVerifier verifier(time_service);
     83 
     84   FilePath certs_dir = GetTestCertsDirectory();
     85   scoped_refptr<X509Certificate> google_cert(
     86       ImportCertFromFile(certs_dir, "google.single.der"));
     87   ASSERT_NE(static_cast<X509Certificate*>(NULL), google_cert);
     88 
     89   int error;
     90   CertVerifyResult verify_result;
     91   TestCompletionCallback callback;
     92   CertVerifier::RequestHandle request_handle;
     93   CertVerifyResult verify_result2;
     94   TestCompletionCallback callback2;
     95   CertVerifier::RequestHandle request_handle2;
     96 
     97   error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result,
     98                           &callback, &request_handle);
     99   ASSERT_EQ(ERR_IO_PENDING, error);
    100   ASSERT_TRUE(request_handle != NULL);
    101   error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result2,
    102                           &callback2, &request_handle2);
    103   ASSERT_EQ(ERR_IO_PENDING, error);
    104   ASSERT_TRUE(request_handle2 != NULL);
    105   error = callback.WaitForResult();
    106   ASSERT_TRUE(IsCertificateError(error));
    107   error = callback2.WaitForResult();
    108   ASSERT_TRUE(IsCertificateError(error));
    109   ASSERT_EQ(2u, verifier.requests());
    110   ASSERT_EQ(0u, verifier.cache_hits());
    111   ASSERT_EQ(1u, verifier.inflight_joins());
    112 }
    113 
    114 // Tests cache entry expiration.
    115 TEST_F(CertVerifierTest, ExpiredCacheEntry) {
    116   TestTimeService* time_service = new TestTimeService;
    117   base::Time current_time = base::Time::Now();
    118   time_service->set_current_time(current_time);
    119   CertVerifier verifier(time_service);
    120 
    121   FilePath certs_dir = GetTestCertsDirectory();
    122   scoped_refptr<X509Certificate> google_cert(
    123       ImportCertFromFile(certs_dir, "google.single.der"));
    124   ASSERT_NE(static_cast<X509Certificate*>(NULL), google_cert);
    125 
    126   int error;
    127   CertVerifyResult verify_result;
    128   TestCompletionCallback callback;
    129   CertVerifier::RequestHandle request_handle;
    130 
    131   error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result,
    132                           &callback, &request_handle);
    133   ASSERT_EQ(ERR_IO_PENDING, error);
    134   ASSERT_TRUE(request_handle != NULL);
    135   error = callback.WaitForResult();
    136   ASSERT_TRUE(IsCertificateError(error));
    137   ASSERT_EQ(1u, verifier.requests());
    138   ASSERT_EQ(0u, verifier.cache_hits());
    139   ASSERT_EQ(0u, verifier.inflight_joins());
    140 
    141   // Before expiration, should have a cache hit.
    142   error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result,
    143                           &callback, &request_handle);
    144   // Synchronous completion.
    145   ASSERT_NE(ERR_IO_PENDING, error);
    146   ASSERT_TRUE(IsCertificateError(error));
    147   ASSERT_TRUE(request_handle == NULL);
    148   ASSERT_EQ(2u, verifier.requests());
    149   ASSERT_EQ(1u, verifier.cache_hits());
    150   ASSERT_EQ(0u, verifier.inflight_joins());
    151 
    152   // After expiration, should not have a cache hit.
    153   ASSERT_EQ(1u, verifier.GetCacheSize());
    154   current_time += base::TimeDelta::FromMinutes(60);
    155   time_service->set_current_time(current_time);
    156   error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result,
    157                           &callback, &request_handle);
    158   ASSERT_EQ(ERR_IO_PENDING, error);
    159   ASSERT_TRUE(request_handle != NULL);
    160   ASSERT_EQ(0u, verifier.GetCacheSize());
    161   error = callback.WaitForResult();
    162   ASSERT_TRUE(IsCertificateError(error));
    163   ASSERT_EQ(3u, verifier.requests());
    164   ASSERT_EQ(1u, verifier.cache_hits());
    165   ASSERT_EQ(0u, verifier.inflight_joins());
    166 }
    167 
    168 // Tests a full cache.
    169 TEST_F(CertVerifierTest, FullCache) {
    170   TestTimeService* time_service = new TestTimeService;
    171   base::Time current_time = base::Time::Now();
    172   time_service->set_current_time(current_time);
    173   CertVerifier verifier(time_service);
    174 
    175   FilePath certs_dir = GetTestCertsDirectory();
    176   scoped_refptr<X509Certificate> google_cert(
    177       ImportCertFromFile(certs_dir, "google.single.der"));
    178   ASSERT_NE(static_cast<X509Certificate*>(NULL), google_cert);
    179 
    180   int error;
    181   CertVerifyResult verify_result;
    182   TestCompletionCallback callback;
    183   CertVerifier::RequestHandle request_handle;
    184 
    185   error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result,
    186                           &callback, &request_handle);
    187   ASSERT_EQ(ERR_IO_PENDING, error);
    188   ASSERT_TRUE(request_handle != NULL);
    189   error = callback.WaitForResult();
    190   ASSERT_TRUE(IsCertificateError(error));
    191   ASSERT_EQ(1u, verifier.requests());
    192   ASSERT_EQ(0u, verifier.cache_hits());
    193   ASSERT_EQ(0u, verifier.inflight_joins());
    194 
    195   const unsigned kCacheSize = 256;
    196 
    197   for (unsigned i = 0; i < kCacheSize; i++) {
    198     std::string hostname = base::StringPrintf("www%d.example.com", i + 1);
    199     error = verifier.Verify(google_cert, hostname, 0, &verify_result,
    200                             &callback, &request_handle);
    201     ASSERT_EQ(ERR_IO_PENDING, error);
    202     ASSERT_TRUE(request_handle != NULL);
    203     error = callback.WaitForResult();
    204     ASSERT_TRUE(IsCertificateError(error));
    205   }
    206   ASSERT_EQ(kCacheSize + 1, verifier.requests());
    207   ASSERT_EQ(0u, verifier.cache_hits());
    208   ASSERT_EQ(0u, verifier.inflight_joins());
    209 
    210   ASSERT_EQ(kCacheSize, verifier.GetCacheSize());
    211   current_time += base::TimeDelta::FromMinutes(60);
    212   time_service->set_current_time(current_time);
    213   error = verifier.Verify(google_cert, "www999.example.com", 0, &verify_result,
    214                           &callback, &request_handle);
    215   ASSERT_EQ(ERR_IO_PENDING, error);
    216   ASSERT_TRUE(request_handle != NULL);
    217   ASSERT_EQ(kCacheSize, verifier.GetCacheSize());
    218   error = callback.WaitForResult();
    219   ASSERT_EQ(1u, verifier.GetCacheSize());
    220   ASSERT_TRUE(IsCertificateError(error));
    221   ASSERT_EQ(kCacheSize + 2, verifier.requests());
    222   ASSERT_EQ(0u, verifier.cache_hits());
    223   ASSERT_EQ(0u, verifier.inflight_joins());
    224 }
    225 
    226 // Tests that the callback of a canceled request is never made.
    227 TEST_F(CertVerifierTest, CancelRequest) {
    228   CertVerifier verifier;
    229 
    230   FilePath certs_dir = GetTestCertsDirectory();
    231   scoped_refptr<X509Certificate> google_cert(
    232       ImportCertFromFile(certs_dir, "google.single.der"));
    233   ASSERT_NE(static_cast<X509Certificate*>(NULL), google_cert);
    234 
    235   int error;
    236   CertVerifyResult verify_result;
    237   ExplodingCallback exploding_callback;
    238   CertVerifier::RequestHandle request_handle;
    239 
    240   error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result,
    241                           &exploding_callback, &request_handle);
    242   ASSERT_EQ(ERR_IO_PENDING, error);
    243   ASSERT_TRUE(request_handle != NULL);
    244   verifier.CancelRequest(request_handle);
    245 
    246   // Issue a few more requests to the worker pool and wait for their
    247   // completion, so that the task of the canceled request (which runs on a
    248   // worker thread) is likely to complete by the end of this test.
    249   TestCompletionCallback callback;
    250   for (int i = 0; i < 5; ++i) {
    251     error = verifier.Verify(google_cert, "www2.example.com", 0, &verify_result,
    252                             &callback, &request_handle);
    253     ASSERT_EQ(ERR_IO_PENDING, error);
    254     ASSERT_TRUE(request_handle != NULL);
    255     error = callback.WaitForResult();
    256     verifier.ClearCache();
    257   }
    258 }
    259 
    260 // Tests that a canceled request is not leaked.
    261 TEST_F(CertVerifierTest, CancelRequestThenQuit) {
    262   CertVerifier verifier;
    263 
    264   FilePath certs_dir = GetTestCertsDirectory();
    265   scoped_refptr<X509Certificate> google_cert(
    266       ImportCertFromFile(certs_dir, "google.single.der"));
    267   ASSERT_NE(static_cast<X509Certificate*>(NULL), google_cert);
    268 
    269   int error;
    270   CertVerifyResult verify_result;
    271   TestCompletionCallback callback;
    272   CertVerifier::RequestHandle request_handle;
    273 
    274   error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result,
    275                           &callback, &request_handle);
    276   ASSERT_EQ(ERR_IO_PENDING, error);
    277   ASSERT_TRUE(request_handle != NULL);
    278   verifier.CancelRequest(request_handle);
    279   // Destroy |verifier| by going out of scope.
    280 }
    281 
    282 }  // namespace net
    283