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

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

Issue 2369373002: LogDnsClient now returns some errors synchronously (Closed)
Patch Set: Addresses Eran's comments Created 4 years, 2 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/callback_helpers.h"
8 #include "base/format_macros.h" 9 #include "base/format_macros.h"
9 #include "base/location.h" 10 #include "base/location.h"
10 #include "base/logging.h" 11 #include "base/logging.h"
11 #include "base/memory/ptr_util.h" 12 #include "base/memory/ptr_util.h"
12 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h" 14 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h" 15 #include "base/strings/stringprintf.h"
15 #include "base/threading/thread_task_runner_handle.h" 16 #include "base/threading/thread_task_runner_handle.h"
16 #include "base/time/time.h" 17 #include "base/time/time.h"
17 #include "components/base32/base32.h" 18 #include "components/base32/base32.h"
18 #include "crypto/sha2.h" 19 #include "crypto/sha2.h"
19 #include "net/base/net_errors.h"
20 #include "net/cert/merkle_audit_proof.h" 20 #include "net/cert/merkle_audit_proof.h"
21 #include "net/dns/dns_client.h" 21 #include "net/dns/dns_client.h"
22 #include "net/dns/dns_config_service.h" 22 #include "net/dns/dns_config_service.h"
23 #include "net/dns/dns_protocol.h" 23 #include "net/dns/dns_protocol.h"
24 #include "net/dns/dns_response.h" 24 #include "net/dns/dns_response.h"
25 #include "net/dns/dns_transaction.h" 25 #include "net/dns/dns_transaction.h"
26 #include "net/dns/record_parsed.h" 26 #include "net/dns/record_parsed.h"
27 #include "net/dns/record_rdata.h" 27 #include "net/dns/record_rdata.h"
28 28
29 namespace certificate_transparency { 29 namespace certificate_transparency {
30 30
31 namespace { 31 namespace {
32 32
33 // Parses the DNS response and extracts a single string from the TXT RDATA. 33 // Parses the DNS response and extracts a single string from the TXT RDATA.
34 // If the response is malformed, not a TXT record, or contains any number of 34 // If the response is malformed, not a TXT record, or contains any number of
35 // strings other than 1, this returns false and extracts nothing. 35 // strings other than 1, this returns false and extracts nothing.
36 // Otherwise, it returns true and the extracted string is assigned to |*txt|. 36 // Otherwise, it returns true and the extracted string is assigned to |*txt|.
37 bool ParseTxtResponse(const net::DnsResponse& response, std::string* txt) { 37 bool ParseTxtResponse(const net::DnsResponse& response, std::string* txt) {
38 DCHECK(txt); 38 DCHECK(txt);
39 39
40 net::DnsRecordParser parser = response.Parser(); 40 net::DnsRecordParser parser = response.Parser();
41 // We don't care about the creation time, since we're going to throw 41 // We don't care about the creation time, since we're going to throw
42 // |parsed_record| away as soon as we've extracted the payload, so provide 42 // |parsed_record| away as soon as we've extracted the payload, so provide
43 // the "null" time. 43 // the "null" time.
44 auto parsed_record = net::RecordParsed::CreateFrom(&parser, base::Time()); 44 auto parsed_record = net::RecordParsed::CreateFrom(&parser, base::Time());
45 if (parsed_record == nullptr) 45 if (!parsed_record)
46 return false; 46 return false;
47 47
48 auto* txt_record = parsed_record->rdata<net::TxtRecordRdata>(); 48 auto* txt_record = parsed_record->rdata<net::TxtRecordRdata>();
49 if (txt_record == nullptr) 49 if (!txt_record)
50 return false; 50 return false;
51 51
52 // The draft CT-over-DNS RFC says that there MUST be exactly one string in the 52 // The draft CT-over-DNS RFC says that there MUST be exactly one string in the
53 // TXT record. 53 // TXT record.
54 if (txt_record->texts().size() != 1) 54 if (txt_record->texts().size() != 1)
55 return false; 55 return false;
56 56
57 *txt = txt_record->texts().front(); 57 *txt = txt_record->texts().front();
58 return true; 58 return true;
59 } 59 }
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
96 return true; 96 return true;
97 } 97 }
98 98
99 } // namespace 99 } // namespace
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 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 106 // The LogDnsClient is guaranteed to outlive the AuditProofQuery, so it's safe
110 // to leave ownership of |dns_client| with LogDnsClient. 107 // to leave ownership of |dns_client| with LogDnsClient.
111 AuditProofQuery(net::DnsClient* dns_client, 108 AuditProofQuery(net::DnsClient* dns_client,
112 const std::string& domain_for_log, 109 const std::string& domain_for_log,
113 uint64_t tree_size, 110 uint64_t tree_size,
114 const net::NetLogWithSource& net_log); 111 const net::NetLogWithSource& net_log);
115 112
116 // Begins the process of getting an audit proof for the CT log entry with a 113 // 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. 114 // leaf hash of |leaf_hash|. If it cannot be obtained synchronously,
118 void Start(base::StringPiece leaf_hash, CompletionCallback callback); 115 // net::ERR_IO_PENDING will be returned and |callback| will be invoked when
119 116 // the operation has completed asynchronously.
120 // Transfers the audit proof to the caller. 117 // Ownership of |proof| remains with the caller, and it must not be deleted
121 // Only call this once the query has completed, otherwise the proof will be 118 // until the operation is complete.
122 // incomplete. 119 net::Error Start(std::string leaf_hash,
123 std::unique_ptr<net::ct::MerkleAuditProof> TakeProof(); 120 const net::CompletionCallback& callback,
121 net::ct::MerkleAuditProof* proof);
124 122
125 private: 123 private:
126 // Requests the leaf index of the CT log entry with |leaf_hash|. 124 enum class State {
127 void QueryLeafIndex(base::StringPiece leaf_hash); 125 NONE,
128 126 REQUEST_LEAF_INDEX,
129 // Processes the response to a leaf index request. 127 REQUEST_LEAF_INDEX_COMPLETE,
130 // The received leaf index will be added to the proof. 128 REQUEST_AUDIT_PROOF_NODES,
131 void QueryLeafIndexComplete(net::DnsTransaction* transaction, 129 REQUEST_AUDIT_PROOF_NODES_COMPLETE,
132 int net_error, 130 };
133 const net::DnsResponse* response); 131
134 132 net::Error DoLoop(net::Error result);
135 // Queries a CT log to retrieve part of an audit proof. The |node_index| 133
136 // indicates which node of the audit proof/ should be requested. The CT log 134 // When a DnsTransaction completes, store the response and resume the state
137 // may return up to 7 nodes, starting from |node_index| (this is the maximum 135 // machine. It is safe to store a pointer to |response| because |transaction|
138 // that will fit in a DNS UDP packet). The nodes will be appended to the 136 // is kept alive in |current_dns_transaction_|.
139 // proof. 137 void OnDnsTransactionComplete(net::DnsTransaction* transaction,
140 void QueryAuditProofNodes(uint64_t node_index); 138 int net_error,
141 139 const net::DnsResponse* response);
142 // Processes the response to an audit proof request. 140
143 // This will contain some, but not necessarily all, of the audit proof nodes. 141 // Requests the leaf index for the CT log entry with |leaf_hash_|.
144 void QueryAuditProofNodesComplete(net::DnsTransaction* transaction, 142 net::Error RequestLeafIndex();
145 int net_error, 143
146 const net::DnsResponse* response); 144 // Stores the received leaf index in |proof_->leaf_index|.
147 145 // If successful, the audit proof nodes will be requested next.
146 net::Error RequestLeafIndexComplete(net::Error result);
147
148 // Requests the next batch of audit proof nodes from a CT log.
149 // The index of the first node required is determined by looking at how many
150 // nodes are already in |proof_->nodes|.
151 // The CT log may return up to 7 nodes - this is the maximum allowed by the
152 // CT-over-DNS draft RFC, as a TXT RDATA string can have a maximum length of
153 // 255 bytes and each node is 32 bytes long (a SHA-256 hash).
154 //
155 // The performance of this could be improved by sending all of the expected
156 // requests up front. Each response can contain a maximum of 7 audit path
157 // nodes, so for an audit proof of size 20, it could send 3 queries (for nodes
158 // 0-6, 7-13 and 14-19) immediately. Currently, it sends only the first and
159 // then, based on the number of nodes received, sends the next query.
160 // The complexity of the code would increase though, as it would need to
161 // detect gaps in the audit proof caused by the server not responding with the
162 // anticipated number of nodes. It would also undermine LogDnsClient's ability
163 // to rate-limit DNS requests.
164 net::Error RequestAuditProofNodes();
165
166 // Appends the received audit proof nodes to |proof_->nodes|.
167 // If any nodes are missing, another request will follow this one.
168 net::Error RequestAuditProofNodesComplete(net::Error result);
169
170 // Sends a TXT record request for the domain |qname|.
171 // Returns true if the request could be started.
172 // OnDnsTransactionComplete() will be invoked with the result of the request.
173 bool StartDnsTransaction(const std::string& qname);
174
175 // The next state that this query will enter.
176 State next_state_;
177 // The DNS domain of the CT log that is being queried.
148 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.
180 std::string leaf_hash_;
181 // The size of the CT log's tree, from which the proof is requested.
149 // TODO(robpercival): Remove |tree_size| once |proof_| has a tree_size member. 182 // TODO(robpercival): Remove |tree_size| once |proof_| has a tree_size member.
150 uint64_t tree_size_; 183 uint64_t tree_size_;
151 std::unique_ptr<net::ct::MerkleAuditProof> proof_; 184 // The audit proof to populate.
152 CompletionCallback callback_; 185 net::ct::MerkleAuditProof* proof_;
186 // The callback to invoke when the query is complete.
187 net::CompletionCallback callback_;
188 // The DnsClient to use for sending DNS requests to the CT log.
153 net::DnsClient* dns_client_; 189 net::DnsClient* dns_client_;
190 // The most recent DNS request. Null if no DNS requests have been made.
154 std::unique_ptr<net::DnsTransaction> current_dns_transaction_; 191 std::unique_ptr<net::DnsTransaction> current_dns_transaction_;
192 // The most recent DNS response. Only valid so long as the corresponding DNS
193 // request is stored in |current_dns_transaction_|.
194 const net::DnsResponse* last_dns_response_;
195 // The NetLog that DNS transactions will log to.
155 net::NetLogWithSource net_log_; 196 net::NetLogWithSource net_log_;
197 // Produces WeakPtrs to |this| for binding callbacks.
156 base::WeakPtrFactory<AuditProofQuery> weak_ptr_factory_; 198 base::WeakPtrFactory<AuditProofQuery> weak_ptr_factory_;
157 }; 199 };
158 200
159 LogDnsClient::AuditProofQuery::AuditProofQuery( 201 LogDnsClient::AuditProofQuery::AuditProofQuery(
160 net::DnsClient* dns_client, 202 net::DnsClient* dns_client,
161 const std::string& domain_for_log, 203 const std::string& domain_for_log,
162 uint64_t tree_size, 204 uint64_t tree_size,
163 const net::NetLogWithSource& net_log) 205 const net::NetLogWithSource& net_log)
164 : domain_for_log_(domain_for_log), 206 : next_state_(State::NONE),
207 domain_for_log_(domain_for_log),
165 tree_size_(tree_size), 208 tree_size_(tree_size),
166 dns_client_(dns_client), 209 dns_client_(dns_client),
167 net_log_(net_log), 210 net_log_(net_log),
168 weak_ptr_factory_(this) { 211 weak_ptr_factory_(this) {
169 DCHECK(dns_client_); 212 DCHECK(dns_client_);
170 DCHECK(!domain_for_log_.empty()); 213 DCHECK(!domain_for_log_.empty());
171 } 214 }
172 215
173 void LogDnsClient::AuditProofQuery::Start(base::StringPiece leaf_hash, 216 // |leaf_hash| is not a const-ref to allow callers to std::move that string into
174 CompletionCallback callback) { 217 // the method, avoiding the need to make a copy.
175 current_dns_transaction_.reset(); 218 net::Error LogDnsClient::AuditProofQuery::Start(
176 proof_ = base::MakeUnique<net::ct::MerkleAuditProof>(); 219 std::string leaf_hash,
220 const net::CompletionCallback& callback,
221 net::ct::MerkleAuditProof* proof) {
222 // It should not already be in progress.
223 DCHECK_EQ(State::NONE, next_state_);
224 proof_ = proof;
225 leaf_hash_ = std::move(leaf_hash);
177 callback_ = callback; 226 callback_ = callback;
178 QueryLeafIndex(leaf_hash); 227 // The first step in the query is to request the leaf index corresponding to
179 } 228 // |leaf_hash| from the CT log.
180 229 next_state_ = State::REQUEST_LEAF_INDEX;
181 std::unique_ptr<net::ct::MerkleAuditProof> 230 // Begin the state machine.
182 LogDnsClient::AuditProofQuery::TakeProof() { 231 return DoLoop(net::OK);
183 return std::move(proof_); 232 }
184 } 233
185 234 net::Error LogDnsClient::AuditProofQuery::DoLoop(net::Error result) {
186 void LogDnsClient::AuditProofQuery::QueryLeafIndex( 235 CHECK_NE(State::NONE, next_state_);
187 base::StringPiece leaf_hash) { 236 do {
188 std::string encoded_leaf_hash = 237 State state = next_state_;
189 base32::Base32Encode(leaf_hash, base32::Base32EncodePolicy::OMIT_PADDING); 238 next_state_ = State::NONE;
190 DCHECK_EQ(encoded_leaf_hash.size(), 52u); 239 switch (state) {
191 240 case State::REQUEST_LEAF_INDEX:
192 std::string qname = base::StringPrintf( 241 result = RequestLeafIndex();
193 "%s.hash.%s.", encoded_leaf_hash.c_str(), domain_for_log_.data()); 242 break;
194 243 case State::REQUEST_LEAF_INDEX_COMPLETE:
195 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory(); 244 result = RequestLeafIndexComplete(result);
196 if (factory == nullptr) { 245 break;
197 base::ThreadTaskRunnerHandle::Get()->PostTask( 246 case State::REQUEST_AUDIT_PROOF_NODES:
198 FROM_HERE, base::Bind(callback_, net::Error::ERR_NAME_RESOLUTION_FAILED, 247 result = RequestAuditProofNodes();
199 base::Unretained(this))); 248 break;
200 return; 249 case State::REQUEST_AUDIT_PROOF_NODES_COMPLETE:
201 } 250 result = RequestAuditProofNodesComplete(result);
202 251 break;
203 net::DnsTransactionFactory::CallbackType transaction_callback = 252 case State::NONE:
204 base::Bind(&LogDnsClient::AuditProofQuery::QueryLeafIndexComplete, 253 NOTREACHED();
205 weak_ptr_factory_.GetWeakPtr()); 254 break;
206 255 }
207 current_dns_transaction_ = factory->CreateTransaction( 256 } while (result != net::ERR_IO_PENDING && next_state_ != State::NONE);
208 qname, net::dns_protocol::kTypeTXT, transaction_callback, net_log_); 257
209 258 return result;
210 current_dns_transaction_->Start(); 259 }
211 } 260
212 261 void LogDnsClient::AuditProofQuery::OnDnsTransactionComplete(
213 void LogDnsClient::AuditProofQuery::QueryLeafIndexComplete(
214 net::DnsTransaction* transaction, 262 net::DnsTransaction* transaction,
215 int net_error, 263 int net_error,
216 const net::DnsResponse* response) { 264 const net::DnsResponse* response) {
217 // If we've received no response but no net::error either (shouldn't 265 DCHECK_EQ(current_dns_transaction_.get(), transaction);
218 // happen), 266 last_dns_response_ = response;
219 // report the response as invalid. 267 net::Error result = DoLoop(static_cast<net::Error>(net_error));
220 if (response == nullptr && net_error == net::OK) { 268
221 net_error = net::ERR_INVALID_RESPONSE; 269 // If DoLoop() indicates that I/O is pending, don't invoke the completion
222 } 270 // callback. OnDnsTransactionComplete() will be invoked again once the I/O
223 271 // is complete, and can invoke the completion callback then if appropriate.
224 if (net_error != net::OK) { 272 if (result != net::ERR_IO_PENDING) {
225 base::ThreadTaskRunnerHandle::Get()->PostTask( 273 // The callback will delete this query (now that it has finished), so copy
226 FROM_HERE, base::Bind(callback_, net_error, base::Unretained(this))); 274 // |callback_| before running it so that it is not deleted along with the
227 return; 275 // query, mid-callback-execution (which would result in a crash).
228 } 276 base::ResetAndReturn(&callback_).Run(result);
229 277 }
230 if (!ParseLeafIndex(*response, &proof_->leaf_index)) { 278 }
231 base::ThreadTaskRunnerHandle::Get()->PostTask( 279
232 FROM_HERE, base::Bind(callback_, net::ERR_DNS_MALFORMED_RESPONSE, 280 net::Error LogDnsClient::AuditProofQuery::RequestLeafIndex() {
233 base::Unretained(this))); 281 std::string encoded_leaf_hash = base32::Base32Encode(
234 return; 282 leaf_hash_, base32::Base32EncodePolicy::OMIT_PADDING);
283 DCHECK_EQ(encoded_leaf_hash.size(), 52u);
284
285 std::string qname = base::StringPrintf(
286 "%s.hash.%s.", encoded_leaf_hash.c_str(), domain_for_log_.c_str());
287
288 if (!StartDnsTransaction(qname)) {
289 return net::ERR_NAME_RESOLUTION_FAILED;
290 }
291
292 next_state_ = State::REQUEST_LEAF_INDEX_COMPLETE;
293 return net::ERR_IO_PENDING;
294 }
295
296 // Stores the received leaf index in |proof_->leaf_index|.
297 // If successful, the audit proof nodes will be requested next.
298 net::Error LogDnsClient::AuditProofQuery::RequestLeafIndexComplete(
299 net::Error result) {
300 if (result != net::OK) {
301 return result;
302 }
303
304 DCHECK(last_dns_response_);
305 if (!ParseLeafIndex(*last_dns_response_, &proof_->leaf_index)) {
306 return net::ERR_DNS_MALFORMED_RESPONSE;
235 } 307 }
236 308
237 // Reject leaf index if it is out-of-range. 309 // Reject leaf index if it is out-of-range.
238 // This indicates either: 310 // This indicates either:
239 // a) the wrong tree_size was provided. 311 // a) the wrong tree_size was provided.
240 // b) the wrong leaf hash was provided. 312 // b) the wrong leaf hash was provided.
241 // c) there is a bug server-side. 313 // c) there is a bug server-side.
242 // The first two are more likely, so return ERR_INVALID_ARGUMENT. 314 // The first two are more likely, so return ERR_INVALID_ARGUMENT.
243 if (proof_->leaf_index >= tree_size_) { 315 if (proof_->leaf_index >= tree_size_) {
244 base::ThreadTaskRunnerHandle::Get()->PostTask( 316 return net::ERR_INVALID_ARGUMENT;
245 FROM_HERE, base::Bind(callback_, net::ERR_INVALID_ARGUMENT, 317 }
246 base::Unretained(this))); 318
247 return; 319 next_state_ = State::REQUEST_AUDIT_PROOF_NODES;
248 } 320 return net::OK;
249 321 }
250 // QueryAuditProof for the first batch of audit proof_ nodes (i.e. starting 322
251 // from 0). 323 net::Error LogDnsClient::AuditProofQuery::RequestAuditProofNodes() {
252 QueryAuditProofNodes(0 /* start node index */); 324 // Test pre-conditions (should be guaranteed by DNS response validation).
253 } 325 if (proof_->leaf_index >= tree_size_ ||
254 326 proof_->nodes.size() >=
255 void LogDnsClient::AuditProofQuery::QueryAuditProofNodes(uint64_t node_index) { 327 net::ct::CalculateAuditPathLength(proof_->leaf_index, tree_size_)) {
256 DCHECK_LT(proof_->leaf_index, tree_size_); 328 return net::ERR_UNEXPECTED;
257 DCHECK_LT(node_index, 329 }
258 net::ct::CalculateAuditPathLength(proof_->leaf_index, tree_size_));
259 330
260 std::string qname = base::StringPrintf( 331 std::string qname = base::StringPrintf(
261 "%" PRIu64 ".%" PRIu64 ".%" PRIu64 ".tree.%s.", node_index, 332 "%zu.%" PRIu64 ".%" PRIu64 ".tree.%s.", proof_->nodes.size(),
262 proof_->leaf_index, tree_size_, domain_for_log_.data()); 333 proof_->leaf_index, tree_size_, domain_for_log_.c_str());
263 334
264 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory(); 335 if (!StartDnsTransaction(qname)) {
265 if (factory == nullptr) { 336 return net::ERR_NAME_RESOLUTION_FAILED;
266 base::ThreadTaskRunnerHandle::Get()->PostTask( 337 }
267 FROM_HERE, base::Bind(callback_, net::Error::ERR_NAME_RESOLUTION_FAILED, 338
268 base::Unretained(this))); 339 next_state_ = State::REQUEST_AUDIT_PROOF_NODES_COMPLETE;
269 return; 340 return net::ERR_IO_PENDING;
270 } 341 }
271 342
272 net::DnsTransactionFactory::CallbackType transaction_callback = 343 net::Error LogDnsClient::AuditProofQuery::RequestAuditProofNodesComplete(
273 base::Bind(&LogDnsClient::AuditProofQuery::QueryAuditProofNodesComplete, 344 net::Error result) {
274 weak_ptr_factory_.GetWeakPtr()); 345 if (result != net::OK) {
275 346 return result;
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 } 347 }
296 348
297 const uint64_t audit_path_length = 349 const uint64_t audit_path_length =
298 net::ct::CalculateAuditPathLength(proof_->leaf_index, tree_size_); 350 net::ct::CalculateAuditPathLength(proof_->leaf_index, tree_size_);
351
299 // The calculated |audit_path_length| can't ever be greater than 64, so 352 // 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| 353 // deriving the amount of memory to reserve from the untrusted |leaf_index|
301 // is safe. 354 // is safe.
302 proof_->nodes.reserve(audit_path_length); 355 proof_->nodes.reserve(audit_path_length);
303 356
304 if (!ParseAuditPath(*response, proof_.get())) { 357 DCHECK(last_dns_response_);
305 base::ThreadTaskRunnerHandle::Get()->PostTask( 358 if (!ParseAuditPath(*last_dns_response_, proof_)) {
306 FROM_HERE, base::Bind(callback_, net::ERR_DNS_MALFORMED_RESPONSE, 359 return net::ERR_DNS_MALFORMED_RESPONSE;
307 base::Unretained(this))); 360 }
308 return; 361
309 } 362 // Keep requesting more proof nodes until all of them are received.
310 363 if (proof_->nodes.size() < audit_path_length) {
311 const uint64_t audit_path_nodes_received = proof_->nodes.size(); 364 next_state_ = State::REQUEST_AUDIT_PROOF_NODES;
312 if (audit_path_nodes_received < audit_path_length) { 365 }
313 QueryAuditProofNodes(audit_path_nodes_received); 366
314 return; 367 return net::OK;
315 } 368 }
316 369
317 base::ThreadTaskRunnerHandle::Get()->PostTask( 370 bool LogDnsClient::AuditProofQuery::StartDnsTransaction(
318 FROM_HERE, base::Bind(callback_, net::OK, base::Unretained(this))); 371 const std::string& qname) {
372 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory();
373 if (!factory) {
374 return false;
375 }
376
377 current_dns_transaction_ = factory->CreateTransaction(
378 qname, net::dns_protocol::kTypeTXT,
379 base::Bind(&LogDnsClient::AuditProofQuery::OnDnsTransactionComplete,
380 weak_ptr_factory_.GetWeakPtr()),
381 net_log_);
382
383 current_dns_transaction_->Start();
384 return true;
319 } 385 }
320 386
321 LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client, 387 LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client,
322 const net::NetLogWithSource& net_log, 388 const net::NetLogWithSource& net_log,
323 size_t max_concurrent_queries) 389 size_t max_concurrent_queries)
324 : dns_client_(std::move(dns_client)), 390 : dns_client_(std::move(dns_client)),
325 net_log_(net_log), 391 net_log_(net_log),
326 max_concurrent_queries_(max_concurrent_queries), 392 max_concurrent_queries_(max_concurrent_queries),
327 weak_ptr_factory_(this) { 393 weak_ptr_factory_(this) {
328 CHECK(dns_client_); 394 CHECK(dns_client_);
329 net::NetworkChangeNotifier::AddDNSObserver(this); 395 net::NetworkChangeNotifier::AddDNSObserver(this);
330 UpdateDnsConfig(); 396 UpdateDnsConfig();
331 } 397 }
332 398
333 LogDnsClient::~LogDnsClient() { 399 LogDnsClient::~LogDnsClient() {
334 net::NetworkChangeNotifier::RemoveDNSObserver(this); 400 net::NetworkChangeNotifier::RemoveDNSObserver(this);
335 } 401 }
336 402
337 void LogDnsClient::OnDNSChanged() { 403 void LogDnsClient::OnDNSChanged() {
338 UpdateDnsConfig(); 404 UpdateDnsConfig();
339 } 405 }
340 406
341 void LogDnsClient::OnInitialDNSConfigRead() { 407 void LogDnsClient::OnInitialDNSConfigRead() {
342 UpdateDnsConfig(); 408 UpdateDnsConfig();
343 } 409 }
344 410
345 // The performance of this could be improved by sending all of the expected 411 // |leaf_hash| is not a const-ref to allow callers to std::move that string into
346 // queries up front. Each response can contain a maximum of 7 audit path nodes, 412 // the method, avoiding LogDnsClient::AuditProofQuery having to make a copy.
347 // so for an audit proof of size 20, it could send 3 queries (for nodes 0-6, 413 net::Error LogDnsClient::QueryAuditProof(
348 // 7-13 and 14-19) immediately. Currently, it sends only the first and then, 414 base::StringPiece domain_for_log,
349 // based on the number of nodes received, sends the next query. The complexity 415 std::string leaf_hash,
350 // of the code would increase though, as it would need to detect gaps in the 416 uint64_t tree_size,
351 // audit proof caused by the server not responding with the anticipated number 417 net::ct::MerkleAuditProof* proof,
352 // of nodes. Ownership of the proof would need to change, as it would be shared 418 const net::CompletionCallback& callback) {
353 // between simultaneous DNS transactions. Throttling of queries would also need 419 DCHECK(proof);
354 // to take into account this increase in parallelism. 420
355 void LogDnsClient::QueryAuditProof(const std::string& domain_for_log,
356 base::StringPiece leaf_hash,
357 uint64_t tree_size,
358 const AuditProofCallback& callback) {
359 if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) { 421 if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) {
360 base::ThreadTaskRunnerHandle::Get()->PostTask( 422 return net::ERR_INVALID_ARGUMENT;
361 FROM_HERE,
362 base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, nullptr));
363 return;
364 } 423 }
365 424
366 if (HasMaxConcurrentQueriesInProgress()) { 425 if (HasMaxConcurrentQueriesInProgress()) {
367 base::ThreadTaskRunnerHandle::Get()->PostTask( 426 return net::ERR_TEMPORARILY_THROTTLED;
368 FROM_HERE,
369 base::Bind(callback, net::Error::ERR_TEMPORARILY_THROTTLED, nullptr));
370 return;
371 } 427 }
372 428
373 audit_proof_queries_.emplace_back(new AuditProofQuery( 429 AuditProofQuery* query = new AuditProofQuery(
374 dns_client_.get(), domain_for_log, tree_size, net_log_)); 430 dns_client_.get(), domain_for_log.as_string(), tree_size, net_log_);
431 // Transfers ownership of |query| to |audit_proof_queries_|.
432 audit_proof_queries_.emplace_back(query);
375 433
376 AuditProofQuery::CompletionCallback internal_callback = 434 return query->Start(std::move(leaf_hash),
377 base::Bind(&LogDnsClient::QueryAuditProofComplete, 435 base::Bind(&LogDnsClient::QueryAuditProofComplete,
378 weak_ptr_factory_.GetWeakPtr(), callback); 436 weak_ptr_factory_.GetWeakPtr(),
379 437 base::Unretained(query), callback),
380 audit_proof_queries_.back()->Start(leaf_hash, internal_callback); 438 proof);
381 } 439 }
382 440
383 void LogDnsClient::QueryAuditProofComplete(const AuditProofCallback& callback, 441 void LogDnsClient::QueryAuditProofComplete(
384 int result, 442 AuditProofQuery* query,
385 AuditProofQuery* query) { 443 const net::CompletionCallback& callback,
444 int net_error) {
386 DCHECK(query); 445 DCHECK(query);
387 446
388 std::unique_ptr<net::ct::MerkleAuditProof> proof;
389 if (result == net::OK) {
390 proof = query->TakeProof();
391 }
392
393 // Finished with the query - destroy it. 447 // Finished with the query - destroy it.
394 auto query_iterator = 448 auto query_iterator =
395 std::find_if(audit_proof_queries_.begin(), audit_proof_queries_.end(), 449 std::find_if(audit_proof_queries_.begin(), audit_proof_queries_.end(),
396 [query](const std::unique_ptr<AuditProofQuery>& p) { 450 [query](const std::unique_ptr<AuditProofQuery>& p) {
397 return p.get() == query; 451 return p.get() == query;
398 }); 452 });
399 DCHECK(query_iterator != audit_proof_queries_.end()); 453 DCHECK(query_iterator != audit_proof_queries_.end());
400 audit_proof_queries_.erase(query_iterator); 454 audit_proof_queries_.erase(query_iterator);
401 455
402 base::ThreadTaskRunnerHandle::Get()->PostTask( 456 callback.Run(net_error);
403 FROM_HERE, base::Bind(callback, result, base::Passed(&proof)));
404 } 457 }
405 458
406 bool LogDnsClient::HasMaxConcurrentQueriesInProgress() const { 459 bool LogDnsClient::HasMaxConcurrentQueriesInProgress() const {
407 return max_concurrent_queries_ != 0 && 460 return max_concurrent_queries_ != 0 &&
408 audit_proof_queries_.size() >= max_concurrent_queries_; 461 audit_proof_queries_.size() >= max_concurrent_queries_;
409 } 462 }
410 463
411 void LogDnsClient::UpdateDnsConfig() { 464 void LogDnsClient::UpdateDnsConfig() {
412 net::DnsConfig config; 465 net::DnsConfig config;
413 net::NetworkChangeNotifier::GetDnsConfig(&config); 466 net::NetworkChangeNotifier::GetDnsConfig(&config);
414 if (config.IsValid()) 467 if (config.IsValid())
415 dns_client_->SetConfig(config); 468 dns_client_->SetConfig(config);
416 } 469 }
417 470
418 } // namespace certificate_transparency 471 } // namespace certificate_transparency
OLDNEW
« no previous file with comments | « components/certificate_transparency/log_dns_client.h ('k') | components/certificate_transparency/log_dns_client_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698