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

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

Powered by Google App Engine
This is Rietveld 408576698