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

Side by Side Diff: components/certificate_transparency/single_tree_tracker.cc

Issue 2017563002: Add Certificate Transparency logs auditing (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Removed unused function in the test. Created 4 years, 1 month 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 2016 The Chromium Authors. All rights reserved. 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 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 "components/certificate_transparency/single_tree_tracker.h" 5 #include "components/certificate_transparency/single_tree_tracker.h"
6 6
7 #include <algorithm>
8 #include <iterator>
9 #include <list>
7 #include <utility> 10 #include <utility>
8 11
12 #include "base/bind.h"
9 #include "base/metrics/histogram_macros.h" 13 #include "base/metrics/histogram_macros.h"
14 #include "components/certificate_transparency/log_dns_client.h"
15 #include "crypto/sha2.h"
16 #include "net/base/hash_value.h"
17 #include "net/base/net_errors.h"
10 #include "net/cert/ct_log_verifier.h" 18 #include "net/cert/ct_log_verifier.h"
19 #include "net/cert/merkle_audit_proof.h"
20 #include "net/cert/merkle_tree_leaf.h"
11 #include "net/cert/signed_certificate_timestamp.h" 21 #include "net/cert/signed_certificate_timestamp.h"
12 #include "net/cert/x509_certificate.h" 22 #include "net/cert/x509_certificate.h"
13 23
24 using net::SHA256HashValue;
25 using net::ct::LogEntry;
26 using net::ct::MerkleTreeLeaf;
27 using net::ct::SignedCertificateTimestamp;
14 using net::ct::SignedTreeHead; 28 using net::ct::SignedTreeHead;
15 29
16 namespace { 30 namespace {
17 31
18 // Enum indicating whether an SCT can be checked for inclusion and if not, 32 // Enum indicating whether an SCT can be checked for inclusion and if not,
19 // the reason it cannot. 33 // the reason it cannot.
20 // 34 //
21 // Note: The numeric values are used within a histogram and should not change 35 // Note: The numeric values are used within a histogram and should not change
22 // or be re-assigned. 36 // or be re-assigned.
23 enum SCTCanBeCheckedForInclusion { 37 enum SCTCanBeCheckedForInclusion {
24 // If the SingleTreeTracker does not have a valid STH, then a valid STH is 38 // If the SingleTreeTracker does not have a valid STH, then a valid STH is
25 // first required to evaluate whether the SCT can be checked for inclusion 39 // first required to evaluate whether the SCT can be checked for inclusion
26 // or not. 40 // or not.
27 VALID_STH_REQUIRED = 0, 41 VALID_STH_REQUIRED = 0,
28 // If the STH does not cover the SCT (the timestamp in the SCT is greater than 42 // If the STH does not cover the SCT (the timestamp in the SCT is greater than
29 // MMD + timestamp in the STH), then a newer STH is needed. 43 // MMD + timestamp in the STH), then a newer STH is needed.
30 NEWER_STH_REQUIRED = 1, 44 NEWER_STH_REQUIRED = 1,
31 // When an SCT is observed, if the SingleTreeTracker instance has a valid STH 45 // When an SCT is observed, if the SingleTreeTracker instance has a valid STH
32 // and the STH covers the SCT (the timestamp in the SCT is less than MMD + 46 // and the STH covers the SCT (the timestamp in the SCT is less than MMD +
33 // timestamp in the STH), then it can be checked for inclusion. 47 // timestamp in the STH), then it can be checked for inclusion.
34 CAN_BE_CHECKED = 2, 48 CAN_BE_CHECKED = 2,
49 // This SCT was not audited because the queue of pending entries was
50 // full.
51 NOT_AUDITED_QUEUE_FULL = 3,
35 SCT_CAN_BE_CHECKED_MAX 52 SCT_CAN_BE_CHECKED_MAX
36 }; 53 };
37 54
38 // Measure how often clients encounter very new SCTs, by measuring whether an 55 // Measure how often clients encounter very new SCTs, by measuring whether an
39 // SCT can be checked for inclusion upon first observation. 56 // SCT can be checked for inclusion upon first observation.
40 void LogCanBeCheckedForInclusionToUMA( 57 void LogCanBeCheckedForInclusionToUMA(
41 SCTCanBeCheckedForInclusion can_be_checked) { 58 SCTCanBeCheckedForInclusion can_be_checked) {
42 UMA_HISTOGRAM_ENUMERATION("Net.CertificateTransparency.CanInclusionCheckSCT", 59 UMA_HISTOGRAM_ENUMERATION("Net.CertificateTransparency.CanInclusionCheckSCT",
43 can_be_checked, SCT_CAN_BE_CHECKED_MAX); 60 can_be_checked, SCT_CAN_BE_CHECKED_MAX);
44 } 61 }
45 62
63 // Enum indicating the outcome of an inclusion check for a particular log
64 // entry.
65 //
66 // Note: The numeric values are used within a histogram and should not change
67 // or be re-assigned.
68 enum LogEntryInclusionCheckResult {
69 // Inclusion check succeeded: Proof obtained and validated successfully.
70 GOT_VALID_INCLUSION_PROOF = 0,
71 // Could not get an inclusion proof.
72 FAILED_GETTING_INCLUSION_PROOF = 1,
73 // An inclusion proof was obtained but it is invalid.
74 GOT_INVALID_INCLUSION_PROOF = 2,
75 // The SCT could not be audited because the client's DNS configuration
76 // is faulty.
77 DNS_QUERY_NOT_POSSIBLE = 3,
78 LOG_ENTRY_INCLUSION_CHECK_RESULT_MAX
79 };
80
81 void LogInclusionCheckResult(LogEntryInclusionCheckResult result) {
82 UMA_HISTOGRAM_ENUMERATION("Net.CertificateTransparency.InclusionCheckResult",
83 result, LOG_ENTRY_INCLUSION_CHECK_RESULT_MAX);
84 }
85
86 // Calculate the leaf hash of the the entry in the log represented by
87 // the given |cert| and |sct|. If leaf hash calculation succeeds returns
88 // true, false otherwise.
89 bool GetLogEntryLeafHash(const net::X509Certificate* cert,
90 const SignedCertificateTimestamp* sct,
91 SHA256HashValue* leaf_hash) {
92 MerkleTreeLeaf leaf;
93 if (!GetMerkleTreeLeaf(cert, sct, &leaf))
94 return false;
95
96 std::string leaf_hash_str;
97 if (!HashMerkleTreeLeaf(leaf, &leaf_hash_str))
98 return false;
99
100 CHECK_EQ(leaf_hash_str.size(), crypto::kSHA256Length);
101 memcpy(leaf_hash->data, leaf_hash_str.data(), crypto::kSHA256Length);
102 return true;
103 }
104
105 // Audit state of a log entry.
106 enum AuditState {
107 // Entry cannot be audited because a newer STH is needed.
108 PENDING_NEWER_STH,
109 // A leaf index has been obtained and the entry is now pending request
110 // of an inclusion proof.
111 PENDING_INCLUSION_PROOF_REQUEST,
112 // An inclusion proof for this entry has been requested from the log.
113 INCLUSION_PROOF_REQUESTED
114 };
115
116 // Maximal size of the checked entries cache.
117 size_t kCheckedEntriesCacheSize = 100;
118
119 // Maximal size of the pending entries queue.
120 size_t kPendingEntriesQueueSize = 100;
121
122 // Maximum Merge Delay - logs can have individual MMD, but all known logs
123 // currently have 24 hours MMD and Chrome's CT policy requires an MMD
124 // that's no greater than that. For simplicity, use 24 hours for all logs.
125 constexpr base::TimeDelta kMaximumMergeDelay = base::TimeDelta::FromHours(24);
126
127 // The log MUST incorporate the a certificate in the tree within the Maximum
128 // Merge Delay, so an entry can be audited once the timestamp from the SCT +
129 // MMD has passed.
130 // Returns true if the timestamp from the STH is newer than SCT timestamp + MMD.
131 bool IsSCTReadyForAudit(base::Time sth_timestamp, base::Time sct_timestamp) {
132 return sct_timestamp + kMaximumMergeDelay < sth_timestamp;
133 }
134
46 } // namespace 135 } // namespace
47 136
48 namespace certificate_transparency { 137 namespace certificate_transparency {
138 // The entry that is being audited. Immutable - once created, the entry
139 // to audit does not change.
140 struct SingleTreeTracker::EntryToAudit {
141 base::Time sct_timestamp;
142 SHA256HashValue leaf_hash;
143
144 explicit EntryToAudit(base::Time timestamp) : sct_timestamp(timestamp) {}
145 };
146
147 // State of a log entry: its audit state and information necessary to
148 // validate an inclusion proof. Gets updated as the entry transitions
149 // between the different audit states.
150 struct SingleTreeTracker::EntryAuditState {
151 // Current phase of inclusion check.
152 AuditState state;
153 // The proof to be filled in by the LogDnsClient
154 net::ct::MerkleAuditProof proof;
155 // The root hash of the tree for which an inclusion proof was requested.
156 // The root hash is needed after the inclusion proof is fetched for validating
157 // the inclusion proof (each inclusion proof is valid for one particular leaf,
158 // denoted by the leaf index, in exactly one particular tree, denoted by the
159 // tree size in the proof).
160 // To avoid having to re-fetch the inclusion proof if a newer STH is provided
161 // to the SingleTreeTracker, the size of the original tree for which the
162 // inclusion proof was requested is stored in |proof| and the root hash
163 // in |root_hash|.
164 std::string root_hash;
165
166 explicit EntryAuditState(AuditState state) : state(state) {}
167 };
168
169 // Orders entries by the SCT timestamp. In case of tie, which is very unlikely
170 // as it requires two SCTs issued from a log at exactly the same time, order
171 // by leaf hash.
172 bool SingleTreeTracker::OrderByTimestamp::operator()(
173 const EntryToAudit& lhs,
174 const EntryToAudit& rhs) const {
175 if (lhs.sct_timestamp != rhs.sct_timestamp)
176 return lhs.sct_timestamp < rhs.sct_timestamp;
177
178 return net::SHA256HashValueLessThan()(lhs.leaf_hash, rhs.leaf_hash);
179 }
180
181 struct SingleTreeTracker::EntryAuditResult {};
49 182
50 SingleTreeTracker::SingleTreeTracker( 183 SingleTreeTracker::SingleTreeTracker(
51 scoped_refptr<const net::CTLogVerifier> ct_log) 184 scoped_refptr<const net::CTLogVerifier> ct_log,
52 : ct_log_(std::move(ct_log)) {} 185 LogDnsClient* dns_client)
186 : ct_log_(std::move(ct_log)),
187 checked_entries_(kCheckedEntriesCacheSize),
188 dns_client_(dns_client),
189 weak_factory_(this) {
190 memory_pressure_listener_.reset(new base::MemoryPressureListener(base::Bind(
191 &SingleTreeTracker::OnMemoryPressure, weak_factory_.GetWeakPtr())));
Eran Messeri 2016/11/22 13:18:49 Follow up with MemoryPressureListener on whether a
192 }
53 193
54 SingleTreeTracker::~SingleTreeTracker() {} 194 SingleTreeTracker::~SingleTreeTracker() {}
55 195
56 void SingleTreeTracker::OnSCTVerified( 196 void SingleTreeTracker::OnSCTVerified(
57 net::X509Certificate* cert, 197 net::X509Certificate* cert,
58 const net::ct::SignedCertificateTimestamp* sct) { 198 const net::ct::SignedCertificateTimestamp* sct) {
59 DCHECK_EQ(ct_log_->key_id(), sct->log_id); 199 DCHECK_EQ(ct_log_->key_id(), sct->log_id);
60 200
61 // SCT was previously observed, so its status should not be changed. 201 EntryToAudit entry(sct->timestamp);
62 if (entries_status_.find(sct->timestamp) != entries_status_.end()) 202 if (!GetLogEntryLeafHash(cert, sct, &entry.leaf_hash))
63 return; 203 return;
64 204
205 // Avoid queueing multiple instances of the same entry.
206 if (GetAuditedEntryInclusionStatus(entry) != SCT_NOT_OBSERVED)
207 return;
208
209 if (pending_entries_.size() >= kPendingEntriesQueueSize) {
210 // Queue is full - cannot audit SCT.
211 LogCanBeCheckedForInclusionToUMA(NOT_AUDITED_QUEUE_FULL);
212 return;
213 }
214
65 // If there isn't a valid STH or the STH is not fresh enough to check 215 // If there isn't a valid STH or the STH is not fresh enough to check
66 // inclusion against, store the SCT for future checking and return. 216 // inclusion against, store the SCT for future checking and return.
67 if (verified_sth_.timestamp.is_null() || 217 if (verified_sth_.timestamp.is_null() ||
68 (verified_sth_.timestamp < 218 !IsSCTReadyForAudit(verified_sth_.timestamp, entry.sct_timestamp)) {
69 (sct->timestamp + base::TimeDelta::FromHours(24)))) { 219 pending_entries_.insert(
70 entries_status_.insert( 220 std::make_pair(std::move(entry), EntryAuditState(PENDING_NEWER_STH)));
71 std::make_pair(sct->timestamp, SCT_PENDING_NEWER_STH));
72 221
73 if (!verified_sth_.timestamp.is_null()) { 222 if (verified_sth_.timestamp.is_null()) {
223 LogCanBeCheckedForInclusionToUMA(VALID_STH_REQUIRED);
224 } else {
74 LogCanBeCheckedForInclusionToUMA(NEWER_STH_REQUIRED); 225 LogCanBeCheckedForInclusionToUMA(NEWER_STH_REQUIRED);
75 } else {
76 LogCanBeCheckedForInclusionToUMA(VALID_STH_REQUIRED);
77 } 226 }
78 227
79 return; 228 return;
80 } 229 }
81 230
82 LogCanBeCheckedForInclusionToUMA(CAN_BE_CHECKED); 231 LogCanBeCheckedForInclusionToUMA(CAN_BE_CHECKED);
83 // TODO(eranm): Check inclusion here. 232 pending_entries_.insert(std::make_pair(
84 entries_status_.insert( 233 std::move(entry), EntryAuditState(PENDING_INCLUSION_PROOF_REQUEST)));
85 std::make_pair(sct->timestamp, SCT_PENDING_INCLUSION_CHECK)); 234
235 ProcessPendingEntries();
86 } 236 }
87 237
88 void SingleTreeTracker::NewSTHObserved(const SignedTreeHead& sth) { 238 void SingleTreeTracker::NewSTHObserved(const SignedTreeHead& sth) {
89 DCHECK_EQ(ct_log_->key_id(), sth.log_id); 239 DCHECK_EQ(ct_log_->key_id(), sth.log_id);
90 240
91 if (!ct_log_->VerifySignedTreeHead(sth)) { 241 if (!ct_log_->VerifySignedTreeHead(sth)) {
92 // Sanity check the STH; the caller should have done this 242 // Sanity check the STH; the caller should have done this
93 // already, but being paranoid here. 243 // already, but being paranoid here.
94 // NOTE(eranm): Right now there's no way to get rid of this check here 244 // NOTE(eranm): Right now there's no way to get rid of this check here
95 // as this is the first object in the chain that has an instance of 245 // as this is the first object in the chain that has an instance of
96 // a CTLogVerifier to verify the STH. 246 // a CTLogVerifier to verify the STH.
97 return; 247 return;
98 } 248 }
99 249
100 // In order to avoid updating |verified_sth_| to an older STH in case 250 // In order to avoid updating |verified_sth_| to an older STH in case
101 // an older STH is observed, check that either the observed STH is for 251 // an older STH is observed, check that either the observed STH is for
102 // a larger tree size or that it is for the same tree size but has 252 // a larger tree size or that it is for the same tree size but has
103 // a newer timestamp. 253 // a newer timestamp.
104 const bool sths_for_same_tree = verified_sth_.tree_size == sth.tree_size; 254 const bool sths_for_same_tree = verified_sth_.tree_size == sth.tree_size;
105 const bool received_sth_is_for_larger_tree = 255 const bool received_sth_is_for_larger_tree =
106 (verified_sth_.tree_size > sth.tree_size); 256 (verified_sth_.tree_size < sth.tree_size);
107 const bool received_sth_is_newer = (sth.timestamp > verified_sth_.timestamp); 257 const bool received_sth_is_newer = (sth.timestamp > verified_sth_.timestamp);
108 258
109 if (verified_sth_.timestamp.is_null() || received_sth_is_for_larger_tree || 259 if (!verified_sth_.timestamp.is_null() && !received_sth_is_for_larger_tree &&
110 (sths_for_same_tree && received_sth_is_newer)) { 260 !(sths_for_same_tree && received_sth_is_newer)) {
111 verified_sth_ = sth; 261 // Observed an old STH - do nothing.
262 return;
112 } 263 }
113 264
114 // Find out which SCTs can now be checked for inclusion. 265 verified_sth_ = sth;
115 // TODO(eranm): Keep two maps of MerkleTreeLeaf instances, one for leaves 266
116 // pending inclusion checks and one for leaves pending a new STH. 267 // Find the first entry in the PENDING_NEWER_STH state - entries
117 // The comparison function between MerkleTreeLeaf instances should use the 268 // before that should be pending leaf index / inclusion proof, no
118 // timestamp to determine sorting order, so that bulk moving from one 269 // reason to inspect them.
119 // map to the other can happen. 270 auto first_entry_to_audit = std::find_if(
120 auto entry = entries_status_.begin(); 271 pending_entries_.begin(), pending_entries_.end(),
121 while (entry != entries_status_.end() && 272 [](std::pair<const EntryToAudit&, const EntryAuditState&> value) {
122 entry->first < verified_sth_.timestamp) { 273 return value.second.state == PENDING_NEWER_STH;
123 entry->second = SCT_PENDING_INCLUSION_CHECK; 274 });
124 ++entry; 275
125 // TODO(eranm): Check inclusion here. 276 // Find where to stop - this is the first entry whose timestamp + MMD
277 // is greater than the STH's timestamp.
278 auto entry_to_stop_at = std::lower_bound(
279 first_entry_to_audit, pending_entries_.end(), sth.timestamp,
280 [](std::pair<const EntryToAudit&, const EntryAuditState&> value,
281 base::Time sth_timestamp) {
282 return IsSCTReadyForAudit(sth_timestamp, value.first.sct_timestamp);
283 });
284
285 // Update the state of all entries that can now be checked for inclusion.
286 for (auto curr_entry = first_entry_to_audit; curr_entry != entry_to_stop_at;
287 ++curr_entry) {
288 DCHECK(curr_entry->second.state == PENDING_NEWER_STH);
289 curr_entry->second.state = PENDING_INCLUSION_PROOF_REQUEST;
126 } 290 }
291
292 ProcessPendingEntries();
127 } 293 }
128 294
129 SingleTreeTracker::SCTInclusionStatus 295 SingleTreeTracker::SCTInclusionStatus
130 SingleTreeTracker::GetLogEntryInclusionStatus( 296 SingleTreeTracker::GetLogEntryInclusionStatus(
131 net::X509Certificate* cert, 297 net::X509Certificate* cert,
132 const net::ct::SignedCertificateTimestamp* sct) { 298 const net::ct::SignedCertificateTimestamp* sct) {
133 auto it = entries_status_.find(sct->timestamp); 299 EntryToAudit entry(sct->timestamp);
300 if (!GetLogEntryLeafHash(cert, sct, &entry.leaf_hash))
301 return SCT_NOT_OBSERVED;
302 return GetAuditedEntryInclusionStatus(entry);
303 }
134 304
135 return it == entries_status_.end() ? SCT_NOT_OBSERVED : it->second; 305 void SingleTreeTracker::ProcessPendingEntries() {
306 for (auto it = pending_entries_.begin(); it != pending_entries_.end(); ++it) {
307 if (it->second.state != PENDING_INCLUSION_PROOF_REQUEST) {
308 continue;
309 }
310
311 it->second.root_hash =
312 std::string(verified_sth_.sha256_root_hash, crypto::kSHA256Length);
313
314 std::string leaf_hash(
315 reinterpret_cast<const char*>(it->first.leaf_hash.data),
316 crypto::kSHA256Length);
317 net::Error result = dns_client_->QueryAuditProof(
318 ct_log_->dns_domain(), leaf_hash, verified_sth_.tree_size,
319 &(it->second.proof),
320 base::Bind(&SingleTreeTracker::OnAuditProofObtained,
321 weak_factory_.GetWeakPtr(), it->first));
322 // Handling proofs returned synchronously is not implemeted.
323 DCHECK_NE(result, net::OK);
324 if (result == net::ERR_IO_PENDING) {
325 // Successfully requested an inclusion proof - change entry state
326 // and continue to the next one.
327 it->second.state = INCLUSION_PROOF_REQUESTED;
328 } else if (result == net::ERR_TEMPORARILY_THROTTLED) {
329 dns_client_->NotifyWhenNotThrottled(
330 base::Bind(&SingleTreeTracker::ProcessPendingEntries,
331 weak_factory_.GetWeakPtr()));
332 // Exit the loop since all subsequent calls to QueryAuditProof
333 // will be throttled.
334 break;
335 } else if (result == net::ERR_NAME_RESOLUTION_FAILED) {
336 LogInclusionCheckResult(DNS_QUERY_NOT_POSSIBLE);
337 // Lookup failed due to bad DNS configuration, erase the entry and
338 // continue to the next one.
339 it = pending_entries_.erase(it);
340 // Break here if it's the last entry to avoid |it| being incremented
341 // by the for loop.
342 if (it == pending_entries_.end())
343 break;
344 } else {
345 // BUG: an invalid argument was provided or an unexpected error
346 // was returned from LogDnsClient.
347 DCHECK_EQ(result, net::ERR_INVALID_ARGUMENT);
348 NOTREACHED();
349 }
350 }
351 }
352
353 SingleTreeTracker::SCTInclusionStatus
354 SingleTreeTracker::GetAuditedEntryInclusionStatus(const EntryToAudit& entry) {
355 const auto checked_entries_iterator = checked_entries_.Get(
356 std::string(reinterpret_cast<const char*>(entry.leaf_hash.data),
357 crypto::kSHA256Length));
358 if (checked_entries_iterator != checked_entries_.end()) {
359 return SCT_INCLUDED_IN_LOG;
360 }
361
362 auto pending_iterator = pending_entries_.find(entry);
363 if (pending_iterator != pending_entries_.end()) {
364 switch (pending_iterator->second.state) {
365 case PENDING_NEWER_STH:
366 return SCT_PENDING_NEWER_STH;
367 case PENDING_INCLUSION_PROOF_REQUEST:
368 case INCLUSION_PROOF_REQUESTED:
369 return SCT_PENDING_INCLUSION_CHECK;
370 }
371 NOTREACHED();
372 }
373
374 return SCT_NOT_OBSERVED;
375 }
376
377 void SingleTreeTracker::OnAuditProofObtained(const EntryToAudit& entry,
378 int net_error) {
379 auto it = pending_entries_.find(entry);
380 // The entry may not be present if it was evacuated due to low memory
381 // pressure.
382 if (it == pending_entries_.end())
383 return;
384
385 DCHECK(it->second.state == INCLUSION_PROOF_REQUESTED);
386
387 if (net_error == net::OK) {
388 std::string leaf_hash(
389 reinterpret_cast<const char*>(it->first.leaf_hash.data),
390 crypto::kSHA256Length);
391
392 if (ct_log_->VerifyAuditProof(it->second.proof, it->second.root_hash,
393 leaf_hash)) {
394 checked_entries_.Put(leaf_hash, EntryAuditResult());
395 LogInclusionCheckResult(GOT_VALID_INCLUSION_PROOF);
396 } else {
397 LogInclusionCheckResult(GOT_INVALID_INCLUSION_PROOF);
398 }
399 } else {
Ryan Sleevi 2016/12/14 01:34:15 Similar to previous notes if (net_error != net::O
400 // XXX(eranm): Should failures be cached? For now, they are not.
401 LogInclusionCheckResult(FAILED_GETTING_INCLUSION_PROOF);
402 }
403
404 pending_entries_.erase(it);
405 }
406
407 void SingleTreeTracker::OnMemoryPressure(
408 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
409 switch (memory_pressure_level) {
410 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
411 break;
412 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
413 pending_entries_.clear();
414 // Fall through to clearing the other cache.
415 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
416 checked_entries_.Clear();
417 break;
418 }
136 } 419 }
137 420
138 } // namespace certificate_transparency 421 } // namespace certificate_transparency
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698