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

Side by Side Diff: net/cert/ct_log_verifier_unittest.cc

Issue 2182533002: Adds a VerifyAuditProof method to CTLogVerifier (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addresses some of Ryan Sleevi's comments Created 4 years, 3 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 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "net/cert/ct_log_verifier.h" 5 #include "net/cert/ct_log_verifier.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <memory> 9 #include <memory>
10 #include <string> 10 #include <string>
11 #include <vector> 11 #include <vector>
12 12
13 #include "base/macros.h"
13 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
14 #include "base/time/time.h" 15 #include "base/time/time.h"
15 #include "crypto/secure_hash.h" 16 #include "crypto/secure_hash.h"
16 #include "net/base/hash_value.h" 17 #include "net/base/hash_value.h"
17 #include "net/cert/ct_log_verifier_util.h" 18 #include "net/cert/ct_log_verifier_util.h"
19 #include "net/cert/merkle_audit_proof.h"
18 #include "net/cert/merkle_consistency_proof.h" 20 #include "net/cert/merkle_consistency_proof.h"
19 #include "net/cert/signed_certificate_timestamp.h" 21 #include "net/cert/signed_certificate_timestamp.h"
20 #include "net/cert/signed_tree_head.h" 22 #include "net/cert/signed_tree_head.h"
21 #include "net/test/ct_test_util.h" 23 #include "net/test/ct_test_util.h"
22 #include "testing/gtest/include/gtest/gtest.h" 24 #include "testing/gtest/include/gtest/gtest.h"
23 25
24 namespace net { 26 namespace net {
25 27
26 namespace { 28 namespace {
27 29
(...skipping 18 matching lines...) Expand all
46 size_t proof_length; 48 size_t proof_length;
47 const char* const proof[3]; 49 const char* const proof[3];
48 }; 50 };
49 51
50 // All test data replicated from 52 // All test data replicated from
51 // https://github.com/google/certificate-transparency/blob/c41b090ecc14ddd6b3531 dc7e5ce36b21e253fdd/cpp/merkletree/merkle_tree_test.cc 53 // https://github.com/google/certificate-transparency/blob/c41b090ecc14ddd6b3531 dc7e5ce36b21e253fdd/cpp/merkletree/merkle_tree_test.cc
52 // A hash of the empty string. 54 // A hash of the empty string.
53 const char* const kSHA256EmptyTreeHash = 55 const char* const kSHA256EmptyTreeHash =
54 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; 56 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
55 57
58 // Hashes of the leaf data for the sample tree (8 leaves).
59 const char* const kSHA256LeafHashes[8] = {
60 "6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d",
61 "96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7",
62 "0298d122906dcfc10892cb53a73992fc5b9f493ea4c9badb27b791b4127a7fe7",
63 "07506a85fd9dd2f120eb694f86011e5bb4662e5c415a62917033d4a9624487e7",
64 "bc1a0643b12e4d2d7c77918f44e0f4f79a838b6cf9ec5b5c283e1f4d88599e6b",
65 "4271a26be0d8a84f0bd54c8c302e7cb3a3b5d1fa6780a40bcce2873477dab658",
66 "b08693ec2e721597130641e8211e7eedccb4c26413963eee6c1e2ed16ffb1a5f",
67 "46f6ffadd3d06a09ff3c5860d2755c8b9819db7df44251788c7d8e3180de8eb1"};
68
56 // Root hashes from building the sample tree of size 8 leaf-by-leaf. 69 // Root hashes from building the sample tree of size 8 leaf-by-leaf.
57 // The first entry is the root at size 0, the last is the root at size 8. 70 // The first entry is the root at size 0, the last is the root at size 8.
58 const char* const kSHA256Roots[8] = { 71 const char* const kSHA256Roots[8] = {
59 "6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d", 72 "6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d",
60 "fac54203e7cc696cf0dfcb42c92a1d9dbaf70ad9e621f4bd8d98662f00e3c125", 73 "fac54203e7cc696cf0dfcb42c92a1d9dbaf70ad9e621f4bd8d98662f00e3c125",
61 "aeb6bcfe274b70a14fb067a5e5578264db0fa9b51af5e0ba159158f329e06e77", 74 "aeb6bcfe274b70a14fb067a5e5578264db0fa9b51af5e0ba159158f329e06e77",
62 "d37ee418976dd95753c1c73862b9398fa2a2cf9b4ff0fdfe8b30cd95209614b7", 75 "d37ee418976dd95753c1c73862b9398fa2a2cf9b4ff0fdfe8b30cd95209614b7",
63 "4e3bbb1f7b478dcfe71fb631631519a3bca12c9aefca1612bfce4c13a86264d4", 76 "4e3bbb1f7b478dcfe71fb631631519a3bca12c9aefca1612bfce4c13a86264d4",
64 "76e67dadbcdf1e10e1b74ddc608abd2f98dfb16fbce75277b5232a127f2087ef", 77 "76e67dadbcdf1e10e1b74ddc608abd2f98dfb16fbce75277b5232a127f2087ef",
65 "ddb89be403809e325750d3d263cd78929c2942b7942a34b77e122c9594a74c8c", 78 "ddb89be403809e325750d3d263cd78929c2942b7942a34b77e122c9594a74c8c",
(...skipping 21 matching lines...) Expand all
87 "ca854ea128ed050b41b35ffc1b87b8eb2bde461e9e3b5596ece6b9d5975a0ae0", 100 "ca854ea128ed050b41b35ffc1b87b8eb2bde461e9e3b5596ece6b9d5975a0ae0",
88 "d37ee418976dd95753c1c73862b9398fa2a2cf9b4ff0fdfe8b30cd95209614b7"}}, 101 "d37ee418976dd95753c1c73862b9398fa2a2cf9b4ff0fdfe8b30cd95209614b7"}},
89 // Consistency proof between tree of size 2 and tree of size 5, with 2 102 // Consistency proof between tree of size 2 and tree of size 5, with 2
90 // nodes in the proof. 103 // nodes in the proof.
91 {2, 104 {2,
92 5, 105 5,
93 2, 106 2,
94 {"5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e", 107 {"5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e",
95 "bc1a0643b12e4d2d7c77918f44e0f4f79a838b6cf9ec5b5c283e1f4d88599e6b", ""}}}; 108 "bc1a0643b12e4d2d7c77918f44e0f4f79a838b6cf9ec5b5c283e1f4d88599e6b", ""}}};
96 109
110 // A single audit proof. Contains the leaf index (leaf), tree size (snapshot),
111 // the length of the proof (proof_length) and at most 3 proof nodes (all test
112 // proofs will be for a tree of size 8).
113 struct PathTestVector {
114 uint64_t leaf;
115 uint64_t snapshot;
116 size_t path_length;
117 const char* const path[3];
118 };
119
120 // A collection of audit proofs for various leaves and sub-trees of the tree
121 // defined by |kSHA256Roots|.
122 const PathTestVector kSHA256Paths[6] = {
123 {0, 0, 0, {"", "", ""}},
124 {1, 1, 0, {"", "", ""}},
125 {1,
126 8,
127 3,
128 {"96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7",
129 "5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e",
130 "6b47aaf29ee3c2af9af889bc1fb9254dabd31177f16232dd6aab035ca39bf6e4"}},
131 {6,
132 8,
133 3,
134 {"bc1a0643b12e4d2d7c77918f44e0f4f79a838b6cf9ec5b5c283e1f4d88599e6b",
135 "ca854ea128ed050b41b35ffc1b87b8eb2bde461e9e3b5596ece6b9d5975a0ae0",
136 "d37ee418976dd95753c1c73862b9398fa2a2cf9b4ff0fdfe8b30cd95209614b7"}},
137 {3,
138 3,
139 1,
140 {"fac54203e7cc696cf0dfcb42c92a1d9dbaf70ad9e621f4bd8d98662f00e3c125", "",
141 ""}},
142 {2,
143 5,
144 3,
145 {"6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d",
146 "5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e",
147 "bc1a0643b12e4d2d7c77918f44e0f4f79a838b6cf9ec5b5c283e1f4d88599e6b"}}};
148
97 // Decodes a hexadecimal string into the binary data it represents. 149 // Decodes a hexadecimal string into the binary data it represents.
98 std::string HexToBytes(const std::string& hex_data) { 150 std::string HexToBytes(const std::string& hex_data) {
99 std::vector<uint8_t> output; 151 std::vector<uint8_t> output;
100 std::string result; 152 std::string result;
101 if (base::HexStringToBytes(hex_data, &output)) 153 if (base::HexStringToBytes(hex_data, &output))
102 result.assign(output.begin(), output.end()); 154 result.assign(output.begin(), output.end());
103 return result; 155 return result;
104 } 156 }
105 157
106 const std::string& GetEmptyTreeHash() { 158 const std::string& GetEmptyTreeHash() {
107 static const std::string empty_hash = HexToBytes(kSHA256EmptyTreeHash); 159 static const std::string empty_hash = HexToBytes(kSHA256EmptyTreeHash);
108 return empty_hash; 160 return empty_hash;
109 } 161 }
110 162
111 // Creates a ct::MerkleConsistencyProof and returns the result of 163 // Creates a ct::MerkleConsistencyProof and returns the result of
112 // calling log->VerifyConsistencyProof with that proof and snapshots. 164 // calling log->VerifyConsistencyProof with that proof and snapshots.
113 bool VerifyConsistencyProof(scoped_refptr<const CTLogVerifier> log, 165 bool VerifyConsistencyProof(scoped_refptr<const CTLogVerifier> log,
114 uint64_t old_tree_size, 166 uint64_t old_tree_size,
115 const std::string& old_tree_root, 167 const std::string& old_tree_root,
116 uint64_t new_tree_size, 168 uint64_t new_tree_size,
117 const std::string& new_tree_root, 169 const std::string& new_tree_root,
118 const std::vector<std::string>& proof) { 170 const std::vector<std::string>& proof) {
119 return log->VerifyConsistencyProof( 171 return log->VerifyConsistencyProof(
120 ct::MerkleConsistencyProof(log->key_id(), proof, old_tree_size, 172 ct::MerkleConsistencyProof(log->key_id(), proof, old_tree_size,
121 new_tree_size), 173 new_tree_size),
122 old_tree_root, new_tree_root); 174 old_tree_root, new_tree_root);
123 } 175 }
124 176
177 bool VerifyAuditProof(scoped_refptr<const CTLogVerifier> log,
Ryan Sleevi 2016/08/25 18:56:24 STYLE: https://chromium.googlesource.com/chromium/
Rob Percival 2016/10/03 17:39:26 Done.
178 uint64_t leaf,
179 uint64_t tree_size,
180 const std::vector<std::string>& proof,
181 const std::string& tree_root,
182 const std::string& leaf_hash) {
183 // Test vectors use a 1-based leaf index, but CTLogVerifier uses a 0-based
184 // index. We need to map |leaf| to a 0-based index but there is no mapping for
185 // 0, so reject it. Subtract 1 from any other value.
186 if (leaf == 0)
187 return false;
188 return log->VerifyAuditProof(ct::MerkleAuditProof(leaf - 1, tree_size, proof),
189 tree_root, leaf_hash);
190 }
191
125 class CTLogVerifierTest : public ::testing::Test { 192 class CTLogVerifierTest : public ::testing::Test {
126 public: 193 public:
127 CTLogVerifierTest() {} 194 CTLogVerifierTest() {}
128 195
129 void SetUp() override { 196 void SetUp() override {
130 log_ = CTLogVerifier::Create(ct::GetTestPublicKey(), "testlog", 197 log_ = CTLogVerifier::Create(ct::GetTestPublicKey(), "testlog",
131 "https://ct.example.com", "ct.example.com"); 198 "https://ct.example.com", "ct.example.com");
132 199
133 ASSERT_TRUE(log_); 200 ASSERT_TRUE(log_);
134 ASSERT_EQ(ct::GetTestPublicKeyId(), log_->key_id()); 201 ASSERT_EQ(ct::GetTestPublicKeyId(), log_->key_id());
135 ASSERT_EQ("ct.example.com", log_->dns_domain()); 202 ASSERT_EQ("ct.example.com", log_->dns_domain());
136 } 203 }
137 204
205 // Given an audit proof for a leaf in the tree, asserts that it verifies and
206 // no other combination of leaves, snapshots and proof nodes verifies.
207 void VerifierCheck(int leaf,
208 int tree_size,
209 const std::vector<std::string>& path,
210 const std::string& root,
211 const std::string& leaf_hash) {
212 // Verify the original path.
213 EXPECT_TRUE(VerifyAuditProof(log_, leaf, tree_size, path, root, leaf_hash));
214
215 // Wrong leaf index.
216 EXPECT_FALSE(
217 VerifyAuditProof(log_, leaf - 1, tree_size, path, root, leaf_hash));
218 EXPECT_FALSE(
219 VerifyAuditProof(log_, leaf + 1, tree_size, path, root, leaf_hash));
220 EXPECT_FALSE(
221 VerifyAuditProof(log_, leaf ^ 2, tree_size, path, root, leaf_hash));
222
223 // Wrong tree height.
224 EXPECT_FALSE(
225 VerifyAuditProof(log_, leaf, tree_size * 2, path, root, leaf_hash));
226 EXPECT_FALSE(
227 VerifyAuditProof(log_, leaf, tree_size / 2, path, root, leaf_hash));
228
229 // Wrong root.
230 EXPECT_FALSE(VerifyAuditProof(log_, leaf, tree_size, path,
231 GetEmptyTreeHash(), leaf_hash));
232
233 // Wrong paths.
234 std::vector<std::string> wrong_path;
235
236 // Modify a single element on the path.
237 for (size_t j = 0; j < path.size(); ++j) {
238 wrong_path = path;
239 wrong_path[j] = HexToBytes(kSHA256EmptyTreeHash);
240 EXPECT_FALSE(
241 VerifyAuditProof(log_, leaf, tree_size, wrong_path, root, leaf_hash));
242 }
243
244 // Add garbage at the end of the path.
245 wrong_path = path;
246 wrong_path.push_back(std::string());
247 EXPECT_FALSE(
248 VerifyAuditProof(log_, leaf, tree_size, wrong_path, root, leaf_hash));
249 wrong_path.pop_back();
250
251 wrong_path.push_back(root);
Ryan Sleevi 2016/08/25 18:56:24 PERFORMANCE: Since you were concerned about perf i
Rob Percival 2016/10/03 17:39:25 Done.
252 EXPECT_FALSE(
253 VerifyAuditProof(log_, leaf, tree_size, wrong_path, root, leaf_hash));
254 wrong_path.pop_back();
255
256 // Remove a node from the end.
257 if (!wrong_path.empty()) {
258 wrong_path.pop_back();
259 EXPECT_FALSE(
260 VerifyAuditProof(log_, leaf, tree_size, wrong_path, root, leaf_hash));
261 }
262
263 // Add garbage in the beginning of the path.
264 wrong_path.clear();
265 wrong_path.push_back(std::string());
266 wrong_path.insert(wrong_path.end(), path.begin(), path.end());
267 EXPECT_FALSE(
268 VerifyAuditProof(log_, leaf, tree_size, wrong_path, root, leaf_hash));
269
270 wrong_path[0] = root;
271 EXPECT_FALSE(
272 VerifyAuditProof(log_, leaf, tree_size, wrong_path, root, leaf_hash));
273 }
274
138 // Given a consistency proof between two snapshots of the tree, asserts that 275 // Given a consistency proof between two snapshots of the tree, asserts that
139 // it verifies and no other combination of snapshots and proof nodes verifies. 276 // it verifies and no other combination of snapshots and proof nodes verifies.
140 void VerifierConsistencyCheck(int snapshot1, 277 void VerifierConsistencyCheck(int snapshot1,
141 int snapshot2, 278 int snapshot2,
142 const std::string& root1, 279 const std::string& root1,
143 const std::string& root2, 280 const std::string& root2,
144 const std::vector<std::string>& proof) { 281 const std::vector<std::string>& proof) {
145 // Verify the original consistency proof. 282 // Verify the original consistency proof.
146 EXPECT_TRUE( 283 EXPECT_TRUE(
147 VerifyConsistencyProof(log_, snapshot1, root1, snapshot2, root2, proof)) 284 VerifyConsistencyProof(log_, snapshot1, root1, snapshot2, root2, proof))
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
354 // proofs with redundant nodes in this case). 491 // proofs with redundant nodes in this case).
355 proof.push_back(empty_tree_hash); 492 proof.push_back(empty_tree_hash);
356 EXPECT_FALSE(VerifyConsistencyProof(log_, 0, empty_tree_hash, 0, 493 EXPECT_FALSE(VerifyConsistencyProof(log_, 0, empty_tree_hash, 0,
357 empty_tree_hash, proof)); 494 empty_tree_hash, proof));
358 EXPECT_FALSE(VerifyConsistencyProof(log_, 0, empty_tree_hash, 1, 495 EXPECT_FALSE(VerifyConsistencyProof(log_, 0, empty_tree_hash, 1,
359 empty_tree_hash, proof)); 496 empty_tree_hash, proof));
360 EXPECT_FALSE(VerifyConsistencyProof(log_, 1, empty_tree_hash, 1, 497 EXPECT_FALSE(VerifyConsistencyProof(log_, 1, empty_tree_hash, 1,
361 empty_tree_hash, proof)); 498 empty_tree_hash, proof));
362 } 499 }
363 500
364 TEST_F(CTLogVerifierTest, VerifiesValidConsistencyProofs) { 501 class CTLogVerifierConsistencyProofTest
502 : public CTLogVerifierTest,
503 public ::testing::WithParamInterface<size_t> {};
Ryan Sleevi 2016/08/25 18:56:24 <size_t /* tree_size */> ?
Rob Percival 2016/10/03 17:39:25 Done.
504
505 TEST_P(CTLogVerifierConsistencyProofTest, VerifiesValidConsistencyProof) {
506 const size_t i = GetParam();
365 std::vector<std::string> proof; 507 std::vector<std::string> proof;
366 std::string root1, root2; 508 for (size_t j = 0; j < kSHA256Proofs[i].proof_length; ++j) {
509 proof.push_back(HexToBytes(kSHA256Proofs[i].proof[j]));
510 }
511 const uint64_t snapshot1 = kSHA256Proofs[i].snapshot1;
512 const uint64_t snapshot2 = kSHA256Proofs[i].snapshot2;
513 const char* const old_root = kSHA256Roots[snapshot1 - 1];
514 const char* const new_root = kSHA256Roots[snapshot2 - 1];
515 VerifierConsistencyCheck(snapshot1, snapshot2, HexToBytes(old_root),
516 HexToBytes(new_root), proof);
517 }
367 518
368 // Known good proofs. 519 INSTANTIATE_TEST_CASE_P(KnownGoodProofs,
369 for (size_t i = 0; i < arraysize(kSHA256Proofs); ++i) { 520 CTLogVerifierConsistencyProofTest,
370 SCOPED_TRACE(i); 521 ::testing::Range(0ul, arraysize(kSHA256Proofs)));
371 proof.clear();
372 for (size_t j = 0; j < kSHA256Proofs[i].proof_length; ++j) {
373 const char* const v = kSHA256Proofs[i].proof[j];
374 proof.push_back(HexToBytes(v));
375 }
376 const uint64_t snapshot1 = kSHA256Proofs[i].snapshot1;
377 const uint64_t snapshot2 = kSHA256Proofs[i].snapshot2;
378 const char* const old_root = kSHA256Roots[snapshot1 - 1];
379 const char* const new_root = kSHA256Roots[snapshot2 - 1];
380 VerifierConsistencyCheck(snapshot1, snapshot2, HexToBytes(old_root),
381 HexToBytes(new_root), proof);
382 }
383 }
384 522
385 const char kLeafPrefix[] = {'\x00'}; 523 const char kLeafPrefix[] = {'\x00'};
386 524
387 // Reference implementation of RFC6962. 525 // Reference implementation of RFC6962.
388 // This allows generation of arbitrary-sized Merkle trees and consistency 526 // This allows generation of arbitrary-sized Merkle trees and consistency
389 // proofs between them for testing the consistency proof validation 527 // proofs between them for testing the consistency proof validation
390 // code. 528 // code.
391 class TreeHasher { 529 class TreeHasher {
392 public: 530 public:
393 static std::string HashLeaf(const std::string& leaf) { 531 static std::string HashLeaf(const std::string& leaf) {
(...skipping 20 matching lines...) Expand all
414 if (input_size == 1) 552 if (input_size == 1)
415 return TreeHasher::HashLeaf(inputs[0]); 553 return TreeHasher::HashLeaf(inputs[0]);
416 554
417 const uint64_t split = CalculateNearestPowerOfTwo(input_size); 555 const uint64_t split = CalculateNearestPowerOfTwo(input_size);
418 556
419 return ct::internal::HashNodes( 557 return ct::internal::HashNodes(
420 ReferenceMerkleTreeHash(&inputs[0], split), 558 ReferenceMerkleTreeHash(&inputs[0], split),
421 ReferenceMerkleTreeHash(&inputs[split], input_size - split)); 559 ReferenceMerkleTreeHash(&inputs[split], input_size - split));
422 } 560 }
423 561
562 // Reference implementation of Merkle paths. Path from leaf to root,
563 // excluding the leaf and root themselves. Returns an audit proof for the tree
564 // leaf with index |leaf| (1-based). The tree is designated by |inputs|.
Ryan Sleevi 2016/08/25 18:56:24 I'm completely struggling to understand what this
Rob Percival 2016/10/03 17:39:26 Don't worry about "piling on", I didn't even write
565 std::vector<std::string> ReferenceMerklePath(std::string* inputs,
Ryan Sleevi 2016/08/25 18:56:24 DESIGN: Do you need to pass as std::string? Or wou
Rob Percival 2016/10/03 17:39:26 Each element of |inputs| can be an arbitrary strin
566 uint64_t input_size,
567 uint64_t leaf) {
Ryan Sleevi 2016/08/25 18:56:24 STYLE: These should be size_t, not uint64_t - http
Rob Percival 2016/10/03 17:39:25 Done.
568 std::vector<std::string> path;
569 if (leaf > input_size || leaf == 0)
570 return path;
571
572 if (input_size == 1)
573 return path;
574
575 const uint64_t split = CalculateNearestPowerOfTwo(input_size);
576
577 std::vector<std::string> subpath;
578 if (leaf <= split) {
579 subpath = ReferenceMerklePath(&inputs[0], split, leaf);
580 path.insert(path.end(), subpath.begin(), subpath.end());
581 path.push_back(ReferenceMerkleTreeHash(&inputs[split], input_size - split));
582 } else {
583 subpath =
584 ReferenceMerklePath(&inputs[split], input_size - split, leaf - split);
585 path.insert(path.end(), subpath.begin(), subpath.end());
586 path.push_back(ReferenceMerkleTreeHash(&inputs[0], split));
587 }
Ryan Sleevi 2016/08/25 18:56:24 You should add more documentation here as to expla
Rob Percival 2016/10/03 17:39:25 Done.
588
589 return path;
590 }
591
424 // Reference implementation of snapshot consistency. Returns a 592 // Reference implementation of snapshot consistency. Returns a
425 // consistency proof between two snapshots of the tree designated 593 // consistency proof between two snapshots of the tree designated
426 // by |inputs|. 594 // by |inputs|.
427 // Call with have_root1 = true. 595 // Call with have_root1 = true.
428 std::vector<std::string> ReferenceSnapshotConsistency(std::string* inputs, 596 std::vector<std::string> ReferenceSnapshotConsistency(std::string* inputs,
429 uint64_t snapshot2, 597 uint64_t snapshot2,
430 uint64_t snapshot1, 598 uint64_t snapshot1,
431 bool have_root1) { 599 bool have_root1) {
432 std::vector<std::string> proof; 600 std::vector<std::string> proof;
433 if (snapshot1 == 0 || snapshot1 > snapshot2) 601 if (snapshot1 == 0 || snapshot1 > snapshot2)
(...skipping 27 matching lines...) Expand all
461 // doesn't contain the root of snapshot1, so set have_root1 = false. 629 // doesn't contain the root of snapshot1, so set have_root1 = false.
462 subproof = ReferenceSnapshotConsistency(&inputs[split], snapshot2 - split, 630 subproof = ReferenceSnapshotConsistency(&inputs[split], snapshot2 - split,
463 snapshot1 - split, false); 631 snapshot1 - split, false);
464 proof.insert(proof.end(), subproof.begin(), subproof.end()); 632 proof.insert(proof.end(), subproof.begin(), subproof.end());
465 // Record the hash of the left subtree (equal in both trees). 633 // Record the hash of the left subtree (equal in both trees).
466 proof.push_back(ReferenceMerkleTreeHash(&inputs[0], split)); 634 proof.push_back(ReferenceMerkleTreeHash(&inputs[0], split));
467 } 635 }
468 return proof; 636 return proof;
469 } 637 }
470 638
639 TEST_F(CTLogVerifierTest, VerifiesAuditProofEdgeCases_InvalidLeafIndex) {
640 std::vector<std::string> path;
641 EXPECT_FALSE(
642 VerifyAuditProof(log_, 1, 0, path, std::string(), std::string()));
643 EXPECT_FALSE(
644 VerifyAuditProof(log_, 2, 1, path, std::string(), std::string()));
645
646 const std::string empty_hash = HexToBytes(kSHA256EmptyTreeHash);
647 EXPECT_FALSE(VerifyAuditProof(log_, 1, 0, path, empty_hash, std::string()));
648 EXPECT_FALSE(VerifyAuditProof(log_, 2, 1, path, empty_hash, std::string()));
649 }
650
651 class CTLogVerifierAuditProofTest
652 : public CTLogVerifierTest,
653 public ::testing::WithParamInterface<size_t> {};
654
655 TEST_P(CTLogVerifierAuditProofTest, VerifiesValidAuditProofs) {
656 size_t i = GetParam();
657 // Construct the path.
658 std::vector<std::string> path;
659 for (size_t j = 0; j < kSHA256Paths[i].path_length; ++j)
660 path.push_back(HexToBytes(kSHA256Paths[i].path[j]));
661 const char* const root_hash = kSHA256Roots[kSHA256Paths[i].snapshot - 1];
662 VerifierCheck(kSHA256Paths[i].leaf, kSHA256Paths[i].snapshot, path,
663 HexToBytes(root_hash),
664 HexToBytes(kSHA256LeafHashes[kSHA256Paths[i].leaf - 1]));
665 }
666
667 // kSHA256Paths[0] is an invalid path, so only use elements 1-5.
668 INSTANTIATE_TEST_CASE_P(KnownGoodPaths,
669 CTLogVerifierAuditProofTest,
670 ::testing::Range(1ul, arraysize(kSHA256Paths)));
671
471 class CTLogVerifierTestUsingReferenceGenerator 672 class CTLogVerifierTestUsingReferenceGenerator
472 : public CTLogVerifierTest, 673 : public CTLogVerifierTest,
473 public ::testing::WithParamInterface<uint64_t> {}; 674 public ::testing::WithParamInterface<uint64_t> {};
474 675
475 const uint64_t kReferenceTreeSize = 256; 676 const uint64_t kReferenceTreeSize = 256;
476 677
477 // Tests that every possible valid consistency proof for a tree of a given size
478 // verifies correctly. Also checks that invalid variations of each proof fail to
479 // verify (see VerifierConsistencyCheck).
480 TEST_P(CTLogVerifierTestUsingReferenceGenerator, 678 TEST_P(CTLogVerifierTestUsingReferenceGenerator,
481 VerifiesValidConsistencyProof) { 679 VerifiesValidConsistencyProof) {
482 std::vector<std::string> data; 680 std::vector<std::string> data;
483 for (uint64_t i = 0; i < kReferenceTreeSize; ++i) 681 for (uint64_t i = 0; i < kReferenceTreeSize; ++i)
484 data.push_back(std::string(1, static_cast<char>(i))); 682 data.emplace_back(1, static_cast<char>(i));
485 683
486 const uint64_t tree_size = GetParam(); 684 const uint64_t tree_size = GetParam();
487 const std::string tree_root = ReferenceMerkleTreeHash(data.data(), tree_size); 685 const std::string tree_root = ReferenceMerkleTreeHash(data.data(), tree_size);
488 686
489 for (uint64_t snapshot = 1; snapshot <= tree_size; ++snapshot) { 687 for (uint64_t snapshot = 1; snapshot <= tree_size; ++snapshot) {
490 SCOPED_TRACE(snapshot); 688 SCOPED_TRACE(snapshot);
491 const std::string snapshot_root = 689 const std::string snapshot_root =
492 ReferenceMerkleTreeHash(data.data(), snapshot); 690 ReferenceMerkleTreeHash(data.data(), snapshot);
493 const std::vector<std::string> proof = 691 const std::vector<std::string> proof =
494 ReferenceSnapshotConsistency(data.data(), tree_size, snapshot, true); 692 ReferenceSnapshotConsistency(data.data(), tree_size, snapshot, true);
495 VerifierConsistencyCheck(snapshot, tree_size, snapshot_root, tree_root, 693 VerifierConsistencyCheck(snapshot, tree_size, snapshot_root, tree_root,
496 proof); 694 proof);
497 } 695 }
498 } 696 }
499 697
500 // Test verification of consistency proofs between all tree sizes from 1 to 128. 698 TEST_P(CTLogVerifierTestUsingReferenceGenerator, VerifiesValidAuditProofs) {
501 INSTANTIATE_TEST_CASE_P(RangeOfTreeSizesAndSnapshots, 699 std::vector<std::string> data;
700 for (uint64_t i = 0; i < kReferenceTreeSize; ++i)
701 data.emplace_back(1, static_cast<char>(i));
702
703 // More tests with reference path generator.
704 const uint64_t tree_size = GetParam();
705 const std::string root = ReferenceMerkleTreeHash(data.data(), tree_size);
706 // Repeat for each leaf in range.
707 for (uint64_t leaf = 1; leaf <= tree_size; ++leaf) {
708 SCOPED_TRACE(leaf);
709 std::vector<std::string> path =
710 ReferenceMerklePath(data.data(), tree_size, leaf);
711 VerifierCheck(leaf, tree_size, path, root,
712 TreeHasher::HashLeaf(data[leaf - 1]));
713 }
714 }
715
716 // Test verification of consistency proofs and audit proofs for all tree sizes
717 // from 1 to |kReferenceTreeSize / 2|.
718 INSTANTIATE_TEST_CASE_P(RangeOfTreeSizes,
502 CTLogVerifierTestUsingReferenceGenerator, 719 CTLogVerifierTestUsingReferenceGenerator,
503 testing::Range(UINT64_C(1), 720 testing::Range(UINT64_C(1),
504 (kReferenceTreeSize / 2) + 1)); 721 (kReferenceTreeSize / 2) + 1));
505 722
506 } // namespace 723 } // namespace
507 724
508 } // namespace net 725 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698