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

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: Ready for review 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 DCHECK(leaf_hash_str.size() == crypto::kSHA256Length);
Ryan Sleevi 2016/11/14 05:03:28 1) Why not DCHECK_EQ 2) Is DCHECK vs CHECK the rig
Eran Messeri 2016/11/16 14:24:10 (1) Done (2) Switched to CHECK, good point.
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 EntryToAudit(base::Time timestamp) : sct_timestamp(timestamp) {}
Ryan Sleevi 2016/11/14 05:03:27 explicit? Necessary?
Eran Messeri 2016/11/16 14:24:10 Done, added.
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 EntryAuditState(AuditState state) : state(state) {}
Ryan Sleevi 2016/11/14 05:03:28 explicit? Necessary?
Eran Messeri 2016/11/16 14:24:10 Done, added.
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 }
49 180
50 SingleTreeTracker::SingleTreeTracker( 181 SingleTreeTracker::SingleTreeTracker(
51 scoped_refptr<const net::CTLogVerifier> ct_log) 182 scoped_refptr<const net::CTLogVerifier> ct_log,
52 : ct_log_(std::move(ct_log)) {} 183 LogDnsClient* dns_client)
184 : ct_log_(std::move(ct_log)),
185 checked_entries_(kCheckedEntriesCacheSize),
186 dns_client_(dns_client),
187 weak_factory_(this) {
188 memory_pressure_listener_.reset(new base::MemoryPressureListener(base::Bind(
189 &SingleTreeTracker::OnMemoryPressure, base::Unretained(this))));
Ryan Sleevi 2016/11/14 05:03:28 Are you guaranteed this is safe? That is, I can't
Eran Messeri 2016/11/16 14:24:10 Switched to using a weakptr. The use of base::Unre
Ryan Sleevi 2016/12/14 01:34:15 Apologies for not providing better guidance. While
190 }
53 191
54 SingleTreeTracker::~SingleTreeTracker() {} 192 SingleTreeTracker::~SingleTreeTracker() {}
55 193
56 void SingleTreeTracker::OnSCTVerified( 194 void SingleTreeTracker::OnSCTVerified(
57 net::X509Certificate* cert, 195 net::X509Certificate* cert,
58 const net::ct::SignedCertificateTimestamp* sct) { 196 const net::ct::SignedCertificateTimestamp* sct) {
59 DCHECK_EQ(ct_log_->key_id(), sct->log_id); 197 DCHECK_EQ(ct_log_->key_id(), sct->log_id);
60 198
61 // SCT was previously observed, so its status should not be changed. 199 EntryToAudit entry(sct->timestamp);
62 if (entries_status_.find(sct->timestamp) != entries_status_.end()) 200 if (!GetLogEntryLeafHash(cert, sct, &entry.leaf_hash))
63 return; 201 return;
64 202
203 // Avoid queueing multiple instances of the same entry.
204 if (GetLogEntryInclusionStatus(entry) != SCT_NOT_OBSERVED)
205 return;
206
207 if (pending_entries_.size() >= kPendingEntriesQueueSize) {
208 // Queue is full - cannot audit SCT.
209 LogCanBeCheckedForInclusionToUMA(NOT_AUDITED_QUEUE_FULL);
210 return;
211 }
212
65 // If there isn't a valid STH or the STH is not fresh enough to check 213 // 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. 214 // inclusion against, store the SCT for future checking and return.
67 if (verified_sth_.timestamp.is_null() || 215 if (verified_sth_.timestamp.is_null() ||
68 (verified_sth_.timestamp < 216 !IsSCTReadyForAudit(verified_sth_.timestamp, entry.sct_timestamp)) {
69 (sct->timestamp + base::TimeDelta::FromHours(24)))) { 217 pending_entries_.insert(
70 entries_status_.insert( 218 std::make_pair(std::move(entry), EntryAuditState(PENDING_NEWER_STH)));
71 std::make_pair(sct->timestamp, SCT_PENDING_NEWER_STH));
72 219
73 if (!verified_sth_.timestamp.is_null()) { 220 if (verified_sth_.timestamp.is_null()) {
221 LogCanBeCheckedForInclusionToUMA(VALID_STH_REQUIRED);
222 } else {
74 LogCanBeCheckedForInclusionToUMA(NEWER_STH_REQUIRED); 223 LogCanBeCheckedForInclusionToUMA(NEWER_STH_REQUIRED);
75 } else {
76 LogCanBeCheckedForInclusionToUMA(VALID_STH_REQUIRED);
77 } 224 }
225 } else {
Ryan Sleevi 2016/11/14 05:03:28 Should these } else { have short-circuited returns
Eran Messeri 2016/11/16 14:24:10 Done.
226 LogCanBeCheckedForInclusionToUMA(CAN_BE_CHECKED);
227 pending_entries_.insert(std::make_pair(
228 std::move(entry), EntryAuditState(PENDING_INCLUSION_PROOF_REQUEST)));
78 229
79 return; 230 ProcessPendingEntries();
80 } 231 }
81
82 LogCanBeCheckedForInclusionToUMA(CAN_BE_CHECKED);
83 // TODO(eranm): Check inclusion here.
84 entries_status_.insert(
85 std::make_pair(sct->timestamp, SCT_PENDING_INCLUSION_CHECK));
86 } 232 }
87 233
88 void SingleTreeTracker::NewSTHObserved(const SignedTreeHead& sth) { 234 void SingleTreeTracker::NewSTHObserved(const SignedTreeHead& sth) {
89 DCHECK_EQ(ct_log_->key_id(), sth.log_id); 235 DCHECK_EQ(ct_log_->key_id(), sth.log_id);
90 236
91 if (!ct_log_->VerifySignedTreeHead(sth)) { 237 if (!ct_log_->VerifySignedTreeHead(sth)) {
92 // Sanity check the STH; the caller should have done this 238 // Sanity check the STH; the caller should have done this
93 // already, but being paranoid here. 239 // already, but being paranoid here.
94 // NOTE(eranm): Right now there's no way to get rid of this check here 240 // 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 241 // as this is the first object in the chain that has an instance of
96 // a CTLogVerifier to verify the STH. 242 // a CTLogVerifier to verify the STH.
97 return; 243 return;
98 } 244 }
99 245
100 // In order to avoid updating |verified_sth_| to an older STH in case 246 // 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 247 // 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 248 // a larger tree size or that it is for the same tree size but has
103 // a newer timestamp. 249 // a newer timestamp.
104 const bool sths_for_same_tree = verified_sth_.tree_size == sth.tree_size; 250 const bool sths_for_same_tree = verified_sth_.tree_size == sth.tree_size;
105 const bool received_sth_is_for_larger_tree = 251 const bool received_sth_is_for_larger_tree =
106 (verified_sth_.tree_size > sth.tree_size); 252 (verified_sth_.tree_size < sth.tree_size);
107 const bool received_sth_is_newer = (sth.timestamp > verified_sth_.timestamp); 253 const bool received_sth_is_newer = (sth.timestamp > verified_sth_.timestamp);
108 254
109 if (verified_sth_.timestamp.is_null() || received_sth_is_for_larger_tree || 255 if (!verified_sth_.timestamp.is_null() && !received_sth_is_for_larger_tree &&
110 (sths_for_same_tree && received_sth_is_newer)) { 256 !(sths_for_same_tree && received_sth_is_newer)) {
111 verified_sth_ = sth; 257 // Observed an old STH - do nothing.
258 return;
112 } 259 }
113 260
114 // Find out which SCTs can now be checked for inclusion. 261 verified_sth_ = sth;
115 // TODO(eranm): Keep two maps of MerkleTreeLeaf instances, one for leaves 262
116 // pending inclusion checks and one for leaves pending a new STH. 263 // Find the first entry in the PENDING_NEWER_STH state - entries
117 // The comparison function between MerkleTreeLeaf instances should use the 264 // before that should be pending leaf index / inclusion proof, no
118 // timestamp to determine sorting order, so that bulk moving from one 265 // reason to inspect them.
119 // map to the other can happen. 266 auto first_entry_to_audit = std::find_if(
120 auto entry = entries_status_.begin(); 267 pending_entries_.begin(), pending_entries_.end(),
121 while (entry != entries_status_.end() && 268 [](std::pair<const EntryToAudit&, const EntryAuditState&> value) {
122 entry->first < verified_sth_.timestamp) { 269 return value.second.state == PENDING_NEWER_STH;
123 entry->second = SCT_PENDING_INCLUSION_CHECK; 270 });
124 ++entry; 271
125 // TODO(eranm): Check inclusion here. 272 // Find where to stop - this is the first entry whose timestamp + MMD
273 // is greater than the STH's timestamp.
274 auto entry_to_stop_at = std::lower_bound(
275 first_entry_to_audit, pending_entries_.end(), sth.timestamp,
276 [](std::pair<const EntryToAudit&, const EntryAuditState&> value,
277 base::Time sth_timestamp) {
278 return IsSCTReadyForAudit(sth_timestamp, value.first.sct_timestamp);
279 });
280
281 // Update the state of all entries that can now be checked for inclusion.
282 for (auto curr_entry = first_entry_to_audit; curr_entry != entry_to_stop_at;
283 ++curr_entry) {
284 DCHECK(curr_entry->second.state == PENDING_NEWER_STH);
285 curr_entry->second.state = PENDING_INCLUSION_PROOF_REQUEST;
126 } 286 }
287
288 ProcessPendingEntries();
127 } 289 }
128 290
129 SingleTreeTracker::SCTInclusionStatus 291 SingleTreeTracker::SCTInclusionStatus
130 SingleTreeTracker::GetLogEntryInclusionStatus( 292 SingleTreeTracker::GetLogEntryInclusionStatus(
131 net::X509Certificate* cert, 293 net::X509Certificate* cert,
132 const net::ct::SignedCertificateTimestamp* sct) { 294 const net::ct::SignedCertificateTimestamp* sct) {
133 auto it = entries_status_.find(sct->timestamp); 295 EntryToAudit entry(sct->timestamp);
296 if (!GetLogEntryLeafHash(cert, sct, &entry.leaf_hash))
297 return SCT_NOT_OBSERVED;
298 return GetLogEntryInclusionStatus(entry);
299 }
134 300
135 return it == entries_status_.end() ? SCT_NOT_OBSERVED : it->second; 301 void SingleTreeTracker::ProcessPendingEntries() {
302 auto it = pending_entries_.begin();
303 while (it != pending_entries_.end()) {
Ryan Sleevi 2016/11/14 05:03:28 DANGER: Why a while loop versus a for loop? It see
Eran Messeri 2016/11/16 14:24:10 Done - switched to a for loop.
304 if (it->second.state == PENDING_INCLUSION_PROOF_REQUEST) {
305 it->second.root_hash =
306 std::string(verified_sth_.sha256_root_hash, crypto::kSHA256Length);
307
308 std::string leaf_hash(
309 reinterpret_cast<const char*>(it->first.leaf_hash.data),
310 crypto::kSHA256Length);
311 net::Error result = dns_client_->QueryAuditProof(
312 ct_log_->dns_domain(), leaf_hash, verified_sth_.tree_size,
313 &(it->second.proof),
314 base::Bind(&SingleTreeTracker::OnAuditProofObtained,
315 weak_factory_.GetWeakPtr(), &(it->first)));
Ryan Sleevi 2016/11/14 05:03:27 DANGER: Messing with the key on a map strikes me a
Eran Messeri 2016/11/16 14:24:10 I wast taking a pointer that was used in a const c
316 DCHECK(result != net::OK)
Ryan Sleevi 2016/11/14 05:03:28 DCHECK_EQ
Eran Messeri 2016/11/16 14:24:10 Done.
317 << "Handling proofs returned synchronously is not implemeted.";
Ryan Sleevi 2016/11/14 05:03:27 Unnecessary
Eran Messeri 2016/11/16 14:24:10 Done.
318 if (result == net::ERR_IO_PENDING) {
319 // Successfully requested an inclusion proof - change entry state
320 // and continue to the next one.
321 it->second.state = INCLUSION_PROOF_REQUESTED;
322 ++it;
323 } else if (result == net::ERR_TEMPORARILY_THROTTLED) {
324 dns_client_->NotifyWhenNotThrottled(
325 base::Bind(&SingleTreeTracker::ProcessPendingEntries,
326 weak_factory_.GetWeakPtr()));
327 // Exit the loop since all subsequent calls to QueryAuditProof
328 // will be throttled.
329 break;
330 } else if (result == net::ERR_NAME_RESOLUTION_FAILED) {
331 LogInclusionCheckResult(DNS_QUERY_NOT_POSSIBLE);
332 // Lookup failed due to bad DNS configuration, erase the entry and
333 // continue to the next one.
334 pending_entries_.erase(it++);
Ryan Sleevi 2016/11/14 05:03:28 BUG: This triggers all of the heuristics for "This
Eran Messeri 2016/11/16 14:24:10 Done.
335 } else {
336 // BUG: an invalid argument was provided or an unexpected error
Ryan Sleevi 2016/11/14 05:03:27 Is this a bug in your code? Or are you saying it's
Eran Messeri 2016/11/16 14:24:10 There are two cases: * ERR_INVALID_ARGUMENT was r
337 // was returned from LogDnsClient.
338 DCHECK(result == net::ERR_INVALID_ARGUMENT);
Ryan Sleevi 2016/11/14 05:03:27 DCHECK_EQ
Eran Messeri 2016/11/16 14:24:10 Done.
339 NOTREACHED();
340 }
341 } else {
342 // Entry not pending inclusion proof request, continue to next one.
343 ++it;
Ryan Sleevi 2016/11/14 05:03:27 nit: error control goes first
Eran Messeri 2016/11/16 14:24:10 Done.
344 }
345 }
346 }
347
348 SingleTreeTracker::SCTInclusionStatus
349 SingleTreeTracker::GetLogEntryInclusionStatus(const EntryToAudit& entry) {
350 auto checked_entries_iterator = checked_entries_.Get(
Ryan Sleevi 2016/11/14 05:03:28 auto or const auto?
Eran Messeri 2016/11/16 14:24:10 Done.
351 std::string(reinterpret_cast<const char*>(entry.leaf_hash.data),
352 crypto::kSHA256Length));
353 if (checked_entries_iterator != checked_entries_.end()) {
354 // Only success is cached, so all values in |checked_entries_|
355 // should be true.
356 DCHECK(checked_entries_iterator->second);
357 return SCT_INCLUDED_IN_LOG;
358 }
359
360 auto pending_iterator = pending_entries_.find(entry);
361 if (pending_iterator != pending_entries_.end()) {
362 switch (pending_iterator->second.state) {
363 case PENDING_NEWER_STH:
364 return SCT_PENDING_NEWER_STH;
365 case PENDING_INCLUSION_PROOF_REQUEST:
366 case INCLUSION_PROOF_REQUESTED:
367 return SCT_PENDING_INCLUSION_CHECK;
368 }
369 NOTREACHED();
370 }
371
372 return SCT_NOT_OBSERVED;
373 }
374
375 void SingleTreeTracker::OnAuditProofObtained(const EntryToAudit* entry,
376 int net_error) {
377 auto it = pending_entries_.find(*entry);
378 // The entry may not be present if it was evacuated due to low memory
379 // pressure.
380 if (it == pending_entries_.end()) {
381 ProcessPendingEntries();
382 return;
383 }
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, true);
395 LogInclusionCheckResult(GOT_VALID_INCLUSION_PROOF);
396 } else {
397 LogInclusionCheckResult(GOT_INVALID_INCLUSION_PROOF);
398 }
399 } else {
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