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

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: Rebase 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 void LogDnsClient::QueryAuditProof(base::StringPiece domain_for_log,
76 uint64_t leaf_index,
77 uint64_t tree_size,
78 const AuditProofCallback& callback) {
79 if (leaf_index >= tree_size) {
80 base::ThreadTaskRunnerHandle::Get()->PostTask(
81 FROM_HERE,
82 base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, nullptr));
83 return;
84 }
85
86 std::unique_ptr<net::ct::MerkleAuditProof> proof(
87 new net::ct::MerkleAuditProof);
88 proof->leaf_index = leaf_index;
89
90 QueryAuditProofNodes(std::move(proof), domain_for_log, leaf_index, tree_size,
91 0, callback);
92 }
93
94 void LogDnsClient::QueryLeafIndexComplete(net::DnsTransaction* transaction,
95 int net_error,
96 const net::DnsResponse* response) {
97 auto query_iterator =
98 std::find_if(leaf_index_queries_.begin(), leaf_index_queries_.end(),
99 [transaction](const Query<LeafIndexCallback>& query) {
100 return query.transaction.get() == transaction;
101 });
102 if (query_iterator == leaf_index_queries_.end()) {
103 NOTREACHED();
104 return;
105 }
106 const Query<LeafIndexCallback> query = std::move(*query_iterator);
107 leaf_index_queries_.erase(query_iterator);
108
109 if (net_error != net::OK) {
110 base::ThreadTaskRunnerHandle::Get()->PostTask(
111 FROM_HERE, base::Bind(query.callback, net_error, 0));
112 return;
113 }
114
115 if (response == nullptr) {
116 base::ThreadTaskRunnerHandle::Get()->PostTask(
117 FROM_HERE, base::Bind(query.callback, net::ERR_INVALID_RESPONSE, 0));
118 return;
119 }
120
121 uint64_t leaf_index;
122 if (!ParseLeafIndex(*response, &leaf_index)) {
123 base::ThreadTaskRunnerHandle::Get()->PostTask(
124 FROM_HERE,
125 base::Bind(query.callback, net::ERR_DNS_MALFORMED_RESPONSE, 0));
126 return;
127 }
128
129 base::ThreadTaskRunnerHandle::Get()->PostTask(
130 FROM_HERE, base::Bind(query.callback, net::OK, leaf_index));
131 }
132
133 void LogDnsClient::QueryAuditProofNodes(
134 std::unique_ptr<net::ct::MerkleAuditProof> proof,
135 base::StringPiece domain_for_log,
136 uint64_t leaf_index,
137 uint64_t tree_size,
138 uint64_t node_index,
139 const AuditProofCallback& callback) {
140 CHECK(proof);
141 CHECK_LT(leaf_index, tree_size);
142 CHECK_LT(node_index,
143 net::ct::CalculateAuditPathLength(leaf_index, tree_size));
144
145 std::string qname = base::Uint64ToString(node_index);
146 qname += ".";
147 qname += base::Uint64ToString(leaf_index);
148 qname += ".";
149 qname += base::Uint64ToString(tree_size);
150 qname += ".tree.";
151 domain_for_log.AppendToString(&qname);
152 qname += ".";
153
154 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory();
155 if (factory == nullptr) {
156 base::ThreadTaskRunnerHandle::Get()->PostTask(
157 FROM_HERE,
158 base::Bind(callback, net::Error::ERR_NAME_RESOLUTION_FAILED, nullptr));
159 return;
160 }
161
162 net::DnsTransactionFactory::CallbackType transaction_callback =
163 base::Bind(&LogDnsClient::QueryAuditProofNodesComplete,
164 weak_ptr_factory_.GetWeakPtr(), base::Passed(std::move(proof)),
165 domain_for_log, leaf_index, tree_size);
166
167 std::unique_ptr<net::DnsTransaction> dns_transaction =
168 factory->CreateTransaction(qname, net::dns_protocol::kTypeTXT,
169 transaction_callback, net_log_);
170 dns_transaction->Start();
171 audit_proof_queries_.push_back({std::move(dns_transaction), callback});
172 }
173
174 void LogDnsClient::QueryAuditProofNodesComplete(
175 std::unique_ptr<net::ct::MerkleAuditProof> proof,
176 base::StringPiece domain_for_log,
177 uint64_t leaf_index,
178 uint64_t tree_size,
179 net::DnsTransaction* transaction,
180 int net_error,
181 const net::DnsResponse* response) {
182 auto query_iterator =
183 std::find_if(audit_proof_queries_.begin(), audit_proof_queries_.end(),
184 [transaction](const Query<AuditProofCallback>& query) {
185 return query.transaction.get() == transaction;
186 });
187
188 if (query_iterator == audit_proof_queries_.end()) {
189 NOTREACHED();
190 return;
191 }
192 const Query<AuditProofCallback> query = std::move(*query_iterator);
193 audit_proof_queries_.erase(query_iterator);
194
195 if (net_error != net::OK) {
196 base::ThreadTaskRunnerHandle::Get()->PostTask(
197 FROM_HERE, base::Bind(query.callback, net_error, nullptr));
198 return;
199 }
200
201 if (response == nullptr) {
202 base::ThreadTaskRunnerHandle::Get()->PostTask(
203 FROM_HERE,
204 base::Bind(query.callback, net::ERR_INVALID_RESPONSE, nullptr));
205 return;
206 }
207
208 if (!ParseAuditPath(*response, proof.get())) {
209 base::ThreadTaskRunnerHandle::Get()->PostTask(
210 FROM_HERE,
211 base::Bind(query.callback, net::ERR_DNS_MALFORMED_RESPONSE, nullptr));
212 return;
213 }
214
215 const uint64_t audit_path_nodes_received = proof->nodes.size();
216 const uint64_t audit_path_length =
217 net::ct::CalculateAuditPathLength(leaf_index, tree_size);
218 if (audit_path_nodes_received < audit_path_length) {
219 QueryAuditProofNodes(std::move(proof), domain_for_log, leaf_index,
220 tree_size, audit_path_nodes_received, query.callback);
221 return;
222 }
223
224 base::ThreadTaskRunnerHandle::Get()->PostTask(
225 FROM_HERE,
226 base::Bind(query.callback, net::OK, base::Passed(std::move(proof))));
227 }
228
229 bool LogDnsClient::ParseTxtResponse(const net::DnsResponse& response,
230 std::string* txt) {
231 DCHECK(txt);
232
233 net::DnsRecordParser parser = response.Parser();
234 auto parsed_record = net::RecordParsed::CreateFrom(&parser, clock_->Now());
235 if (parsed_record == nullptr)
236 return false;
237
238 auto txt_record = parsed_record->rdata<net::TxtRecordRdata>();
239 if (txt_record == nullptr)
240 return false;
241
242 *txt = base::JoinString(txt_record->texts(), "");
243 return true;
244 }
245
246 bool LogDnsClient::ParseLeafIndex(const net::DnsResponse& response,
247 uint64_t* index) {
248 std::string index_str;
249 if (!ParseTxtResponse(response, &index_str))
250 return false;
251
252 return base::StringToUint64(index_str, index);
253 }
254
255 bool LogDnsClient::ParseAuditPath(const net::DnsResponse& response,
256 net::ct::MerkleAuditProof* proof) {
257 std::string audit_path;
258 if (!ParseTxtResponse(response, &audit_path))
259 return false;
260
261 for (size_t i = 0; i < audit_path.size(); i += crypto::kSHA256Length) {
262 std::string node = audit_path.substr(i, crypto::kSHA256Length);
263
264 if (node.size() == crypto::kSHA256Length)
265 proof->nodes.push_back(node);
266 else
267 return false;
268 }
269
270 return true;
271 }
272
273 } // namespace certificate_transparency
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698