• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
Now()21   virtual base::Time Now() { return current_time_; }
22 
set_current_time(base::Time now)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:
RunWithParams(const Tuple1<int> & params)34   virtual void RunWithParams(const Tuple1<int>& params) {
35     FAIL();
36   }
37 };
38 
39 // Tests a cache hit, which should results in synchronous completion.
TEST_F(CertVerifierTest,CacheHit)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.
TEST_F(CertVerifierTest,InflightJoin)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.
TEST_F(CertVerifierTest,ExpiredCacheEntry)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.
TEST_F(CertVerifierTest,FullCache)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.
TEST_F(CertVerifierTest,CancelRequest)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.
TEST_F(CertVerifierTest,CancelRequestThenQuit)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