Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(532)

Side by Side Diff: net/cert/multi_threaded_cert_verifier.cc

Issue 1991653002: Move caching out of MultiThreadedCertVerifier (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@request_params
Patch Set: Rebased Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/cert/multi_threaded_cert_verifier.h" 5 #include "net/cert/multi_threaded_cert_verifier.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <memory> 8 #include <memory>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/bind_helpers.h" 12 #include "base/bind_helpers.h"
13 #include "base/callback_helpers.h" 13 #include "base/callback_helpers.h"
14 #include "base/compiler_specific.h" 14 #include "base/compiler_specific.h"
15 #include "base/containers/linked_list.h" 15 #include "base/containers/linked_list.h"
16 #include "base/memory/ptr_util.h" 16 #include "base/memory/ptr_util.h"
17 #include "base/message_loop/message_loop.h" 17 #include "base/message_loop/message_loop.h"
18 #include "base/metrics/histogram_macros.h" 18 #include "base/metrics/histogram_macros.h"
19 #include "base/profiler/scoped_tracker.h" 19 #include "base/profiler/scoped_tracker.h"
20 #include "base/sha1.h" 20 #include "base/sha1.h"
21 #include "base/stl_util.h" 21 #include "base/stl_util.h"
22 #include "base/threading/worker_pool.h" 22 #include "base/threading/worker_pool.h"
23 #include "base/time/time.h" 23 #include "base/time/time.h"
24 #include "base/trace_event/trace_event.h" 24 #include "base/trace_event/trace_event.h"
25 #include "base/values.h" 25 #include "base/values.h"
26 #include "net/base/hash_value.h" 26 #include "net/base/hash_value.h"
27 #include "net/base/net_errors.h" 27 #include "net/base/net_errors.h"
28 #include "net/cert/cert_trust_anchor_provider.h"
29 #include "net/cert/cert_verify_proc.h" 28 #include "net/cert/cert_verify_proc.h"
30 #include "net/cert/crl_set.h" 29 #include "net/cert/crl_set.h"
31 #include "net/cert/x509_certificate.h" 30 #include "net/cert/x509_certificate.h"
32 #include "net/cert/x509_certificate_net_log_param.h" 31 #include "net/cert/x509_certificate_net_log_param.h"
33 #include "net/log/net_log.h" 32 #include "net/log/net_log.h"
34 33
35 #if defined(USE_NSS_CERTS) 34 #if defined(USE_NSS_CERTS)
36 #include <private/pprthred.h> // PR_DetachThread 35 #include <private/pprthred.h> // PR_DetachThread
37 #endif 36 #endif
38 37
39 namespace net { 38 namespace net {
40 39
41 //////////////////////////////////////////////////////////////////////////// 40 ////////////////////////////////////////////////////////////////////////////
42 // 41 //
43 // MultiThreadedCertVerifier is a thread-unsafe object which lives, dies, and is 42 // MultiThreadedCertVerifier is a thread-unsafe object which lives, dies, and is
44 // operated on a single thread, henceforth referred to as the "origin" thread. 43 // operated on a single thread, henceforth referred to as the "origin" thread.
45 // 44 //
46 // On a cache hit, MultiThreadedCertVerifier::Verify() returns synchronously 45 // On a cache hit, MultiThreadedCertVerifier::Verify() returns synchronously
eroman 2016/06/10 00:08:05 no longer accurate comment (the synchronous cache
47 // without posting a task to a worker thread. 46 // without posting a task to a worker thread.
48 // 47 //
49 // Otherwise when an incoming Verify() request is received, 48 // Otherwise when an incoming Verify() request is received,
50 // MultiThreadedCertVerifier checks if there is an outstanding "job" 49 // MultiThreadedCertVerifier checks if there is an outstanding "job"
51 // (CertVerifierJob) in progress that can service the request. If there is, 50 // (CertVerifierJob) in progress that can service the request. If there is,
52 // the request is attached to that job. Otherwise a new job is started. 51 // the request is attached to that job. Otherwise a new job is started.
53 // 52 //
54 // A job (CertVerifierJob) and is a way to de-duplicate requests that are 53 // A job (CertVerifierJob) and is a way to de-duplicate requests that are
55 // fundamentally doing the same verification. CertVerifierJob is similarly 54 // fundamentally doing the same verification. CertVerifierJob is similarly
56 // thread-unsafe and lives on the origin thread. 55 // thread-unsafe and lives on the origin thread.
(...skipping 15 matching lines...) Expand all
72 // 71 //
73 // This automatically cancels all outstanding requests. This is accomplished 72 // This automatically cancels all outstanding requests. This is accomplished
74 // by deleting each of the jobs owned by the MultiThreadedCertVerifier, 73 // by deleting each of the jobs owned by the MultiThreadedCertVerifier,
75 // whose destructor in turn marks each attached request as canceled. 74 // whose destructor in turn marks each attached request as canceled.
76 // 75 //
77 // TODO(eroman): If the MultiThreadedCertVerifier is deleted from within a 76 // TODO(eroman): If the MultiThreadedCertVerifier is deleted from within a
78 // callback, the remaining requests in the completing job will NOT be cancelled. 77 // callback, the remaining requests in the completing job will NOT be cancelled.
79 78
80 namespace { 79 namespace {
81 80
82 // The maximum number of cache entries to use for the ExpiringCache.
83 const unsigned kMaxCacheEntries = 256;
84
85 // The number of seconds to cache entries.
86 const unsigned kTTLSecs = 1800; // 30 minutes.
87
88 std::unique_ptr<base::Value> CertVerifyResultCallback( 81 std::unique_ptr<base::Value> CertVerifyResultCallback(
89 const CertVerifyResult& verify_result, 82 const CertVerifyResult& verify_result,
90 NetLogCaptureMode capture_mode) { 83 NetLogCaptureMode capture_mode) {
91 std::unique_ptr<base::DictionaryValue> results(new base::DictionaryValue()); 84 std::unique_ptr<base::DictionaryValue> results(new base::DictionaryValue());
92 results->SetBoolean("has_md5", verify_result.has_md5); 85 results->SetBoolean("has_md5", verify_result.has_md5);
93 results->SetBoolean("has_md2", verify_result.has_md2); 86 results->SetBoolean("has_md2", verify_result.has_md2);
94 results->SetBoolean("has_md4", verify_result.has_md4); 87 results->SetBoolean("has_md4", verify_result.has_md4);
95 results->SetBoolean("is_issued_by_known_root", 88 results->SetBoolean("is_issued_by_known_root",
96 verify_result.is_issued_by_known_root); 89 verify_result.is_issued_by_known_root);
97 results->SetBoolean("is_issued_by_additional_trust_anchor", 90 results->SetBoolean("is_issued_by_additional_trust_anchor",
(...skipping 10 matching lines...) Expand all
108 verify_result.public_key_hashes.begin(); 101 verify_result.public_key_hashes.begin();
109 it != verify_result.public_key_hashes.end(); 102 it != verify_result.public_key_hashes.end();
110 ++it) { 103 ++it) {
111 hashes->AppendString(it->ToString()); 104 hashes->AppendString(it->ToString());
112 } 105 }
113 results->Set("public_key_hashes", std::move(hashes)); 106 results->Set("public_key_hashes", std::move(hashes));
114 107
115 return std::move(results); 108 return std::move(results);
116 } 109 }
117 110
111 // Helper structure used to keep |verify_result| alive for the lifetime of
112 // the verification on the worker thread, and to communicate it back to the
113 // calling thread.
114 struct ResultHelper {
115 int error;
116 CertVerifyResult result;
117 };
118
118 } // namespace 119 } // namespace
119 120
120 MultiThreadedCertVerifier::CachedResult::CachedResult() : error(ERR_FAILED) {}
121
122 MultiThreadedCertVerifier::CachedResult::~CachedResult() {}
123
124 MultiThreadedCertVerifier::CacheValidityPeriod::CacheValidityPeriod(
125 const base::Time& now)
126 : verification_time(now),
127 expiration_time(now) {
128 }
129
130 MultiThreadedCertVerifier::CacheValidityPeriod::CacheValidityPeriod(
131 const base::Time& now,
132 const base::Time& expiration)
133 : verification_time(now),
134 expiration_time(expiration) {
135 }
136
137 bool MultiThreadedCertVerifier::CacheExpirationFunctor::operator()(
138 const CacheValidityPeriod& now,
139 const CacheValidityPeriod& expiration) const {
140 // Ensure this functor is being used for expiration only, and not strict
141 // weak ordering/sorting. |now| should only ever contain a single
142 // base::Time.
143 // Note: DCHECK_EQ is not used due to operator<< overloading requirements.
144 DCHECK(now.verification_time == now.expiration_time);
145
146 // |now| contains only a single time (verification_time), while |expiration|
147 // contains the validity range - both when the certificate was verified and
148 // when the verification result should expire.
149 //
150 // If the user receives a "not yet valid" message, and adjusts their clock
151 // foward to the correct time, this will (typically) cause
152 // now.verification_time to advance past expiration.expiration_time, thus
153 // treating the cached result as an expired entry and re-verifying.
154 // If the user receives a "expired" message, and adjusts their clock
155 // backwards to the correct time, this will cause now.verification_time to
156 // be less than expiration_verification_time, thus treating the cached
157 // result as an expired entry and re-verifying.
158 // If the user receives either of those messages, and does not adjust their
159 // clock, then the result will be (typically) be cached until the expiration
160 // TTL.
161 //
162 // This algorithm is only problematic if the user consistently keeps
163 // adjusting their clock backwards in increments smaller than the expiration
164 // TTL, in which case, cached elements continue to be added. However,
165 // because the cache has a fixed upper bound, if no entries are expired, a
166 // 'random' entry will be, thus keeping the memory constraints bounded over
167 // time.
168 return now.verification_time >= expiration.verification_time &&
169 now.verification_time < expiration.expiration_time;
170 };
171
172 // Represents the output and result callback of a request. The 121 // Represents the output and result callback of a request. The
173 // CertVerifierRequest is owned by the caller that initiated the call to 122 // CertVerifierRequest is owned by the caller that initiated the call to
174 // CertVerifier::Verify(). 123 // CertVerifier::Verify().
175 class CertVerifierRequest : public base::LinkNode<CertVerifierRequest>, 124 class CertVerifierRequest : public base::LinkNode<CertVerifierRequest>,
176 public CertVerifier::Request { 125 public CertVerifier::Request {
177 public: 126 public:
178 CertVerifierRequest(CertVerifierJob* job, 127 CertVerifierRequest(CertVerifierJob* job,
179 const CompletionCallback& callback, 128 const CompletionCallback& callback,
180 CertVerifyResult* verify_result, 129 CertVerifyResult* verify_result,
181 const BoundNetLog& net_log) 130 const BoundNetLog& net_log)
(...skipping 13 matching lines...) Expand all
195 144
196 // Remove the request from the Job. No attempt is made to cancel the job 145 // Remove the request from the Job. No attempt is made to cancel the job
197 // even though it may no longer have any requests attached to it. Because 146 // even though it may no longer have any requests attached to it. Because
198 // it is running on a worker thread aborting it isn't feasible. 147 // it is running on a worker thread aborting it isn't feasible.
199 RemoveFromList(); 148 RemoveFromList();
200 } 149 }
201 } 150 }
202 151
203 // Copies the contents of |verify_result| to the caller's 152 // Copies the contents of |verify_result| to the caller's
204 // CertVerifyResult and calls the callback. 153 // CertVerifyResult and calls the callback.
205 void Post(const MultiThreadedCertVerifier::CachedResult& verify_result) { 154 void Post(const ResultHelper& verify_result) {
206 DCHECK(job_); 155 DCHECK(job_);
207 job_ = nullptr; 156 job_ = nullptr;
208 157
209 net_log_.EndEvent(NetLog::TYPE_CERT_VERIFIER_REQUEST); 158 net_log_.EndEvent(NetLog::TYPE_CERT_VERIFIER_REQUEST);
210 *verify_result_ = verify_result.result; 159 *verify_result_ = verify_result.result;
211 160
212 base::ResetAndReturn(&callback_).Run(verify_result.error); 161 base::ResetAndReturn(&callback_).Run(verify_result.error);
213 } 162 }
214 163
215 void OnJobCancelled() { 164 void OnJobCancelled() {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 } 203 }
255 204
256 // CertVerifierJob lives only on the verifier's origin message loop. 205 // CertVerifierJob lives only on the verifier's origin message loop.
257 class CertVerifierJob { 206 class CertVerifierJob {
258 public: 207 public:
259 CertVerifierJob(const CertVerifier::RequestParams& key, 208 CertVerifierJob(const CertVerifier::RequestParams& key,
260 NetLog* net_log, 209 NetLog* net_log,
261 MultiThreadedCertVerifier* cert_verifier) 210 MultiThreadedCertVerifier* cert_verifier)
262 : key_(key), 211 : key_(key),
263 start_time_(base::TimeTicks::Now()), 212 start_time_(base::TimeTicks::Now()),
264 wall_start_time_(base::Time::Now()),
265 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_CERT_VERIFIER_JOB)), 213 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_CERT_VERIFIER_JOB)),
266 cert_verifier_(cert_verifier), 214 cert_verifier_(cert_verifier),
267 is_first_job_(false), 215 is_first_job_(false),
268 weak_ptr_factory_(this) { 216 weak_ptr_factory_(this) {
269 net_log_.BeginEvent(NetLog::TYPE_CERT_VERIFIER_JOB, 217 net_log_.BeginEvent(NetLog::TYPE_CERT_VERIFIER_JOB,
270 base::Bind(&NetLogX509CertificateCallback, 218 base::Bind(&NetLogX509CertificateCallback,
271 base::Unretained(key.certificate().get()))); 219 base::Unretained(key.certificate().get())));
272 } 220 }
273 221
274 // Indicates whether this was the first job started by the CertVerifier. This 222 // Indicates whether this was the first job started by the CertVerifier. This
275 // is only used for logging certain UMA stats. 223 // is only used for logging certain UMA stats.
276 void set_is_first_job(bool is_first_job) { is_first_job_ = is_first_job; } 224 void set_is_first_job(bool is_first_job) { is_first_job_ = is_first_job; }
277 225
278 const CertVerifier::RequestParams& key() const { return key_; } 226 const CertVerifier::RequestParams& key() const { return key_; }
279 227
280 // Posts a task to the worker pool to do the verification. Once the 228 // Posts a task to the worker pool to do the verification. Once the
281 // verification has completed on the worker thread, it will call 229 // verification has completed on the worker thread, it will call
282 // OnJobCompleted() on the origin thread. 230 // OnJobCompleted() on the origin thread.
283 bool Start(const scoped_refptr<CertVerifyProc>& verify_proc, 231 bool Start(const scoped_refptr<CertVerifyProc>& verify_proc,
284 const scoped_refptr<CRLSet>& crl_set) { 232 const scoped_refptr<CRLSet>& crl_set) {
285 // Owned by the bound reply callback. 233 // Owned by the bound reply callback.
286 std::unique_ptr<MultiThreadedCertVerifier::CachedResult> owned_result( 234 std::unique_ptr<ResultHelper> owned_result(new ResultHelper());
287 new MultiThreadedCertVerifier::CachedResult());
288 235
289 // Parameter evaluation order is undefined in C++. Ensure the pointer value 236 // Parameter evaluation order is undefined in C++. Ensure the pointer value
290 // is gotten before calling base::Passed(). 237 // is gotten before calling base::Passed().
291 auto result = owned_result.get(); 238 auto result = owned_result.get();
292 239
293 return base::WorkerPool::PostTaskAndReply( 240 return base::WorkerPool::PostTaskAndReply(
294 FROM_HERE, 241 FROM_HERE,
295 base::Bind(&DoVerifyOnWorkerThread, verify_proc, key_.certificate(), 242 base::Bind(&DoVerifyOnWorkerThread, verify_proc, key_.certificate(),
296 key_.hostname(), key_.ocsp_response(), key_.flags(), crl_set, 243 key_.hostname(), key_.ocsp_response(), key_.flags(), crl_set,
297 key_.additional_trust_anchors(), &result->error, 244 key_.additional_trust_anchors(), &result->error,
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 net_log_.source().ToEventParametersCallback()); 277 net_log_.source().ToEventParametersCallback());
331 278
332 requests_.Append(request.get()); 279 requests_.Append(request.get());
333 return request; 280 return request;
334 } 281 }
335 282
336 private: 283 private:
337 using RequestList = base::LinkedList<CertVerifierRequest>; 284 using RequestList = base::LinkedList<CertVerifierRequest>;
338 285
339 // Called on completion of the Job to log UMA metrics and NetLog events. 286 // Called on completion of the Job to log UMA metrics and NetLog events.
340 void LogMetrics( 287 void LogMetrics(const ResultHelper& verify_result) {
341 const MultiThreadedCertVerifier::CachedResult& verify_result) {
342 net_log_.EndEvent( 288 net_log_.EndEvent(
343 NetLog::TYPE_CERT_VERIFIER_JOB, 289 NetLog::TYPE_CERT_VERIFIER_JOB,
344 base::Bind(&CertVerifyResultCallback, verify_result.result)); 290 base::Bind(&CertVerifyResultCallback, verify_result.result));
345 base::TimeDelta latency = base::TimeTicks::Now() - start_time_; 291 base::TimeDelta latency = base::TimeTicks::Now() - start_time_;
346 UMA_HISTOGRAM_CUSTOM_TIMES("Net.CertVerifier_Job_Latency", 292 UMA_HISTOGRAM_CUSTOM_TIMES("Net.CertVerifier_Job_Latency",
347 latency, 293 latency,
348 base::TimeDelta::FromMilliseconds(1), 294 base::TimeDelta::FromMilliseconds(1),
349 base::TimeDelta::FromMinutes(10), 295 base::TimeDelta::FromMinutes(10),
350 100); 296 100);
351 if (is_first_job_) { 297 if (is_first_job_) {
352 UMA_HISTOGRAM_CUSTOM_TIMES("Net.CertVerifier_First_Job_Latency", 298 UMA_HISTOGRAM_CUSTOM_TIMES("Net.CertVerifier_First_Job_Latency",
353 latency, 299 latency,
354 base::TimeDelta::FromMilliseconds(1), 300 base::TimeDelta::FromMilliseconds(1),
355 base::TimeDelta::FromMinutes(10), 301 base::TimeDelta::FromMinutes(10),
356 100); 302 100);
357 } 303 }
358 } 304 }
359 305
360 void OnJobCompleted( 306 void OnJobCompleted(std::unique_ptr<ResultHelper> verify_result) {
361 std::unique_ptr<MultiThreadedCertVerifier::CachedResult> verify_result) {
362 TRACE_EVENT0("net", "CertVerifierJob::OnJobCompleted"); 307 TRACE_EVENT0("net", "CertVerifierJob::OnJobCompleted");
363 std::unique_ptr<CertVerifierJob> keep_alive = 308 std::unique_ptr<CertVerifierJob> keep_alive =
364 cert_verifier_->RemoveJob(this); 309 cert_verifier_->RemoveJob(this);
365 310
366 LogMetrics(*verify_result); 311 LogMetrics(*verify_result);
367 cert_verifier_->SaveResultToCache(key_, wall_start_time_, *verify_result);
368 cert_verifier_ = nullptr; 312 cert_verifier_ = nullptr;
369 313
370 // TODO(eroman): If the cert_verifier_ is deleted from within one of the 314 // TODO(eroman): If the cert_verifier_ is deleted from within one of the
371 // callbacks, any remaining requests for that job should be cancelled. Right 315 // callbacks, any remaining requests for that job should be cancelled. Right
372 // now they will be called. 316 // now they will be called.
373 while (!requests_.empty()) { 317 while (!requests_.empty()) {
374 base::LinkNode<CertVerifierRequest>* request = requests_.head(); 318 base::LinkNode<CertVerifierRequest>* request = requests_.head();
375 request->RemoveFromList(); 319 request->RemoveFromList();
376 request->value()->Post(*verify_result); 320 request->value()->Post(*verify_result);
377 } 321 }
378 } 322 }
379 323
380 const CertVerifier::RequestParams key_; 324 const CertVerifier::RequestParams key_;
381 // The tick count of when the job started. This is used to measure how long 325 // The tick count of when the job started. This is used to measure how long
382 // the job actually took to complete. 326 // the job actually took to complete.
383 const base::TimeTicks start_time_; 327 const base::TimeTicks start_time_;
384 328
385 // The wall time of when the job started. This is to account for situations
386 // where the system clock may have changed after the Job had started, which
387 // could otherwise result in caching the wrong data.
388 const base::Time wall_start_time_;
389
390 RequestList requests_; // Non-owned. 329 RequestList requests_; // Non-owned.
391 330
392 const BoundNetLog net_log_; 331 const BoundNetLog net_log_;
393 MultiThreadedCertVerifier* cert_verifier_; // Non-owned. 332 MultiThreadedCertVerifier* cert_verifier_; // Non-owned.
394 333
395 bool is_first_job_; 334 bool is_first_job_;
396 base::WeakPtrFactory<CertVerifierJob> weak_ptr_factory_; 335 base::WeakPtrFactory<CertVerifierJob> weak_ptr_factory_;
397 }; 336 };
398 337
399 MultiThreadedCertVerifier::MultiThreadedCertVerifier( 338 MultiThreadedCertVerifier::MultiThreadedCertVerifier(
400 CertVerifyProc* verify_proc) 339 CertVerifyProc* verify_proc)
401 : cache_(kMaxCacheEntries), 340 : requests_(0), inflight_joins_(0), verify_proc_(verify_proc) {}
402 requests_(0),
403 cache_hits_(0),
404 inflight_joins_(0),
405 verify_proc_(verify_proc),
406 trust_anchor_provider_(NULL) {
407 CertDatabase::GetInstance()->AddObserver(this);
408 }
409 341
410 MultiThreadedCertVerifier::~MultiThreadedCertVerifier() { 342 MultiThreadedCertVerifier::~MultiThreadedCertVerifier() {
411 STLDeleteElements(&inflight_); 343 STLDeleteElements(&inflight_);
412 CertDatabase::GetInstance()->RemoveObserver(this);
413 }
414
415 void MultiThreadedCertVerifier::SetCertTrustAnchorProvider(
416 CertTrustAnchorProvider* trust_anchor_provider) {
417 DCHECK(CalledOnValidThread());
418 trust_anchor_provider_ = trust_anchor_provider;
419 } 344 }
420 345
421 int MultiThreadedCertVerifier::Verify(const RequestParams& params, 346 int MultiThreadedCertVerifier::Verify(const RequestParams& params,
422 CRLSet* crl_set, 347 CRLSet* crl_set,
423 CertVerifyResult* verify_result, 348 CertVerifyResult* verify_result,
424 const CompletionCallback& callback, 349 const CompletionCallback& callback,
425 std::unique_ptr<Request>* out_req, 350 std::unique_ptr<Request>* out_req,
426 const BoundNetLog& net_log) { 351 const BoundNetLog& net_log) {
427 out_req->reset(); 352 out_req->reset();
428 353
429 DCHECK(CalledOnValidThread()); 354 DCHECK(CalledOnValidThread());
430 355
431 if (callback.is_null() || !verify_result || params.hostname().empty()) 356 if (callback.is_null() || !verify_result || params.hostname().empty())
432 return ERR_INVALID_ARGUMENT; 357 return ERR_INVALID_ARGUMENT;
433 358
434 requests_++; 359 requests_++;
435 360
436 CertificateList new_trust_anchors(params.additional_trust_anchors()); 361 // See if an identical request is currently in flight.
437 if (trust_anchor_provider_) { 362 CertVerifierJob* job = FindJob(params);
438 const CertificateList& trust_anchors =
439 trust_anchor_provider_->GetAdditionalTrustAnchors();
440 new_trust_anchors.insert(new_trust_anchors.end(), trust_anchors.begin(),
441 trust_anchors.end());
442 }
443
444 const RequestParams key(params.certificate(), params.hostname(),
445 params.flags(), params.ocsp_response(),
446 new_trust_anchors);
447 const CertVerifierCache::value_type* cached_entry =
448 cache_.Get(key, CacheValidityPeriod(base::Time::Now()));
449 if (cached_entry) {
450 ++cache_hits_;
451 *verify_result = cached_entry->result;
452 return cached_entry->error;
453 }
454
455 // No cache hit. See if an identical request is currently in flight.
456 CertVerifierJob* job = FindJob(key);
457 if (job) { 363 if (job) {
458 // An identical request is in flight already. We'll just attach our 364 // An identical request is in flight already. We'll just attach our
459 // callback. 365 // callback.
460 inflight_joins_++; 366 inflight_joins_++;
461 } else { 367 } else {
462 // Need to make a new job. 368 // Need to make a new job.
463 std::unique_ptr<CertVerifierJob> new_job( 369 std::unique_ptr<CertVerifierJob> new_job(
464 new CertVerifierJob(key, net_log.net_log(), this)); 370 new CertVerifierJob(params, net_log.net_log(), this));
465 371
466 if (!new_job->Start(verify_proc_, crl_set)) { 372 if (!new_job->Start(verify_proc_, crl_set)) {
467 // TODO(wtc): log to the NetLog. 373 // TODO(wtc): log to the NetLog.
468 LOG(ERROR) << "CertVerifierJob couldn't be started."; 374 LOG(ERROR) << "CertVerifierJob couldn't be started.";
469 return ERR_INSUFFICIENT_RESOURCES; // Just a guess. 375 return ERR_INSUFFICIENT_RESOURCES; // Just a guess.
470 } 376 }
471 377
472 job = new_job.release(); 378 job = new_job.release();
473 inflight_.insert(job); 379 inflight_.insert(job);
474 380
(...skipping 10 matching lines...) Expand all
485 bool MultiThreadedCertVerifier::SupportsOCSPStapling() { 391 bool MultiThreadedCertVerifier::SupportsOCSPStapling() {
486 return verify_proc_->SupportsOCSPStapling(); 392 return verify_proc_->SupportsOCSPStapling();
487 } 393 }
488 394
489 bool MultiThreadedCertVerifier::JobComparator::operator()( 395 bool MultiThreadedCertVerifier::JobComparator::operator()(
490 const CertVerifierJob* job1, 396 const CertVerifierJob* job1,
491 const CertVerifierJob* job2) const { 397 const CertVerifierJob* job2) const {
492 return job1->key() < job2->key(); 398 return job1->key() < job2->key();
493 } 399 }
494 400
495 void MultiThreadedCertVerifier::SaveResultToCache(const RequestParams& key,
496 const base::Time& start_time,
497 const CachedResult& result) {
498 DCHECK(CalledOnValidThread());
499
500 // When caching, this uses the time that validation started as the
501 // beginning of the validity, rather than the time that it ended (aka
502 // base::Time::Now()), to account for the fact that during validation,
503 // the clock may have changed.
504 //
505 // If the clock has changed significantly, then this result will ideally
506 // be evicted and the next time the certificate is encountered, it will
507 // be revalidated.
508 //
509 // Because of this, it's possible for situations to arise where the
510 // clock was correct at the start of validation, changed to an
511 // incorrect time during validation (such as too far in the past or
512 // future), and then was reset to the correct time. If this happens,
513 // it's likely that the result will not be a valid/correct result,
514 // but will still be used from the cache because the clock was reset
515 // to the correct time after the (bad) validation result completed.
516 //
517 // However, this solution optimizes for the case where the clock is
518 // bad at the start of validation, and subsequently is corrected. In
519 // that situation, the result is also incorrect, but because the clock
520 // was corrected after validation, if the cache validity period was
521 // computed at the end of validation, it would continue to serve an
522 // invalid result for kTTLSecs.
523 cache_.Put(
524 key, result, CacheValidityPeriod(start_time),
525 CacheValidityPeriod(start_time,
526 start_time + base::TimeDelta::FromSeconds(kTTLSecs)));
527 }
528
529 std::unique_ptr<CertVerifierJob> MultiThreadedCertVerifier::RemoveJob( 401 std::unique_ptr<CertVerifierJob> MultiThreadedCertVerifier::RemoveJob(
530 CertVerifierJob* job) { 402 CertVerifierJob* job) {
531 DCHECK(CalledOnValidThread()); 403 DCHECK(CalledOnValidThread());
532 bool erased_job = inflight_.erase(job) == 1; 404 bool erased_job = inflight_.erase(job) == 1;
533 DCHECK(erased_job); 405 DCHECK(erased_job);
534 return base::WrapUnique(job); 406 return base::WrapUnique(job);
535 } 407 }
536 408
537 void MultiThreadedCertVerifier::OnCACertChanged(
538 const X509Certificate* cert) {
539 DCHECK(CalledOnValidThread());
540
541 ClearCache();
542 }
543
544 struct MultiThreadedCertVerifier::JobToRequestParamsComparator { 409 struct MultiThreadedCertVerifier::JobToRequestParamsComparator {
545 bool operator()(const CertVerifierJob* job, 410 bool operator()(const CertVerifierJob* job,
546 const CertVerifier::RequestParams& value) const { 411 const CertVerifier::RequestParams& value) const {
547 return job->key() < value; 412 return job->key() < value;
548 } 413 }
549 }; 414 };
550 415
551 CertVerifierJob* MultiThreadedCertVerifier::FindJob(const RequestParams& key) { 416 CertVerifierJob* MultiThreadedCertVerifier::FindJob(const RequestParams& key) {
552 DCHECK(CalledOnValidThread()); 417 DCHECK(CalledOnValidThread());
553 418
554 // The JobSet is kept in sorted order so items can be found using binary 419 // The JobSet is kept in sorted order so items can be found using binary
555 // search. 420 // search.
556 auto it = std::lower_bound(inflight_.begin(), inflight_.end(), key, 421 auto it = std::lower_bound(inflight_.begin(), inflight_.end(), key,
557 JobToRequestParamsComparator()); 422 JobToRequestParamsComparator());
558 if (it != inflight_.end() && !(key < (*it)->key())) 423 if (it != inflight_.end() && !(key < (*it)->key()))
559 return *it; 424 return *it;
560 return nullptr; 425 return nullptr;
561 } 426 }
562 427
563 } // namespace net 428 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698