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

Side by Side Diff: net/cert/caching_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
(Empty)
1 // Copyright 2016 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/cert/caching_cert_verifier.h"
6
7 #include "base/time/time.h"
8 #include "net/base/net_errors.h"
9 #include "net/cert/cert_trust_anchor_provider.h"
10
11 namespace net {
12
13 namespace {
14
15 // The maximum number of cache entries to use for the ExpiringCache.
16 const unsigned kMaxCacheEntries = 256;
17
18 // The number of seconds to cache entries.
19 const unsigned kTTLSecs = 1800; // 30 minutes.
20
21 } // namespace
22
23 CachingCertVerifier::CachingCertVerifier(std::unique_ptr<CertVerifier> verifier)
24 : verifier_(std::move(verifier)),
25 trust_anchor_provider_(nullptr),
26 cache_(kMaxCacheEntries),
27 requests_(0u),
28 cache_hits_(0u) {
29 CertDatabase::GetInstance()->AddObserver(this);
30 }
31
32 CachingCertVerifier::~CachingCertVerifier() {
33 CertDatabase::GetInstance()->RemoveObserver(this);
34 }
35
36 void CachingCertVerifier::SetCertTrustAnchorProvider(
37 CertTrustAnchorProvider* trust_anchor_provider) {
38 DCHECK(!trust_anchor_provider_);
39 trust_anchor_provider_ = trust_anchor_provider;
40 }
41
42 int CachingCertVerifier::Verify(const CertVerifier::RequestParams& params,
43 CRLSet* crl_set,
44 CertVerifyResult* verify_result,
45 const CompletionCallback& callback,
46 std::unique_ptr<Request>* out_req,
47 const BoundNetLog& net_log) {
48 out_req->reset();
49
50 requests_++;
51
52 CertificateList additional_trust_anchors(params.additional_trust_anchors());
eroman 2016/06/10 00:08:03 This is... eeew. I realize this CL doesn't introd
Ryan Sleevi 2016/06/10 00:41:10 Right after the Symantec stuff finishes or, if tha
eroman 2016/06/10 01:26:38 OK, sounds good as is then. I knew you weren't fo
53 if (trust_anchor_provider_) {
54 const CertificateList& trust_anchors =
55 trust_anchor_provider_->GetAdditionalTrustAnchors();
56 additional_trust_anchors.insert(additional_trust_anchors.begin(),
57 trust_anchors.begin(), trust_anchors.end());
58 }
59
60 const CertVerifier::RequestParams new_params(
61 params.certificate(), params.hostname(), params.flags(),
62 params.ocsp_response(), additional_trust_anchors);
63 const CertVerificationCache::value_type* cached_entry =
64 cache_.Get(new_params, CacheValidityPeriod(base::Time::Now()));
65 if (cached_entry) {
66 ++cache_hits_;
67 *verify_result = cached_entry->result;
68 return cached_entry->error;
69 }
70
71 base::Time start_time = base::Time::Now();
72 CompletionCallback caching_callback = base::Bind(
73 &CachingCertVerifier::OnRequestFinished, base::Unretained(this),
74 new_params, start_time, callback, verify_result);
75 int result = verifier_->Verify(new_params, crl_set, verify_result,
76 caching_callback, out_req, net_log);
77 if (result != ERR_IO_PENDING) {
78 // Synchronous completion; add directly to cache.
79 AddResultToCache(new_params, start_time, *verify_result, result);
80 }
81
82 return result;
83 }
84
85 bool CachingCertVerifier::SupportsOCSPStapling() {
86 return verifier_->SupportsOCSPStapling();
87 }
88
89 CachingCertVerifier::CachedResult::CachedResult() : error(ERR_FAILED) {}
90
91 CachingCertVerifier::CachedResult::~CachedResult() {}
92
93 CachingCertVerifier::CacheValidityPeriod::CacheValidityPeriod(base::Time now)
94 : verification_time(now), expiration_time(now) {}
95
96 CachingCertVerifier::CacheValidityPeriod::CacheValidityPeriod(
97 base::Time now,
98 base::Time expiration)
99 : verification_time(now), expiration_time(expiration) {}
100
101 bool CachingCertVerifier::CacheExpirationFunctor::operator()(
102 const CacheValidityPeriod& now,
103 const CacheValidityPeriod& expiration) const {
104 // Ensure this functor is being used for expiration only, and not strict
105 // weak ordering/sorting. |now| should only ever contain a single
106 // base::Time.
107 // Note: DCHECK_EQ is not used due to operator<< overloading requirements.
108 DCHECK(now.verification_time == now.expiration_time);
109
110 // |now| contains only a single time (verification_time), while |expiration|
111 // contains the validity range - both when the certificate was verified and
112 // when the verification result should expire.
113 //
114 // If the user receives a "not yet valid" message, and adjusts their clock
115 // foward to the correct time, this will (typically) cause
116 // now.verification_time to advance past expiration.expiration_time, thus
117 // treating the cached result as an expired entry and re-verifying.
118 // If the user receives a "expired" message, and adjusts their clock
119 // backwards to the correct time, this will cause now.verification_time to
120 // be less than expiration_verification_time, thus treating the cached
121 // result as an expired entry and re-verifying.
122 // If the user receives either of those messages, and does not adjust their
123 // clock, then the result will be (typically) be cached until the expiration
124 // TTL.
125 //
126 // This algorithm is only problematic if the user consistently keeps
127 // adjusting their clock backwards in increments smaller than the expiration
128 // TTL, in which case, cached elements continue to be added. However,
129 // because the cache has a fixed upper bound, if no entries are expired, a
130 // 'random' entry will be, thus keeping the memory constraints bounded over
131 // time.
132 return now.verification_time >= expiration.verification_time &&
133 now.verification_time < expiration.expiration_time;
134 };
135
136 void CachingCertVerifier::OnRequestFinished(const RequestParams& params,
137 base::Time start_time,
138 const CompletionCallback& callback,
139 CertVerifyResult* verify_result,
140 int error) {
141 AddResultToCache(params, start_time, *verify_result, error);
142
143 // Now chain to the user's callback, which may delete |this|.
144 callback.Run(error);
145 }
146
147 void CachingCertVerifier::AddResultToCache(
148 const RequestParams& params,
149 base::Time start_time,
150 const CertVerifyResult& verify_result,
151 int error) {
152 // When caching, this uses the time that validation started as the
153 // beginning of the validity, rather than the time that it ended (aka
154 // base::Time::Now()), to account for the fact that during validation,
155 // the clock may have changed.
156 //
157 // If the clock has changed significantly, then this result will ideally
158 // be evicted and the next time the certificate is encountered, it will
159 // be revalidated.
160 //
161 // Because of this, it's possible for situations to arise where the
162 // clock was correct at the start of validation, changed to an
163 // incorrect time during validation (such as too far in the past or
164 // future), and then was reset to the correct time. If this happens,
165 // it's likely that the result will not be a valid/correct result,
166 // but will still be used from the cache because the clock was reset
167 // to the correct time after the (bad) validation result completed.
168 //
169 // However, this solution optimizes for the case where the clock is
170 // bad at the start of validation, and subsequently is corrected. In
171 // that situation, the result is also incorrect, but because the clock
172 // was corrected after validation, if the cache validity period was
173 // computed at the end of validation, it would continue to serve an
174 // invalid result for kTTLSecs.
175 CachedResult cached_result;
176 cached_result.error = error;
177 cached_result.result = verify_result;
178 cache_.Put(
179 params, cached_result, CacheValidityPeriod(start_time),
180 CacheValidityPeriod(start_time,
181 start_time + base::TimeDelta::FromSeconds(kTTLSecs)));
182 }
183
184 void CachingCertVerifier::OnCACertChanged(const X509Certificate* cert) {
185 ClearCache();
186 }
187
188 void CachingCertVerifier::ClearCache() {
189 cache_.Clear();
190 }
191
192 size_t CachingCertVerifier::GetCacheSize() const {
193 return cache_.size();
194 }
195
196 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698