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/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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |