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/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" |
| 11 #include "base/memory/ptr_util.h" |
11 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
12 #include "base/strings/string_util.h" | 13 #include "base/strings/string_util.h" |
13 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.h" |
14 #include "base/threading/thread_task_runner_handle.h" | 15 #include "base/threading/thread_task_runner_handle.h" |
15 #include "base/time/time.h" | 16 #include "base/time/time.h" |
16 #include "components/base32/base32.h" | 17 #include "components/base32/base32.h" |
17 #include "crypto/sha2.h" | 18 #include "crypto/sha2.h" |
18 #include "net/base/net_errors.h" | 19 #include "net/base/net_errors.h" |
19 #include "net/cert/merkle_audit_proof.h" | 20 #include "net/cert/merkle_audit_proof.h" |
20 #include "net/dns/dns_client.h" | 21 #include "net/dns/dns_client.h" |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 | 91 |
91 for (size_t i = 0; i < audit_path.size(); i += crypto::kSHA256Length) { | 92 for (size_t i = 0; i < audit_path.size(); i += crypto::kSHA256Length) { |
92 proof->nodes.push_back(audit_path.substr(i, crypto::kSHA256Length)); | 93 proof->nodes.push_back(audit_path.substr(i, crypto::kSHA256Length)); |
93 } | 94 } |
94 | 95 |
95 return true; | 96 return true; |
96 } | 97 } |
97 | 98 |
98 } // namespace | 99 } // namespace |
99 | 100 |
| 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 |
| 103 // series of DNS requests to get the nodes of the proof. |
| 104 class LogDnsClient::AuditProofQuery { |
| 105 public: |
| 106 using CompletionCallback = |
| 107 base::Callback<void(int net_error, AuditProofQuery* query)>; |
| 108 |
| 109 // The LogDnsClient is guaranteed to outlive the AuditProofQuery, so it's safe |
| 110 // to leave ownership of |dns_client| with LogDnsClient. |
| 111 AuditProofQuery(net::DnsClient* dns_client, |
| 112 const std::string& domain_for_log, |
| 113 uint64_t tree_size, |
| 114 const net::NetLogWithSource& net_log); |
| 115 |
| 116 // Begins the process of getting an audit proof for the CT log entry with a |
| 117 // leaf hash of |leaf_hash|. The |callback| will be invoked when finished. |
| 118 void Start(base::StringPiece leaf_hash, CompletionCallback callback); |
| 119 |
| 120 // Transfers the audit proof to the caller. |
| 121 // Only call this once the query has completed, otherwise the proof will be |
| 122 // incomplete. |
| 123 std::unique_ptr<net::ct::MerkleAuditProof> TakeProof(); |
| 124 |
| 125 private: |
| 126 // Requests the leaf index of the CT log entry with |leaf_hash|. |
| 127 void QueryLeafIndex(base::StringPiece leaf_hash); |
| 128 |
| 129 // Processes the response to a leaf index request. |
| 130 // The received leaf index will be added to the proof. |
| 131 void QueryLeafIndexComplete(net::DnsTransaction* transaction, |
| 132 int net_error, |
| 133 const net::DnsResponse* response); |
| 134 |
| 135 // Queries a CT log to retrieve part of an audit proof. The |node_index| |
| 136 // indicates which node of the audit proof/ should be requested. The CT log |
| 137 // may return up to 7 nodes, starting from |node_index| (this is the maximum |
| 138 // that will fit in a DNS UDP packet). The nodes will be appended to the |
| 139 // proof. |
| 140 void QueryAuditProofNodes(uint64_t node_index); |
| 141 |
| 142 // Processes the response to an audit proof request. |
| 143 // This will contain some, but not necessarily all, of the audit proof nodes. |
| 144 void QueryAuditProofNodesComplete(net::DnsTransaction* transaction, |
| 145 int net_error, |
| 146 const net::DnsResponse* response); |
| 147 |
| 148 std::string domain_for_log_; |
| 149 // TODO(robpercival): Remove |tree_size| once |proof_| has a tree_size member. |
| 150 uint64_t tree_size_; |
| 151 std::unique_ptr<net::ct::MerkleAuditProof> proof_; |
| 152 CompletionCallback callback_; |
| 153 net::DnsClient* dns_client_; |
| 154 std::unique_ptr<net::DnsTransaction> current_dns_transaction_; |
| 155 net::NetLogWithSource net_log_; |
| 156 base::WeakPtrFactory<AuditProofQuery> weak_ptr_factory_; |
| 157 }; |
| 158 |
| 159 LogDnsClient::AuditProofQuery::AuditProofQuery( |
| 160 net::DnsClient* dns_client, |
| 161 const std::string& domain_for_log, |
| 162 uint64_t tree_size, |
| 163 const net::NetLogWithSource& net_log) |
| 164 : domain_for_log_(domain_for_log), |
| 165 tree_size_(tree_size), |
| 166 dns_client_(dns_client), |
| 167 net_log_(net_log), |
| 168 weak_ptr_factory_(this) { |
| 169 DCHECK(dns_client_); |
| 170 DCHECK(!domain_for_log_.empty()); |
| 171 } |
| 172 |
| 173 void LogDnsClient::AuditProofQuery::Start(base::StringPiece leaf_hash, |
| 174 CompletionCallback callback) { |
| 175 current_dns_transaction_.reset(); |
| 176 proof_ = base::MakeUnique<net::ct::MerkleAuditProof>(); |
| 177 callback_ = callback; |
| 178 QueryLeafIndex(leaf_hash); |
| 179 } |
| 180 |
| 181 std::unique_ptr<net::ct::MerkleAuditProof> |
| 182 LogDnsClient::AuditProofQuery::TakeProof() { |
| 183 return std::move(proof_); |
| 184 } |
| 185 |
| 186 void LogDnsClient::AuditProofQuery::QueryLeafIndex( |
| 187 base::StringPiece leaf_hash) { |
| 188 std::string encoded_leaf_hash = |
| 189 base32::Base32Encode(leaf_hash, base32::Base32EncodePolicy::OMIT_PADDING); |
| 190 DCHECK_EQ(encoded_leaf_hash.size(), 52u); |
| 191 |
| 192 std::string qname = base::StringPrintf( |
| 193 "%s.hash.%s.", encoded_leaf_hash.c_str(), domain_for_log_.data()); |
| 194 |
| 195 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory(); |
| 196 if (factory == nullptr) { |
| 197 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 198 FROM_HERE, base::Bind(callback_, net::Error::ERR_NAME_RESOLUTION_FAILED, |
| 199 base::Unretained(this))); |
| 200 return; |
| 201 } |
| 202 |
| 203 net::DnsTransactionFactory::CallbackType transaction_callback = |
| 204 base::Bind(&LogDnsClient::AuditProofQuery::QueryLeafIndexComplete, |
| 205 weak_ptr_factory_.GetWeakPtr()); |
| 206 |
| 207 current_dns_transaction_ = factory->CreateTransaction( |
| 208 qname, net::dns_protocol::kTypeTXT, transaction_callback, net_log_); |
| 209 |
| 210 current_dns_transaction_->Start(); |
| 211 } |
| 212 |
| 213 void LogDnsClient::AuditProofQuery::QueryLeafIndexComplete( |
| 214 net::DnsTransaction* transaction, |
| 215 int net_error, |
| 216 const net::DnsResponse* response) { |
| 217 // If we've received no response but no net::error either (shouldn't |
| 218 // happen), |
| 219 // report the response as invalid. |
| 220 if (response == nullptr && net_error == net::OK) { |
| 221 net_error = net::ERR_INVALID_RESPONSE; |
| 222 } |
| 223 |
| 224 if (net_error != net::OK) { |
| 225 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 226 FROM_HERE, base::Bind(callback_, net_error, base::Unretained(this))); |
| 227 return; |
| 228 } |
| 229 |
| 230 if (!ParseLeafIndex(*response, &proof_->leaf_index)) { |
| 231 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 232 FROM_HERE, base::Bind(callback_, net::ERR_DNS_MALFORMED_RESPONSE, |
| 233 base::Unretained(this))); |
| 234 return; |
| 235 } |
| 236 |
| 237 // Reject leaf index if it is out-of-range. |
| 238 // This indicates either: |
| 239 // a) the wrong tree_size was provided. |
| 240 // b) the wrong leaf hash was provided. |
| 241 // c) there is a bug server-side. |
| 242 // The first two are more likely, so return ERR_INVALID_ARGUMENT. |
| 243 if (proof_->leaf_index >= tree_size_) { |
| 244 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 245 FROM_HERE, base::Bind(callback_, net::ERR_INVALID_ARGUMENT, |
| 246 base::Unretained(this))); |
| 247 return; |
| 248 } |
| 249 |
| 250 // QueryAuditProof for the first batch of audit proof_ nodes (i.e. starting |
| 251 // from 0). |
| 252 QueryAuditProofNodes(0 /* start node index */); |
| 253 } |
| 254 |
| 255 void LogDnsClient::AuditProofQuery::QueryAuditProofNodes(uint64_t node_index) { |
| 256 DCHECK_LT(proof_->leaf_index, tree_size_); |
| 257 DCHECK_LT(node_index, |
| 258 net::ct::CalculateAuditPathLength(proof_->leaf_index, tree_size_)); |
| 259 |
| 260 std::string qname = base::StringPrintf( |
| 261 "%" PRIu64 ".%" PRIu64 ".%" PRIu64 ".tree.%s.", node_index, |
| 262 proof_->leaf_index, tree_size_, domain_for_log_.data()); |
| 263 |
| 264 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory(); |
| 265 if (factory == nullptr) { |
| 266 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 267 FROM_HERE, base::Bind(callback_, net::Error::ERR_NAME_RESOLUTION_FAILED, |
| 268 base::Unretained(this))); |
| 269 return; |
| 270 } |
| 271 |
| 272 net::DnsTransactionFactory::CallbackType transaction_callback = |
| 273 base::Bind(&LogDnsClient::AuditProofQuery::QueryAuditProofNodesComplete, |
| 274 weak_ptr_factory_.GetWeakPtr()); |
| 275 |
| 276 current_dns_transaction_ = factory->CreateTransaction( |
| 277 qname, net::dns_protocol::kTypeTXT, transaction_callback, net_log_); |
| 278 current_dns_transaction_->Start(); |
| 279 } |
| 280 |
| 281 void LogDnsClient::AuditProofQuery::QueryAuditProofNodesComplete( |
| 282 net::DnsTransaction* transaction, |
| 283 int net_error, |
| 284 const net::DnsResponse* response) { |
| 285 // If we receive no response but no net::error either (shouldn't happen), |
| 286 // report the response as invalid. |
| 287 if (response == nullptr && net_error == net::OK) { |
| 288 net_error = net::ERR_INVALID_RESPONSE; |
| 289 } |
| 290 |
| 291 if (net_error != net::OK) { |
| 292 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 293 FROM_HERE, base::Bind(callback_, net_error, base::Unretained(this))); |
| 294 return; |
| 295 } |
| 296 |
| 297 const uint64_t audit_path_length = |
| 298 net::ct::CalculateAuditPathLength(proof_->leaf_index, tree_size_); |
| 299 // The calculated |audit_path_length| can't ever be greater than 64, so |
| 300 // deriving the amount of memory to reserve from the untrusted |leaf_index| |
| 301 // is safe. |
| 302 proof_->nodes.reserve(audit_path_length); |
| 303 |
| 304 if (!ParseAuditPath(*response, proof_.get())) { |
| 305 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 306 FROM_HERE, base::Bind(callback_, net::ERR_DNS_MALFORMED_RESPONSE, |
| 307 base::Unretained(this))); |
| 308 return; |
| 309 } |
| 310 |
| 311 const uint64_t audit_path_nodes_received = proof_->nodes.size(); |
| 312 if (audit_path_nodes_received < audit_path_length) { |
| 313 QueryAuditProofNodes(audit_path_nodes_received); |
| 314 return; |
| 315 } |
| 316 |
| 317 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 318 FROM_HERE, base::Bind(callback_, net::OK, base::Unretained(this))); |
| 319 } |
| 320 |
100 LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client, | 321 LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client, |
101 const net::NetLogWithSource& net_log, | 322 const net::NetLogWithSource& net_log, |
102 size_t max_concurrent_queries) | 323 size_t max_concurrent_queries) |
103 : dns_client_(std::move(dns_client)), | 324 : dns_client_(std::move(dns_client)), |
104 net_log_(net_log), | 325 net_log_(net_log), |
105 max_concurrent_queries_(max_concurrent_queries), | 326 max_concurrent_queries_(max_concurrent_queries), |
106 weak_ptr_factory_(this) { | 327 weak_ptr_factory_(this) { |
107 CHECK(dns_client_); | 328 CHECK(dns_client_); |
108 net::NetworkChangeNotifier::AddDNSObserver(this); | 329 net::NetworkChangeNotifier::AddDNSObserver(this); |
109 UpdateDnsConfig(); | 330 UpdateDnsConfig(); |
110 } | 331 } |
111 | 332 |
112 LogDnsClient::~LogDnsClient() { | 333 LogDnsClient::~LogDnsClient() { |
113 net::NetworkChangeNotifier::RemoveDNSObserver(this); | 334 net::NetworkChangeNotifier::RemoveDNSObserver(this); |
114 } | 335 } |
115 | 336 |
116 void LogDnsClient::OnDNSChanged() { | 337 void LogDnsClient::OnDNSChanged() { |
117 UpdateDnsConfig(); | 338 UpdateDnsConfig(); |
118 } | 339 } |
119 | 340 |
120 void LogDnsClient::OnInitialDNSConfigRead() { | 341 void LogDnsClient::OnInitialDNSConfigRead() { |
121 UpdateDnsConfig(); | 342 UpdateDnsConfig(); |
122 } | 343 } |
123 | 344 |
124 void LogDnsClient::QueryLeafIndex(base::StringPiece domain_for_log, | |
125 base::StringPiece leaf_hash, | |
126 const LeafIndexCallback& callback) { | |
127 if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) { | |
128 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
129 FROM_HERE, base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, 0)); | |
130 return; | |
131 } | |
132 | |
133 if (HasMaxConcurrentQueriesInProgress()) { | |
134 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
135 FROM_HERE, | |
136 base::Bind(callback, net::Error::ERR_TEMPORARILY_THROTTLED, 0)); | |
137 return; | |
138 } | |
139 | |
140 std::string encoded_leaf_hash = | |
141 base32::Base32Encode(leaf_hash, base32::Base32EncodePolicy::OMIT_PADDING); | |
142 DCHECK_EQ(encoded_leaf_hash.size(), 52u); | |
143 | |
144 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory(); | |
145 if (factory == nullptr) { | |
146 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
147 FROM_HERE, | |
148 base::Bind(callback, net::Error::ERR_NAME_RESOLUTION_FAILED, 0)); | |
149 return; | |
150 } | |
151 | |
152 std::string qname = base::StringPrintf( | |
153 "%s.hash.%s.", encoded_leaf_hash.c_str(), domain_for_log.data()); | |
154 | |
155 net::DnsTransactionFactory::CallbackType transaction_callback = base::Bind( | |
156 &LogDnsClient::QueryLeafIndexComplete, weak_ptr_factory_.GetWeakPtr()); | |
157 | |
158 std::unique_ptr<net::DnsTransaction> dns_transaction = | |
159 factory->CreateTransaction(qname, net::dns_protocol::kTypeTXT, | |
160 transaction_callback, net_log_); | |
161 | |
162 dns_transaction->Start(); | |
163 leaf_index_queries_.push_back({std::move(dns_transaction), callback}); | |
164 } | |
165 | |
166 // The performance of this could be improved by sending all of the expected | 345 // The performance of this could be improved by sending all of the expected |
167 // queries up front. Each response can contain a maximum of 7 audit path nodes, | 346 // queries up front. Each response can contain a maximum of 7 audit path nodes, |
168 // so for an audit proof of size 20, it could send 3 queries (for nodes 0-6, | 347 // so for an audit proof of size 20, it could send 3 queries (for nodes 0-6, |
169 // 7-13 and 14-19) immediately. Currently, it sends only the first and then, | 348 // 7-13 and 14-19) immediately. Currently, it sends only the first and then, |
170 // based on the number of nodes received, sends the next query. The complexity | 349 // based on the number of nodes received, sends the next query. The complexity |
171 // of the code would increase though, as it would need to detect gaps in the | 350 // of the code would increase though, as it would need to detect gaps in the |
172 // audit proof caused by the server not responding with the anticipated number | 351 // audit proof caused by the server not responding with the anticipated number |
173 // of nodes. Ownership of the proof would need to change, as it would be shared | 352 // of nodes. Ownership of the proof would need to change, as it would be shared |
174 // between simultaneous DNS transactions. Throttling of queries would also need | 353 // between simultaneous DNS transactions. Throttling of queries would also need |
175 // to take into account this increase in parallelism. | 354 // to take into account this increase in parallelism. |
176 void LogDnsClient::QueryAuditProof(base::StringPiece domain_for_log, | 355 void LogDnsClient::QueryAuditProof(const std::string& domain_for_log, |
177 uint64_t leaf_index, | 356 base::StringPiece leaf_hash, |
178 uint64_t tree_size, | 357 uint64_t tree_size, |
179 const AuditProofCallback& callback) { | 358 const AuditProofCallback& callback) { |
180 if (domain_for_log.empty() || leaf_index >= tree_size) { | 359 if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) { |
181 base::ThreadTaskRunnerHandle::Get()->PostTask( | 360 base::ThreadTaskRunnerHandle::Get()->PostTask( |
182 FROM_HERE, | 361 FROM_HERE, |
183 base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, nullptr)); | 362 base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, nullptr)); |
184 return; | 363 return; |
185 } | 364 } |
186 | 365 |
187 if (HasMaxConcurrentQueriesInProgress()) { | 366 if (HasMaxConcurrentQueriesInProgress()) { |
188 base::ThreadTaskRunnerHandle::Get()->PostTask( | 367 base::ThreadTaskRunnerHandle::Get()->PostTask( |
189 FROM_HERE, | 368 FROM_HERE, |
190 base::Bind(callback, net::Error::ERR_TEMPORARILY_THROTTLED, nullptr)); | 369 base::Bind(callback, net::Error::ERR_TEMPORARILY_THROTTLED, nullptr)); |
191 return; | 370 return; |
192 } | 371 } |
193 | 372 |
194 std::unique_ptr<net::ct::MerkleAuditProof> proof( | 373 audit_proof_queries_.emplace_back(new AuditProofQuery( |
195 new net::ct::MerkleAuditProof); | 374 dns_client_.get(), domain_for_log, tree_size, net_log_)); |
196 proof->leaf_index = leaf_index; | |
197 // TODO(robpercival): Once a "tree_size" field is added to MerkleAuditProof, | |
198 // pass |tree_size| to QueryAuditProofNodes using that. | |
199 | 375 |
200 // Query for the first batch of audit proof nodes (i.e. starting from 0). | 376 AuditProofQuery::CompletionCallback internal_callback = |
201 QueryAuditProofNodes(std::move(proof), domain_for_log, tree_size, 0, | 377 base::Bind(&LogDnsClient::QueryAuditProofComplete, |
202 callback); | 378 weak_ptr_factory_.GetWeakPtr(), callback); |
| 379 |
| 380 audit_proof_queries_.back()->Start(leaf_hash, internal_callback); |
203 } | 381 } |
204 | 382 |
205 void LogDnsClient::QueryLeafIndexComplete(net::DnsTransaction* transaction, | 383 void LogDnsClient::QueryAuditProofComplete(const AuditProofCallback& callback, |
206 int net_error, | 384 int result, |
207 const net::DnsResponse* response) { | 385 AuditProofQuery* query) { |
208 auto query_iterator = | 386 DCHECK(query); |
209 std::find_if(leaf_index_queries_.begin(), leaf_index_queries_.end(), | |
210 [transaction](const Query<LeafIndexCallback>& query) { | |
211 return query.transaction.get() == transaction; | |
212 }); | |
213 if (query_iterator == leaf_index_queries_.end()) { | |
214 NOTREACHED(); | |
215 return; | |
216 } | |
217 const Query<LeafIndexCallback> query = std::move(*query_iterator); | |
218 leaf_index_queries_.erase(query_iterator); | |
219 | 387 |
220 // If we've received no response but no net::error either (shouldn't happen), | 388 std::unique_ptr<net::ct::MerkleAuditProof> proof; |
221 // report the response as invalid. | 389 if (result == net::OK) { |
222 if (response == nullptr && net_error == net::OK) { | 390 proof = query->TakeProof(); |
223 net_error = net::ERR_INVALID_RESPONSE; | |
224 } | 391 } |
225 | 392 |
226 if (net_error != net::OK) { | 393 // Finished with the query - destroy it. |
227 base::ThreadTaskRunnerHandle::Get()->PostTask( | 394 auto query_iterator = |
228 FROM_HERE, base::Bind(query.callback, net_error, 0)); | 395 std::find_if(audit_proof_queries_.begin(), audit_proof_queries_.end(), |
229 return; | 396 [query](const std::unique_ptr<AuditProofQuery>& p) { |
230 } | 397 return p.get() == query; |
231 | 398 }); |
232 uint64_t leaf_index; | 399 DCHECK(query_iterator != audit_proof_queries_.end()); |
233 if (!ParseLeafIndex(*response, &leaf_index)) { | 400 audit_proof_queries_.erase(query_iterator); |
234 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
235 FROM_HERE, | |
236 base::Bind(query.callback, net::ERR_DNS_MALFORMED_RESPONSE, 0)); | |
237 return; | |
238 } | |
239 | 401 |
240 base::ThreadTaskRunnerHandle::Get()->PostTask( | 402 base::ThreadTaskRunnerHandle::Get()->PostTask( |
241 FROM_HERE, base::Bind(query.callback, net::OK, leaf_index)); | 403 FROM_HERE, base::Bind(callback, result, base::Passed(&proof))); |
242 } | |
243 | |
244 void LogDnsClient::QueryAuditProofNodes( | |
245 std::unique_ptr<net::ct::MerkleAuditProof> proof, | |
246 base::StringPiece domain_for_log, | |
247 uint64_t tree_size, | |
248 uint64_t node_index, | |
249 const AuditProofCallback& callback) { | |
250 // Preconditions that should be guaranteed internally by this class. | |
251 DCHECK(proof); | |
252 DCHECK(!domain_for_log.empty()); | |
253 DCHECK_LT(proof->leaf_index, tree_size); | |
254 DCHECK_LT(node_index, | |
255 net::ct::CalculateAuditPathLength(proof->leaf_index, tree_size)); | |
256 | |
257 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory(); | |
258 if (factory == nullptr) { | |
259 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
260 FROM_HERE, | |
261 base::Bind(callback, net::Error::ERR_NAME_RESOLUTION_FAILED, nullptr)); | |
262 return; | |
263 } | |
264 | |
265 std::string qname = base::StringPrintf( | |
266 "%" PRIu64 ".%" PRIu64 ".%" PRIu64 ".tree.%s.", node_index, | |
267 proof->leaf_index, tree_size, domain_for_log.data()); | |
268 | |
269 net::DnsTransactionFactory::CallbackType transaction_callback = | |
270 base::Bind(&LogDnsClient::QueryAuditProofNodesComplete, | |
271 weak_ptr_factory_.GetWeakPtr(), base::Passed(std::move(proof)), | |
272 domain_for_log, tree_size); | |
273 | |
274 std::unique_ptr<net::DnsTransaction> dns_transaction = | |
275 factory->CreateTransaction(qname, net::dns_protocol::kTypeTXT, | |
276 transaction_callback, net_log_); | |
277 dns_transaction->Start(); | |
278 audit_proof_queries_.push_back({std::move(dns_transaction), callback}); | |
279 } | |
280 | |
281 void LogDnsClient::QueryAuditProofNodesComplete( | |
282 std::unique_ptr<net::ct::MerkleAuditProof> proof, | |
283 base::StringPiece domain_for_log, | |
284 uint64_t tree_size, | |
285 net::DnsTransaction* transaction, | |
286 int net_error, | |
287 const net::DnsResponse* response) { | |
288 // Preconditions that should be guaranteed internally by this class. | |
289 DCHECK(proof); | |
290 DCHECK(!domain_for_log.empty()); | |
291 | |
292 auto query_iterator = | |
293 std::find_if(audit_proof_queries_.begin(), audit_proof_queries_.end(), | |
294 [transaction](const Query<AuditProofCallback>& query) { | |
295 return query.transaction.get() == transaction; | |
296 }); | |
297 | |
298 if (query_iterator == audit_proof_queries_.end()) { | |
299 NOTREACHED(); | |
300 return; | |
301 } | |
302 const Query<AuditProofCallback> query = std::move(*query_iterator); | |
303 audit_proof_queries_.erase(query_iterator); | |
304 | |
305 // If we've received no response but no net::error either (shouldn't happen), | |
306 // report the response as invalid. | |
307 if (response == nullptr && net_error == net::OK) { | |
308 net_error = net::ERR_INVALID_RESPONSE; | |
309 } | |
310 | |
311 if (net_error != net::OK) { | |
312 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
313 FROM_HERE, base::Bind(query.callback, net_error, nullptr)); | |
314 return; | |
315 } | |
316 | |
317 const uint64_t audit_path_length = | |
318 net::ct::CalculateAuditPathLength(proof->leaf_index, tree_size); | |
319 proof->nodes.reserve(audit_path_length); | |
320 | |
321 if (!ParseAuditPath(*response, proof.get())) { | |
322 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
323 FROM_HERE, | |
324 base::Bind(query.callback, net::ERR_DNS_MALFORMED_RESPONSE, nullptr)); | |
325 return; | |
326 } | |
327 | |
328 const uint64_t audit_path_nodes_received = proof->nodes.size(); | |
329 if (audit_path_nodes_received < audit_path_length) { | |
330 QueryAuditProofNodes(std::move(proof), domain_for_log, tree_size, | |
331 audit_path_nodes_received, query.callback); | |
332 return; | |
333 } | |
334 | |
335 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
336 FROM_HERE, | |
337 base::Bind(query.callback, net::OK, base::Passed(std::move(proof)))); | |
338 } | 404 } |
339 | 405 |
340 bool LogDnsClient::HasMaxConcurrentQueriesInProgress() const { | 406 bool LogDnsClient::HasMaxConcurrentQueriesInProgress() const { |
341 const size_t queries_in_progress = | |
342 leaf_index_queries_.size() + audit_proof_queries_.size(); | |
343 | |
344 return max_concurrent_queries_ != 0 && | 407 return max_concurrent_queries_ != 0 && |
345 queries_in_progress >= max_concurrent_queries_; | 408 audit_proof_queries_.size() >= max_concurrent_queries_; |
346 } | 409 } |
347 | 410 |
348 void LogDnsClient::UpdateDnsConfig() { | 411 void LogDnsClient::UpdateDnsConfig() { |
349 net::DnsConfig config; | 412 net::DnsConfig config; |
350 net::NetworkChangeNotifier::GetDnsConfig(&config); | 413 net::NetworkChangeNotifier::GetDnsConfig(&config); |
351 if (config.IsValid()) | 414 if (config.IsValid()) |
352 dns_client_->SetConfig(config); | 415 dns_client_->SetConfig(config); |
353 } | 416 } |
354 | 417 |
355 } // namespace certificate_transparency | 418 } // namespace certificate_transparency |
OLD | NEW |