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

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

Issue 1987113002: Introduce CertVerifier::RequestParams (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Move tests Created 4 years, 7 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
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after
249 // PR_Cleanup. Unless we detach them from NSPR, net_unittests gets 249 // PR_Cleanup. Unless we detach them from NSPR, net_unittests gets
250 // segfaults on shutdown when the threads' thread-specific data 250 // segfaults on shutdown when the threads' thread-specific data
251 // destructors run. 251 // destructors run.
252 PR_DetachThread(); 252 PR_DetachThread();
253 #endif 253 #endif
254 } 254 }
255 255
256 // CertVerifierJob lives only on the verifier's origin message loop. 256 // CertVerifierJob lives only on the verifier's origin message loop.
257 class CertVerifierJob { 257 class CertVerifierJob {
258 public: 258 public:
259 CertVerifierJob(const MultiThreadedCertVerifier::RequestParams& key, 259 CertVerifierJob(const CertVerifier::RequestParams& key,
260 NetLog* net_log, 260 NetLog* net_log,
261 X509Certificate* cert, 261 X509Certificate* cert,
262 MultiThreadedCertVerifier* cert_verifier) 262 MultiThreadedCertVerifier* cert_verifier)
263 : key_(key), 263 : key_(key),
264 start_time_(base::TimeTicks::Now()), 264 start_time_(base::TimeTicks::Now()),
265 wall_start_time_(base::Time::Now()),
265 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_CERT_VERIFIER_JOB)), 266 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_CERT_VERIFIER_JOB)),
266 cert_verifier_(cert_verifier), 267 cert_verifier_(cert_verifier),
267 is_first_job_(false), 268 is_first_job_(false),
268 weak_ptr_factory_(this) { 269 weak_ptr_factory_(this) {
269 net_log_.BeginEvent( 270 net_log_.BeginEvent(
270 NetLog::TYPE_CERT_VERIFIER_JOB, 271 NetLog::TYPE_CERT_VERIFIER_JOB,
271 base::Bind(&NetLogX509CertificateCallback, base::Unretained(cert))); 272 base::Bind(&NetLogX509CertificateCallback, base::Unretained(cert)));
272 } 273 }
273 274
274 // Indicates whether this was the first job started by the CertVerifier. This 275 // Indicates whether this was the first job started by the CertVerifier. This
275 // is only used for logging certain UMA stats. 276 // is only used for logging certain UMA stats.
276 void set_is_first_job(bool is_first_job) { is_first_job_ = is_first_job; } 277 void set_is_first_job(bool is_first_job) { is_first_job_ = is_first_job; }
277 278
278 const MultiThreadedCertVerifier::RequestParams& key() const { return key_; } 279 const CertVerifier::RequestParams& key() const { return key_; }
279 280
280 // Posts a task to the worker pool to do the verification. Once the 281 // Posts a task to the worker pool to do the verification. Once the
281 // verification has completed on the worker thread, it will call 282 // verification has completed on the worker thread, it will call
282 // OnJobCompleted() on the origin thread. 283 // OnJobCompleted() on the origin thread.
283 bool Start(const scoped_refptr<CertVerifyProc>& verify_proc, 284 bool Start(const scoped_refptr<CertVerifyProc>& verify_proc,
284 const scoped_refptr<X509Certificate>& cert, 285 const scoped_refptr<X509Certificate>& cert,
285 const std::string& hostname, 286 const std::string& hostname,
286 const std::string& ocsp_response, 287 const std::string& ocsp_response,
287 int flags, 288 int flags,
288 const scoped_refptr<CRLSet>& crl_set, 289 const scoped_refptr<CRLSet>& crl_set,
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 } 362 }
362 } 363 }
363 364
364 void OnJobCompleted( 365 void OnJobCompleted(
365 std::unique_ptr<MultiThreadedCertVerifier::CachedResult> verify_result) { 366 std::unique_ptr<MultiThreadedCertVerifier::CachedResult> verify_result) {
366 TRACE_EVENT0("net", "CertVerifierJob::OnJobCompleted"); 367 TRACE_EVENT0("net", "CertVerifierJob::OnJobCompleted");
367 std::unique_ptr<CertVerifierJob> keep_alive = 368 std::unique_ptr<CertVerifierJob> keep_alive =
368 cert_verifier_->RemoveJob(this); 369 cert_verifier_->RemoveJob(this);
369 370
370 LogMetrics(*verify_result); 371 LogMetrics(*verify_result);
371 cert_verifier_->SaveResultToCache(key_, *verify_result); 372 cert_verifier_->SaveResultToCache(key_, wall_start_time_, *verify_result);
372 cert_verifier_ = nullptr; 373 cert_verifier_ = nullptr;
373 374
374 // TODO(eroman): If the cert_verifier_ is deleted from within one of the 375 // TODO(eroman): If the cert_verifier_ is deleted from within one of the
375 // callbacks, any remaining requests for that job should be cancelled. Right 376 // callbacks, any remaining requests for that job should be cancelled. Right
376 // now they will be called. 377 // now they will be called.
377 while (!requests_.empty()) { 378 while (!requests_.empty()) {
378 base::LinkNode<CertVerifierRequest>* request = requests_.head(); 379 base::LinkNode<CertVerifierRequest>* request = requests_.head();
379 request->RemoveFromList(); 380 request->RemoveFromList();
380 request->value()->Post(*verify_result); 381 request->value()->Post(*verify_result);
381 } 382 }
382 } 383 }
383 384
384 const MultiThreadedCertVerifier::RequestParams key_; 385 const CertVerifier::RequestParams key_;
386 // The tick count of when the job started. This is used to measure how long
387 // the job actually took to complete.
385 const base::TimeTicks start_time_; 388 const base::TimeTicks start_time_;
386 389
390 // The wall time of when the job started. This is to account for situations
391 // where the system clock may have changed after the Job had started, which
392 // could otherwise result in caching the wrong data.
393 const base::Time wall_start_time_;
394
387 RequestList requests_; // Non-owned. 395 RequestList requests_; // Non-owned.
388 396
389 const BoundNetLog net_log_; 397 const BoundNetLog net_log_;
390 MultiThreadedCertVerifier* cert_verifier_; // Non-owned. 398 MultiThreadedCertVerifier* cert_verifier_; // Non-owned.
391 399
392 bool is_first_job_; 400 bool is_first_job_;
393 base::WeakPtrFactory<CertVerifierJob> weak_ptr_factory_; 401 base::WeakPtrFactory<CertVerifierJob> weak_ptr_factory_;
394 }; 402 };
395 403
396 MultiThreadedCertVerifier::MultiThreadedCertVerifier( 404 MultiThreadedCertVerifier::MultiThreadedCertVerifier(
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 if (callback.is_null() || !verify_result || hostname.empty()) 439 if (callback.is_null() || !verify_result || hostname.empty())
432 return ERR_INVALID_ARGUMENT; 440 return ERR_INVALID_ARGUMENT;
433 441
434 requests_++; 442 requests_++;
435 443
436 const CertificateList empty_cert_list; 444 const CertificateList empty_cert_list;
437 const CertificateList& additional_trust_anchors = 445 const CertificateList& additional_trust_anchors =
438 trust_anchor_provider_ ? 446 trust_anchor_provider_ ?
439 trust_anchor_provider_->GetAdditionalTrustAnchors() : empty_cert_list; 447 trust_anchor_provider_->GetAdditionalTrustAnchors() : empty_cert_list;
440 448
441 const RequestParams key(cert->fingerprint(), cert->ca_fingerprint(), hostname, 449 const CertVerifier::RequestParams key(cert, hostname, flags, ocsp_response,
442 ocsp_response, flags, additional_trust_anchors); 450 additional_trust_anchors);
443 const CertVerifierCache::value_type* cached_entry = 451 const CertVerifierCache::value_type* cached_entry =
444 cache_.Get(key, CacheValidityPeriod(base::Time::Now())); 452 cache_.Get(key, CacheValidityPeriod(base::Time::Now()));
445 if (cached_entry) { 453 if (cached_entry) {
446 ++cache_hits_; 454 ++cache_hits_;
447 *verify_result = cached_entry->result; 455 *verify_result = cached_entry->result;
448 return cached_entry->error; 456 return cached_entry->error;
449 } 457 }
450 458
451 // No cache hit. See if an identical request is currently in flight. 459 // No cache hit. See if an identical request is currently in flight.
452 CertVerifierJob* job = FindJob(key); 460 CertVerifierJob* job = FindJob(key);
(...skipping 23 matching lines...) Expand all
476 std::unique_ptr<CertVerifierRequest> request = 484 std::unique_ptr<CertVerifierRequest> request =
477 job->CreateRequest(callback, verify_result, net_log); 485 job->CreateRequest(callback, verify_result, net_log);
478 *out_req = std::move(request); 486 *out_req = std::move(request);
479 return ERR_IO_PENDING; 487 return ERR_IO_PENDING;
480 } 488 }
481 489
482 bool MultiThreadedCertVerifier::SupportsOCSPStapling() { 490 bool MultiThreadedCertVerifier::SupportsOCSPStapling() {
483 return verify_proc_->SupportsOCSPStapling(); 491 return verify_proc_->SupportsOCSPStapling();
484 } 492 }
485 493
486 MultiThreadedCertVerifier::RequestParams::RequestParams(
487 const SHA1HashValue& cert_fingerprint_arg,
488 const SHA1HashValue& ca_fingerprint_arg,
489 const std::string& hostname_arg,
490 const std::string& ocsp_response_arg,
491 int flags_arg,
492 const CertificateList& additional_trust_anchors)
493 : hostname(hostname_arg), flags(flags_arg), start_time(base::Time::Now()) {
494 hash_values.reserve(3 + additional_trust_anchors.size());
495 SHA1HashValue ocsp_hash;
496 base::SHA1HashBytes(
497 reinterpret_cast<const unsigned char*>(ocsp_response_arg.data()),
498 ocsp_response_arg.size(), ocsp_hash.data);
499 hash_values.push_back(ocsp_hash);
500 hash_values.push_back(cert_fingerprint_arg);
501 hash_values.push_back(ca_fingerprint_arg);
502 for (size_t i = 0; i < additional_trust_anchors.size(); ++i)
503 hash_values.push_back(additional_trust_anchors[i]->fingerprint());
504 }
505
506 MultiThreadedCertVerifier::RequestParams::RequestParams(
507 const RequestParams& other) = default;
508
509 MultiThreadedCertVerifier::RequestParams::~RequestParams() {}
510
511 bool MultiThreadedCertVerifier::RequestParams::operator<(
512 const RequestParams& other) const {
513 // |flags| is compared before |cert_fingerprint|, |ca_fingerprint|,
514 // |hostname|, and |ocsp_response|, under assumption that integer comparisons
515 // are faster than memory and string comparisons.
516 if (flags != other.flags)
517 return flags < other.flags;
518 if (hostname != other.hostname)
519 return hostname < other.hostname;
520 return std::lexicographical_compare(
521 hash_values.begin(), hash_values.end(), other.hash_values.begin(),
522 other.hash_values.end(), SHA1HashValueLessThan());
523 }
524
525 bool MultiThreadedCertVerifier::JobComparator::operator()( 494 bool MultiThreadedCertVerifier::JobComparator::operator()(
526 const CertVerifierJob* job1, 495 const CertVerifierJob* job1,
527 const CertVerifierJob* job2) const { 496 const CertVerifierJob* job2) const {
528 return job1->key() < job2->key(); 497 return job1->key() < job2->key();
529 } 498 }
530 499
531 void MultiThreadedCertVerifier::SaveResultToCache(const RequestParams& key, 500 void MultiThreadedCertVerifier::SaveResultToCache(
532 const CachedResult& result) { 501 const CertVerifier::RequestParams& key,
502 const base::Time& start_time,
503 const CachedResult& result) {
533 DCHECK(CalledOnValidThread()); 504 DCHECK(CalledOnValidThread());
534 505
535 // When caching, this uses the time that validation started as the 506 // When caching, this uses the time that validation started as the
536 // beginning of the validity, rather than the time that it ended (aka 507 // beginning of the validity, rather than the time that it ended (aka
537 // base::Time::Now()), to account for the fact that during validation, 508 // base::Time::Now()), to account for the fact that during validation,
538 // the clock may have changed. 509 // the clock may have changed.
539 // 510 //
540 // If the clock has changed significantly, then this result will ideally 511 // If the clock has changed significantly, then this result will ideally
541 // be evicted and the next time the certificate is encountered, it will 512 // be evicted and the next time the certificate is encountered, it will
542 // be revalidated. 513 // be revalidated.
543 // 514 //
544 // Because of this, it's possible for situations to arise where the 515 // Because of this, it's possible for situations to arise where the
545 // clock was correct at the start of validation, changed to an 516 // clock was correct at the start of validation, changed to an
546 // incorrect time during validation (such as too far in the past or 517 // incorrect time during validation (such as too far in the past or
547 // future), and then was reset to the correct time. If this happens, 518 // future), and then was reset to the correct time. If this happens,
548 // it's likely that the result will not be a valid/correct result, 519 // it's likely that the result will not be a valid/correct result,
549 // but will still be used from the cache because the clock was reset 520 // but will still be used from the cache because the clock was reset
550 // to the correct time after the (bad) validation result completed. 521 // to the correct time after the (bad) validation result completed.
551 // 522 //
552 // However, this solution optimizes for the case where the clock is 523 // However, this solution optimizes for the case where the clock is
553 // bad at the start of validation, and subsequently is corrected. In 524 // bad at the start of validation, and subsequently is corrected. In
554 // that situation, the result is also incorrect, but because the clock 525 // that situation, the result is also incorrect, but because the clock
555 // was corrected after validation, if the cache validity period was 526 // was corrected after validation, if the cache validity period was
556 // computed at the end of validation, it would continue to serve an 527 // computed at the end of validation, it would continue to serve an
557 // invalid result for kTTLSecs. 528 // invalid result for kTTLSecs.
558 const base::Time start_time = key.start_time;
559 cache_.Put( 529 cache_.Put(
560 key, result, CacheValidityPeriod(start_time), 530 key, result, CacheValidityPeriod(start_time),
561 CacheValidityPeriod(start_time, 531 CacheValidityPeriod(start_time,
562 start_time + base::TimeDelta::FromSeconds(kTTLSecs))); 532 start_time + base::TimeDelta::FromSeconds(kTTLSecs)));
563 } 533 }
564 534
565 std::unique_ptr<CertVerifierJob> MultiThreadedCertVerifier::RemoveJob( 535 std::unique_ptr<CertVerifierJob> MultiThreadedCertVerifier::RemoveJob(
566 CertVerifierJob* job) { 536 CertVerifierJob* job) {
567 DCHECK(CalledOnValidThread()); 537 DCHECK(CalledOnValidThread());
568 bool erased_job = inflight_.erase(job) == 1; 538 bool erased_job = inflight_.erase(job) == 1;
569 DCHECK(erased_job); 539 DCHECK(erased_job);
570 return base::WrapUnique(job); 540 return base::WrapUnique(job);
571 } 541 }
572 542
573 void MultiThreadedCertVerifier::OnCACertChanged( 543 void MultiThreadedCertVerifier::OnCACertChanged(
574 const X509Certificate* cert) { 544 const X509Certificate* cert) {
575 DCHECK(CalledOnValidThread()); 545 DCHECK(CalledOnValidThread());
576 546
577 ClearCache(); 547 ClearCache();
578 } 548 }
579 549
580 struct MultiThreadedCertVerifier::JobToRequestParamsComparator { 550 struct MultiThreadedCertVerifier::JobToRequestParamsComparator {
581 bool operator()(const CertVerifierJob* job, 551 bool operator()(const CertVerifierJob* job,
582 const MultiThreadedCertVerifier::RequestParams& value) const { 552 const CertVerifier::RequestParams& value) const {
583 return job->key() < value; 553 return job->key() < value;
584 } 554 }
585 }; 555 };
586 556
587 CertVerifierJob* MultiThreadedCertVerifier::FindJob(const RequestParams& key) { 557 CertVerifierJob* MultiThreadedCertVerifier::FindJob(
558 const CertVerifier::RequestParams& key) {
588 DCHECK(CalledOnValidThread()); 559 DCHECK(CalledOnValidThread());
589 560
590 // The JobSet is kept in sorted order so items can be found using binary 561 // The JobSet is kept in sorted order so items can be found using binary
591 // search. 562 // search.
592 auto it = std::lower_bound(inflight_.begin(), inflight_.end(), key, 563 auto it = std::lower_bound(inflight_.begin(), inflight_.end(), key,
593 JobToRequestParamsComparator()); 564 JobToRequestParamsComparator());
594 if (it != inflight_.end() && !(key < (*it)->key())) 565 if (it != inflight_.end() && !(key < (*it)->key()))
595 return *it; 566 return *it;
596 return nullptr; 567 return nullptr;
597 } 568 }
598 569
599 } // namespace net 570 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698