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

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

Issue 2066553002: Certificate Transparency DNS log client (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@mock_dns_responses
Patch Set: Removes unneeded #include Created 4 years, 5 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "components/certificate_transparency/log_dns_client.h"
6
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/threading/thread_task_runner_handle.h"
13 #include "components/base32/base32.h"
14 #include "crypto/sha2.h"
15 #include "net/base/net_errors.h"
16 #include "net/cert/merkle_audit_proof.h"
17 #include "net/dns/dns_client.h"
18 #include "net/dns/dns_protocol.h"
19 #include "net/dns/dns_response.h"
20 #include "net/dns/dns_transaction.h"
21 #include "net/dns/record_parsed.h"
22 #include "net/dns/record_rdata.h"
23
24 namespace certificate_transparency {
25
26 LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client,
27 const net::BoundNetLog& net_log,
28 base::Clock* clock)
29 : dns_client_(std::move(dns_client)),
30 net_log_(net_log),
31 clock_(clock),
32 weak_ptr_factory_(this) {
33 CHECK(dns_client_);
34 CHECK(clock_);
35 }
36
37 LogDnsClient::~LogDnsClient() {}
38
39 void LogDnsClient::QueryLeafIndex(base::StringPiece domain_for_log,
40 base::StringPiece leaf_hash,
41 const LeafIndexCallback& callback) {
42 if (leaf_hash.size() != crypto::kSHA256Length) {
43 base::ThreadTaskRunnerHandle::Get()->PostTask(
44 FROM_HERE, base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, 0));
45 return;
46 }
47
48 std::string encoded_leaf_hash =
49 base32::Base32Encode(leaf_hash, base32::Base32EncodePolicy::OMIT_PADDING);
50 DCHECK_EQ(encoded_leaf_hash.size(), 52u);
51 std::string qname = encoded_leaf_hash;
52 qname += ".hash.";
53 domain_for_log.AppendToString(&qname);
54 qname += ".";
55
56 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory();
57 if (factory == nullptr) {
58 base::ThreadTaskRunnerHandle::Get()->PostTask(
59 FROM_HERE,
60 base::Bind(callback, net::Error::ERR_NAME_RESOLUTION_FAILED, 0));
61 return;
62 }
63
64 net::DnsTransactionFactory::CallbackType transaction_callback = base::Bind(
65 &LogDnsClient::QueryLeafIndexComplete, weak_ptr_factory_.GetWeakPtr());
66
67 std::unique_ptr<net::DnsTransaction> dns_transaction =
68 factory->CreateTransaction(qname, net::dns_protocol::kTypeTXT,
69 transaction_callback, net_log_);
70
71 dns_transaction->Start();
72 leaf_index_queries_.push_back({std::move(dns_transaction), callback});
73 }
74
75 // The performance of this could be improved by sending all of the expected
76 // queries up front. Each response can contain a maximum of 7 audit path nodes,
77 // so for an audit proof of size 20, it could send 3 queries (for nodes 0-6,
78 // 7-13 and 14-19) immediately. Currently, it sends only the first and then,
79 // based on the number of nodes received, sends the next query. The complexity
80 // of the code would increase though, as it would need to detect gaps in the
81 // audit proof caused by the server not responding with the anticipated number
82 // of nodes. Ownership of the proof would need to change, as it would be shared
83 // between simultaneous DNS transactions.
84 void LogDnsClient::QueryAuditProof(base::StringPiece domain_for_log,
85 uint64_t leaf_index,
86 uint64_t tree_size,
87 const AuditProofCallback& callback) {
88 if (leaf_index >= tree_size) {
89 base::ThreadTaskRunnerHandle::Get()->PostTask(
90 FROM_HERE,
91 base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, nullptr));
92 return;
93 }
94
95 std::unique_ptr<net::ct::MerkleAuditProof> proof(
96 new net::ct::MerkleAuditProof);
97 proof->leaf_index = leaf_index;
98
99 QueryAuditProofNodes(std::move(proof), domain_for_log, leaf_index, tree_size,
100 0, callback);
101 }
102
103 void LogDnsClient::QueryLeafIndexComplete(net::DnsTransaction* transaction,
104 int net_error,
105 const net::DnsResponse* response) {
106 auto query_iterator =
107 std::find_if(leaf_index_queries_.begin(), leaf_index_queries_.end(),
108 [transaction](const Query<LeafIndexCallback>& query) {
109 return query.transaction.get() == transaction;
110 });
111 if (query_iterator == leaf_index_queries_.end()) {
112 NOTREACHED();
113 return;
114 }
115 const Query<LeafIndexCallback> query = std::move(*query_iterator);
116 leaf_index_queries_.erase(query_iterator);
117
118 if (net_error != net::OK) {
119 base::ThreadTaskRunnerHandle::Get()->PostTask(
120 FROM_HERE, base::Bind(query.callback, net_error, 0));
121 return;
122 }
123
124 if (response == nullptr) {
125 base::ThreadTaskRunnerHandle::Get()->PostTask(
126 FROM_HERE, base::Bind(query.callback, net::ERR_INVALID_RESPONSE, 0));
127 return;
128 }
129
130 uint64_t leaf_index;
131 if (!ParseLeafIndex(*response, &leaf_index)) {
132 base::ThreadTaskRunnerHandle::Get()->PostTask(
133 FROM_HERE,
134 base::Bind(query.callback, net::ERR_DNS_MALFORMED_RESPONSE, 0));
135 return;
136 }
137
138 base::ThreadTaskRunnerHandle::Get()->PostTask(
139 FROM_HERE, base::Bind(query.callback, net::OK, leaf_index));
140 }
141
142 void LogDnsClient::QueryAuditProofNodes(
143 std::unique_ptr<net::ct::MerkleAuditProof> proof,
144 base::StringPiece domain_for_log,
145 uint64_t leaf_index,
146 uint64_t tree_size,
147 uint64_t node_index,
148 const AuditProofCallback& callback) {
149 CHECK(proof);
150 CHECK_LT(leaf_index, tree_size);
151 CHECK_LT(node_index,
152 net::ct::CalculateAuditPathLength(leaf_index, tree_size));
153
154 std::string qname = base::Uint64ToString(node_index);
155 qname += ".";
156 qname += base::Uint64ToString(leaf_index);
157 qname += ".";
158 qname += base::Uint64ToString(tree_size);
159 qname += ".tree.";
160 domain_for_log.AppendToString(&qname);
161 qname += ".";
162
163 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory();
164 if (factory == nullptr) {
165 base::ThreadTaskRunnerHandle::Get()->PostTask(
166 FROM_HERE,
167 base::Bind(callback, net::Error::ERR_NAME_RESOLUTION_FAILED, nullptr));
168 return;
169 }
170
171 net::DnsTransactionFactory::CallbackType transaction_callback =
172 base::Bind(&LogDnsClient::QueryAuditProofNodesComplete,
173 weak_ptr_factory_.GetWeakPtr(), base::Passed(std::move(proof)),
174 domain_for_log, leaf_index, tree_size);
175
176 std::unique_ptr<net::DnsTransaction> dns_transaction =
177 factory->CreateTransaction(qname, net::dns_protocol::kTypeTXT,
178 transaction_callback, net_log_);
179 dns_transaction->Start();
180 audit_proof_queries_.push_back({std::move(dns_transaction), callback});
181 }
182
183 void LogDnsClient::QueryAuditProofNodesComplete(
184 std::unique_ptr<net::ct::MerkleAuditProof> proof,
185 base::StringPiece domain_for_log,
186 uint64_t leaf_index,
187 uint64_t tree_size,
188 net::DnsTransaction* transaction,
189 int net_error,
190 const net::DnsResponse* response) {
191 auto query_iterator =
192 std::find_if(audit_proof_queries_.begin(), audit_proof_queries_.end(),
193 [transaction](const Query<AuditProofCallback>& query) {
194 return query.transaction.get() == transaction;
195 });
196
197 if (query_iterator == audit_proof_queries_.end()) {
198 NOTREACHED();
199 return;
200 }
201 const Query<AuditProofCallback> query = std::move(*query_iterator);
202 audit_proof_queries_.erase(query_iterator);
203
204 if (net_error != net::OK) {
205 base::ThreadTaskRunnerHandle::Get()->PostTask(
206 FROM_HERE, base::Bind(query.callback, net_error, nullptr));
207 return;
208 }
209
210 if (response == nullptr) {
211 base::ThreadTaskRunnerHandle::Get()->PostTask(
212 FROM_HERE,
213 base::Bind(query.callback, net::ERR_INVALID_RESPONSE, nullptr));
214 return;
215 }
216
217 const uint64_t audit_path_length =
218 net::ct::CalculateAuditPathLength(leaf_index, tree_size);
219 proof->nodes.reserve(audit_path_length);
220
221 if (!ParseAuditPath(*response, proof.get())) {
222 base::ThreadTaskRunnerHandle::Get()->PostTask(
223 FROM_HERE,
224 base::Bind(query.callback, net::ERR_DNS_MALFORMED_RESPONSE, nullptr));
225 return;
226 }
227
228 const uint64_t audit_path_nodes_received = proof->nodes.size();
229 if (audit_path_nodes_received < audit_path_length) {
230 QueryAuditProofNodes(std::move(proof), domain_for_log, leaf_index,
231 tree_size, audit_path_nodes_received, query.callback);
232 return;
233 }
234
235 base::ThreadTaskRunnerHandle::Get()->PostTask(
236 FROM_HERE,
237 base::Bind(query.callback, net::OK, base::Passed(std::move(proof))));
238 }
239
240 bool LogDnsClient::ParseTxtResponse(const net::DnsResponse& response,
241 std::string* txt) {
242 DCHECK(txt);
243
244 net::DnsRecordParser parser = response.Parser();
245 auto parsed_record = net::RecordParsed::CreateFrom(&parser, clock_->Now());
246 if (parsed_record == nullptr)
247 return false;
248
249 auto txt_record = parsed_record->rdata<net::TxtRecordRdata>();
250 if (txt_record == nullptr)
251 return false;
252
253 *txt = base::JoinString(txt_record->texts(), "");
254 return true;
255 }
256
257 bool LogDnsClient::ParseLeafIndex(const net::DnsResponse& response,
258 uint64_t* index) {
259 std::string index_str;
260 if (!ParseTxtResponse(response, &index_str))
261 return false;
262
263 return base::StringToUint64(index_str, index);
264 }
265
266 bool LogDnsClient::ParseAuditPath(const net::DnsResponse& response,
267 net::ct::MerkleAuditProof* proof) {
268 std::string audit_path;
269 if (!ParseTxtResponse(response, &audit_path))
270 return false;
271
272 for (size_t i = 0; i < audit_path.size(); i += crypto::kSHA256Length) {
273 std::string node = audit_path.substr(i, crypto::kSHA256Length);
274
275 if (node.size() == crypto::kSHA256Length)
276 proof->nodes.push_back(node);
277 else
278 return false;
279 }
280
281 return true;
282 }
283
284 } // namespace certificate_transparency
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698