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

Side by Side Diff: components/certificate_transparency/log_dns_client_unittest.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 <algorithm>
8 #include <numeric>
9 #include <utility>
10 #include <vector>
11
12 #include "base/big_endian.h"
13 #include "base/macros.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/run_loop.h"
16 #include "base/sys_byteorder.h"
17 #include "base/test/test_timeouts.h"
18 #include "crypto/sha2.h"
19 #include "net/base/net_errors.h"
20 #include "net/cert/merkle_audit_proof.h"
21 #include "net/cert/merkle_tree_leaf.h"
22 #include "net/cert/signed_certificate_timestamp.h"
23 #include "net/dns/dns_client.h"
24 #include "net/dns/dns_config_service.h"
25 #include "net/dns/dns_protocol.h"
26 #include "net/log/net_log.h"
27 #include "net/socket/socket_test_util.h"
28 #include "testing/gmock/include/gmock/gmock.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30
31 namespace certificate_transparency {
32 namespace {
33
34 using ::testing::IsNull;
35 using ::testing::NotNull;
36
37 constexpr char kLeafHash[] =
38 "\x1f\x25\xe1\xca\xba\x4f\xf9\xb8\x27\x24\x83\x0f\xca\x60\xe4\xc2\xbe\xa8"
39 "\xc3\xa9\x44\x1c\x27\xb0\xb4\x3e\x6a\x96\x94\xc7\xb8\x04";
40
41 MATCHER(IsNetOk,
42 std::string(negation ? "not " : "") + net::ErrorToString(net::OK)) {
43 if (arg <= net::OK)
44 *result_listener << net::ErrorToString(arg);
45 return arg == net::OK;
46 }
47
48 MATCHER_P(IsNetError,
49 expected,
50 std::string(negation ? "not " : "") + net::ErrorToString(expected)) {
51 if (arg <= net::OK)
52 *result_listener << net::ErrorToString(arg);
53 return arg == expected;
54 }
55
56 // Always return min, to simplify testing.
57 // This should result in the DNS query ID always being 0.
58 int FakeRandInt(int min, int max) {
59 return min;
60 }
61
62 std::vector<char> CreateDnsTxtRequest(base::StringPiece qname) {
63 std::string encoded_qname;
64 EXPECT_TRUE(net::DNSDomainFromDot(qname, &encoded_qname));
65
66 const size_t query_section_size = encoded_qname.size() + 4;
67
68 std::vector<char> request(sizeof(net::dns_protocol::Header) +
69 query_section_size);
70 base::BigEndianWriter writer(request.data(), request.size());
71
72 // Header
73 net::dns_protocol::Header header = {};
74 header.flags = base::HostToNet16(net::dns_protocol::kFlagRD);
75 header.qdcount = base::HostToNet16(1);
76 EXPECT_TRUE(writer.WriteBytes(&header, sizeof(header)));
77 // Query section
78 EXPECT_TRUE(writer.WriteBytes(encoded_qname.data(), encoded_qname.size()));
79 EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kTypeTXT));
80 EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kClassIN));
81 EXPECT_EQ(0, writer.remaining());
82
83 return request;
84 }
85
86 std::vector<char> CreateDnsTxtResponse(const std::vector<char>& request,
87 base::StringPiece answer) {
88 const size_t answers_section_size = 12 + answer.size();
89 constexpr uint32_t ttl = 86400; // seconds
90
91 std::vector<char> response(request.size() + answers_section_size);
92 std::copy(request.begin(), request.end(), response.begin());
93 // Modify the header
94 net::dns_protocol::Header* header =
95 reinterpret_cast<net::dns_protocol::Header*>(response.data());
96 header->ancount = base::HostToNet16(1);
97 header->flags |= base::HostToNet16(net::dns_protocol::kFlagResponse);
98
99 // Write the answer section
100 base::BigEndianWriter writer(response.data() + request.size(),
101 response.size() - request.size());
102 EXPECT_TRUE(writer.WriteU8(0xc0)); // qname is a pointer
103 EXPECT_TRUE(writer.WriteU8(
104 sizeof(*header))); // address of qname (start of query section)
105 EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kTypeTXT));
106 EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kClassIN));
107 EXPECT_TRUE(writer.WriteU32(ttl));
108 EXPECT_TRUE(writer.WriteU16(answer.size()));
109 EXPECT_TRUE(writer.WriteBytes(answer.data(), answer.size()));
110 EXPECT_EQ(0, writer.remaining());
111
112 return response;
113 }
114
115 std::vector<char> CreateDnsErrorResponse(const std::vector<char>& request,
116 uint8_t rcode) {
117 std::vector<char> response(request);
118 // Modify the header
119 net::dns_protocol::Header* header =
120 reinterpret_cast<net::dns_protocol::Header*>(response.data());
121 header->ancount = base::HostToNet16(1);
122 header->flags |= base::HostToNet16(net::dns_protocol::kFlagResponse | rcode);
123
124 return response;
125 }
126
127 std::vector<std::string> GetSampleAuditProof(size_t length) {
128 std::vector<std::string> audit_proof(length);
129 // Makes each node of the audit proof different, so that tests are able to
130 // confirm that the audit proof is reconstructed in the correct order.
131 for (size_t i = 0; i < length; ++i) {
132 std::string node(crypto::kSHA256Length, '\0');
133 // Each node is 32 bytes, with each byte having a different value.
134 for (size_t j = 0; j < crypto::kSHA256Length; ++j) {
135 node[j] = static_cast<char>((-127 + i + j) % 128);
136 }
137 audit_proof[i].assign(std::move(node));
138 }
139
140 return audit_proof;
141 }
142
143 class MockLeafIndexCallback {
144 public:
145 MockLeafIndexCallback() : called_(false) {}
146
147 bool called() const { return called_; }
148 int net_error() const { return net_error_; }
149 uint64_t leaf_index() const { return leaf_index_; }
150
151 void Run(int net_error, uint64_t leaf_index) {
152 EXPECT_TRUE(!called_);
153 called_ = true;
154 net_error_ = net_error;
155 leaf_index_ = leaf_index;
156 run_loop_.Quit();
157 }
158
159 LogDnsClient::LeafIndexCallback AsCallback() {
160 return base::Bind(&MockLeafIndexCallback::Run, base::Unretained(this));
161 }
162
163 void WaitUntilRun() { run_loop_.Run(); }
164
165 private:
166 bool called_;
167 int net_error_;
168 uint64_t leaf_index_;
169 base::RunLoop run_loop_;
170 };
171
172 class MockAuditProofCallback {
173 public:
174 MockAuditProofCallback() : called_(false) {}
175
176 bool called() const { return called_; }
177 int net_error() const { return net_error_; }
178 const net::ct::MerkleAuditProof* proof() const { return proof_.get(); }
179
180 void Run(int net_error, std::unique_ptr<net::ct::MerkleAuditProof> proof) {
181 EXPECT_TRUE(!called_);
182 called_ = true;
183 net_error_ = net_error;
184 proof_ = std::move(proof);
185 run_loop_.Quit();
186 }
187
188 LogDnsClient::AuditProofCallback AsCallback() {
189 return base::Bind(&MockAuditProofCallback::Run, base::Unretained(this));
190 }
191
192 void WaitUntilRun() { run_loop_.Run(); }
193
194 private:
195 bool called_;
196 int net_error_;
197 std::unique_ptr<net::ct::MerkleAuditProof> proof_;
198 base::RunLoop run_loop_;
199 };
200
201 // A container for all of the data we need to keep alive for a mock socket.
202 // This is useful because Mock{Read,Write}, SequencedSocketData and
203 // MockClientSocketFactory all do not take ownership of or copy their arguments,
204 // so we have to manage the lifetime of those arguments ourselves. Wrapping all
205 // of that up in a single class simplifies this.
206 class MockSocketData {
207 public:
208 // A socket that expects one write and one read operation.
209 MockSocketData(const std::vector<char>& write, const std::vector<char>& read)
210 : expected_write_payload_(write),
211 expected_read_payload_(read),
212 expected_write_(net::SYNCHRONOUS,
213 expected_write_payload_.data(),
214 expected_write_payload_.size(),
215 0),
216 expected_read_(net::ASYNC,
217 expected_read_payload_.data(),
218 expected_read_payload_.size(),
219 1),
220 socket_data_(&expected_read_, 1, &expected_write_, 1) {}
221
222 // A socket that expects one write and a read error.
223 MockSocketData(const std::vector<char>& write, int net_error)
224 : expected_write_payload_(write),
225 expected_write_(net::SYNCHRONOUS,
226 expected_write_payload_.data(),
227 expected_write_payload_.size(),
228 0),
229 expected_read_(net::ASYNC, net_error, 1),
230 socket_data_(&expected_read_, 1, &expected_write_, 1) {}
231
232 void SetWriteMode(net::IoMode mode) { expected_write_.mode = mode; }
233 void SetReadMode(net::IoMode mode) { expected_read_.mode = mode; }
234
235 void AddToFactory(net::MockClientSocketFactory* socket_factory) {
236 socket_factory->AddSocketDataProvider(&socket_data_);
237 }
238
239 private:
240 const std::vector<char> expected_write_payload_;
241 const std::vector<char> expected_read_payload_;
242 net::MockWrite expected_write_;
243 net::MockRead expected_read_;
244 net::SequencedSocketData socket_data_;
245
246 DISALLOW_COPY_AND_ASSIGN(MockSocketData);
247 };
248
249 class LogDnsClientTest : public ::testing::TestWithParam<net::IoMode> {
250 protected:
251 std::unique_ptr<net::DnsClient> CreateDnsClient() {
252 net::DnsConfig config;
253 // Use an invalid nameserver address. This prevents the tests accidentally
254 // sending real DNS queries. The mock sockets don't care that the address
255 // is invalid.
256 config.nameservers.push_back(net::IPEndPoint());
257 // Don't attempt retransmissions - just fail.
258 config.attempts = 1;
259 // This ensures timeouts are long enough for memory tests.
260 config.timeout = TestTimeouts::action_timeout();
261 // Simplify testing - don't require random numbers for the source port.
262 // This means our FakeRandInt function should only be called to get query
263 // IDs.
264 config.randomize_ports = false;
265
266 std::unique_ptr<net::DnsClient> client =
267 net::DnsClient::CreateClientForTesting(nullptr, &socket_factory_,
268 base::Bind(&FakeRandInt));
269 client->SetConfig(config);
270 return client;
271 }
272
273 void ExpectRequestAndResponse(base::StringPiece qname,
274 base::StringPiece answer) {
275 std::vector<char> request = CreateDnsTxtRequest(qname);
276 std::vector<char> response = CreateDnsTxtResponse(request, answer);
277
278 mock_socket_data_.emplace_back(new MockSocketData(request, response));
279 mock_socket_data_.back()->SetReadMode(GetParam());
280 mock_socket_data_.back()->AddToFactory(&socket_factory_);
281 }
282
283 void ExpectRequestAndErrorResponse(base::StringPiece qname, uint8_t rcode) {
284 std::vector<char> request = CreateDnsTxtRequest(qname);
285 std::vector<char> response = CreateDnsErrorResponse(request, rcode);
286
287 mock_socket_data_.emplace_back(new MockSocketData(request, response));
288 mock_socket_data_.back()->SetReadMode(GetParam());
289 mock_socket_data_.back()->AddToFactory(&socket_factory_);
290 }
291
292 void ExpectRequestAndSocketError(base::StringPiece qname, int net_error) {
293 std::vector<char> request = CreateDnsTxtRequest(qname);
294
295 mock_socket_data_.emplace_back(new MockSocketData(request, net_error));
296 mock_socket_data_.back()->SetReadMode(GetParam());
297 mock_socket_data_.back()->AddToFactory(&socket_factory_);
298 }
299
300 void ExpectLeafIndexRequestAndResponse(base::StringPiece qname,
301 base::StringPiece leaf_index) {
302 // Prepend size to leaf_index to create the query answer (rdata)
303 ASSERT_LE(leaf_index.size(), 0xFFul); // size must fit into a single byte
304 std::string answer = leaf_index.as_string();
305 answer.insert(answer.begin(), static_cast<char>(leaf_index.size()));
306
307 ExpectRequestAndResponse(qname, answer);
308 }
309
310 void ExpectAuditProofRequestAndResponse(
311 base::StringPiece qname,
312 std::vector<std::string>::const_iterator audit_path_start,
313 std::vector<std::string>::const_iterator audit_path_end) {
314 // Join nodes in the audit path into a single string.
315 std::string proof =
316 std::accumulate(audit_path_start, audit_path_end, std::string());
317
318 // Prepend size to proof to create the query answer (rdata)
319 ASSERT_LE(proof.size(), 0xFFul); // size must fit into a single byte
320 proof.insert(proof.begin(), static_cast<char>(proof.size()));
321
322 ExpectRequestAndResponse(qname, proof);
323 }
324
325 void QueryLeafIndex(base::StringPiece log_domain,
326 base::StringPiece leaf_hash,
327 MockLeafIndexCallback* callback) {
328 std::unique_ptr<net::DnsClient> dns_client = CreateDnsClient();
329 LogDnsClient log_client(std::move(dns_client), net::BoundNetLog());
330
331 log_client.QueryLeafIndex(log_domain, leaf_hash, callback->AsCallback());
332 callback->WaitUntilRun();
333 }
334
335 void QueryAuditProof(base::StringPiece log_domain,
336 uint64_t leaf_index,
337 uint64_t tree_size,
338 MockAuditProofCallback* callback) {
339 std::unique_ptr<net::DnsClient> dns_client = CreateDnsClient();
340 LogDnsClient log_client(std::move(dns_client), net::BoundNetLog());
341
342 log_client.QueryAuditProof(log_domain, leaf_index, tree_size,
343 callback->AsCallback());
344 callback->WaitUntilRun();
345 }
346
347 base::MessageLoopForIO message_loop_;
348 std::vector<std::unique_ptr<MockSocketData>> mock_socket_data_;
349 net::MockClientSocketFactory socket_factory_;
350 };
351
352 TEST_P(LogDnsClientTest, QueryLeafIndex) {
353 ExpectLeafIndexRequestAndResponse(
354 "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
355 "123456");
356
357 MockLeafIndexCallback callback;
358 QueryLeafIndex("ct.test", kLeafHash, &callback);
359 ASSERT_TRUE(callback.called());
360 EXPECT_THAT(callback.net_error(), IsNetOk());
361 EXPECT_THAT(callback.leaf_index(), 123456);
362 }
363
364 TEST_P(LogDnsClientTest, QueryLeafIndexReportsThatLogDomainDoesNotExist) {
365 ExpectRequestAndErrorResponse(
366 "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
367 net::dns_protocol::kRcodeNXDOMAIN);
368
369 MockLeafIndexCallback callback;
370 QueryLeafIndex("ct.test", kLeafHash, &callback);
371 ASSERT_TRUE(callback.called());
372 EXPECT_THAT(callback.net_error(), IsNetError(net::ERR_NAME_NOT_RESOLVED));
373 EXPECT_THAT(callback.leaf_index(), 0);
374 }
375
376 TEST_P(LogDnsClientTest, QueryLeafIndexReportsServerFailure) {
377 ExpectRequestAndErrorResponse(
378 "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
379 net::dns_protocol::kRcodeSERVFAIL);
380
381 MockLeafIndexCallback callback;
382 QueryLeafIndex("ct.test", kLeafHash, &callback);
383 ASSERT_TRUE(callback.called());
384 EXPECT_THAT(callback.net_error(), IsNetError(net::ERR_DNS_SERVER_FAILED));
385 EXPECT_THAT(callback.leaf_index(), 0);
386 }
387
388 TEST_P(LogDnsClientTest, QueryLeafIndexReportsServerRefusal) {
389 ExpectRequestAndErrorResponse(
390 "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
391 net::dns_protocol::kRcodeREFUSED);
392
393 MockLeafIndexCallback callback;
394 QueryLeafIndex("ct.test", kLeafHash, &callback);
395 ASSERT_TRUE(callback.called());
396 EXPECT_THAT(callback.net_error(), IsNetError(net::ERR_DNS_SERVER_FAILED));
397 EXPECT_THAT(callback.leaf_index(), 0);
398 }
399
400 TEST_P(LogDnsClientTest,
401 QueryLeafIndexReportsMalformedResponseIfLeafIndexIsNotNumeric) {
402 ExpectLeafIndexRequestAndResponse(
403 "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
404 "foo");
405
406 MockLeafIndexCallback callback;
407 QueryLeafIndex("ct.test", kLeafHash, &callback);
408 ASSERT_TRUE(callback.called());
409 EXPECT_THAT(callback.net_error(),
410 IsNetError(net::ERR_DNS_MALFORMED_RESPONSE));
411 EXPECT_THAT(callback.leaf_index(), 0);
412 }
413
414 TEST_P(LogDnsClientTest,
415 QueryLeafIndexReportsMalformedResponseIfLeafIndexIsFloatingPoint) {
416 ExpectLeafIndexRequestAndResponse(
417 "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
418 "123456.0");
419
420 MockLeafIndexCallback callback;
421 QueryLeafIndex("ct.test", kLeafHash, &callback);
422 ASSERT_TRUE(callback.called());
423 EXPECT_THAT(callback.net_error(),
424 IsNetError(net::ERR_DNS_MALFORMED_RESPONSE));
425 EXPECT_THAT(callback.leaf_index(), 0);
426 }
427
428 TEST_P(LogDnsClientTest,
429 QueryLeafIndexReportsMalformedResponseIfLeafIndexIsEmpty) {
430 ExpectLeafIndexRequestAndResponse(
431 "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.", "");
432
433 MockLeafIndexCallback callback;
434 QueryLeafIndex("ct.test", kLeafHash, &callback);
435 ASSERT_TRUE(callback.called());
436 EXPECT_THAT(callback.net_error(),
437 IsNetError(net::ERR_DNS_MALFORMED_RESPONSE));
438 EXPECT_THAT(callback.leaf_index(), 0);
439 }
440
441 TEST_P(LogDnsClientTest,
442 QueryLeafIndexReportsMalformedResponseIfLeafIndexHasNonNumericPrefix) {
443 ExpectLeafIndexRequestAndResponse(
444 "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
445 "foo123456");
446
447 MockLeafIndexCallback callback;
448 QueryLeafIndex("ct.test", kLeafHash, &callback);
449 ASSERT_TRUE(callback.called());
450 EXPECT_THAT(callback.net_error(),
451 IsNetError(net::ERR_DNS_MALFORMED_RESPONSE));
452 EXPECT_THAT(callback.leaf_index(), 0);
453 }
454
455 TEST_P(LogDnsClientTest,
456 QueryLeafIndexReportsMalformedResponseIfLeafIndexHasNonNumericSuffix) {
457 ExpectLeafIndexRequestAndResponse(
458 "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
459 "123456foo");
460
461 MockLeafIndexCallback callback;
462 QueryLeafIndex("ct.test", kLeafHash, &callback);
463 ASSERT_TRUE(callback.called());
464 EXPECT_THAT(callback.net_error(),
465 IsNetError(net::ERR_DNS_MALFORMED_RESPONSE));
466 EXPECT_THAT(callback.leaf_index(), 0);
467 }
468
469 TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLogDomainIsEmpty) {
470 MockLeafIndexCallback callback;
471 QueryLeafIndex("", kLeafHash, &callback);
472 ASSERT_TRUE(callback.called());
473 EXPECT_THAT(callback.net_error(), IsNetError(net::ERR_INVALID_ARGUMENT));
474 EXPECT_THAT(callback.leaf_index(), 0);
475 }
476
477 TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLogDomainIsNull) {
478 MockLeafIndexCallback callback;
479 QueryLeafIndex(nullptr, kLeafHash, &callback);
480 ASSERT_TRUE(callback.called());
481 EXPECT_THAT(callback.net_error(), IsNetError(net::ERR_INVALID_ARGUMENT));
482 EXPECT_THAT(callback.leaf_index(), 0);
483 }
484
485 TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsInvalid) {
486 MockLeafIndexCallback callback;
487 QueryLeafIndex("ct.test", "foo", &callback);
488 ASSERT_TRUE(callback.called());
489 EXPECT_THAT(callback.net_error(), IsNetError(net::ERR_INVALID_ARGUMENT));
490 EXPECT_THAT(callback.leaf_index(), 0);
491 }
492
493 TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsEmpty) {
494 MockLeafIndexCallback callback;
495 QueryLeafIndex("ct.test", "", &callback);
496 ASSERT_TRUE(callback.called());
497 EXPECT_THAT(callback.net_error(), IsNetError(net::ERR_INVALID_ARGUMENT));
498 EXPECT_THAT(callback.leaf_index(), 0);
499 }
500
501 TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsNull) {
502 MockLeafIndexCallback callback;
503 QueryLeafIndex("ct.test", nullptr, &callback);
504 ASSERT_TRUE(callback.called());
505 EXPECT_THAT(callback.net_error(), IsNetError(net::ERR_INVALID_ARGUMENT));
506 EXPECT_THAT(callback.leaf_index(), 0);
507 }
508
509 TEST_P(LogDnsClientTest, QueryLeafIndexReportsSocketError) {
510 ExpectRequestAndSocketError(
511 "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
512 net::ERR_CONNECTION_REFUSED);
513
514 MockLeafIndexCallback callback;
515 QueryLeafIndex("ct.test", kLeafHash, &callback);
516 ASSERT_TRUE(callback.called());
517 EXPECT_THAT(callback.net_error(), IsNetError(net::ERR_CONNECTION_REFUSED));
518 EXPECT_THAT(callback.leaf_index(), 0);
519 }
520
521 TEST_P(LogDnsClientTest, QueryAuditProof) {
522 const std::vector<std::string> audit_proof = GetSampleAuditProof(20);
523
524 // It should require 3 queries to collect the entire audit proof, as there is
525 // only space for 7 nodes per UDP packet.
526 ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
527 audit_proof.begin(),
528 audit_proof.begin() + 7);
529 ExpectAuditProofRequestAndResponse("7.123456.999999.tree.ct.test.",
530 audit_proof.begin() + 7,
531 audit_proof.begin() + 14);
532 ExpectAuditProofRequestAndResponse("14.123456.999999.tree.ct.test.",
533 audit_proof.begin() + 14,
534 audit_proof.end());
535
536 MockAuditProofCallback callback;
537 QueryAuditProof("ct.test", 123456, 999999, &callback);
538 ASSERT_TRUE(callback.called());
539 EXPECT_THAT(callback.net_error(), IsNetOk());
540 ASSERT_THAT(callback.proof(), NotNull());
541 EXPECT_THAT(callback.proof()->leaf_index, 123456);
542 EXPECT_THAT(callback.proof()->nodes, audit_proof);
543 }
544
545 TEST_P(LogDnsClientTest,
546 QueryAuditProofHandlesResponsesWithEmptyAndShortAuditPaths) {
547 const std::vector<std::string> audit_proof = GetSampleAuditProof(20);
548
549 // Make some of the responses empty or contain fewer audit proof nodes than
550 // they can hold.
551 ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
552 audit_proof.begin(), audit_proof.begin());
553 ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
554 audit_proof.begin(),
555 audit_proof.begin() + 1);
556 ExpectAuditProofRequestAndResponse("1.123456.999999.tree.ct.test.",
557 audit_proof.begin() + 1,
558 audit_proof.begin() + 3);
559 ExpectAuditProofRequestAndResponse("3.123456.999999.tree.ct.test.",
560 audit_proof.begin() + 3,
561 audit_proof.begin() + 6);
562 ExpectAuditProofRequestAndResponse("6.123456.999999.tree.ct.test.",
563 audit_proof.begin() + 6,
564 audit_proof.begin() + 10);
565 ExpectAuditProofRequestAndResponse("10.123456.999999.tree.ct.test.",
566 audit_proof.begin() + 10,
567 audit_proof.begin() + 13);
568 ExpectAuditProofRequestAndResponse("13.123456.999999.tree.ct.test.",
569 audit_proof.begin() + 13,
570 audit_proof.end());
571
572 MockAuditProofCallback callback;
573 QueryAuditProof("ct.test", 123456, 999999, &callback);
574 ASSERT_TRUE(callback.called());
575 EXPECT_THAT(callback.net_error(), IsNetOk());
576 ASSERT_THAT(callback.proof(), NotNull());
577 EXPECT_THAT(callback.proof()->leaf_index, 123456);
578 EXPECT_THAT(callback.proof()->nodes, audit_proof);
579 }
580
581 TEST_P(LogDnsClientTest, QueryAuditProofReportsThatLogDomainDoesNotExist) {
582 ExpectRequestAndErrorResponse("0.123456.999999.tree.ct.test.",
583 net::dns_protocol::kRcodeNXDOMAIN);
584
585 MockAuditProofCallback callback;
586 QueryAuditProof("ct.test", 123456, 999999, &callback);
587 ASSERT_TRUE(callback.called());
588 EXPECT_THAT(callback.net_error(), IsNetError(net::ERR_NAME_NOT_RESOLVED));
589 EXPECT_THAT(callback.proof(), IsNull());
590 }
591
592 TEST_P(LogDnsClientTest, QueryAuditProofReportsServerFailure) {
593 ExpectRequestAndErrorResponse("0.123456.999999.tree.ct.test.",
594 net::dns_protocol::kRcodeSERVFAIL);
595
596 MockAuditProofCallback callback;
597 QueryAuditProof("ct.test", 123456, 999999, &callback);
598 ASSERT_TRUE(callback.called());
599 EXPECT_THAT(callback.net_error(), IsNetError(net::ERR_DNS_SERVER_FAILED));
600 EXPECT_THAT(callback.proof(), IsNull());
601 }
602
603 TEST_P(LogDnsClientTest, QueryAuditProofReportsServerRefusal) {
604 ExpectRequestAndErrorResponse("0.123456.999999.tree.ct.test.",
605 net::dns_protocol::kRcodeREFUSED);
606
607 MockAuditProofCallback callback;
608 QueryAuditProof("ct.test", 123456, 999999, &callback);
609 ASSERT_TRUE(callback.called());
610 EXPECT_THAT(callback.net_error(), IsNetError(net::ERR_DNS_SERVER_FAILED));
611 EXPECT_THAT(callback.proof(), IsNull());
612 }
613
614 TEST_P(LogDnsClientTest,
615 QueryAuditProofReportsResponseMalformedIfNodeTooShort) {
616 // node is shorter than a SHA-256 hash (31 vs 32 bytes)
617 const std::vector<std::string> audit_proof(1, std::string(31, 'a'));
618
619 ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
620 audit_proof.begin(), audit_proof.end());
621
622 MockAuditProofCallback callback;
623 QueryAuditProof("ct.test", 123456, 999999, &callback);
624 ASSERT_TRUE(callback.called());
625 EXPECT_THAT(callback.net_error(),
626 IsNetError(net::ERR_DNS_MALFORMED_RESPONSE));
627 EXPECT_THAT(callback.proof(), IsNull());
628 }
629
630 TEST_P(LogDnsClientTest, QueryAuditProofReportsResponseMalformedIfNodeTooLong) {
631 // node is longer than a SHA-256 hash (33 vs 32 bytes)
632 const std::vector<std::string> audit_proof(1, std::string(33, 'a'));
633
634 ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
635 audit_proof.begin(), audit_proof.end());
636
637 MockAuditProofCallback callback;
638 QueryAuditProof("ct.test", 123456, 999999, &callback);
639 ASSERT_TRUE(callback.called());
640 EXPECT_THAT(callback.net_error(),
641 IsNetError(net::ERR_DNS_MALFORMED_RESPONSE));
642 EXPECT_THAT(callback.proof(), IsNull());
643 }
644
645 TEST_P(LogDnsClientTest, QueryAuditProofReportsInvalidArgIfLogDomainIsEmpty) {
646 MockAuditProofCallback callback;
647 QueryAuditProof("", 123456, 999999, &callback);
648 ASSERT_TRUE(callback.called());
649 EXPECT_THAT(callback.net_error(), IsNetError(net::ERR_INVALID_ARGUMENT));
650 EXPECT_THAT(callback.proof(), IsNull());
651 }
652
653 TEST_P(LogDnsClientTest, QueryAuditProofReportsInvalidArgIfLogDomainIsNull) {
654 MockAuditProofCallback callback;
655 QueryAuditProof(nullptr, 123456, 999999, &callback);
656 ASSERT_TRUE(callback.called());
657 EXPECT_THAT(callback.net_error(), IsNetError(net::ERR_INVALID_ARGUMENT));
658 EXPECT_THAT(callback.proof(), IsNull());
659 }
660
661 TEST_P(LogDnsClientTest,
662 QueryAuditProofReportsInvalidArgIfLeafIndexEqualToTreeSize) {
663 MockAuditProofCallback callback;
664 QueryAuditProof("ct.test", 123456, 123456, &callback);
665 ASSERT_TRUE(callback.called());
666 EXPECT_THAT(callback.net_error(), IsNetError(net::ERR_INVALID_ARGUMENT));
667 EXPECT_THAT(callback.proof(), IsNull());
668 }
669
670 TEST_P(LogDnsClientTest,
671 QueryAuditProofReportsInvalidArgIfLeafIndexGreaterThanTreeSize) {
672 MockAuditProofCallback callback;
673 QueryAuditProof("ct.test", 999999, 123456, &callback);
674 ASSERT_TRUE(callback.called());
675 EXPECT_THAT(callback.net_error(), IsNetError(net::ERR_INVALID_ARGUMENT));
676 EXPECT_THAT(callback.proof(), IsNull());
677 }
678
679 TEST_P(LogDnsClientTest, QueryAuditProofReportsSocketError) {
680 ExpectRequestAndSocketError("0.123456.999999.tree.ct.test.",
681 net::ERR_CONNECTION_REFUSED);
682
683 MockAuditProofCallback callback;
684 QueryAuditProof("ct.test", 123456, 999999, &callback);
685 ASSERT_TRUE(callback.called());
686 EXPECT_THAT(callback.net_error(), IsNetError(net::ERR_CONNECTION_REFUSED));
687 EXPECT_THAT(callback.proof(), IsNull());
688 }
689
690 INSTANTIATE_TEST_CASE_P(ReadMode,
691 LogDnsClientTest,
692 ::testing::Values(net::IoMode::ASYNC,
693 net::IoMode::SYNCHRONOUS));
694
695 } // namespace
696 } // namespace certificate_transparency
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698