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

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

Powered by Google App Engine
This is Rietveld 408576698