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

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: CrOS fixes 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"
29 #include "net/cert/cert_verify_result.h"
30 #include "net/cert/crl_set.h" 30 #include "net/cert/crl_set.h"
31 #include "net/cert/x509_certificate.h" 31 #include "net/cert/x509_certificate.h"
32 #include "net/cert/x509_certificate_net_log_param.h" 32 #include "net/cert/x509_certificate_net_log_param.h"
33 #include "net/log/net_log.h" 33 #include "net/log/net_log.h"
34 34
35 #if defined(USE_NSS_CERTS) 35 #if defined(USE_NSS_CERTS)
36 #include <private/pprthred.h> // PR_DetachThread 36 #include <private/pprthred.h> // PR_DetachThread
37 #endif 37 #endif
38 38
39 namespace net { 39 namespace net {
40 40
41 //////////////////////////////////////////////////////////////////////////// 41 ////////////////////////////////////////////////////////////////////////////
42 // 42 //
43 // MultiThreadedCertVerifier is a thread-unsafe object which lives, dies, and is 43 // MultiThreadedCertVerifier is a thread-unsafe object which lives, dies, and is
44 // operated on a single thread, henceforth referred to as the "origin" thread. 44 // operated on a single thread, henceforth referred to as the "origin" thread.
45 // 45 //
46 // On a cache hit, MultiThreadedCertVerifier::Verify() returns synchronously 46 // When an incoming Verify() request is received, MultiThreadedCertVerifier
47 // without posting a task to a worker thread. 47 // checks if there is an outstanding "job" (CertVerifierJob) in progress that
48 // can service the request. If there is, the request is attached to that job.
49 // Otherwise a new job is started.
48 // 50 //
49 // Otherwise when an incoming Verify() request is received, 51 // A job (CertVerifierJob) is a way to de-duplicate requests that are
50 // MultiThreadedCertVerifier checks if there is an outstanding "job"
51 // (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.
53 //
54 // A job (CertVerifierJob) and is a way to de-duplicate requests that are
55 // fundamentally doing the same verification. CertVerifierJob is similarly 52 // fundamentally doing the same verification. CertVerifierJob is similarly
56 // thread-unsafe and lives on the origin thread. 53 // thread-unsafe and lives on the origin thread.
57 // 54 //
58 // To do the actual work, CertVerifierJob posts a task to WorkerPool 55 // To do the actual work, CertVerifierJob posts a task to WorkerPool
59 // (PostTaskAndReply), and on completion notifies all requests attached to it. 56 // (PostTaskAndReply), and on completion notifies all requests attached to it.
60 // 57 //
61 // Cancellation: 58 // Cancellation:
62 // 59 //
63 // There are two ways for a request to be cancelled. 60 // There are two ways for a request to be cancelled.
64 // 61 //
65 // (1) When the caller explicitly frees the Request. 62 // (1) When the caller explicitly frees the Request.
66 // 63 //
67 // If the request was in-flight (attached to a job), then it is detached. 64 // If the request was in-flight (attached to a job), then it is detached.
68 // Note that no effort is made to reap jobs which have no attached requests. 65 // Note that no effort is made to reap jobs which have no attached requests.
69 // (Because the worker task isn't cancelable). 66 // (Because the worker task isn't cancelable).
70 // 67 //
71 // (2) When the MultiThreadedCertVerifier is deleted. 68 // (2) When the MultiThreadedCertVerifier is deleted.
72 // 69 //
73 // This automatically cancels all outstanding requests. This is accomplished 70 // This automatically cancels all outstanding requests. This is accomplished
74 // by deleting each of the jobs owned by the MultiThreadedCertVerifier, 71 // by deleting each of the jobs owned by the MultiThreadedCertVerifier,
75 // whose destructor in turn marks each attached request as canceled. 72 // whose destructor in turn marks each attached request as canceled.
76 // 73 //
77 // TODO(eroman): If the MultiThreadedCertVerifier is deleted from within a 74 // TODO(eroman): If the MultiThreadedCertVerifier is deleted from within a
78 // callback, the remaining requests in the completing job will NOT be cancelled. 75 // callback, the remaining requests in the completing job will NOT be cancelled.
79 76
80 namespace { 77 namespace {
81 78
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( 79 std::unique_ptr<base::Value> CertVerifyResultCallback(
89 const CertVerifyResult& verify_result, 80 const CertVerifyResult& verify_result,
90 NetLogCaptureMode capture_mode) { 81 NetLogCaptureMode capture_mode) {
91 std::unique_ptr<base::DictionaryValue> results(new base::DictionaryValue()); 82 std::unique_ptr<base::DictionaryValue> results(new base::DictionaryValue());
92 results->SetBoolean("has_md5", verify_result.has_md5); 83 results->SetBoolean("has_md5", verify_result.has_md5);
93 results->SetBoolean("has_md2", verify_result.has_md2); 84 results->SetBoolean("has_md2", verify_result.has_md2);
94 results->SetBoolean("has_md4", verify_result.has_md4); 85 results->SetBoolean("has_md4", verify_result.has_md4);
95 results->SetBoolean("is_issued_by_known_root", 86 results->SetBoolean("is_issued_by_known_root",
96 verify_result.is_issued_by_known_root); 87 verify_result.is_issued_by_known_root);
97 results->SetBoolean("is_issued_by_additional_trust_anchor", 88 results->SetBoolean("is_issued_by_additional_trust_anchor",
(...skipping 10 matching lines...) Expand all
108 verify_result.public_key_hashes.begin(); 99 verify_result.public_key_hashes.begin();
109 it != verify_result.public_key_hashes.end(); 100 it != verify_result.public_key_hashes.end();
110 ++it) { 101 ++it) {
111 hashes->AppendString(it->ToString()); 102 hashes->AppendString(it->ToString());
112 } 103 }
113 results->Set("public_key_hashes", std::move(hashes)); 104 results->Set("public_key_hashes", std::move(hashes));
114 105
115 return std::move(results); 106 return std::move(results);
116 } 107 }
117 108
109 // Helper structure used to keep |verify_result| alive for the lifetime of
110 // the verification on the worker thread, and to communicate it back to the
111 // calling thread.
112 struct ResultHelper {
113 int error;
114 CertVerifyResult result;
115 };
116
118 } // namespace 117 } // namespace
119 118
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 119 // Represents the output and result callback of a request. The
173 // CertVerifierRequest is owned by the caller that initiated the call to 120 // CertVerifierRequest is owned by the caller that initiated the call to
174 // CertVerifier::Verify(). 121 // CertVerifier::Verify().
175 class CertVerifierRequest : public base::LinkNode<CertVerifierRequest>, 122 class CertVerifierRequest : public base::LinkNode<CertVerifierRequest>,
176 public CertVerifier::Request { 123 public CertVerifier::Request {
177 public: 124 public:
178 CertVerifierRequest(CertVerifierJob* job, 125 CertVerifierRequest(CertVerifierJob* job,
179 const CompletionCallback& callback, 126 const CompletionCallback& callback,
180 CertVerifyResult* verify_result, 127 CertVerifyResult* verify_result,
181 const BoundNetLog& net_log) 128 const BoundNetLog& net_log)
(...skipping 13 matching lines...) Expand all
195 142
196 // Remove the request from the Job. No attempt is made to cancel the job 143 // 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 144 // 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. 145 // it is running on a worker thread aborting it isn't feasible.
199 RemoveFromList(); 146 RemoveFromList();
200 } 147 }
201 } 148 }
202 149
203 // Copies the contents of |verify_result| to the caller's 150 // Copies the contents of |verify_result| to the caller's
204 // CertVerifyResult and calls the callback. 151 // CertVerifyResult and calls the callback.
205 void Post(const MultiThreadedCertVerifier::CachedResult& verify_result) { 152 void Post(const ResultHelper& verify_result) {
206 DCHECK(job_); 153 DCHECK(job_);
207 job_ = nullptr; 154 job_ = nullptr;
208 155
209 net_log_.EndEvent(NetLog::TYPE_CERT_VERIFIER_REQUEST); 156 net_log_.EndEvent(NetLog::TYPE_CERT_VERIFIER_REQUEST);
210 *verify_result_ = verify_result.result; 157 *verify_result_ = verify_result.result;
211 158
212 base::ResetAndReturn(&callback_).Run(verify_result.error); 159 base::ResetAndReturn(&callback_).Run(verify_result.error);
213 } 160 }
214 161
215 void OnJobCancelled() { 162 void OnJobCancelled() {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 } 201 }
255 202
256 // CertVerifierJob lives only on the verifier's origin message loop. 203 // CertVerifierJob lives only on the verifier's origin message loop.
257 class CertVerifierJob { 204 class CertVerifierJob {
258 public: 205 public:
259 CertVerifierJob(const CertVerifier::RequestParams& key, 206 CertVerifierJob(const CertVerifier::RequestParams& key,
260 NetLog* net_log, 207 NetLog* net_log,
261 MultiThreadedCertVerifier* cert_verifier) 208 MultiThreadedCertVerifier* cert_verifier)
262 : key_(key), 209 : key_(key),
263 start_time_(base::TimeTicks::Now()), 210 start_time_(base::TimeTicks::Now()),
264 wall_start_time_(base::Time::Now()),
265 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_CERT_VERIFIER_JOB)), 211 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_CERT_VERIFIER_JOB)),
266 cert_verifier_(cert_verifier), 212 cert_verifier_(cert_verifier),
267 is_first_job_(false), 213 is_first_job_(false),
268 weak_ptr_factory_(this) { 214 weak_ptr_factory_(this) {
269 net_log_.BeginEvent(NetLog::TYPE_CERT_VERIFIER_JOB, 215 net_log_.BeginEvent(NetLog::TYPE_CERT_VERIFIER_JOB,
270 base::Bind(&NetLogX509CertificateCallback, 216 base::Bind(&NetLogX509CertificateCallback,
271 base::Unretained(key.certificate().get()))); 217 base::Unretained(key.certificate().get())));
272 } 218 }
273 219
274 // Indicates whether this was the first job started by the CertVerifier. This 220 // Indicates whether this was the first job started by the CertVerifier. This
275 // is only used for logging certain UMA stats. 221 // is only used for logging certain UMA stats.
276 void set_is_first_job(bool is_first_job) { is_first_job_ = is_first_job; } 222 void set_is_first_job(bool is_first_job) { is_first_job_ = is_first_job; }
277 223
278 const CertVerifier::RequestParams& key() const { return key_; } 224 const CertVerifier::RequestParams& key() const { return key_; }
279 225
280 // Posts a task to the worker pool to do the verification. Once the 226 // Posts a task to the worker pool to do the verification. Once the
281 // verification has completed on the worker thread, it will call 227 // verification has completed on the worker thread, it will call
282 // OnJobCompleted() on the origin thread. 228 // OnJobCompleted() on the origin thread.
283 bool Start(const scoped_refptr<CertVerifyProc>& verify_proc, 229 bool Start(const scoped_refptr<CertVerifyProc>& verify_proc,
284 const scoped_refptr<CRLSet>& crl_set) { 230 const scoped_refptr<CRLSet>& crl_set) {
285 // Owned by the bound reply callback. 231 // Owned by the bound reply callback.
286 std::unique_ptr<MultiThreadedCertVerifier::CachedResult> owned_result( 232 std::unique_ptr<ResultHelper> owned_result(new ResultHelper());
287 new MultiThreadedCertVerifier::CachedResult());
288 233
289 // Parameter evaluation order is undefined in C++. Ensure the pointer value 234 // Parameter evaluation order is undefined in C++. Ensure the pointer value
290 // is gotten before calling base::Passed(). 235 // is gotten before calling base::Passed().
291 auto result = owned_result.get(); 236 auto result = owned_result.get();
292 237
293 return base::WorkerPool::PostTaskAndReply( 238 return base::WorkerPool::PostTaskAndReply(
294 FROM_HERE, 239 FROM_HERE,
295 base::Bind(&DoVerifyOnWorkerThread, verify_proc, key_.certificate(), 240 base::Bind(&DoVerifyOnWorkerThread, verify_proc, key_.certificate(),
296 key_.hostname(), key_.ocsp_response(), key_.flags(), crl_set, 241 key_.hostname(), key_.ocsp_response(), key_.flags(), crl_set,
297 key_.additional_trust_anchors(), &result->error, 242 key_.additional_trust_anchors(), &result->error,
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 net_log_.source().ToEventParametersCallback()); 275 net_log_.source().ToEventParametersCallback());
331 276
332 requests_.Append(request.get()); 277 requests_.Append(request.get());
333 return request; 278 return request;
334 } 279 }
335 280
336 private: 281 private:
337 using RequestList = base::LinkedList<CertVerifierRequest>; 282 using RequestList = base::LinkedList<CertVerifierRequest>;
338 283
339 // Called on completion of the Job to log UMA metrics and NetLog events. 284 // Called on completion of the Job to log UMA metrics and NetLog events.
340 void LogMetrics( 285 void LogMetrics(const ResultHelper& verify_result) {
341 const MultiThreadedCertVerifier::CachedResult& verify_result) {
342 net_log_.EndEvent( 286 net_log_.EndEvent(
343 NetLog::TYPE_CERT_VERIFIER_JOB, 287 NetLog::TYPE_CERT_VERIFIER_JOB,
344 base::Bind(&CertVerifyResultCallback, verify_result.result)); 288 base::Bind(&CertVerifyResultCallback, verify_result.result));
345 base::TimeDelta latency = base::TimeTicks::Now() - start_time_; 289 base::TimeDelta latency = base::TimeTicks::Now() - start_time_;
346 UMA_HISTOGRAM_CUSTOM_TIMES("Net.CertVerifier_Job_Latency", 290 UMA_HISTOGRAM_CUSTOM_TIMES("Net.CertVerifier_Job_Latency",
347 latency, 291 latency,
348 base::TimeDelta::FromMilliseconds(1), 292 base::TimeDelta::FromMilliseconds(1),
349 base::TimeDelta::FromMinutes(10), 293 base::TimeDelta::FromMinutes(10),
350 100); 294 100);
351 if (is_first_job_) { 295 if (is_first_job_) {
352 UMA_HISTOGRAM_CUSTOM_TIMES("Net.CertVerifier_First_Job_Latency", 296 UMA_HISTOGRAM_CUSTOM_TIMES("Net.CertVerifier_First_Job_Latency",
353 latency, 297 latency,
354 base::TimeDelta::FromMilliseconds(1), 298 base::TimeDelta::FromMilliseconds(1),
355 base::TimeDelta::FromMinutes(10), 299 base::TimeDelta::FromMinutes(10),
356 100); 300 100);
357 } 301 }
358 } 302 }
359 303
360 void OnJobCompleted( 304 void OnJobCompleted(std::unique_ptr<ResultHelper> verify_result) {
361 std::unique_ptr<MultiThreadedCertVerifier::CachedResult> verify_result) {
362 TRACE_EVENT0("net", "CertVerifierJob::OnJobCompleted"); 305 TRACE_EVENT0("net", "CertVerifierJob::OnJobCompleted");
363 std::unique_ptr<CertVerifierJob> keep_alive = 306 std::unique_ptr<CertVerifierJob> keep_alive =
364 cert_verifier_->RemoveJob(this); 307 cert_verifier_->RemoveJob(this);
365 308
366 LogMetrics(*verify_result); 309 LogMetrics(*verify_result);
367 cert_verifier_->SaveResultToCache(key_, wall_start_time_, *verify_result);
368 cert_verifier_ = nullptr; 310 cert_verifier_ = nullptr;
369 311
370 // TODO(eroman): If the cert_verifier_ is deleted from within one of the 312 // 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 313 // callbacks, any remaining requests for that job should be cancelled. Right
372 // now they will be called. 314 // now they will be called.
373 while (!requests_.empty()) { 315 while (!requests_.empty()) {
374 base::LinkNode<CertVerifierRequest>* request = requests_.head(); 316 base::LinkNode<CertVerifierRequest>* request = requests_.head();
375 request->RemoveFromList(); 317 request->RemoveFromList();
376 request->value()->Post(*verify_result); 318 request->value()->Post(*verify_result);
377 } 319 }
378 } 320 }
379 321
380 const CertVerifier::RequestParams key_; 322 const CertVerifier::RequestParams key_;
381 // The tick count of when the job started. This is used to measure how long 323 // The tick count of when the job started. This is used to measure how long
382 // the job actually took to complete. 324 // the job actually took to complete.
383 const base::TimeTicks start_time_; 325 const base::TimeTicks start_time_;
384 326
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. 327 RequestList requests_; // Non-owned.
391 328
392 const BoundNetLog net_log_; 329 const BoundNetLog net_log_;
393 MultiThreadedCertVerifier* cert_verifier_; // Non-owned. 330 MultiThreadedCertVerifier* cert_verifier_; // Non-owned.
394 331
395 bool is_first_job_; 332 bool is_first_job_;
396 base::WeakPtrFactory<CertVerifierJob> weak_ptr_factory_; 333 base::WeakPtrFactory<CertVerifierJob> weak_ptr_factory_;
397 }; 334 };
398 335
399 MultiThreadedCertVerifier::MultiThreadedCertVerifier( 336 MultiThreadedCertVerifier::MultiThreadedCertVerifier(
400 CertVerifyProc* verify_proc) 337 CertVerifyProc* verify_proc)
401 : cache_(kMaxCacheEntries), 338 : 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 339
410 MultiThreadedCertVerifier::~MultiThreadedCertVerifier() { 340 MultiThreadedCertVerifier::~MultiThreadedCertVerifier() {
411 STLDeleteElements(&inflight_); 341 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 } 342 }
420 343
421 int MultiThreadedCertVerifier::Verify(const RequestParams& params, 344 int MultiThreadedCertVerifier::Verify(const RequestParams& params,
422 CRLSet* crl_set, 345 CRLSet* crl_set,
423 CertVerifyResult* verify_result, 346 CertVerifyResult* verify_result,
424 const CompletionCallback& callback, 347 const CompletionCallback& callback,
425 std::unique_ptr<Request>* out_req, 348 std::unique_ptr<Request>* out_req,
426 const BoundNetLog& net_log) { 349 const BoundNetLog& net_log) {
427 out_req->reset(); 350 out_req->reset();
428 351
429 DCHECK(CalledOnValidThread()); 352 DCHECK(CalledOnValidThread());
430 353
431 if (callback.is_null() || !verify_result || params.hostname().empty()) 354 if (callback.is_null() || !verify_result || params.hostname().empty())
432 return ERR_INVALID_ARGUMENT; 355 return ERR_INVALID_ARGUMENT;
433 356
434 requests_++; 357 requests_++;
435 358
436 CertificateList new_trust_anchors(params.additional_trust_anchors()); 359 // See if an identical request is currently in flight.
437 if (trust_anchor_provider_) { 360 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) { 361 if (job) {
458 // An identical request is in flight already. We'll just attach our 362 // An identical request is in flight already. We'll just attach our
459 // callback. 363 // callback.
460 inflight_joins_++; 364 inflight_joins_++;
461 } else { 365 } else {
462 // Need to make a new job. 366 // Need to make a new job.
463 std::unique_ptr<CertVerifierJob> new_job( 367 std::unique_ptr<CertVerifierJob> new_job(
464 new CertVerifierJob(key, net_log.net_log(), this)); 368 new CertVerifierJob(params, net_log.net_log(), this));
465 369
466 if (!new_job->Start(verify_proc_, crl_set)) { 370 if (!new_job->Start(verify_proc_, crl_set)) {
467 // TODO(wtc): log to the NetLog. 371 // TODO(wtc): log to the NetLog.
468 LOG(ERROR) << "CertVerifierJob couldn't be started."; 372 LOG(ERROR) << "CertVerifierJob couldn't be started.";
469 return ERR_INSUFFICIENT_RESOURCES; // Just a guess. 373 return ERR_INSUFFICIENT_RESOURCES; // Just a guess.
470 } 374 }
471 375
472 job = new_job.release(); 376 job = new_job.release();
473 inflight_.insert(job); 377 inflight_.insert(job);
474 378
(...skipping 10 matching lines...) Expand all
485 bool MultiThreadedCertVerifier::SupportsOCSPStapling() { 389 bool MultiThreadedCertVerifier::SupportsOCSPStapling() {
486 return verify_proc_->SupportsOCSPStapling(); 390 return verify_proc_->SupportsOCSPStapling();
487 } 391 }
488 392
489 bool MultiThreadedCertVerifier::JobComparator::operator()( 393 bool MultiThreadedCertVerifier::JobComparator::operator()(
490 const CertVerifierJob* job1, 394 const CertVerifierJob* job1,
491 const CertVerifierJob* job2) const { 395 const CertVerifierJob* job2) const {
492 return job1->key() < job2->key(); 396 return job1->key() < job2->key();
493 } 397 }
494 398
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( 399 std::unique_ptr<CertVerifierJob> MultiThreadedCertVerifier::RemoveJob(
530 CertVerifierJob* job) { 400 CertVerifierJob* job) {
531 DCHECK(CalledOnValidThread()); 401 DCHECK(CalledOnValidThread());
532 bool erased_job = inflight_.erase(job) == 1; 402 bool erased_job = inflight_.erase(job) == 1;
533 DCHECK(erased_job); 403 DCHECK(erased_job);
534 return base::WrapUnique(job); 404 return base::WrapUnique(job);
535 } 405 }
536 406
537 void MultiThreadedCertVerifier::OnCACertChanged(
538 const X509Certificate* cert) {
539 DCHECK(CalledOnValidThread());
540
541 ClearCache();
542 }
543
544 struct MultiThreadedCertVerifier::JobToRequestParamsComparator { 407 struct MultiThreadedCertVerifier::JobToRequestParamsComparator {
545 bool operator()(const CertVerifierJob* job, 408 bool operator()(const CertVerifierJob* job,
546 const CertVerifier::RequestParams& value) const { 409 const CertVerifier::RequestParams& value) const {
547 return job->key() < value; 410 return job->key() < value;
548 } 411 }
549 }; 412 };
550 413
551 CertVerifierJob* MultiThreadedCertVerifier::FindJob(const RequestParams& key) { 414 CertVerifierJob* MultiThreadedCertVerifier::FindJob(const RequestParams& key) {
552 DCHECK(CalledOnValidThread()); 415 DCHECK(CalledOnValidThread());
553 416
554 // The JobSet is kept in sorted order so items can be found using binary 417 // The JobSet is kept in sorted order so items can be found using binary
555 // search. 418 // search.
556 auto it = std::lower_bound(inflight_.begin(), inflight_.end(), key, 419 auto it = std::lower_bound(inflight_.begin(), inflight_.end(), key,
557 JobToRequestParamsComparator()); 420 JobToRequestParamsComparator());
558 if (it != inflight_.end() && !(key < (*it)->key())) 421 if (it != inflight_.end() && !(key < (*it)->key()))
559 return *it; 422 return *it;
560 return nullptr; 423 return nullptr;
561 } 424 }
562 425
563 } // namespace net 426 } // namespace net
OLDNEW
« no previous file with comments | « net/cert/multi_threaded_cert_verifier.h ('k') | net/cert/multi_threaded_cert_verifier_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698