OLD | NEW |
---|---|
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"; | |
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 Loading... | |
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. | |
Rob Percival
2016/07/25 16:29:37
I can more heavily modify the tests (which were ad
| |
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"); | 226 "https://ct.example.com"); |
144 | 227 |
145 ASSERT_TRUE(log_); | 228 ASSERT_TRUE(log_); |
146 ASSERT_EQ(log_->key_id(), ct::GetTestPublicKeyId()); | 229 ASSERT_EQ(log_->key_id(), ct::GetTestPublicKeyId()); |
147 } | 230 } |
148 | 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 | |
149 // 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 |
150 // 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. |
151 void VerifierConsistencyCheck(int snapshot1, | 304 void VerifierConsistencyCheck(int snapshot1, |
152 int snapshot2, | 305 int snapshot2, |
153 const std::string& root1, | 306 const std::string& root1, |
154 const std::string& root2, | 307 const std::string& root2, |
155 const std::vector<std::string>& proof) { | 308 const std::vector<std::string>& proof) { |
156 // Verify the original consistency proof. | 309 // Verify the original consistency proof. |
157 EXPECT_TRUE( | 310 EXPECT_TRUE( |
158 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 Loading... | |
371 EXPECT_FALSE(VerifyConsistencyProof(log_, 1, empty_tree_hash, 1, | 524 EXPECT_FALSE(VerifyConsistencyProof(log_, 1, empty_tree_hash, 1, |
372 empty_tree_hash, proof)); | 525 empty_tree_hash, proof)); |
373 } | 526 } |
374 | 527 |
375 TEST_F(CTLogVerifierTest, VerifiesValidConsistencyProofs) { | 528 TEST_F(CTLogVerifierTest, VerifiesValidConsistencyProofs) { |
376 std::vector<std::string> proof; | 529 std::vector<std::string> proof; |
377 std::string root1, root2; | 530 std::string root1, root2; |
378 | 531 |
379 // Known good proofs. | 532 // Known good proofs. |
380 for (size_t i = 0; i < arraysize(kSHA256Proofs); ++i) { | 533 for (size_t i = 0; i < arraysize(kSHA256Proofs); ++i) { |
534 SCOPED_TRACE(i); | |
381 proof.clear(); | 535 proof.clear(); |
382 for (size_t j = 0; j < kSHA256Proofs[i].proof_length; ++j) { | 536 for (size_t j = 0; j < kSHA256Proofs[i].proof_length; ++j) { |
383 const TestVector& v = kSHA256Proofs[i].proof[j]; | 537 const TestVector& v = kSHA256Proofs[i].proof[j]; |
384 proof.push_back(HexToBytes(v.str, v.length_bytes)); | 538 proof.push_back(HexToBytes(v)); |
385 } | 539 } |
386 const uint64_t snapshot1 = kSHA256Proofs[i].snapshot1; | 540 const uint64_t snapshot1 = kSHA256Proofs[i].snapshot1; |
387 const uint64_t snapshot2 = kSHA256Proofs[i].snapshot2; | 541 const uint64_t snapshot2 = kSHA256Proofs[i].snapshot2; |
388 const TestVector& old_root = kSHA256Roots[snapshot1 - 1]; | 542 const TestVector& old_root = kSHA256Roots[snapshot1 - 1]; |
389 const TestVector& new_root = kSHA256Roots[snapshot2 - 1]; | 543 const TestVector& new_root = kSHA256Roots[snapshot2 - 1]; |
390 VerifierConsistencyCheck( | 544 VerifierConsistencyCheck(snapshot1, snapshot2, HexToBytes(old_root), |
391 snapshot1, snapshot2, HexToBytes(old_root.str, old_root.length_bytes), | 545 HexToBytes(new_root), proof); |
392 HexToBytes(new_root.str, new_root.length_bytes), proof); | |
393 } | 546 } |
394 } | 547 } |
395 | 548 |
396 const char kLeafPrefix[] = {'\x00'}; | 549 const char kLeafPrefix[] = {'\x00'}; |
397 | 550 |
398 // Reference implementation of RFC6962. | 551 // Reference implementation of RFC6962. |
399 // This allows generation of arbitrary-sized Merkle trees and consistency | 552 // This allows generation of arbitrary-sized Merkle trees and consistency |
400 // proofs between them for testing the consistency proof validation | 553 // proofs between them for testing the consistency proof validation |
401 // code. | 554 // code. |
402 class TreeHasher { | 555 class TreeHasher { |
403 public: | 556 public: |
404 static std::string HashEmpty() { | 557 static std::string HashEmpty() { return HexToBytes(kSHA256EmptyTreeHash); } |
405 return HexToBytes(kSHA256EmptyTreeHash.str, | |
406 kSHA256EmptyTreeHash.length_bytes); | |
407 } | |
408 | 558 |
409 static std::string HashLeaf(const std::string& leaf) { | 559 static std::string HashLeaf(const std::string& leaf) { |
410 SHA256HashValue sha256; | 560 SHA256HashValue sha256; |
411 memset(sha256.data, 0, sizeof(sha256.data)); | 561 memset(sha256.data, 0, sizeof(sha256.data)); |
412 | 562 |
413 std::unique_ptr<crypto::SecureHash> hash( | 563 std::unique_ptr<crypto::SecureHash> hash( |
414 crypto::SecureHash::Create(crypto::SecureHash::SHA256)); | 564 crypto::SecureHash::Create(crypto::SecureHash::SHA256)); |
415 hash->Update(kLeafPrefix, 1); | 565 hash->Update(kLeafPrefix, 1); |
416 hash->Update(leaf.data(), leaf.size()); | 566 hash->Update(leaf.data(), leaf.size()); |
417 hash->Finish(sha256.data, sizeof(sha256.data)); | 567 hash->Finish(sha256.data, sizeof(sha256.data)); |
418 | 568 |
419 return std::string(reinterpret_cast<const char*>(sha256.data), | 569 return std::string(reinterpret_cast<const char*>(sha256.data), |
420 sizeof(sha256.data)); | 570 sizeof(sha256.data)); |
421 } | 571 } |
422 }; | 572 }; |
423 | 573 |
424 // Reference implementation of Merkle hash, for cross-checking. | 574 // Reference implementation of Merkle hash, for cross-checking. |
425 // Recursively calculates the hash of the root given the leaf data | 575 // Recursively calculates the hash of the root given the leaf data |
426 // specified in |inputs|. | 576 // specified in |inputs|. |
427 std::string ReferenceMerkleTreeHash(std::string* inputs, uint64_t input_size) { | 577 std::string ReferenceMerkleTreeHash(std::string* inputs, uint64_t input_size) { |
428 if (!input_size) | 578 // Memoize function - this requires 34 bytes of memory per unique pair of |
429 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 // Use of the cache can be disabled using the --no-hash-cache flag, which | |
584 // makes it easy to see how much memory the cache is consuming. | |
585 static bool is_cache_enabled = | |
586 !base::CommandLine::ForCurrentProcess()->HasSwitch(kNoHashCacheFlag); | |
587 | |
588 std::string hash; | |
589 if (is_cache_enabled) { | |
590 auto iter = cache.find(std::make_pair(inputs, input_size)); | |
591 if (iter != cache.end()) | |
592 hash = iter->second; | |
593 } | |
594 | |
595 if (hash.empty()) { | |
596 if (!input_size) { | |
597 hash = TreeHasher::HashEmpty(); | |
598 } else if (input_size == 1) { | |
599 hash = TreeHasher::HashLeaf(inputs[0]); | |
600 } else { | |
601 const uint64_t split = CalculateNearestPowerOfTwo(input_size); | |
602 | |
603 hash = ct::internal::HashNodes( | |
604 ReferenceMerkleTreeHash(&inputs[0], split), | |
605 ReferenceMerkleTreeHash(&inputs[split], input_size - split)); | |
606 } | |
607 | |
608 if (is_cache_enabled) | |
609 cache[std::make_pair(inputs, input_size)] = hash; | |
610 } | |
611 | |
612 return hash; | |
613 } | |
614 | |
615 // Reference implementation of Merkle paths. Path from leaf to root, | |
616 // excluding the leaf and root themselves. Returns an audit proof for the tree | |
617 // leaf with index |leaf| (1-based). The tree is designated by |inputs|. | |
618 std::vector<std::string> ReferenceMerklePath(std::string* inputs, | |
619 uint64_t input_size, | |
620 uint64_t leaf) { | |
621 std::vector<std::string> path; | |
622 if (leaf > input_size || leaf == 0) | |
623 return path; | |
624 | |
430 if (input_size == 1) | 625 if (input_size == 1) |
431 return TreeHasher::HashLeaf(inputs[0]); | 626 return path; |
432 | 627 |
433 const uint64_t split = CalculateNearestPowerOfTwo(input_size); | 628 const uint64_t split = CalculateNearestPowerOfTwo(input_size); |
434 | 629 |
435 return ct::internal::HashNodes( | 630 std::vector<std::string> subpath; |
436 ReferenceMerkleTreeHash(&inputs[0], split), | 631 if (leaf <= split) { |
437 ReferenceMerkleTreeHash(&inputs[split], input_size - split)); | 632 subpath = ReferenceMerklePath(&inputs[0], split, leaf); |
633 path.insert(path.end(), subpath.begin(), subpath.end()); | |
634 path.push_back(ReferenceMerkleTreeHash(&inputs[split], input_size - split)); | |
635 } else { | |
636 subpath = | |
637 ReferenceMerklePath(&inputs[split], input_size - split, leaf - split); | |
638 path.insert(path.end(), subpath.begin(), subpath.end()); | |
639 path.push_back(ReferenceMerkleTreeHash(&inputs[0], split)); | |
640 } | |
641 | |
642 return path; | |
438 } | 643 } |
439 | 644 |
440 // Reference implementation of snapshot consistency. Returns a | 645 // Reference implementation of snapshot consistency. Returns a |
441 // consistency proof between two snapshots of the tree designated | 646 // consistency proof between two snapshots of the tree designated |
442 // by |inputs|. | 647 // by |inputs|. |
443 // Call with have_root1 = true. | 648 // Call with have_root1 = true. |
444 std::vector<std::string> ReferenceSnapshotConsistency(std::string* inputs, | 649 std::vector<std::string> ReferenceSnapshotConsistency(std::string* inputs, |
445 uint64_t snapshot2, | 650 uint64_t snapshot2, |
446 uint64_t snapshot1, | 651 uint64_t snapshot1, |
447 bool have_root1) { | 652 bool have_root1) { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
495 TEST_F(CTLogVerifierTest, | 700 TEST_F(CTLogVerifierTest, |
496 MAYBE_VerifiesValidConsistencyProofsFromReferenceGenerator) { | 701 MAYBE_VerifiesValidConsistencyProofsFromReferenceGenerator) { |
497 std::vector<std::string> data; | 702 std::vector<std::string> data; |
498 for (int i = 0; i < 256; ++i) | 703 for (int i = 0; i < 256; ++i) |
499 data.push_back(std::string(1, i)); | 704 data.push_back(std::string(1, i)); |
500 | 705 |
501 std::vector<std::string> proof; | 706 std::vector<std::string> proof; |
502 std::string root1, root2; | 707 std::string root1, root2; |
503 // More tests with reference proof generator. | 708 // More tests with reference proof generator. |
504 for (size_t tree_size = 1; tree_size <= data.size() / 2; ++tree_size) { | 709 for (size_t tree_size = 1; tree_size <= data.size() / 2; ++tree_size) { |
710 SCOPED_TRACE(tree_size); | |
505 root2 = ReferenceMerkleTreeHash(data.data(), tree_size); | 711 root2 = ReferenceMerkleTreeHash(data.data(), tree_size); |
506 // Repeat for each snapshot in range. | 712 // Repeat for each snapshot in range. |
507 for (size_t snapshot = 1; snapshot <= tree_size; ++snapshot) { | 713 for (size_t snapshot = 1; snapshot <= tree_size; ++snapshot) { |
714 SCOPED_TRACE(snapshot); | |
508 proof = | 715 proof = |
509 ReferenceSnapshotConsistency(data.data(), tree_size, snapshot, true); | 716 ReferenceSnapshotConsistency(data.data(), tree_size, snapshot, true); |
510 root1 = ReferenceMerkleTreeHash(data.data(), snapshot); | 717 root1 = ReferenceMerkleTreeHash(data.data(), snapshot); |
511 VerifierConsistencyCheck(snapshot, tree_size, root1, root2, proof); | 718 VerifierConsistencyCheck(snapshot, tree_size, root1, root2, proof); |
512 } | 719 } |
513 } | 720 } |
514 } | 721 } |
515 | 722 |
723 TEST_F(CTLogVerifierTest, VerifiesAuditProofEdgeCases_EmptyProof) { | |
724 std::vector<std::string> path; | |
725 // Various invalid paths. | |
726 EXPECT_FALSE( | |
727 VerifyAuditProof(log_, 0, 0, path, std::string(), std::string())); | |
728 EXPECT_FALSE( | |
729 VerifyAuditProof(log_, 0, 1, path, std::string(), std::string())); | |
730 EXPECT_FALSE( | |
731 VerifyAuditProof(log_, 1, 0, path, std::string(), std::string())); | |
732 EXPECT_FALSE( | |
733 VerifyAuditProof(log_, 2, 1, path, std::string(), std::string())); | |
734 | |
735 const std::string empty_hash = HexToBytes(kSHA256EmptyTreeHash); | |
736 EXPECT_FALSE(VerifyAuditProof(log_, 0, 0, path, empty_hash, std::string())); | |
737 EXPECT_FALSE(VerifyAuditProof(log_, 0, 1, path, empty_hash, std::string())); | |
738 EXPECT_FALSE(VerifyAuditProof(log_, 1, 0, path, empty_hash, std::string())); | |
739 EXPECT_FALSE(VerifyAuditProof(log_, 2, 1, path, empty_hash, std::string())); | |
740 } | |
741 | |
742 TEST_F(CTLogVerifierTest, VerifiesValidAuditProofs) { | |
743 std::vector<std::string> path; | |
744 // Known good paths. | |
745 // i = 0 is an invalid path. | |
746 for (int i = 1; i < 6; ++i) { | |
747 SCOPED_TRACE(i); | |
748 // Construct the path. | |
749 path.clear(); | |
750 for (int j = 0; j < kSHA256Paths[i].path_length; ++j) | |
751 path.push_back(HexToBytes(kSHA256Paths[i].path[j])); | |
752 const TestVector& root_hash = kSHA256Roots[kSHA256Paths[i].snapshot - 1]; | |
753 VerifierCheck(kSHA256Paths[i].leaf, kSHA256Paths[i].snapshot, path, | |
754 HexToBytes(root_hash), | |
755 HexToBytes(kSHA256LeafHashes[kSHA256Paths[i].leaf - 1])); | |
756 } | |
757 } | |
758 | |
759 TEST_F(CTLogVerifierTest, VerifiesValidAuditProofsFromReferenceGenerator) { | |
760 std::vector<std::string> data; | |
761 for (size_t i = 0; i < 256; ++i) | |
762 data.emplace_back(1, i); | |
763 | |
764 // More tests with reference path generator. | |
765 std::string root; | |
766 std::vector<std::string> path; | |
767 for (size_t tree_size = 1; tree_size <= data.size() / 2; ++tree_size) { | |
768 SCOPED_TRACE(tree_size); | |
769 // Repeat for each leaf in range. | |
770 for (size_t leaf = 1; leaf <= tree_size; ++leaf) { | |
771 SCOPED_TRACE(leaf); | |
772 path = ReferenceMerklePath(data.data(), tree_size, leaf); | |
773 root = ReferenceMerkleTreeHash(data.data(), tree_size); | |
774 VerifierCheck(leaf, tree_size, path, root, | |
775 TreeHasher::HashLeaf(data[leaf - 1])); | |
776 } | |
777 } | |
778 } | |
779 | |
516 } // namespace | 780 } // namespace |
517 | 781 |
518 } // namespace net | 782 } // namespace net |
OLD | NEW |