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

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: Marking comparator const Created 4 years, 5 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
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>
7 #include <utility> 9 #include <utility>
8 10
9 #include "net/cert/ct_log_verifier.h" 11 #include "net/cert/ct_log_verifier.h"
10 #include "net/cert/signed_certificate_timestamp.h" 12 #include "net/cert/signed_certificate_timestamp.h"
11 #include "net/cert/x509_certificate.h" 13 #include "net/cert/x509_certificate.h"
12 14
15 using net::ct::LogEntry;
16 using net::ct::MerkleTreeLeaf;
13 using net::ct::SignedTreeHead; 17 using net::ct::SignedTreeHead;
14 18
15 namespace certificate_transparency { 19 namespace certificate_transparency {
16 20
17 SingleTreeTracker::SingleTreeTracker( 21 SingleTreeTracker::SingleTreeTracker(
18 scoped_refptr<const net::CTLogVerifier> ct_log) 22 scoped_refptr<const net::CTLogVerifier> ct_log)
19 : ct_log_(std::move(ct_log)) {} 23 : ct_log_(std::move(ct_log)) {}
20 24
21 SingleTreeTracker::~SingleTreeTracker() {} 25 SingleTreeTracker::~SingleTreeTracker() {}
22 26
23 void SingleTreeTracker::OnSCTVerified( 27 void SingleTreeTracker::OnSCTVerified(
24 net::X509Certificate* cert, 28 net::X509Certificate* cert,
25 const net::ct::SignedCertificateTimestamp* sct) { 29 const net::ct::SignedCertificateTimestamp* sct) {
26 DCHECK_EQ(ct_log_->key_id(), sct->log_id); 30 DCHECK_EQ(ct_log_->key_id(), sct->log_id);
27 31
28 // SCT was previously observed, so its status should not be changed. 32 MerkleTreeLeaf leaf;
29 if (entries_status_.find(sct->timestamp) != entries_status_.end()) 33 if (!GetMerkleTreeLeaf(cert, sct, &leaf))
30 return; 34 return;
31 35
36 // SCT was previously observed, so its status should not be changed.
37 if (LeafAlreadyEncountered(leaf))
38 return;
39
40 SCTInclusionStatus state = SCT_NOT_OBSERVED;
41 const base::TimeDelta kMaximumMergeDelay = base::TimeDelta::FromHours(24);
32 // If there isn't a valid STH or the STH is not fresh enough to check 42 // If there isn't a valid STH or the STH is not fresh enough to check
33 // inclusion against, store the SCT for future checking and return. 43 // inclusion against, store the SCT for future checking and return.
34 if (verified_sth_.timestamp.is_null() || 44 if (verified_sth_.timestamp.is_null() ||
35 (verified_sth_.timestamp < 45 (verified_sth_.timestamp < (sct->timestamp + kMaximumMergeDelay))) {
36 (sct->timestamp + base::TimeDelta::FromHours(24)))) {
37 // TODO(eranm): UMA - how often SCTs have to wait for a newer STH for 46 // TODO(eranm): UMA - how often SCTs have to wait for a newer STH for
38 // inclusion check. 47 // inclusion check.
39 entries_status_.insert( 48 state = SCT_PENDING_NEWER_STH;
40 std::make_pair(sct->timestamp, SCT_PENDING_NEWER_STH)); 49 } else {
41 return; 50 // TODO(eranm): UMA - how often inclusion can be checked immediately.
51 state = SCT_PENDING_INCLUSION_CHECK;
42 } 52 }
43 53
44 // TODO(eranm): Check inclusion here. 54 // TODO(eranm): Check inclusion here, see https://crbug.com/624894
45 // TODO(eranm): UMA - how often inclusion can be checked immediately. 55 observed_entries_.insert(
46 entries_status_.insert( 56 std::make_pair(std::move(leaf), LeafState(state, base::Time::Now())));
47 std::make_pair(sct->timestamp, SCT_PENDING_INCLUSION_CHECK));
48 } 57 }
49 58
50 void SingleTreeTracker::NewSTHObserved(const SignedTreeHead& sth) { 59 void SingleTreeTracker::NewSTHObserved(const SignedTreeHead& sth) {
51 DCHECK_EQ(ct_log_->key_id(), sth.log_id); 60 DCHECK_EQ(ct_log_->key_id(), sth.log_id);
52 61
53 if (!ct_log_->VerifySignedTreeHead(sth)) { 62 if (!ct_log_->VerifySignedTreeHead(sth)) {
54 // Sanity check the STH; the caller should have done this 63 // Sanity check the STH; the caller should have done this
55 // already, but being paranoid here. 64 // already, but being paranoid here.
56 // NOTE(eranm): Right now there's no way to get rid of this check here 65 // NOTE(eranm): Right now there's no way to get rid of this check here
57 // as this is the first object in the chain that has an instance of 66 // as this is the first object in the chain that has an instance of
58 // a CTLogVerifier to verify the STH. 67 // a CTLogVerifier to verify the STH.
59 return; 68 return;
60 } 69 }
61 70
62 // In order to avoid updating |verified_sth_| to an older STH in case 71 // In order to avoid updating |verified_sth_| to an older STH in case
63 // an older STH is observed, check that either the observed STH is for 72 // an older STH is observed, check that either the observed STH is for
64 // a larger tree size or that it is for the same tree size but has 73 // a larger tree size or that it is for the same tree size but has
65 // a newer timestamp. 74 // a newer timestamp.
66 const bool sths_for_same_tree = verified_sth_.tree_size == sth.tree_size; 75 const bool sths_for_same_tree = verified_sth_.tree_size == sth.tree_size;
67 const bool received_sth_is_for_larger_tree = 76 const bool received_sth_is_for_larger_tree =
68 (verified_sth_.tree_size > sth.tree_size); 77 (verified_sth_.tree_size > sth.tree_size);
69 const bool received_sth_is_newer = (sth.timestamp > verified_sth_.timestamp); 78 const bool received_sth_is_newer = (sth.timestamp > verified_sth_.timestamp);
70 79
71 if (verified_sth_.timestamp.is_null() || received_sth_is_for_larger_tree || 80 if (verified_sth_.timestamp.is_null() || received_sth_is_for_larger_tree ||
72 (sths_for_same_tree && received_sth_is_newer)) { 81 (sths_for_same_tree && received_sth_is_newer)) {
73 verified_sth_ = sth; 82 verified_sth_ = sth;
74 } 83 }
75 84
76 // Find out which SCTs can now be checked for inclusion. 85 // Find out which SCTs can now be checked for inclusion.
77 // TODO(eranm): Keep two maps of MerkleTreeLeaf instances, one for leaves 86 auto first_entry_not_included = std::find_if(
78 // pending inclusion checks and one for leaves pending a new STH. 87 observed_entries_.begin(), observed_entries_.end(),
79 // The comparison function between MerkleTreeLeaf instances should use the 88 [&sth](const std::pair<const MerkleTreeLeaf&, const LeafState&> entry) {
80 // timestamp to determine sorting order, so that bulk moving from one 89 return entry.first.timestamp > sth.timestamp;
81 // map to the other can happen. 90 });
82 auto entry = entries_status_.begin(); 91 for (auto it = observed_entries_.begin(); it != first_entry_not_included;
83 while (entry != entries_status_.end() && 92 ++it) {
84 entry->first < verified_sth_.timestamp) { 93 it->second.SetState(SCT_PENDING_INCLUSION_CHECK);
85 entry->second = SCT_PENDING_INCLUSION_CHECK;
86 ++entry;
87 // TODO(eranm): Check inclusion here.
88 } 94 }
95
96 // TODO(eranm): Check inclusion here of entries that can now be checked.
97 // See https://crbug.com/624894
89 } 98 }
90 99
91 SingleTreeTracker::SCTInclusionStatus 100 SingleTreeTracker::SCTInclusionStatus
92 SingleTreeTracker::GetLogEntryInclusionStatus( 101 SingleTreeTracker::GetLogEntryInclusionStatus(
93 net::X509Certificate* cert, 102 net::X509Certificate* cert,
94 const net::ct::SignedCertificateTimestamp* sct) { 103 const net::ct::SignedCertificateTimestamp* sct) {
95 auto it = entries_status_.find(sct->timestamp); 104 MerkleTreeLeaf leaf;
105 if (!GetMerkleTreeLeaf(cert, sct, &leaf))
106 return SCT_NOT_OBSERVED;
96 107
97 return it == entries_status_.end() ? SCT_NOT_OBSERVED : it->second; 108 auto entry_iterator = observed_entries_.find(leaf);
109 if (entry_iterator == observed_entries_.end())
110 return SCT_NOT_OBSERVED;
111
112 return entry_iterator->second.State();
113 }
114
115 SingleTreeTracker::LeafState::LeafState(SCTInclusionStatus status,
116 const base::Time& observed_at)
117 : observed_at_(observed_at), state_(status) {}
118
119 SingleTreeTracker::LeafState::LeafState(const LeafState& other) = default;
120
121 SingleTreeTracker::LeafState::LeafState(LeafState&&) = default;
122
123 SingleTreeTracker::LeafState::~LeafState() = default;
124
125 void SingleTreeTracker::LeafState::SetLeafIndex(uint64_t index) {
126 // The leaf index may be set only once. Doing so more than once indicates
127 // a programming error where the index is fetched more than once for a given
128 // leaf.
129 DCHECK(!leaf_index_);
130 leaf_index_ = index;
131 }
132
133 bool SingleTreeTracker::LeafState::HasLeafIndex() const {
134 return bool(leaf_index_);
135 }
136
137 uint64_t SingleTreeTracker::LeafState::GetLeafIndex() const {
138 DCHECK(leaf_index_);
139 return leaf_index_.value();
140 }
141
142 const base::Time& SingleTreeTracker::LeafState::ObservedAt() const {
143 return observed_at_;
144 }
145
146 SingleTreeTracker::SCTInclusionStatus SingleTreeTracker::LeafState::State()
147 const {
148 return state_;
149 }
150
151 void SingleTreeTracker::LeafState::SetState(
152 SingleTreeTracker::SCTInclusionStatus state) {
153 DCHECK_NE(state, SCT_NOT_OBSERVED);
154 DCHECK_NE(state, state_);
155 state_ = state;
156 }
157
158 bool SingleTreeTracker::OrderByTimestamp::operator()(
159 const MerkleTreeLeaf& lhs,
160 const MerkleTreeLeaf& rhs) const {
161 // This comparator should only used for containers where leaves from
162 // different logs are not mixed.
163 DCHECK_EQ(lhs.log_id, rhs.log_id);
164
165 if (lhs.timestamp != rhs.timestamp)
166 return lhs.timestamp < rhs.timestamp;
167
168 const LogEntry& lhs_entry = lhs.log_entry;
169 const LogEntry& rhs_entry = rhs.log_entry;
170 if (lhs_entry.type != rhs_entry.type)
171 return lhs_entry.type < rhs_entry.type;
172
173 if (lhs_entry.type == LogEntry::LOG_ENTRY_TYPE_X509)
174 return lhs_entry.leaf_certificate < rhs_entry.leaf_certificate;
175
176 // lhs_entry.type == LOG_ENTRY_TYPE_PRECERT
177 return lhs_entry.tbs_certificate < rhs_entry.tbs_certificate &&
178 net::SHA256HashValueLessThan()(lhs_entry.issuer_key_hash,
179 rhs_entry.issuer_key_hash);
180 }
181
182 bool SingleTreeTracker::LeafAlreadyEncountered(const MerkleTreeLeaf& leaf) {
183 return observed_entries_.find(leaf) != observed_entries_.end();
98 } 184 }
99 185
100 } // namespace certificate_transparency 186 } // namespace certificate_transparency
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698