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

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: 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
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 <map>
9 #include <memory> 10 #include <memory>
10 #include <string> 11 #include <string>
12 #include <utility>
13 #include <vector>
11 14
15 #include "base/command_line.h"
16 #include "base/macros.h"
12 #include "base/strings/string_number_conversions.h" 17 #include "base/strings/string_number_conversions.h"
13 #include "base/time/time.h" 18 #include "base/time/time.h"
14 #include "crypto/secure_hash.h" 19 #include "crypto/secure_hash.h"
15 #include "net/base/hash_value.h" 20 #include "net/base/hash_value.h"
16 #include "net/cert/ct_log_verifier_util.h" 21 #include "net/cert/ct_log_verifier_util.h"
22 #include "net/cert/merkle_audit_proof.h"
17 #include "net/cert/merkle_consistency_proof.h" 23 #include "net/cert/merkle_consistency_proof.h"
18 #include "net/cert/signed_certificate_timestamp.h" 24 #include "net/cert/signed_certificate_timestamp.h"
19 #include "net/cert/signed_tree_head.h" 25 #include "net/cert/signed_tree_head.h"
20 #include "net/test/ct_test_util.h" 26 #include "net/test/ct_test_util.h"
21 #include "testing/gtest/include/gtest/gtest.h" 27 #include "testing/gtest/include/gtest/gtest.h"
22 28
23 namespace net { 29 namespace net {
24 30
25 namespace { 31 namespace {
26 32
33 // Disables the node hash cache used to accelerate some of the tests.
34 // The cache reduces the duration of some tests by at least 50%, in exchange for
35 // significantly higher memory usage.
36 const char* kNoHashCacheFlag = "no-hash-cache";
Ryan Sleevi 2016/07/25 19:41:41 This is not a good design for unittests to have ar
Rob Percival 2016/07/26 14:24:29 Ok, I'll drop the flag. It really only exists for
37
27 // Calculate the power of two nearest to, but less than, |n|. 38 // Calculate the power of two nearest to, but less than, |n|.
28 // |n| must be at least 2. 39 // |n| must be at least 2.
29 uint64_t CalculateNearestPowerOfTwo(uint64_t n) { 40 uint64_t CalculateNearestPowerOfTwo(uint64_t n) {
30 DCHECK_GT(n, 1u); 41 DCHECK_GT(n, 1u);
31 42
32 uint64_t ret = UINT64_C(1) << 63; 43 uint64_t ret = UINT64_C(1) << 63;
33 while (ret >= n) 44 while (ret >= n)
34 ret >>= 1; 45 ret >>= 1;
35 46
36 return ret; 47 return ret;
37 } 48 }
38 49
39 // The following structures, TestVector and ProofTestVector are used for 50 // The following structures, TestVector and ProofTestVector are used for
40 // definining test proofs later on. 51 // definining test proofs later on.
41 52
42 // A single hash node. 53 // A single hash node.
43 struct TestVector { 54 struct TestVector {
44 const char* const str; 55 const char* const str; // hex string
45 size_t length_bytes; 56 size_t length_bytes; // number of bytes represented by |str|
46 }; 57 };
47 58
48 // A single consistency proof. Contains the old and new tree sizes 59 // A single consistency proof. Contains the old and new tree sizes
49 // (snapshot1 and snapshot2), the length of the proof (proof_length) and 60 // (snapshot1 and snapshot2), the length of the proof (proof_length) and
50 // at most 3 proof nodes (all test proofs will be for a tree of size 8). 61 // at most 3 proof nodes (all test proofs will be for a tree of size 8).
51 struct ProofTestVector { 62 struct ProofTestVector {
52 uint64_t snapshot1; 63 uint64_t snapshot1;
53 uint64_t snapshot2; 64 uint64_t snapshot2;
54 size_t proof_length; 65 size_t proof_length;
55 TestVector proof[3]; 66 TestVector proof[3];
56 }; 67 };
57 68
58 // All test data replicated from 69 // All test data replicated from
59 // https://github.com/google/certificate-transparency/blob/c41b090ecc14ddd6b3531 dc7e5ce36b21e253fdd/cpp/merkletree/merkle_tree_test.cc 70 // https://github.com/google/certificate-transparency/blob/c41b090ecc14ddd6b3531 dc7e5ce36b21e253fdd/cpp/merkletree/merkle_tree_test.cc
60 // A hash of the empty string. 71 // A hash of the empty string.
61 const TestVector kSHA256EmptyTreeHash = { 72 const TestVector kSHA256EmptyTreeHash = {
62 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 32}; 73 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 32};
63 74
64 // Node hashes for a sample tree of size 8 (each element in this array is 75 // Hashes of the leaf data for the sample tree (8 leaves).
65 // a node hash, not leaf data; order represents order of the nodes in the tree). 76 const TestVector kSHA256LeafHashes[8] = {
77 {"6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d", 32},
78 {"96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7", 32},
79 {"0298d122906dcfc10892cb53a73992fc5b9f493ea4c9badb27b791b4127a7fe7", 32},
80 {"07506a85fd9dd2f120eb694f86011e5bb4662e5c415a62917033d4a9624487e7", 32},
81 {"bc1a0643b12e4d2d7c77918f44e0f4f79a838b6cf9ec5b5c283e1f4d88599e6b", 32},
82 {"4271a26be0d8a84f0bd54c8c302e7cb3a3b5d1fa6780a40bcce2873477dab658", 32},
83 {"b08693ec2e721597130641e8211e7eedccb4c26413963eee6c1e2ed16ffb1a5f", 32},
84 {"46f6ffadd3d06a09ff3c5860d2755c8b9819db7df44251788c7d8e3180de8eb1", 32},
85 };
86
87 // Incremental roots from building the sample tree of size 8 leaf-by-leaf.
88 // The first entry is the root at size 0, the last is the root at size 8.
66 const TestVector kSHA256Roots[8] = { 89 const TestVector kSHA256Roots[8] = {
67 {"6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d", 32}, 90 {"6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d", 32},
68 {"fac54203e7cc696cf0dfcb42c92a1d9dbaf70ad9e621f4bd8d98662f00e3c125", 32}, 91 {"fac54203e7cc696cf0dfcb42c92a1d9dbaf70ad9e621f4bd8d98662f00e3c125", 32},
69 {"aeb6bcfe274b70a14fb067a5e5578264db0fa9b51af5e0ba159158f329e06e77", 32}, 92 {"aeb6bcfe274b70a14fb067a5e5578264db0fa9b51af5e0ba159158f329e06e77", 32},
70 {"d37ee418976dd95753c1c73862b9398fa2a2cf9b4ff0fdfe8b30cd95209614b7", 32}, 93 {"d37ee418976dd95753c1c73862b9398fa2a2cf9b4ff0fdfe8b30cd95209614b7", 32},
71 {"4e3bbb1f7b478dcfe71fb631631519a3bca12c9aefca1612bfce4c13a86264d4", 32}, 94 {"4e3bbb1f7b478dcfe71fb631631519a3bca12c9aefca1612bfce4c13a86264d4", 32},
72 {"76e67dadbcdf1e10e1b74ddc608abd2f98dfb16fbce75277b5232a127f2087ef", 32}, 95 {"76e67dadbcdf1e10e1b74ddc608abd2f98dfb16fbce75277b5232a127f2087ef", 32},
73 {"ddb89be403809e325750d3d263cd78929c2942b7942a34b77e122c9594a74c8c", 32}, 96 {"ddb89be403809e325750d3d263cd78929c2942b7942a34b77e122c9594a74c8c", 32},
74 {"5dc9da79a70659a9ad559cb701ded9a2ab9d823aad2f4960cfe370eff4604328", 32}}; 97 {"5dc9da79a70659a9ad559cb701ded9a2ab9d823aad2f4960cfe370eff4604328", 32}};
75 98
76 // A collection of consistency proofs between various sub-trees of the tree 99 // A collection of consistency proofs between various nodes of the sample tree.
77 // defined by |kSHA256Roots|.
78 const ProofTestVector kSHA256Proofs[4] = { 100 const ProofTestVector kSHA256Proofs[4] = {
79 // Empty consistency proof between trees of the same size (1). 101 // Empty consistency proof between trees of the same size (1).
80 {1, 1, 0, {{"", 0}, {"", 0}, {"", 0}}}, 102 {1, 1, 0, {{"", 0}, {"", 0}, {"", 0}}},
81 // Consistency proof between tree of size 1 and tree of size 8, with 3 103 // Consistency proof between tree of size 1 and tree of size 8, with 3
82 // nodes in the proof. 104 // nodes in the proof.
83 {1, 105 {1,
84 8, 106 8,
85 3, 107 3,
86 {{"96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7", 32}, 108 {{"96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7", 32},
87 {"5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e", 32}, 109 {"5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e", 32},
(...skipping 10 matching lines...) Expand all
98 32}}}, 120 32}}},
99 // Consistency proof between tree of size 2 and tree of size 5, with 2 121 // Consistency proof between tree of size 2 and tree of size 5, with 2
100 // nodes in the proof. 122 // nodes in the proof.
101 {2, 123 {2,
102 5, 124 5,
103 2, 125 2,
104 {{"5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e", 32}, 126 {{"5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e", 32},
105 {"bc1a0643b12e4d2d7c77918f44e0f4f79a838b6cf9ec5b5c283e1f4d88599e6b", 32}, 127 {"bc1a0643b12e4d2d7c77918f44e0f4f79a838b6cf9ec5b5c283e1f4d88599e6b", 32},
106 {"", 0}}}}; 128 {"", 0}}}};
107 129
130 // A single audit proof. Contains the leaf index (leaf), tree size (snapshot),
131 // the length of the proof (proof_length) and at most 3 proof nodes (all test
132 // proofs will be for a tree of size 8).
133 struct PathTestVector {
134 int leaf;
135 int snapshot;
136 int path_length;
137 TestVector path[3];
138 };
139
140 // A collection of audit proofs for various leaves and sub-trees of the tree
141 // defined by |kSHA256Roots|.
142 const PathTestVector kSHA256Paths[6] = {
143 {0, 0, 0, {{"", 0}, {"", 0}, {"", 0}}},
144 {1, 1, 0, {{"", 0}, {"", 0}, {"", 0}}},
145 {1,
146 8,
147 3,
148 {{"96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7", 32},
149 {"5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e", 32},
150 {"6b47aaf29ee3c2af9af889bc1fb9254dabd31177f16232dd6aab035ca39bf6e4",
151 32}}},
152 {6,
153 8,
154 3,
155 {{"bc1a0643b12e4d2d7c77918f44e0f4f79a838b6cf9ec5b5c283e1f4d88599e6b", 32},
156 {"ca854ea128ed050b41b35ffc1b87b8eb2bde461e9e3b5596ece6b9d5975a0ae0", 32},
157 {"d37ee418976dd95753c1c73862b9398fa2a2cf9b4ff0fdfe8b30cd95209614b7",
158 32}}},
159 {3,
160 3,
161 1,
162 {{"fac54203e7cc696cf0dfcb42c92a1d9dbaf70ad9e621f4bd8d98662f00e3c125", 32},
163 {"", 0},
164 {"", 0}}},
165 {2,
166 5,
167 3,
168 {{"6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d", 32},
169 {"5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e", 32},
170 {"bc1a0643b12e4d2d7c77918f44e0f4f79a838b6cf9ec5b5c283e1f4d88599e6b",
171 32}}}};
172
108 // Decodes a hexadecimal string into the binary data it represents. 173 // Decodes a hexadecimal string into the binary data it represents.
109 std::string HexToBytes(const char* hex_data, size_t hex_data_length) { 174 std::string HexToBytes(const char* hex_data, size_t hex_data_length) {
110 std::vector<uint8_t> output; 175 std::vector<uint8_t> output;
111 std::string result; 176 std::string result;
112 std::string hex_data_input(hex_data, hex_data_length); 177 std::string hex_data_input(hex_data, hex_data_length);
113 if (base::HexStringToBytes(hex_data, &output)) 178 if (base::HexStringToBytes(hex_data, &output))
114 result.assign(reinterpret_cast<const char*>(&output[0]), output.size()); 179 result.assign(reinterpret_cast<const char*>(&output[0]), output.size());
115 return result; 180 return result;
116 } 181 }
117 182
183 std::string HexToBytes(const TestVector& x) {
184 std::string bytes = HexToBytes(x.str, x.length_bytes * 2);
185 CHECK_EQ(x.length_bytes, bytes.size());
186 return bytes;
187 }
188
118 std::string GetEmptyTreeHash() { 189 std::string GetEmptyTreeHash() {
119 return HexToBytes(kSHA256EmptyTreeHash.str, 190 return HexToBytes(kSHA256EmptyTreeHash);
120 kSHA256EmptyTreeHash.length_bytes);
121 } 191 }
122 192
123 // Creates a ct::MerkleConsistencyProof and returns the result of 193 // Creates a ct::MerkleConsistencyProof and returns the result of
124 // calling log->VerifyConsistencyProof with that proof and snapshots. 194 // calling log->VerifyConsistencyProof with that proof and snapshots.
125 bool VerifyConsistencyProof(scoped_refptr<const CTLogVerifier> log, 195 bool VerifyConsistencyProof(scoped_refptr<const CTLogVerifier> log,
126 uint64_t old_tree_size, 196 uint64_t old_tree_size,
127 const std::string& old_tree_root, 197 const std::string& old_tree_root,
128 uint64_t new_tree_size, 198 uint64_t new_tree_size,
129 const std::string& new_tree_root, 199 const std::string& new_tree_root,
130 const std::vector<std::string>& proof) { 200 const std::vector<std::string>& proof) {
131 return log->VerifyConsistencyProof( 201 return log->VerifyConsistencyProof(
132 ct::MerkleConsistencyProof(log->key_id(), proof, old_tree_size, 202 ct::MerkleConsistencyProof(log->key_id(), proof, old_tree_size,
133 new_tree_size), 203 new_tree_size),
134 old_tree_root, new_tree_root); 204 old_tree_root, new_tree_root);
135 } 205 }
136 206
207 bool VerifyAuditProof(scoped_refptr<const CTLogVerifier> log,
208 uint64_t leaf,
209 uint64_t tree_size,
210 const std::vector<std::string>& proof,
211 const std::string& tree_root,
212 const std::string& leaf_hash) {
213 // Test vectors use a 1-based leaf index, but our code uses a 0-based index.
214 if (leaf == 0)
215 return false;
216 return log->VerifyAuditProof(ct::MerkleAuditProof(leaf - 1, tree_size, proof),
217 tree_root, leaf_hash);
218 }
219
137 class CTLogVerifierTest : public ::testing::Test { 220 class CTLogVerifierTest : public ::testing::Test {
138 public: 221 public:
139 CTLogVerifierTest() {} 222 CTLogVerifierTest() {}
140 223
141 void SetUp() override { 224 void SetUp() override {
142 log_ = CTLogVerifier::Create(ct::GetTestPublicKey(), "testlog", 225 log_ = CTLogVerifier::Create(ct::GetTestPublicKey(), "testlog",
143 "https://ct.example.com", "ct.example.com"); 226 "https://ct.example.com", "ct.example.com");
144 227
145 ASSERT_TRUE(log_); 228 ASSERT_TRUE(log_);
146 ASSERT_EQ(ct::GetTestPublicKeyId(), log_->key_id()); 229 ASSERT_EQ(ct::GetTestPublicKeyId(), log_->key_id());
147 ASSERT_EQ("ct.example.com", log_->dns_domain()); 230 ASSERT_EQ("ct.example.com", log_->dns_domain());
148 } 231 }
149 232
233 // Given an audit proof for a leaf in the tree, asserts that it verifies and
234 // no other combination of leaves, snapshots and proof nodes verifies.
235 void VerifierCheck(int leaf,
236 int tree_size,
237 const std::vector<std::string>& path,
238 const std::string& root,
239 const std::string& leaf_hash) {
240 // Verify the original path.
241 EXPECT_TRUE(VerifyAuditProof(log_, leaf, tree_size, path, root, leaf_hash));
242
243 // Wrong leaf index.
244 EXPECT_FALSE(
245 VerifyAuditProof(log_, leaf - 1, tree_size, path, root, leaf_hash));
246 EXPECT_FALSE(
247 VerifyAuditProof(log_, leaf + 1, tree_size, path, root, leaf_hash));
248 EXPECT_FALSE(
249 VerifyAuditProof(log_, leaf ^ 2, tree_size, path, root, leaf_hash));
250
251 // Wrong tree height.
252 EXPECT_FALSE(
253 VerifyAuditProof(log_, leaf, tree_size * 2, path, root, leaf_hash));
254 EXPECT_FALSE(
255 VerifyAuditProof(log_, leaf, tree_size / 2, path, root, leaf_hash));
256
257 // Wrong root.
258 EXPECT_FALSE(VerifyAuditProof(log_, leaf, tree_size, path,
259 HexToBytes(kSHA256EmptyTreeHash), leaf_hash));
260
261 // Wrong paths.
262 std::vector<std::string> wrong_path;
263
264 // Modify a single element on the path.
265 for (size_t j = 0; j < path.size(); ++j) {
266 wrong_path = path;
267 wrong_path[j] = HexToBytes(kSHA256EmptyTreeHash);
268 EXPECT_FALSE(
269 VerifyAuditProof(log_, leaf, tree_size, wrong_path, root, leaf_hash));
270 }
271
272 // Add garbage at the end of the path.
273 wrong_path = path;
274 wrong_path.push_back(std::string());
275 EXPECT_FALSE(
276 VerifyAuditProof(log_, leaf, tree_size, wrong_path, root, leaf_hash));
277 wrong_path.pop_back();
278
279 wrong_path.push_back(root);
280 EXPECT_FALSE(
281 VerifyAuditProof(log_, leaf, tree_size, wrong_path, root, leaf_hash));
282 wrong_path.pop_back();
283
284 // Remove a node from the end.
285 if (!wrong_path.empty()) {
286 wrong_path.pop_back();
287 EXPECT_FALSE(
288 VerifyAuditProof(log_, leaf, tree_size, wrong_path, root, leaf_hash));
289 }
290
291 // Add garbage in the beginning of the path.
292 wrong_path.clear();
293 wrong_path.push_back(std::string());
294 wrong_path.insert(wrong_path.end(), path.begin(), path.end());
295 EXPECT_FALSE(
296 VerifyAuditProof(log_, leaf, tree_size, wrong_path, root, leaf_hash));
297
298 wrong_path[0] = root;
299 EXPECT_FALSE(
300 VerifyAuditProof(log_, leaf, tree_size, wrong_path, root, leaf_hash));
301 }
302
150 // Given a consistency proof between two snapshots of the tree, asserts that 303 // Given a consistency proof between two snapshots of the tree, asserts that
151 // it verifies and no other combination of snapshots and proof nodes verifies. 304 // it verifies and no other combination of snapshots and proof nodes verifies.
152 void VerifierConsistencyCheck(int snapshot1, 305 void VerifierConsistencyCheck(int snapshot1,
153 int snapshot2, 306 int snapshot2,
154 const std::string& root1, 307 const std::string& root1,
155 const std::string& root2, 308 const std::string& root2,
156 const std::vector<std::string>& proof) { 309 const std::vector<std::string>& proof) {
157 // Verify the original consistency proof. 310 // Verify the original consistency proof.
158 EXPECT_TRUE( 311 EXPECT_TRUE(
159 VerifyConsistencyProof(log_, snapshot1, root1, snapshot2, root2, proof)) 312 VerifyConsistencyProof(log_, snapshot1, root1, snapshot2, root2, proof))
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
372 EXPECT_FALSE(VerifyConsistencyProof(log_, 1, empty_tree_hash, 1, 525 EXPECT_FALSE(VerifyConsistencyProof(log_, 1, empty_tree_hash, 1,
373 empty_tree_hash, proof)); 526 empty_tree_hash, proof));
374 } 527 }
375 528
376 TEST_F(CTLogVerifierTest, VerifiesValidConsistencyProofs) { 529 TEST_F(CTLogVerifierTest, VerifiesValidConsistencyProofs) {
377 std::vector<std::string> proof; 530 std::vector<std::string> proof;
378 std::string root1, root2; 531 std::string root1, root2;
379 532
380 // Known good proofs. 533 // Known good proofs.
381 for (size_t i = 0; i < arraysize(kSHA256Proofs); ++i) { 534 for (size_t i = 0; i < arraysize(kSHA256Proofs); ++i) {
535 SCOPED_TRACE(i);
382 proof.clear(); 536 proof.clear();
383 for (size_t j = 0; j < kSHA256Proofs[i].proof_length; ++j) { 537 for (size_t j = 0; j < kSHA256Proofs[i].proof_length; ++j) {
384 const TestVector& v = kSHA256Proofs[i].proof[j]; 538 const TestVector& v = kSHA256Proofs[i].proof[j];
385 proof.push_back(HexToBytes(v.str, v.length_bytes)); 539 proof.push_back(HexToBytes(v));
386 } 540 }
387 const uint64_t snapshot1 = kSHA256Proofs[i].snapshot1; 541 const uint64_t snapshot1 = kSHA256Proofs[i].snapshot1;
388 const uint64_t snapshot2 = kSHA256Proofs[i].snapshot2; 542 const uint64_t snapshot2 = kSHA256Proofs[i].snapshot2;
389 const TestVector& old_root = kSHA256Roots[snapshot1 - 1]; 543 const TestVector& old_root = kSHA256Roots[snapshot1 - 1];
390 const TestVector& new_root = kSHA256Roots[snapshot2 - 1]; 544 const TestVector& new_root = kSHA256Roots[snapshot2 - 1];
391 VerifierConsistencyCheck( 545 VerifierConsistencyCheck(snapshot1, snapshot2, HexToBytes(old_root),
392 snapshot1, snapshot2, HexToBytes(old_root.str, old_root.length_bytes), 546 HexToBytes(new_root), proof);
393 HexToBytes(new_root.str, new_root.length_bytes), proof);
394 } 547 }
395 } 548 }
396 549
397 const char kLeafPrefix[] = {'\x00'}; 550 const char kLeafPrefix[] = {'\x00'};
398 551
399 // Reference implementation of RFC6962. 552 // Reference implementation of RFC6962.
400 // This allows generation of arbitrary-sized Merkle trees and consistency 553 // This allows generation of arbitrary-sized Merkle trees and consistency
401 // proofs between them for testing the consistency proof validation 554 // proofs between them for testing the consistency proof validation
402 // code. 555 // code.
403 class TreeHasher { 556 class TreeHasher {
404 public: 557 public:
405 static std::string HashEmpty() { 558 static std::string HashEmpty() { return HexToBytes(kSHA256EmptyTreeHash); }
406 return HexToBytes(kSHA256EmptyTreeHash.str,
407 kSHA256EmptyTreeHash.length_bytes);
408 }
409 559
410 static std::string HashLeaf(const std::string& leaf) { 560 static std::string HashLeaf(const std::string& leaf) {
411 SHA256HashValue sha256; 561 SHA256HashValue sha256;
412 memset(sha256.data, 0, sizeof(sha256.data)); 562 memset(sha256.data, 0, sizeof(sha256.data));
413 563
414 std::unique_ptr<crypto::SecureHash> hash( 564 std::unique_ptr<crypto::SecureHash> hash(
415 crypto::SecureHash::Create(crypto::SecureHash::SHA256)); 565 crypto::SecureHash::Create(crypto::SecureHash::SHA256));
416 hash->Update(kLeafPrefix, 1); 566 hash->Update(kLeafPrefix, 1);
417 hash->Update(leaf.data(), leaf.size()); 567 hash->Update(leaf.data(), leaf.size());
418 hash->Finish(sha256.data, sizeof(sha256.data)); 568 hash->Finish(sha256.data, sizeof(sha256.data));
419 569
420 return std::string(reinterpret_cast<const char*>(sha256.data), 570 return std::string(reinterpret_cast<const char*>(sha256.data),
421 sizeof(sha256.data)); 571 sizeof(sha256.data));
422 } 572 }
423 }; 573 };
424 574
425 // Reference implementation of Merkle hash, for cross-checking. 575 // Reference implementation of Merkle hash, for cross-checking.
426 // Recursively calculates the hash of the root given the leaf data 576 // Recursively calculates the hash of the root given the leaf data
427 // specified in |inputs|. 577 // specified in |inputs|.
428 std::string ReferenceMerkleTreeHash(std::string* inputs, uint64_t input_size) { 578 std::string ReferenceMerkleTreeHash(std::string* inputs, uint64_t input_size) {
429 if (!input_size) 579 // Memoize function - this requires 34 bytes of memory per unique pair of
430 return TreeHasher::HashEmpty(); 580 // |inputs| and |input_size|, plus std::map and std::string overhead.
581 // This results in a ~50% reduction in time required to run the
582 // *FromReferenceGenerator tests.
583 static std::map<std::pair<std::string*, uint64_t>, std::string> cache;
584 // Use of the cache can be disabled using the --no-hash-cache flag, which
585 // makes it easy to see how much memory the cache is consuming.
586 static bool is_cache_enabled =
587 !base::CommandLine::ForCurrentProcess()->HasSwitch(kNoHashCacheFlag);
588
589 std::string hash;
590 if (is_cache_enabled) {
591 auto iter = cache.find(std::make_pair(inputs, input_size));
592 if (iter != cache.end())
593 hash = iter->second;
594 }
595
596 if (hash.empty()) {
Ryan Sleevi 2016/07/25 19:41:41 DESIGN: Do error handling first if (!hash.empty()
Rob Percival 2016/07/26 14:24:29 That isn't error handling - it's checking whether
597 if (!input_size) {
598 hash = TreeHasher::HashEmpty();
599 } else if (input_size == 1) {
600 hash = TreeHasher::HashLeaf(inputs[0]);
601 } else {
602 const uint64_t split = CalculateNearestPowerOfTwo(input_size);
603
604 hash = ct::internal::HashNodes(
605 ReferenceMerkleTreeHash(&inputs[0], split),
606 ReferenceMerkleTreeHash(&inputs[split], input_size - split));
607 }
608
609 if (is_cache_enabled)
610 cache[std::make_pair(inputs, input_size)] = hash;
611 }
612
613 return hash;
614 }
615
616 // Reference implementation of Merkle paths. Path from leaf to root,
617 // excluding the leaf and root themselves. Returns an audit proof for the tree
618 // leaf with index |leaf| (1-based). The tree is designated by |inputs|.
619 std::vector<std::string> ReferenceMerklePath(std::string* inputs,
620 uint64_t input_size,
621 uint64_t leaf) {
622 std::vector<std::string> path;
623 if (leaf > input_size || leaf == 0)
624 return path;
625
431 if (input_size == 1) 626 if (input_size == 1)
432 return TreeHasher::HashLeaf(inputs[0]); 627 return path;
433 628
434 const uint64_t split = CalculateNearestPowerOfTwo(input_size); 629 const uint64_t split = CalculateNearestPowerOfTwo(input_size);
435 630
436 return ct::internal::HashNodes( 631 std::vector<std::string> subpath;
437 ReferenceMerkleTreeHash(&inputs[0], split), 632 if (leaf <= split) {
438 ReferenceMerkleTreeHash(&inputs[split], input_size - split)); 633 subpath = ReferenceMerklePath(&inputs[0], split, leaf);
634 path.insert(path.end(), subpath.begin(), subpath.end());
635 path.push_back(ReferenceMerkleTreeHash(&inputs[split], input_size - split));
636 } else {
637 subpath =
638 ReferenceMerklePath(&inputs[split], input_size - split, leaf - split);
639 path.insert(path.end(), subpath.begin(), subpath.end());
640 path.push_back(ReferenceMerkleTreeHash(&inputs[0], split));
641 }
642
643 return path;
439 } 644 }
440 645
441 // Reference implementation of snapshot consistency. Returns a 646 // Reference implementation of snapshot consistency. Returns a
442 // consistency proof between two snapshots of the tree designated 647 // consistency proof between two snapshots of the tree designated
443 // by |inputs|. 648 // by |inputs|.
444 // Call with have_root1 = true. 649 // Call with have_root1 = true.
445 std::vector<std::string> ReferenceSnapshotConsistency(std::string* inputs, 650 std::vector<std::string> ReferenceSnapshotConsistency(std::string* inputs,
446 uint64_t snapshot2, 651 uint64_t snapshot2,
447 uint64_t snapshot1, 652 uint64_t snapshot1,
448 bool have_root1) { 653 bool have_root1) {
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
496 TEST_F(CTLogVerifierTest, 701 TEST_F(CTLogVerifierTest,
497 MAYBE_VerifiesValidConsistencyProofsFromReferenceGenerator) { 702 MAYBE_VerifiesValidConsistencyProofsFromReferenceGenerator) {
498 std::vector<std::string> data; 703 std::vector<std::string> data;
499 for (int i = 0; i < 256; ++i) 704 for (int i = 0; i < 256; ++i)
500 data.push_back(std::string(1, i)); 705 data.push_back(std::string(1, i));
501 706
502 std::vector<std::string> proof; 707 std::vector<std::string> proof;
503 std::string root1, root2; 708 std::string root1, root2;
504 // More tests with reference proof generator. 709 // More tests with reference proof generator.
505 for (size_t tree_size = 1; tree_size <= data.size() / 2; ++tree_size) { 710 for (size_t tree_size = 1; tree_size <= data.size() / 2; ++tree_size) {
711 SCOPED_TRACE(tree_size);
506 root2 = ReferenceMerkleTreeHash(data.data(), tree_size); 712 root2 = ReferenceMerkleTreeHash(data.data(), tree_size);
507 // Repeat for each snapshot in range. 713 // Repeat for each snapshot in range.
508 for (size_t snapshot = 1; snapshot <= tree_size; ++snapshot) { 714 for (size_t snapshot = 1; snapshot <= tree_size; ++snapshot) {
715 SCOPED_TRACE(snapshot);
509 proof = 716 proof =
510 ReferenceSnapshotConsistency(data.data(), tree_size, snapshot, true); 717 ReferenceSnapshotConsistency(data.data(), tree_size, snapshot, true);
511 root1 = ReferenceMerkleTreeHash(data.data(), snapshot); 718 root1 = ReferenceMerkleTreeHash(data.data(), snapshot);
512 VerifierConsistencyCheck(snapshot, tree_size, root1, root2, proof); 719 VerifierConsistencyCheck(snapshot, tree_size, root1, root2, proof);
513 } 720 }
514 } 721 }
515 } 722 }
516 723
724 TEST_F(CTLogVerifierTest, VerifiesAuditProofEdgeCases_EmptyProof) {
725 std::vector<std::string> path;
726 // Various invalid paths.
727 EXPECT_FALSE(
728 VerifyAuditProof(log_, 0, 0, path, std::string(), std::string()));
729 EXPECT_FALSE(
730 VerifyAuditProof(log_, 0, 1, path, std::string(), std::string()));
731 EXPECT_FALSE(
732 VerifyAuditProof(log_, 1, 0, path, std::string(), std::string()));
733 EXPECT_FALSE(
734 VerifyAuditProof(log_, 2, 1, path, std::string(), std::string()));
735
736 const std::string empty_hash = HexToBytes(kSHA256EmptyTreeHash);
737 EXPECT_FALSE(VerifyAuditProof(log_, 0, 0, path, empty_hash, std::string()));
738 EXPECT_FALSE(VerifyAuditProof(log_, 0, 1, path, empty_hash, std::string()));
739 EXPECT_FALSE(VerifyAuditProof(log_, 1, 0, path, empty_hash, std::string()));
740 EXPECT_FALSE(VerifyAuditProof(log_, 2, 1, path, empty_hash, std::string()));
741 }
742
743 TEST_F(CTLogVerifierTest, VerifiesValidAuditProofs) {
744 std::vector<std::string> path;
745 // Known good paths.
746 // i = 0 is an invalid path.
747 for (int i = 1; i < 6; ++i) {
748 SCOPED_TRACE(i);
749 // Construct the path.
750 path.clear();
751 for (int j = 0; j < kSHA256Paths[i].path_length; ++j)
752 path.push_back(HexToBytes(kSHA256Paths[i].path[j]));
753 const TestVector& root_hash = kSHA256Roots[kSHA256Paths[i].snapshot - 1];
754 VerifierCheck(kSHA256Paths[i].leaf, kSHA256Paths[i].snapshot, path,
755 HexToBytes(root_hash),
756 HexToBytes(kSHA256LeafHashes[kSHA256Paths[i].leaf - 1]));
757 }
758 }
759
760 TEST_F(CTLogVerifierTest, VerifiesValidAuditProofsFromReferenceGenerator) {
761 std::vector<std::string> data;
762 for (size_t i = 0; i < 256; ++i)
763 data.emplace_back(1, i);
764
765 // More tests with reference path generator.
766 std::string root;
767 std::vector<std::string> path;
768 for (size_t tree_size = 1; tree_size <= data.size() / 2; ++tree_size) {
769 SCOPED_TRACE(tree_size);
770 // Repeat for each leaf in range.
771 for (size_t leaf = 1; leaf <= tree_size; ++leaf) {
772 SCOPED_TRACE(leaf);
773 path = ReferenceMerklePath(data.data(), tree_size, leaf);
774 root = ReferenceMerkleTreeHash(data.data(), tree_size);
775 VerifierCheck(leaf, tree_size, path, root,
776 TreeHasher::HashLeaf(data[leaf - 1]));
777 }
778 }
779 }
780
517 } // namespace 781 } // namespace
518 782
519 } // namespace net 783 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698