| 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 |