| Index: net/cert/multi_threaded_cert_verifier.cc
|
| diff --git a/net/cert/multi_threaded_cert_verifier.cc b/net/cert/multi_threaded_cert_verifier.cc
|
| index a1a5fb83b750d06bdd84187a919bd221c8772d5d..91120ad326ed20228b05a8bbb5eeaf7fde569074 100644
|
| --- a/net/cert/multi_threaded_cert_verifier.cc
|
| +++ b/net/cert/multi_threaded_cert_verifier.cc
|
| @@ -25,8 +25,8 @@
|
| #include "base/values.h"
|
| #include "net/base/hash_value.h"
|
| #include "net/base/net_errors.h"
|
| -#include "net/cert/cert_trust_anchor_provider.h"
|
| #include "net/cert/cert_verify_proc.h"
|
| +#include "net/cert/cert_verify_result.h"
|
| #include "net/cert/crl_set.h"
|
| #include "net/cert/x509_certificate.h"
|
| #include "net/cert/x509_certificate_net_log_param.h"
|
| @@ -43,15 +43,12 @@ namespace net {
|
| // MultiThreadedCertVerifier is a thread-unsafe object which lives, dies, and is
|
| // operated on a single thread, henceforth referred to as the "origin" thread.
|
| //
|
| -// On a cache hit, MultiThreadedCertVerifier::Verify() returns synchronously
|
| -// without posting a task to a worker thread.
|
| +// When an incoming Verify() request is received, MultiThreadedCertVerifier
|
| +// checks if there is an outstanding "job" (CertVerifierJob) in progress that
|
| +// can service the request. If there is, the request is attached to that job.
|
| +// Otherwise a new job is started.
|
| //
|
| -// Otherwise when an incoming Verify() request is received,
|
| -// MultiThreadedCertVerifier checks if there is an outstanding "job"
|
| -// (CertVerifierJob) in progress that can service the request. If there is,
|
| -// the request is attached to that job. Otherwise a new job is started.
|
| -//
|
| -// A job (CertVerifierJob) and is a way to de-duplicate requests that are
|
| +// A job (CertVerifierJob) is a way to de-duplicate requests that are
|
| // fundamentally doing the same verification. CertVerifierJob is similarly
|
| // thread-unsafe and lives on the origin thread.
|
| //
|
| @@ -79,12 +76,6 @@ namespace net {
|
|
|
| namespace {
|
|
|
| -// The maximum number of cache entries to use for the ExpiringCache.
|
| -const unsigned kMaxCacheEntries = 256;
|
| -
|
| -// The number of seconds to cache entries.
|
| -const unsigned kTTLSecs = 1800; // 30 minutes.
|
| -
|
| std::unique_ptr<base::Value> CertVerifyResultCallback(
|
| const CertVerifyResult& verify_result,
|
| NetLogCaptureMode capture_mode) {
|
| @@ -115,60 +106,16 @@ std::unique_ptr<base::Value> CertVerifyResultCallback(
|
| return std::move(results);
|
| }
|
|
|
| -} // namespace
|
| -
|
| -MultiThreadedCertVerifier::CachedResult::CachedResult() : error(ERR_FAILED) {}
|
| -
|
| -MultiThreadedCertVerifier::CachedResult::~CachedResult() {}
|
| -
|
| -MultiThreadedCertVerifier::CacheValidityPeriod::CacheValidityPeriod(
|
| - const base::Time& now)
|
| - : verification_time(now),
|
| - expiration_time(now) {
|
| -}
|
| -
|
| -MultiThreadedCertVerifier::CacheValidityPeriod::CacheValidityPeriod(
|
| - const base::Time& now,
|
| - const base::Time& expiration)
|
| - : verification_time(now),
|
| - expiration_time(expiration) {
|
| -}
|
| -
|
| -bool MultiThreadedCertVerifier::CacheExpirationFunctor::operator()(
|
| - const CacheValidityPeriod& now,
|
| - const CacheValidityPeriod& expiration) const {
|
| - // Ensure this functor is being used for expiration only, and not strict
|
| - // weak ordering/sorting. |now| should only ever contain a single
|
| - // base::Time.
|
| - // Note: DCHECK_EQ is not used due to operator<< overloading requirements.
|
| - DCHECK(now.verification_time == now.expiration_time);
|
| -
|
| - // |now| contains only a single time (verification_time), while |expiration|
|
| - // contains the validity range - both when the certificate was verified and
|
| - // when the verification result should expire.
|
| - //
|
| - // If the user receives a "not yet valid" message, and adjusts their clock
|
| - // foward to the correct time, this will (typically) cause
|
| - // now.verification_time to advance past expiration.expiration_time, thus
|
| - // treating the cached result as an expired entry and re-verifying.
|
| - // If the user receives a "expired" message, and adjusts their clock
|
| - // backwards to the correct time, this will cause now.verification_time to
|
| - // be less than expiration_verification_time, thus treating the cached
|
| - // result as an expired entry and re-verifying.
|
| - // If the user receives either of those messages, and does not adjust their
|
| - // clock, then the result will be (typically) be cached until the expiration
|
| - // TTL.
|
| - //
|
| - // This algorithm is only problematic if the user consistently keeps
|
| - // adjusting their clock backwards in increments smaller than the expiration
|
| - // TTL, in which case, cached elements continue to be added. However,
|
| - // because the cache has a fixed upper bound, if no entries are expired, a
|
| - // 'random' entry will be, thus keeping the memory constraints bounded over
|
| - // time.
|
| - return now.verification_time >= expiration.verification_time &&
|
| - now.verification_time < expiration.expiration_time;
|
| +// Helper structure used to keep |verify_result| alive for the lifetime of
|
| +// the verification on the worker thread, and to communicate it back to the
|
| +// calling thread.
|
| +struct ResultHelper {
|
| + int error;
|
| + CertVerifyResult result;
|
| };
|
|
|
| +} // namespace
|
| +
|
| // Represents the output and result callback of a request. The
|
| // CertVerifierRequest is owned by the caller that initiated the call to
|
| // CertVerifier::Verify().
|
| @@ -202,7 +149,7 @@ class CertVerifierRequest : public base::LinkNode<CertVerifierRequest>,
|
|
|
| // Copies the contents of |verify_result| to the caller's
|
| // CertVerifyResult and calls the callback.
|
| - void Post(const MultiThreadedCertVerifier::CachedResult& verify_result) {
|
| + void Post(const ResultHelper& verify_result) {
|
| DCHECK(job_);
|
| job_ = nullptr;
|
|
|
| @@ -261,7 +208,6 @@ class CertVerifierJob {
|
| MultiThreadedCertVerifier* cert_verifier)
|
| : key_(key),
|
| start_time_(base::TimeTicks::Now()),
|
| - wall_start_time_(base::Time::Now()),
|
| net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_CERT_VERIFIER_JOB)),
|
| cert_verifier_(cert_verifier),
|
| is_first_job_(false),
|
| @@ -283,8 +229,7 @@ class CertVerifierJob {
|
| bool Start(const scoped_refptr<CertVerifyProc>& verify_proc,
|
| const scoped_refptr<CRLSet>& crl_set) {
|
| // Owned by the bound reply callback.
|
| - std::unique_ptr<MultiThreadedCertVerifier::CachedResult> owned_result(
|
| - new MultiThreadedCertVerifier::CachedResult());
|
| + std::unique_ptr<ResultHelper> owned_result(new ResultHelper());
|
|
|
| // Parameter evaluation order is undefined in C++. Ensure the pointer value
|
| // is gotten before calling base::Passed().
|
| @@ -337,8 +282,7 @@ class CertVerifierJob {
|
| using RequestList = base::LinkedList<CertVerifierRequest>;
|
|
|
| // Called on completion of the Job to log UMA metrics and NetLog events.
|
| - void LogMetrics(
|
| - const MultiThreadedCertVerifier::CachedResult& verify_result) {
|
| + void LogMetrics(const ResultHelper& verify_result) {
|
| net_log_.EndEvent(
|
| NetLog::TYPE_CERT_VERIFIER_JOB,
|
| base::Bind(&CertVerifyResultCallback, verify_result.result));
|
| @@ -357,14 +301,12 @@ class CertVerifierJob {
|
| }
|
| }
|
|
|
| - void OnJobCompleted(
|
| - std::unique_ptr<MultiThreadedCertVerifier::CachedResult> verify_result) {
|
| + void OnJobCompleted(std::unique_ptr<ResultHelper> verify_result) {
|
| TRACE_EVENT0("net", "CertVerifierJob::OnJobCompleted");
|
| std::unique_ptr<CertVerifierJob> keep_alive =
|
| cert_verifier_->RemoveJob(this);
|
|
|
| LogMetrics(*verify_result);
|
| - cert_verifier_->SaveResultToCache(key_, wall_start_time_, *verify_result);
|
| cert_verifier_ = nullptr;
|
|
|
| // TODO(eroman): If the cert_verifier_ is deleted from within one of the
|
| @@ -382,11 +324,6 @@ class CertVerifierJob {
|
| // the job actually took to complete.
|
| const base::TimeTicks start_time_;
|
|
|
| - // The wall time of when the job started. This is to account for situations
|
| - // where the system clock may have changed after the Job had started, which
|
| - // could otherwise result in caching the wrong data.
|
| - const base::Time wall_start_time_;
|
| -
|
| RequestList requests_; // Non-owned.
|
|
|
| const BoundNetLog net_log_;
|
| @@ -398,24 +335,10 @@ class CertVerifierJob {
|
|
|
| MultiThreadedCertVerifier::MultiThreadedCertVerifier(
|
| CertVerifyProc* verify_proc)
|
| - : cache_(kMaxCacheEntries),
|
| - requests_(0),
|
| - cache_hits_(0),
|
| - inflight_joins_(0),
|
| - verify_proc_(verify_proc),
|
| - trust_anchor_provider_(NULL) {
|
| - CertDatabase::GetInstance()->AddObserver(this);
|
| -}
|
| + : requests_(0), inflight_joins_(0), verify_proc_(verify_proc) {}
|
|
|
| MultiThreadedCertVerifier::~MultiThreadedCertVerifier() {
|
| STLDeleteElements(&inflight_);
|
| - CertDatabase::GetInstance()->RemoveObserver(this);
|
| -}
|
| -
|
| -void MultiThreadedCertVerifier::SetCertTrustAnchorProvider(
|
| - CertTrustAnchorProvider* trust_anchor_provider) {
|
| - DCHECK(CalledOnValidThread());
|
| - trust_anchor_provider_ = trust_anchor_provider;
|
| }
|
|
|
| int MultiThreadedCertVerifier::Verify(const RequestParams& params,
|
| @@ -433,27 +356,8 @@ int MultiThreadedCertVerifier::Verify(const RequestParams& params,
|
|
|
| requests_++;
|
|
|
| - CertificateList new_trust_anchors(params.additional_trust_anchors());
|
| - if (trust_anchor_provider_) {
|
| - const CertificateList& trust_anchors =
|
| - trust_anchor_provider_->GetAdditionalTrustAnchors();
|
| - new_trust_anchors.insert(new_trust_anchors.end(), trust_anchors.begin(),
|
| - trust_anchors.end());
|
| - }
|
| -
|
| - const RequestParams key(params.certificate(), params.hostname(),
|
| - params.flags(), params.ocsp_response(),
|
| - new_trust_anchors);
|
| - const CertVerifierCache::value_type* cached_entry =
|
| - cache_.Get(key, CacheValidityPeriod(base::Time::Now()));
|
| - if (cached_entry) {
|
| - ++cache_hits_;
|
| - *verify_result = cached_entry->result;
|
| - return cached_entry->error;
|
| - }
|
| -
|
| - // No cache hit. See if an identical request is currently in flight.
|
| - CertVerifierJob* job = FindJob(key);
|
| + // See if an identical request is currently in flight.
|
| + CertVerifierJob* job = FindJob(params);
|
| if (job) {
|
| // An identical request is in flight already. We'll just attach our
|
| // callback.
|
| @@ -461,7 +365,7 @@ int MultiThreadedCertVerifier::Verify(const RequestParams& params,
|
| } else {
|
| // Need to make a new job.
|
| std::unique_ptr<CertVerifierJob> new_job(
|
| - new CertVerifierJob(key, net_log.net_log(), this));
|
| + new CertVerifierJob(params, net_log.net_log(), this));
|
|
|
| if (!new_job->Start(verify_proc_, crl_set)) {
|
| // TODO(wtc): log to the NetLog.
|
| @@ -492,40 +396,6 @@ bool MultiThreadedCertVerifier::JobComparator::operator()(
|
| return job1->key() < job2->key();
|
| }
|
|
|
| -void MultiThreadedCertVerifier::SaveResultToCache(const RequestParams& key,
|
| - const base::Time& start_time,
|
| - const CachedResult& result) {
|
| - DCHECK(CalledOnValidThread());
|
| -
|
| - // When caching, this uses the time that validation started as the
|
| - // beginning of the validity, rather than the time that it ended (aka
|
| - // base::Time::Now()), to account for the fact that during validation,
|
| - // the clock may have changed.
|
| - //
|
| - // If the clock has changed significantly, then this result will ideally
|
| - // be evicted and the next time the certificate is encountered, it will
|
| - // be revalidated.
|
| - //
|
| - // Because of this, it's possible for situations to arise where the
|
| - // clock was correct at the start of validation, changed to an
|
| - // incorrect time during validation (such as too far in the past or
|
| - // future), and then was reset to the correct time. If this happens,
|
| - // it's likely that the result will not be a valid/correct result,
|
| - // but will still be used from the cache because the clock was reset
|
| - // to the correct time after the (bad) validation result completed.
|
| - //
|
| - // However, this solution optimizes for the case where the clock is
|
| - // bad at the start of validation, and subsequently is corrected. In
|
| - // that situation, the result is also incorrect, but because the clock
|
| - // was corrected after validation, if the cache validity period was
|
| - // computed at the end of validation, it would continue to serve an
|
| - // invalid result for kTTLSecs.
|
| - cache_.Put(
|
| - key, result, CacheValidityPeriod(start_time),
|
| - CacheValidityPeriod(start_time,
|
| - start_time + base::TimeDelta::FromSeconds(kTTLSecs)));
|
| -}
|
| -
|
| std::unique_ptr<CertVerifierJob> MultiThreadedCertVerifier::RemoveJob(
|
| CertVerifierJob* job) {
|
| DCHECK(CalledOnValidThread());
|
| @@ -534,13 +404,6 @@ std::unique_ptr<CertVerifierJob> MultiThreadedCertVerifier::RemoveJob(
|
| return base::WrapUnique(job);
|
| }
|
|
|
| -void MultiThreadedCertVerifier::OnCACertChanged(
|
| - const X509Certificate* cert) {
|
| - DCHECK(CalledOnValidThread());
|
| -
|
| - ClearCache();
|
| -}
|
| -
|
| struct MultiThreadedCertVerifier::JobToRequestParamsComparator {
|
| bool operator()(const CertVerifierJob* job,
|
| const CertVerifier::RequestParams& value) const {
|
|
|