OLD | NEW |
---|---|
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> | 7 #include <algorithm> |
8 #include <iterator> | 8 #include <iterator> |
9 #include <list> | 9 #include <list> |
10 #include <utility> | 10 #include <utility> |
11 | 11 |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/metrics/histogram_macros.h" | 13 #include "base/metrics/histogram_macros.h" |
14 #include "base/strings/string_number_conversions.h" | |
15 #include "base/values.h" | |
14 #include "components/certificate_transparency/log_dns_client.h" | 16 #include "components/certificate_transparency/log_dns_client.h" |
15 #include "crypto/sha2.h" | 17 #include "crypto/sha2.h" |
16 #include "net/base/hash_value.h" | 18 #include "net/base/hash_value.h" |
17 #include "net/base/net_errors.h" | 19 #include "net/base/net_errors.h" |
18 #include "net/cert/ct_log_verifier.h" | 20 #include "net/cert/ct_log_verifier.h" |
19 #include "net/cert/merkle_audit_proof.h" | 21 #include "net/cert/merkle_audit_proof.h" |
20 #include "net/cert/merkle_tree_leaf.h" | 22 #include "net/cert/merkle_tree_leaf.h" |
21 #include "net/cert/signed_certificate_timestamp.h" | 23 #include "net/cert/signed_certificate_timestamp.h" |
22 #include "net/cert/x509_certificate.h" | 24 #include "net/cert/x509_certificate.h" |
25 #include "net/log/net_log.h" | |
23 | 26 |
24 using net::SHA256HashValue; | 27 using net::SHA256HashValue; |
25 using net::ct::LogEntry; | 28 using net::ct::LogEntry; |
26 using net::ct::MerkleAuditProof; | 29 using net::ct::MerkleAuditProof; |
27 using net::ct::MerkleTreeLeaf; | 30 using net::ct::MerkleTreeLeaf; |
28 using net::ct::SignedCertificateTimestamp; | 31 using net::ct::SignedCertificateTimestamp; |
29 using net::ct::SignedTreeHead; | 32 using net::ct::SignedTreeHead; |
30 | 33 |
31 // Overview of the process for auditing CT log entries | 34 // Overview of the process for auditing CT log entries |
32 // | 35 // |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
159 constexpr base::TimeDelta kMaximumMergeDelay = base::TimeDelta::FromHours(24); | 162 constexpr base::TimeDelta kMaximumMergeDelay = base::TimeDelta::FromHours(24); |
160 | 163 |
161 // The log MUST incorporate the a certificate in the tree within the Maximum | 164 // The log MUST incorporate the a certificate in the tree within the Maximum |
162 // Merge Delay, so an entry can be audited once the timestamp from the SCT + | 165 // Merge Delay, so an entry can be audited once the timestamp from the SCT + |
163 // MMD has passed. | 166 // MMD has passed. |
164 // Returns true if the timestamp from the STH is newer than SCT timestamp + MMD. | 167 // Returns true if the timestamp from the STH is newer than SCT timestamp + MMD. |
165 bool IsSCTReadyForAudit(base::Time sth_timestamp, base::Time sct_timestamp) { | 168 bool IsSCTReadyForAudit(base::Time sth_timestamp, base::Time sct_timestamp) { |
166 return sct_timestamp + kMaximumMergeDelay < sth_timestamp; | 169 return sct_timestamp + kMaximumMergeDelay < sth_timestamp; |
167 } | 170 } |
168 | 171 |
172 std::unique_ptr<base::Value> NetLogEntryAuditingEventCallback( | |
173 const SHA256HashValue* log_entry, | |
174 base::StringPiece log_id, | |
175 bool success, | |
176 net::NetLogCaptureMode capture_mode) { | |
177 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | |
178 | |
179 dict->SetString("log_entry", | |
180 base::HexEncode(log_entry->data, crypto::kSHA256Length)); | |
181 dict->SetString("log_id", base::HexEncode(log_id.data(), log_id.size())); | |
182 dict->SetBoolean("success", success); | |
183 | |
184 return std::move(dict); | |
185 } | |
186 | |
169 } // namespace | 187 } // namespace |
170 | 188 |
171 // The entry that is being audited. | 189 // The entry that is being audited. |
172 struct SingleTreeTracker::EntryToAudit { | 190 struct SingleTreeTracker::EntryToAudit { |
173 base::Time sct_timestamp; | 191 base::Time sct_timestamp; |
174 SHA256HashValue leaf_hash; | 192 SHA256HashValue leaf_hash; |
175 | 193 |
176 explicit EntryToAudit(base::Time timestamp) : sct_timestamp(timestamp) {} | 194 explicit EntryToAudit(base::Time timestamp) : sct_timestamp(timestamp) {} |
177 }; | 195 }; |
178 | 196 |
(...skipping 28 matching lines...) Expand all Loading... | |
207 const EntryToAudit& lhs, | 225 const EntryToAudit& lhs, |
208 const EntryToAudit& rhs) const { | 226 const EntryToAudit& rhs) const { |
209 if (lhs.sct_timestamp != rhs.sct_timestamp) | 227 if (lhs.sct_timestamp != rhs.sct_timestamp) |
210 return lhs.sct_timestamp < rhs.sct_timestamp; | 228 return lhs.sct_timestamp < rhs.sct_timestamp; |
211 | 229 |
212 return net::SHA256HashValueLessThan()(lhs.leaf_hash, rhs.leaf_hash); | 230 return net::SHA256HashValueLessThan()(lhs.leaf_hash, rhs.leaf_hash); |
213 } | 231 } |
214 | 232 |
215 SingleTreeTracker::SingleTreeTracker( | 233 SingleTreeTracker::SingleTreeTracker( |
216 scoped_refptr<const net::CTLogVerifier> ct_log, | 234 scoped_refptr<const net::CTLogVerifier> ct_log, |
217 LogDnsClient* dns_client) | 235 LogDnsClient* dns_client, |
236 net::NetLog* net_log) | |
218 : ct_log_(std::move(ct_log)), | 237 : ct_log_(std::move(ct_log)), |
219 checked_entries_(kCheckedEntriesCacheSize), | 238 checked_entries_(kCheckedEntriesCacheSize), |
220 dns_client_(dns_client), | 239 dns_client_(dns_client), |
240 net_log_(net::NetLogWithSource::Make( | |
241 net_log, | |
242 net::NetLogSourceType::CT_TREE_STATE_TRACKER)), | |
221 weak_factory_(this) { | 243 weak_factory_(this) { |
222 memory_pressure_listener_.reset(new base::MemoryPressureListener(base::Bind( | 244 memory_pressure_listener_.reset(new base::MemoryPressureListener(base::Bind( |
223 &SingleTreeTracker::OnMemoryPressure, base::Unretained(this)))); | 245 &SingleTreeTracker::OnMemoryPressure, base::Unretained(this)))); |
224 } | 246 } |
225 | 247 |
226 SingleTreeTracker::~SingleTreeTracker() {} | 248 SingleTreeTracker::~SingleTreeTracker() {} |
227 | 249 |
228 void SingleTreeTracker::OnSCTVerified(net::X509Certificate* cert, | 250 void SingleTreeTracker::OnSCTVerified(net::X509Certificate* cert, |
229 const SignedCertificateTimestamp* sct) { | 251 const SignedCertificateTimestamp* sct) { |
230 DCHECK_EQ(ct_log_->key_id(), sct->log_id); | 252 DCHECK_EQ(ct_log_->key_id(), sct->log_id); |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
361 it->second.state = INCLUSION_PROOF_REQUESTED; | 383 it->second.state = INCLUSION_PROOF_REQUESTED; |
362 } else if (result == net::ERR_TEMPORARILY_THROTTLED) { | 384 } else if (result == net::ERR_TEMPORARILY_THROTTLED) { |
363 dns_client_->NotifyWhenNotThrottled( | 385 dns_client_->NotifyWhenNotThrottled( |
364 base::Bind(&SingleTreeTracker::ProcessPendingEntries, | 386 base::Bind(&SingleTreeTracker::ProcessPendingEntries, |
365 weak_factory_.GetWeakPtr())); | 387 weak_factory_.GetWeakPtr())); |
366 // Exit the loop since all subsequent calls to QueryAuditProof | 388 // Exit the loop since all subsequent calls to QueryAuditProof |
367 // will be throttled. | 389 // will be throttled. |
368 break; | 390 break; |
369 } else if (result == net::ERR_NAME_RESOLUTION_FAILED) { | 391 } else if (result == net::ERR_NAME_RESOLUTION_FAILED) { |
370 LogInclusionCheckResult(DNS_QUERY_NOT_POSSIBLE); | 392 LogInclusionCheckResult(DNS_QUERY_NOT_POSSIBLE); |
393 LogAuditResultToNetLog(it->first, false); | |
371 // Lookup failed due to bad DNS configuration, erase the entry and | 394 // Lookup failed due to bad DNS configuration, erase the entry and |
372 // continue to the next one. | 395 // continue to the next one. |
373 it = pending_entries_.erase(it); | 396 it = pending_entries_.erase(it); |
374 // Break here if it's the last entry to avoid |it| being incremented | 397 // Break here if it's the last entry to avoid |it| being incremented |
375 // by the for loop. | 398 // by the for loop. |
376 if (it == pending_entries_.end()) | 399 if (it == pending_entries_.end()) |
377 break; | 400 break; |
378 } else { | 401 } else { |
379 // BUG: an invalid argument was provided or an unexpected error | 402 // BUG: an invalid argument was provided or an unexpected error |
380 // was returned from LogDnsClient. | 403 // was returned from LogDnsClient. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
412 int net_error) { | 435 int net_error) { |
413 auto it = pending_entries_.find(entry); | 436 auto it = pending_entries_.find(entry); |
414 // The entry may not be present if it was evacuated due to low memory | 437 // The entry may not be present if it was evacuated due to low memory |
415 // pressure. | 438 // pressure. |
416 if (it == pending_entries_.end()) | 439 if (it == pending_entries_.end()) |
417 return; | 440 return; |
418 | 441 |
419 DCHECK_EQ(it->second.state, INCLUSION_PROOF_REQUESTED); | 442 DCHECK_EQ(it->second.state, INCLUSION_PROOF_REQUESTED); |
420 | 443 |
421 if (net_error != net::OK) { | 444 if (net_error != net::OK) { |
422 // XXX(eranm): Should failures be cached? For now, they are not. | 445 // XXX(eranm): Should failures be cached? For now, they are not. |
eroman
2017/01/31 19:24:25
Can you update this to TODO(eranm) ?
Eran Messeri
2017/01/31 21:18:25
Done.
| |
423 LogInclusionCheckResult(FAILED_GETTING_INCLUSION_PROOF); | 446 LogInclusionCheckResult(FAILED_GETTING_INCLUSION_PROOF); |
447 LogAuditResultToNetLog(entry, false); | |
424 pending_entries_.erase(it); | 448 pending_entries_.erase(it); |
425 return; | 449 return; |
426 } | 450 } |
427 | 451 |
428 std::string leaf_hash(reinterpret_cast<const char*>(entry.leaf_hash.data), | 452 std::string leaf_hash(reinterpret_cast<const char*>(entry.leaf_hash.data), |
429 crypto::kSHA256Length); | 453 crypto::kSHA256Length); |
430 | 454 |
431 bool verified = ct_log_->VerifyAuditProof(it->second.proof, | 455 bool verified = ct_log_->VerifyAuditProof(it->second.proof, |
432 it->second.root_hash, leaf_hash); | 456 it->second.root_hash, leaf_hash); |
457 LogAuditResultToNetLog(entry, verified); | |
433 | 458 |
434 if (!verified) { | 459 if (!verified) { |
435 LogInclusionCheckResult(GOT_INVALID_INCLUSION_PROOF); | 460 LogInclusionCheckResult(GOT_INVALID_INCLUSION_PROOF); |
436 } else { | 461 } else { |
437 LogInclusionCheckResult(GOT_VALID_INCLUSION_PROOF); | 462 LogInclusionCheckResult(GOT_VALID_INCLUSION_PROOF); |
438 checked_entries_.Put(entry.leaf_hash, EntryAuditResult()); | 463 checked_entries_.Put(entry.leaf_hash, EntryAuditResult()); |
439 } | 464 } |
440 | 465 |
441 pending_entries_.erase(it); | 466 pending_entries_.erase(it); |
442 } | 467 } |
443 | 468 |
444 void SingleTreeTracker::OnMemoryPressure( | 469 void SingleTreeTracker::OnMemoryPressure( |
445 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { | 470 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { |
446 switch (memory_pressure_level) { | 471 switch (memory_pressure_level) { |
447 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE: | 472 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE: |
448 break; | 473 break; |
449 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL: | 474 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL: |
450 pending_entries_.clear(); | 475 pending_entries_.clear(); |
451 // Fall through to clearing the other cache. | 476 // Fall through to clearing the other cache. |
452 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE: | 477 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE: |
453 checked_entries_.Clear(); | 478 checked_entries_.Clear(); |
454 break; | 479 break; |
455 } | 480 } |
456 } | 481 } |
457 | 482 |
483 void SingleTreeTracker::LogAuditResultToNetLog(const EntryToAudit& entry, | |
484 bool success) { | |
485 net::NetLogParametersCallback net_log_callback = | |
486 base::Bind(&NetLogEntryAuditingEventCallback, &entry.leaf_hash, | |
487 ct_log_->key_id(), success); | |
488 | |
489 net_log_.AddEvent(net::NetLogEventType::CT_LOG_ENTRY_AUDITED, | |
490 net_log_callback); | |
491 } | |
492 | |
458 } // namespace certificate_transparency | 493 } // namespace certificate_transparency |
OLD | NEW |