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

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

Issue 2367523002: Merge LogDnsClient's QueryLeafIndex and QueryAuditProof methods (Closed)
Patch Set: Created 4 years, 3 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/log_dns_client.h" 5 #include "components/certificate_transparency/log_dns_client.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/format_macros.h" 8 #include "base/format_macros.h"
9 #include "base/location.h" 9 #include "base/location.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 74
75 for (size_t i = 0; i < audit_path.size(); i += crypto::kSHA256Length) { 75 for (size_t i = 0; i < audit_path.size(); i += crypto::kSHA256Length) {
76 proof->nodes.push_back(audit_path.substr(i, crypto::kSHA256Length)); 76 proof->nodes.push_back(audit_path.substr(i, crypto::kSHA256Length));
77 } 77 }
78 78
79 return true; 79 return true;
80 } 80 }
81 81
82 } // namespace 82 } // namespace
83 83
84 struct LogDnsClient::Query
85 {
86 std::unique_ptr<net::DnsTransaction> transaction;
87 AuditProofCallback callback;
88 };
89
84 LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client, 90 LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client,
85 const net::BoundNetLog& net_log, 91 const net::BoundNetLog& net_log,
86 size_t max_concurrent_queries) 92 size_t max_concurrent_queries)
87 : dns_client_(std::move(dns_client)), 93 : dns_client_(std::move(dns_client)),
88 net_log_(net_log), 94 net_log_(net_log),
89 max_concurrent_queries_(max_concurrent_queries), 95 max_concurrent_queries_(max_concurrent_queries),
90 weak_ptr_factory_(this) { 96 weak_ptr_factory_(this) {
91 CHECK(dns_client_); 97 CHECK(dns_client_);
92 net::NetworkChangeNotifier::AddDNSObserver(this); 98 net::NetworkChangeNotifier::AddDNSObserver(this);
93 UpdateDnsConfig(); 99 UpdateDnsConfig();
94 } 100 }
95 101
96 LogDnsClient::~LogDnsClient() { 102 LogDnsClient::~LogDnsClient() {
97 net::NetworkChangeNotifier::RemoveDNSObserver(this); 103 net::NetworkChangeNotifier::RemoveDNSObserver(this);
98 } 104 }
99 105
100 void LogDnsClient::OnDNSChanged() { 106 void LogDnsClient::OnDNSChanged() {
101 UpdateDnsConfig(); 107 UpdateDnsConfig();
102 } 108 }
103 109
104 void LogDnsClient::OnInitialDNSConfigRead() { 110 void LogDnsClient::OnInitialDNSConfigRead() {
105 UpdateDnsConfig(); 111 UpdateDnsConfig();
106 } 112 }
107 113
108 void LogDnsClient::QueryLeafIndex(base::StringPiece domain_for_log,
109 base::StringPiece leaf_hash,
110 const LeafIndexCallback& callback) {
111 if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) {
112 base::ThreadTaskRunnerHandle::Get()->PostTask(
113 FROM_HERE, base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, 0));
114 return;
115 }
116
117 if (HasMaxConcurrentQueriesInProgress()) {
118 base::ThreadTaskRunnerHandle::Get()->PostTask(
119 FROM_HERE,
120 base::Bind(callback, net::Error::ERR_TEMPORARILY_THROTTLED, 0));
121 return;
122 }
123
124 std::string encoded_leaf_hash =
125 base32::Base32Encode(leaf_hash, base32::Base32EncodePolicy::OMIT_PADDING);
126 DCHECK_EQ(encoded_leaf_hash.size(), 52u);
127
128 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory();
129 if (factory == nullptr) {
130 base::ThreadTaskRunnerHandle::Get()->PostTask(
131 FROM_HERE,
132 base::Bind(callback, net::Error::ERR_NAME_RESOLUTION_FAILED, 0));
133 return;
134 }
135
136 std::string qname = base::StringPrintf(
137 "%s.hash.%s.", encoded_leaf_hash.c_str(), domain_for_log.data());
138
139 net::DnsTransactionFactory::CallbackType transaction_callback = base::Bind(
140 &LogDnsClient::QueryLeafIndexComplete, weak_ptr_factory_.GetWeakPtr());
141
142 std::unique_ptr<net::DnsTransaction> dns_transaction =
143 factory->CreateTransaction(qname, net::dns_protocol::kTypeTXT,
144 transaction_callback, net_log_);
145
146 dns_transaction->Start();
147 leaf_index_queries_.push_back({std::move(dns_transaction), callback});
148 }
149
150 // The performance of this could be improved by sending all of the expected 114 // The performance of this could be improved by sending all of the expected
151 // queries up front. Each response can contain a maximum of 7 audit path nodes, 115 // queries up front. Each response can contain a maximum of 7 audit path nodes,
152 // so for an audit proof of size 20, it could send 3 queries (for nodes 0-6, 116 // so for an audit proof of size 20, it could send 3 queries (for nodes 0-6,
153 // 7-13 and 14-19) immediately. Currently, it sends only the first and then, 117 // 7-13 and 14-19) immediately. Currently, it sends only the first and then,
154 // based on the number of nodes received, sends the next query. The complexity 118 // based on the number of nodes received, sends the next query. The complexity
155 // of the code would increase though, as it would need to detect gaps in the 119 // of the code would increase though, as it would need to detect gaps in the
156 // audit proof caused by the server not responding with the anticipated number 120 // audit proof caused by the server not responding with the anticipated number
157 // of nodes. Ownership of the proof would need to change, as it would be shared 121 // of nodes. Ownership of the proof would need to change, as it would be shared
158 // between simultaneous DNS transactions. Throttling of queries would also need 122 // between simultaneous DNS transactions. Throttling of queries would also need
159 // to take into account this increase in parallelism. 123 // to take into account this increase in parallelism.
160 void LogDnsClient::QueryAuditProof(base::StringPiece domain_for_log, 124 void LogDnsClient::QueryAuditProof(base::StringPiece domain_for_log,
161 uint64_t leaf_index, 125 base::StringPiece leaf_hash,
162 uint64_t tree_size, 126 uint64_t tree_size,
163 const AuditProofCallback& callback) { 127 const AuditProofCallback& callback) {
164 if (domain_for_log.empty() || leaf_index >= tree_size) { 128 if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) {
165 base::ThreadTaskRunnerHandle::Get()->PostTask( 129 base::ThreadTaskRunnerHandle::Get()->PostTask(
166 FROM_HERE, 130 FROM_HERE,
167 base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, nullptr)); 131 base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, nullptr));
168 return; 132 return;
169 } 133 }
170 134
171 if (HasMaxConcurrentQueriesInProgress()) { 135 if (HasMaxConcurrentQueriesInProgress()) {
172 base::ThreadTaskRunnerHandle::Get()->PostTask( 136 base::ThreadTaskRunnerHandle::Get()->PostTask(
173 FROM_HERE, 137 FROM_HERE,
174 base::Bind(callback, net::Error::ERR_TEMPORARILY_THROTTLED, nullptr)); 138 base::Bind(callback, net::Error::ERR_TEMPORARILY_THROTTLED, nullptr));
175 return; 139 return;
176 } 140 }
177 141
178 std::unique_ptr<net::ct::MerkleAuditProof> proof( 142 QueryLeafIndex(domain_for_log, leaf_hash, tree_size, callback);
Eran Messeri 2016/09/23 12:59:31 Nit: domain_for_log and tree_size seem to always b
Rob Percival 2016/09/27 17:44:17 Done.
179 new net::ct::MerkleAuditProof);
180 proof->leaf_index = leaf_index;
181 // TODO(robpercival): Once a "tree_size" field is added to MerkleAuditProof,
182 // pass |tree_size| to QueryAuditProofNodes using that.
183
184 // Query for the first batch of audit proof nodes (i.e. starting from 0).
185 QueryAuditProofNodes(std::move(proof), domain_for_log, tree_size, 0,
186 callback);
187 } 143 }
188 144
189 void LogDnsClient::QueryLeafIndexComplete(net::DnsTransaction* transaction, 145 void LogDnsClient::QueryLeafIndex(base::StringPiece domain_for_log,
146 base::StringPiece leaf_hash,
147 uint64_t tree_size,
148 const AuditProofCallback& callback) {
149 std::string encoded_leaf_hash =
150 base32::Base32Encode(leaf_hash, base32::Base32EncodePolicy::OMIT_PADDING);
151 DCHECK_EQ(encoded_leaf_hash.size(), 52u);
152
153 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory();
154 if (factory == nullptr) {
155 base::ThreadTaskRunnerHandle::Get()->PostTask(
156 FROM_HERE,
157 base::Bind(callback, net::Error::ERR_NAME_RESOLUTION_FAILED, nullptr));
158 return;
159 }
160
161 std::string qname = base::StringPrintf(
162 "%s.hash.%s.", encoded_leaf_hash.c_str(), domain_for_log.data());
163
164 net::DnsTransactionFactory::CallbackType transaction_callback =
165 base::Bind(&LogDnsClient::QueryLeafIndexComplete,
166 weak_ptr_factory_.GetWeakPtr(), domain_for_log, tree_size);
Eran Messeri 2016/09/23 12:59:31 Here it seems like the tree_size and domain_for_lo
Rob Percival 2016/09/27 17:44:17 Done.
167
168 std::unique_ptr<net::DnsTransaction> dns_transaction =
169 factory->CreateTransaction(qname, net::dns_protocol::kTypeTXT,
170 transaction_callback, net_log_);
171
172 dns_transaction->Start();
173 audit_proof_queries_.push_back({std::move(dns_transaction), callback});
174 }
175
176 void LogDnsClient::QueryLeafIndexComplete(base::StringPiece domain_for_log,
177 uint64_t tree_size,
178 net::DnsTransaction* transaction,
190 int net_error, 179 int net_error,
191 const net::DnsResponse* response) { 180 const net::DnsResponse* response) {
192 auto query_iterator = 181 auto query_iterator =
193 std::find_if(leaf_index_queries_.begin(), leaf_index_queries_.end(), 182 std::find_if(audit_proof_queries_.begin(), audit_proof_queries_.end(),
194 [transaction](const Query<LeafIndexCallback>& query) { 183 [transaction](const Query& query) {
195 return query.transaction.get() == transaction; 184 return query.transaction.get() == transaction;
196 }); 185 });
197 if (query_iterator == leaf_index_queries_.end()) { 186 if (query_iterator == audit_proof_queries_.end()) {
198 NOTREACHED(); 187 NOTREACHED();
199 return; 188 return;
200 } 189 }
201 const Query<LeafIndexCallback> query = std::move(*query_iterator); 190 const Query query = std::move(*query_iterator);
202 leaf_index_queries_.erase(query_iterator); 191 audit_proof_queries_.erase(query_iterator);
203 192
204 // If we've received no response but no net::error either (shouldn't happen), 193 // If we've received no response but no net::error either (shouldn't happen),
205 // report the response as invalid. 194 // report the response as invalid.
206 if (response == nullptr && net_error == net::OK) { 195 if (response == nullptr && net_error == net::OK) {
207 net_error = net::ERR_INVALID_RESPONSE; 196 net_error = net::ERR_INVALID_RESPONSE;
208 } 197 }
209 198
210 if (net_error != net::OK) { 199 if (net_error != net::OK) {
211 base::ThreadTaskRunnerHandle::Get()->PostTask( 200 base::ThreadTaskRunnerHandle::Get()->PostTask(
212 FROM_HERE, base::Bind(query.callback, net_error, 0)); 201 FROM_HERE, base::Bind(query.callback, net_error, nullptr));
213 return; 202 return;
214 } 203 }
215 204
216 uint64_t leaf_index; 205 std::unique_ptr<net::ct::MerkleAuditProof> proof(
217 if (!ParseLeafIndex(*response, &leaf_index)) { 206 new net::ct::MerkleAuditProof);
207
208 if (!ParseLeafIndex(*response, &proof->leaf_index)) {
218 base::ThreadTaskRunnerHandle::Get()->PostTask( 209 base::ThreadTaskRunnerHandle::Get()->PostTask(
219 FROM_HERE, 210 FROM_HERE,
220 base::Bind(query.callback, net::ERR_DNS_MALFORMED_RESPONSE, 0)); 211 base::Bind(query.callback, net::ERR_DNS_MALFORMED_RESPONSE, nullptr));
221 return; 212 return;
222 } 213 }
223 214
224 base::ThreadTaskRunnerHandle::Get()->PostTask( 215 // Reject leaf index if it is out-of-range.
225 FROM_HERE, base::Bind(query.callback, net::OK, leaf_index)); 216 // This indicates either:
217 // a) the wrong tree_size was provided.
218 // b) the wrong leaf hash was provided.
219 // c) there is a bug server-side.
220 // The first two are more likely, so return ERR_INVALID_ARGUMENT.
221 if (proof->leaf_index >= tree_size) {
222 base::ThreadTaskRunnerHandle::Get()->PostTask(
223 FROM_HERE,
224 base::Bind(query.callback, net::ERR_INVALID_ARGUMENT, nullptr));
225 return;
226 }
227
228 // TODO(robpercival): Once a "tree_size" field is added to MerkleAuditProof,
229 // pass |tree_size| to QueryAuditProofNodes using that.
230
231 // Query for the first batch of audit proof nodes (i.e. starting from 0).
232 QueryAuditProofNodes(std::move(proof), domain_for_log, tree_size, 0,
Eran Messeri 2016/09/23 12:59:32 Document the 0: tree_size, 0 /* start node index *
Rob Percival 2016/09/27 17:44:17 Done.
233 query.callback);
226 } 234 }
227 235
228 void LogDnsClient::QueryAuditProofNodes( 236 void LogDnsClient::QueryAuditProofNodes(
229 std::unique_ptr<net::ct::MerkleAuditProof> proof, 237 std::unique_ptr<net::ct::MerkleAuditProof> proof,
230 base::StringPiece domain_for_log, 238 base::StringPiece domain_for_log,
231 uint64_t tree_size, 239 uint64_t tree_size,
232 uint64_t node_index, 240 uint64_t node_index,
233 const AuditProofCallback& callback) { 241 const AuditProofCallback& callback) {
234 // Preconditions that should be guaranteed internally by this class. 242 // Preconditions that should be guaranteed internally by this class.
235 DCHECK(proof); 243 DCHECK(proof);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 uint64_t tree_size, 276 uint64_t tree_size,
269 net::DnsTransaction* transaction, 277 net::DnsTransaction* transaction,
270 int net_error, 278 int net_error,
271 const net::DnsResponse* response) { 279 const net::DnsResponse* response) {
272 // Preconditions that should be guaranteed internally by this class. 280 // Preconditions that should be guaranteed internally by this class.
273 DCHECK(proof); 281 DCHECK(proof);
274 DCHECK(!domain_for_log.empty()); 282 DCHECK(!domain_for_log.empty());
275 283
276 auto query_iterator = 284 auto query_iterator =
277 std::find_if(audit_proof_queries_.begin(), audit_proof_queries_.end(), 285 std::find_if(audit_proof_queries_.begin(), audit_proof_queries_.end(),
278 [transaction](const Query<AuditProofCallback>& query) { 286 [transaction](const Query& query) {
279 return query.transaction.get() == transaction; 287 return query.transaction.get() == transaction;
280 }); 288 });
281 289
282 if (query_iterator == audit_proof_queries_.end()) { 290 if (query_iterator == audit_proof_queries_.end()) {
283 NOTREACHED(); 291 NOTREACHED();
284 return; 292 return;
285 } 293 }
286 const Query<AuditProofCallback> query = std::move(*query_iterator); 294 const Query query = std::move(*query_iterator);
287 audit_proof_queries_.erase(query_iterator); 295 audit_proof_queries_.erase(query_iterator);
288 296
289 // If we've received no response but no net::error either (shouldn't happen), 297 // If we've received no response but no net::error either (shouldn't happen),
290 // report the response as invalid. 298 // report the response as invalid.
291 if (response == nullptr && net_error == net::OK) { 299 if (response == nullptr && net_error == net::OK) {
292 net_error = net::ERR_INVALID_RESPONSE; 300 net_error = net::ERR_INVALID_RESPONSE;
293 } 301 }
294 302
295 if (net_error != net::OK) { 303 if (net_error != net::OK) {
296 base::ThreadTaskRunnerHandle::Get()->PostTask( 304 base::ThreadTaskRunnerHandle::Get()->PostTask(
(...skipping 18 matching lines...) Expand all
315 audit_path_nodes_received, query.callback); 323 audit_path_nodes_received, query.callback);
316 return; 324 return;
317 } 325 }
318 326
319 base::ThreadTaskRunnerHandle::Get()->PostTask( 327 base::ThreadTaskRunnerHandle::Get()->PostTask(
320 FROM_HERE, 328 FROM_HERE,
321 base::Bind(query.callback, net::OK, base::Passed(std::move(proof)))); 329 base::Bind(query.callback, net::OK, base::Passed(std::move(proof))));
322 } 330 }
323 331
324 bool LogDnsClient::HasMaxConcurrentQueriesInProgress() const { 332 bool LogDnsClient::HasMaxConcurrentQueriesInProgress() const {
325 const size_t queries_in_progress =
326 leaf_index_queries_.size() + audit_proof_queries_.size();
327
328 return max_concurrent_queries_ != 0 && 333 return max_concurrent_queries_ != 0 &&
329 queries_in_progress >= max_concurrent_queries_; 334 audit_proof_queries_.size() >= max_concurrent_queries_;
330 } 335 }
331 336
332 void LogDnsClient::UpdateDnsConfig() { 337 void LogDnsClient::UpdateDnsConfig() {
333 net::DnsConfig config; 338 net::DnsConfig config;
334 net::NetworkChangeNotifier::GetDnsConfig(&config); 339 net::NetworkChangeNotifier::GetDnsConfig(&config);
335 if (config.IsValid()) 340 if (config.IsValid())
336 dns_client_->SetConfig(config); 341 dns_client_->SetConfig(config);
337 } 342 }
338 343
339 } // namespace certificate_transparency 344 } // namespace certificate_transparency
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698