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/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/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
10 #include "base/location.h" | 10 #include "base/location.h" |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 | 100 |
101 // Encapsulates the state machine required to get an audit proof from a Merkle | 101 // Encapsulates the state machine required to get an audit proof from a Merkle |
102 // leaf hash. This requires a DNS request to obtain the leaf index, then a | 102 // leaf hash. This requires a DNS request to obtain the leaf index, then a |
103 // series of DNS requests to get the nodes of the proof. | 103 // series of DNS requests to get the nodes of the proof. |
104 class LogDnsClient::AuditProofQuery { | 104 class LogDnsClient::AuditProofQuery { |
105 public: | 105 public: |
106 // The LogDnsClient is guaranteed to outlive the AuditProofQuery, so it's safe | 106 // The LogDnsClient is guaranteed to outlive the AuditProofQuery, so it's safe |
107 // to leave ownership of |dns_client| with LogDnsClient. | 107 // to leave ownership of |dns_client| with LogDnsClient. |
108 AuditProofQuery(net::DnsClient* dns_client, | 108 AuditProofQuery(net::DnsClient* dns_client, |
109 const std::string& domain_for_log, | 109 const std::string& domain_for_log, |
110 uint64_t tree_size, | |
111 const net::NetLogWithSource& net_log); | 110 const net::NetLogWithSource& net_log); |
112 | 111 |
113 // Begins the process of getting an audit |proof| for the CT log entry with a | 112 // Begins the process of getting an audit proof for the CT log entry with a |
114 // leaf hash of |leaf_hash|. If it cannot be obtained synchronously, | 113 // leaf hash of |leaf_hash|. The proof will be for a tree of size |tree_size|. |
115 // net::ERR_IO_PENDING will be returned and |callback| will be invoked when | 114 // If it cannot be obtained synchronously, net::ERR_IO_PENDING will be |
116 // the operation has completed asynchronously. | 115 // returned and |callback| will be invoked when the operation has completed |
117 // Ownership of |proof| remains with the caller, and it must not be deleted | 116 // asynchronously. Ownership of |proof| remains with the caller, and it must |
118 // until the operation is complete. | 117 // not be deleted until the operation is complete. |
119 net::Error Start(std::string leaf_hash, | 118 net::Error Start(std::string leaf_hash, |
| 119 uint64_t tree_size, |
120 const net::CompletionCallback& callback, | 120 const net::CompletionCallback& callback, |
121 net::ct::MerkleAuditProof* proof); | 121 net::ct::MerkleAuditProof* out_proof); |
122 | 122 |
123 private: | 123 private: |
124 enum class State { | 124 enum class State { |
125 NONE, | 125 NONE, |
126 REQUEST_LEAF_INDEX, | 126 REQUEST_LEAF_INDEX, |
127 REQUEST_LEAF_INDEX_COMPLETE, | 127 REQUEST_LEAF_INDEX_COMPLETE, |
128 REQUEST_AUDIT_PROOF_NODES, | 128 REQUEST_AUDIT_PROOF_NODES, |
129 REQUEST_AUDIT_PROOF_NODES_COMPLETE, | 129 REQUEST_AUDIT_PROOF_NODES_COMPLETE, |
130 }; | 130 }; |
131 | 131 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
171 // Returns true if the request could be started. | 171 // Returns true if the request could be started. |
172 // OnDnsTransactionComplete() will be invoked with the result of the request. | 172 // OnDnsTransactionComplete() will be invoked with the result of the request. |
173 bool StartDnsTransaction(const std::string& qname); | 173 bool StartDnsTransaction(const std::string& qname); |
174 | 174 |
175 // The next state that this query will enter. | 175 // The next state that this query will enter. |
176 State next_state_; | 176 State next_state_; |
177 // The DNS domain of the CT log that is being queried. | 177 // The DNS domain of the CT log that is being queried. |
178 std::string domain_for_log_; | 178 std::string domain_for_log_; |
179 // The Merkle leaf hash of the CT log entry an audit proof is required for. | 179 // The Merkle leaf hash of the CT log entry an audit proof is required for. |
180 std::string leaf_hash_; | 180 std::string leaf_hash_; |
181 // The size of the CT log's tree, from which the proof is requested. | |
182 // TODO(robpercival): Remove |tree_size| once |proof_| has a tree_size member. | |
183 uint64_t tree_size_; | |
184 // The audit proof to populate. | 181 // The audit proof to populate. |
185 net::ct::MerkleAuditProof* proof_; | 182 net::ct::MerkleAuditProof* proof_; |
186 // The callback to invoke when the query is complete. | 183 // The callback to invoke when the query is complete. |
187 net::CompletionCallback callback_; | 184 net::CompletionCallback callback_; |
188 // The DnsClient to use for sending DNS requests to the CT log. | 185 // The DnsClient to use for sending DNS requests to the CT log. |
189 net::DnsClient* dns_client_; | 186 net::DnsClient* dns_client_; |
190 // The most recent DNS request. Null if no DNS requests have been made. | 187 // The most recent DNS request. Null if no DNS requests have been made. |
191 std::unique_ptr<net::DnsTransaction> current_dns_transaction_; | 188 std::unique_ptr<net::DnsTransaction> current_dns_transaction_; |
192 // The most recent DNS response. Only valid so long as the corresponding DNS | 189 // The most recent DNS response. Only valid so long as the corresponding DNS |
193 // request is stored in |current_dns_transaction_|. | 190 // request is stored in |current_dns_transaction_|. |
194 const net::DnsResponse* last_dns_response_; | 191 const net::DnsResponse* last_dns_response_; |
195 // The NetLog that DNS transactions will log to. | 192 // The NetLog that DNS transactions will log to. |
196 net::NetLogWithSource net_log_; | 193 net::NetLogWithSource net_log_; |
197 // Produces WeakPtrs to |this| for binding callbacks. | 194 // Produces WeakPtrs to |this| for binding callbacks. |
198 base::WeakPtrFactory<AuditProofQuery> weak_ptr_factory_; | 195 base::WeakPtrFactory<AuditProofQuery> weak_ptr_factory_; |
199 }; | 196 }; |
200 | 197 |
201 LogDnsClient::AuditProofQuery::AuditProofQuery( | 198 LogDnsClient::AuditProofQuery::AuditProofQuery( |
202 net::DnsClient* dns_client, | 199 net::DnsClient* dns_client, |
203 const std::string& domain_for_log, | 200 const std::string& domain_for_log, |
204 uint64_t tree_size, | |
205 const net::NetLogWithSource& net_log) | 201 const net::NetLogWithSource& net_log) |
206 : next_state_(State::NONE), | 202 : next_state_(State::NONE), |
207 domain_for_log_(domain_for_log), | 203 domain_for_log_(domain_for_log), |
208 tree_size_(tree_size), | |
209 dns_client_(dns_client), | 204 dns_client_(dns_client), |
210 net_log_(net_log), | 205 net_log_(net_log), |
211 weak_ptr_factory_(this) { | 206 weak_ptr_factory_(this) { |
212 DCHECK(dns_client_); | 207 DCHECK(dns_client_); |
213 DCHECK(!domain_for_log_.empty()); | 208 DCHECK(!domain_for_log_.empty()); |
214 } | 209 } |
215 | 210 |
216 // |leaf_hash| is not a const-ref to allow callers to std::move that string into | 211 // |leaf_hash| is not a const-ref to allow callers to std::move that string into |
217 // the method, avoiding the need to make a copy. | 212 // the method, avoiding the need to make a copy. |
218 net::Error LogDnsClient::AuditProofQuery::Start( | 213 net::Error LogDnsClient::AuditProofQuery::Start( |
219 std::string leaf_hash, | 214 std::string leaf_hash, |
| 215 uint64_t tree_size, |
220 const net::CompletionCallback& callback, | 216 const net::CompletionCallback& callback, |
221 net::ct::MerkleAuditProof* proof) { | 217 net::ct::MerkleAuditProof* proof) { |
222 // It should not already be in progress. | 218 // It should not already be in progress. |
223 DCHECK_EQ(State::NONE, next_state_); | 219 DCHECK_EQ(State::NONE, next_state_); |
224 proof_ = proof; | 220 proof_ = proof; |
| 221 proof_->tree_size = tree_size; |
225 leaf_hash_ = std::move(leaf_hash); | 222 leaf_hash_ = std::move(leaf_hash); |
226 callback_ = callback; | 223 callback_ = callback; |
227 // The first step in the query is to request the leaf index corresponding to | 224 // The first step in the query is to request the leaf index corresponding to |
228 // |leaf_hash| from the CT log. | 225 // |leaf_hash| from the CT log. |
229 next_state_ = State::REQUEST_LEAF_INDEX; | 226 next_state_ = State::REQUEST_LEAF_INDEX; |
230 // Begin the state machine. | 227 // Begin the state machine. |
231 return DoLoop(net::OK); | 228 return DoLoop(net::OK); |
232 } | 229 } |
233 | 230 |
234 net::Error LogDnsClient::AuditProofQuery::DoLoop(net::Error result) { | 231 net::Error LogDnsClient::AuditProofQuery::DoLoop(net::Error result) { |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 if (!ParseLeafIndex(*last_dns_response_, &proof_->leaf_index)) { | 302 if (!ParseLeafIndex(*last_dns_response_, &proof_->leaf_index)) { |
306 return net::ERR_DNS_MALFORMED_RESPONSE; | 303 return net::ERR_DNS_MALFORMED_RESPONSE; |
307 } | 304 } |
308 | 305 |
309 // Reject leaf index if it is out-of-range. | 306 // Reject leaf index if it is out-of-range. |
310 // This indicates either: | 307 // This indicates either: |
311 // a) the wrong tree_size was provided. | 308 // a) the wrong tree_size was provided. |
312 // b) the wrong leaf hash was provided. | 309 // b) the wrong leaf hash was provided. |
313 // c) there is a bug server-side. | 310 // c) there is a bug server-side. |
314 // The first two are more likely, so return ERR_INVALID_ARGUMENT. | 311 // The first two are more likely, so return ERR_INVALID_ARGUMENT. |
315 if (proof_->leaf_index >= tree_size_) { | 312 if (proof_->leaf_index >= proof_->tree_size) { |
316 return net::ERR_INVALID_ARGUMENT; | 313 return net::ERR_INVALID_ARGUMENT; |
317 } | 314 } |
318 | 315 |
319 next_state_ = State::REQUEST_AUDIT_PROOF_NODES; | 316 next_state_ = State::REQUEST_AUDIT_PROOF_NODES; |
320 return net::OK; | 317 return net::OK; |
321 } | 318 } |
322 | 319 |
323 net::Error LogDnsClient::AuditProofQuery::RequestAuditProofNodes() { | 320 net::Error LogDnsClient::AuditProofQuery::RequestAuditProofNodes() { |
324 // Test pre-conditions (should be guaranteed by DNS response validation). | 321 // Test pre-conditions (should be guaranteed by DNS response validation). |
325 if (proof_->leaf_index >= tree_size_ || | 322 if (proof_->leaf_index >= proof_->tree_size || |
326 proof_->nodes.size() >= | 323 proof_->nodes.size() >= net::ct::CalculateAuditPathLength( |
327 net::ct::CalculateAuditPathLength(proof_->leaf_index, tree_size_)) { | 324 proof_->leaf_index, proof_->tree_size)) { |
328 return net::ERR_UNEXPECTED; | 325 return net::ERR_UNEXPECTED; |
329 } | 326 } |
330 | 327 |
331 std::string qname = base::StringPrintf( | 328 std::string qname = base::StringPrintf( |
332 "%zu.%" PRIu64 ".%" PRIu64 ".tree.%s.", proof_->nodes.size(), | 329 "%zu.%" PRIu64 ".%" PRIu64 ".tree.%s.", proof_->nodes.size(), |
333 proof_->leaf_index, tree_size_, domain_for_log_.c_str()); | 330 proof_->leaf_index, proof_->tree_size, domain_for_log_.c_str()); |
334 | 331 |
335 if (!StartDnsTransaction(qname)) { | 332 if (!StartDnsTransaction(qname)) { |
336 return net::ERR_NAME_RESOLUTION_FAILED; | 333 return net::ERR_NAME_RESOLUTION_FAILED; |
337 } | 334 } |
338 | 335 |
339 next_state_ = State::REQUEST_AUDIT_PROOF_NODES_COMPLETE; | 336 next_state_ = State::REQUEST_AUDIT_PROOF_NODES_COMPLETE; |
340 return net::ERR_IO_PENDING; | 337 return net::ERR_IO_PENDING; |
341 } | 338 } |
342 | 339 |
343 net::Error LogDnsClient::AuditProofQuery::RequestAuditProofNodesComplete( | 340 net::Error LogDnsClient::AuditProofQuery::RequestAuditProofNodesComplete( |
344 net::Error result) { | 341 net::Error result) { |
345 if (result != net::OK) { | 342 if (result != net::OK) { |
346 return result; | 343 return result; |
347 } | 344 } |
348 | 345 |
349 const uint64_t audit_path_length = | 346 const uint64_t audit_path_length = |
350 net::ct::CalculateAuditPathLength(proof_->leaf_index, tree_size_); | 347 net::ct::CalculateAuditPathLength(proof_->leaf_index, proof_->tree_size); |
351 | 348 |
352 // The calculated |audit_path_length| can't ever be greater than 64, so | 349 // The calculated |audit_path_length| can't ever be greater than 64, so |
353 // deriving the amount of memory to reserve from the untrusted |leaf_index| | 350 // deriving the amount of memory to reserve from the untrusted |leaf_index| |
354 // is safe. | 351 // is safe. |
355 proof_->nodes.reserve(audit_path_length); | 352 proof_->nodes.reserve(audit_path_length); |
356 | 353 |
357 DCHECK(last_dns_response_); | 354 DCHECK(last_dns_response_); |
358 if (!ParseAuditPath(*last_dns_response_, proof_)) { | 355 if (!ParseAuditPath(*last_dns_response_, proof_)) { |
359 return net::ERR_DNS_MALFORMED_RESPONSE; | 356 return net::ERR_DNS_MALFORMED_RESPONSE; |
360 } | 357 } |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
425 | 422 |
426 if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) { | 423 if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) { |
427 return net::ERR_INVALID_ARGUMENT; | 424 return net::ERR_INVALID_ARGUMENT; |
428 } | 425 } |
429 | 426 |
430 if (HasMaxConcurrentQueriesInProgress()) { | 427 if (HasMaxConcurrentQueriesInProgress()) { |
431 return net::ERR_TEMPORARILY_THROTTLED; | 428 return net::ERR_TEMPORARILY_THROTTLED; |
432 } | 429 } |
433 | 430 |
434 AuditProofQuery* query = new AuditProofQuery( | 431 AuditProofQuery* query = new AuditProofQuery( |
435 dns_client_.get(), domain_for_log.as_string(), tree_size, net_log_); | 432 dns_client_.get(), domain_for_log.as_string(), net_log_); |
436 // Transfers ownership of |query| to |audit_proof_queries_|. | 433 // Transfers ownership of |query| to |audit_proof_queries_|. |
437 audit_proof_queries_.emplace_back(query); | 434 audit_proof_queries_.emplace_back(query); |
438 | 435 |
439 return query->Start(std::move(leaf_hash), | 436 return query->Start(std::move(leaf_hash), tree_size, |
440 base::Bind(&LogDnsClient::QueryAuditProofComplete, | 437 base::Bind(&LogDnsClient::QueryAuditProofComplete, |
441 weak_ptr_factory_.GetWeakPtr(), | 438 weak_ptr_factory_.GetWeakPtr(), |
442 base::Unretained(query), callback), | 439 base::Unretained(query), callback), |
443 proof); | 440 proof); |
444 } | 441 } |
445 | 442 |
446 void LogDnsClient::QueryAuditProofComplete( | 443 void LogDnsClient::QueryAuditProofComplete( |
447 AuditProofQuery* query, | 444 AuditProofQuery* query, |
448 const net::CompletionCallback& callback, | 445 const net::CompletionCallback& callback, |
449 int net_error) { | 446 int net_error) { |
(...skipping 23 matching lines...) Expand all Loading... |
473 } | 470 } |
474 | 471 |
475 void LogDnsClient::UpdateDnsConfig() { | 472 void LogDnsClient::UpdateDnsConfig() { |
476 net::DnsConfig config; | 473 net::DnsConfig config; |
477 net::NetworkChangeNotifier::GetDnsConfig(&config); | 474 net::NetworkChangeNotifier::GetDnsConfig(&config); |
478 if (config.IsValid()) | 475 if (config.IsValid()) |
479 dns_client_->SetConfig(config); | 476 dns_client_->SetConfig(config); |
480 } | 477 } |
481 | 478 |
482 } // namespace certificate_transparency | 479 } // namespace certificate_transparency |
OLD | NEW |