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

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: 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
« no previous file with comments | « net/cert/ct_log_verifier.cc ('k') | net/cert/merkle_audit_proof.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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";
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.
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
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
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
OLDNEW
« no previous file with comments | « net/cert/ct_log_verifier.cc ('k') | net/cert/merkle_audit_proof.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698