• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "net/cert/ct_log_verifier.h"
11 
12 #include <stdint.h>
13 
14 #include <algorithm>
15 #include <memory>
16 #include <string>
17 #include <vector>
18 
19 #include "base/strings/string_number_conversions.h"
20 #include "base/time/time.h"
21 #include "crypto/secure_hash.h"
22 #include "net/base/hash_value.h"
23 #include "net/cert/ct_log_verifier_util.h"
24 #include "net/cert/merkle_audit_proof.h"
25 #include "net/cert/merkle_consistency_proof.h"
26 #include "net/cert/signed_certificate_timestamp.h"
27 #include "net/cert/signed_tree_head.h"
28 #include "net/test/ct_test_util.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 
31 namespace net {
32 
33 namespace {
34 
35 // Calculate the power of two nearest to, but less than, |n|.
36 // |n| must be at least 2.
CalculateNearestPowerOfTwo(size_t n)37 size_t CalculateNearestPowerOfTwo(size_t n) {
38   DCHECK_GT(n, 1u);
39 
40   size_t ret = size_t(1) << (sizeof(size_t) * 8 - 1);
41   while (ret >= n)
42     ret >>= 1;
43 
44   return ret;
45 }
46 
47 // All test data replicated from
48 // https://github.com/google/certificate-transparency/blob/c41b090ecc14ddd6b3531dc7e5ce36b21e253fdd/cpp/merkletree/merkle_tree_test.cc
49 
50 // The SHA-256 hash of an empty Merkle tree.
51 const uint8_t kEmptyTreeHash[32] = {
52     0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4,
53     0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b,
54     0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55};
55 
GetEmptyTreeHash()56 std::string GetEmptyTreeHash() {
57   return std::string(std::begin(kEmptyTreeHash), std::end(kEmptyTreeHash));
58 }
59 
60 // SHA-256 Merkle leaf hashes for the sample tree that all of the other test
61 // data relates to (8 leaves).
62 const char* const kLeafHashes[8] = {
63     "6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d",
64     "96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7",
65     "0298d122906dcfc10892cb53a73992fc5b9f493ea4c9badb27b791b4127a7fe7",
66     "07506a85fd9dd2f120eb694f86011e5bb4662e5c415a62917033d4a9624487e7",
67     "bc1a0643b12e4d2d7c77918f44e0f4f79a838b6cf9ec5b5c283e1f4d88599e6b",
68     "4271a26be0d8a84f0bd54c8c302e7cb3a3b5d1fa6780a40bcce2873477dab658",
69     "b08693ec2e721597130641e8211e7eedccb4c26413963eee6c1e2ed16ffb1a5f",
70     "46f6ffadd3d06a09ff3c5860d2755c8b9819db7df44251788c7d8e3180de8eb1"};
71 
72 // SHA-256 Merkle root hashes from building the sample tree leaf-by-leaf.
73 // The first entry is the root when the tree contains 1 leaf, and the last is
74 // the root when the tree contains all 8 leaves.
75 const char* const kRootHashes[8] = {
76     "6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d",
77     "fac54203e7cc696cf0dfcb42c92a1d9dbaf70ad9e621f4bd8d98662f00e3c125",
78     "aeb6bcfe274b70a14fb067a5e5578264db0fa9b51af5e0ba159158f329e06e77",
79     "d37ee418976dd95753c1c73862b9398fa2a2cf9b4ff0fdfe8b30cd95209614b7",
80     "4e3bbb1f7b478dcfe71fb631631519a3bca12c9aefca1612bfce4c13a86264d4",
81     "76e67dadbcdf1e10e1b74ddc608abd2f98dfb16fbce75277b5232a127f2087ef",
82     "ddb89be403809e325750d3d263cd78929c2942b7942a34b77e122c9594a74c8c",
83     "5dc9da79a70659a9ad559cb701ded9a2ab9d823aad2f4960cfe370eff4604328"};
84 
85 // A single consistency proof. Contains at most 3 proof nodes (all test proofs
86 // will be for a tree of size 8).
87 struct ConsistencyProofTestVector {
88   size_t old_tree_size;
89   size_t new_tree_size;
90   size_t proof_length;
91   const char* const proof[3];
92 };
93 
94 // A collection of consistency proofs between various sub-trees of the sample
95 // tree.
96 const ConsistencyProofTestVector kConsistencyProofs[] = {
97     // Empty consistency proof between trees of the same size (1).
98     {1, 1, 0, {"", "", ""}},
99     // Consistency proof between tree of size 1 and tree of size 8, with 3
100     // nodes in the proof.
101     {1,
102      8,
103      3,
104      {"96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7",
105       "5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e",
106       "6b47aaf29ee3c2af9af889bc1fb9254dabd31177f16232dd6aab035ca39bf6e4"}},
107     // Consistency proof between tree of size 6 and tree of size 8, with 3
108     // nodes in the proof.
109     {6,
110      8,
111      3,
112      {"0ebc5d3437fbe2db158b9f126a1d118e308181031d0a949f8dededebc558ef6a",
113       "ca854ea128ed050b41b35ffc1b87b8eb2bde461e9e3b5596ece6b9d5975a0ae0",
114       "d37ee418976dd95753c1c73862b9398fa2a2cf9b4ff0fdfe8b30cd95209614b7"}},
115     // Consistency proof between tree of size 2 and tree of size 5, with 2
116     // nodes in the proof.
117     {2,
118      5,
119      2,
120      {"5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e",
121       "bc1a0643b12e4d2d7c77918f44e0f4f79a838b6cf9ec5b5c283e1f4d88599e6b", ""}}};
122 
123 // A single audit proof. Contains at most 3 proof nodes (all test proofs will be
124 // for a tree of size 8).
125 struct AuditProofTestVector {
126   size_t leaf;
127   size_t tree_size;
128   size_t proof_length;
129   const char* const proof[3];
130 };
131 
132 // A collection of audit proofs for various leaves and sub-trees of the tree
133 // defined by |kRootHashes|.
134 const AuditProofTestVector kAuditProofs[] = {
135     {0, 1, 0, {"", "", ""}},
136     {0,
137      8,
138      3,
139      {"96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7",
140       "5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e",
141       "6b47aaf29ee3c2af9af889bc1fb9254dabd31177f16232dd6aab035ca39bf6e4"}},
142     {5,
143      8,
144      3,
145      {"bc1a0643b12e4d2d7c77918f44e0f4f79a838b6cf9ec5b5c283e1f4d88599e6b",
146       "ca854ea128ed050b41b35ffc1b87b8eb2bde461e9e3b5596ece6b9d5975a0ae0",
147       "d37ee418976dd95753c1c73862b9398fa2a2cf9b4ff0fdfe8b30cd95209614b7"}},
148     {2,
149      3,
150      1,
151      {"fac54203e7cc696cf0dfcb42c92a1d9dbaf70ad9e621f4bd8d98662f00e3c125", "",
152       ""}},
153     {1,
154      5,
155      3,
156      {"6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d",
157       "5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e",
158       "bc1a0643b12e4d2d7c77918f44e0f4f79a838b6cf9ec5b5c283e1f4d88599e6b"}}};
159 
160 // Decodes a hexadecimal string into the binary data it represents.
HexToBytes(const std::string & hex_data)161 std::string HexToBytes(const std::string& hex_data) {
162   std::string result;
163   if (!base::HexStringToString(hex_data, &result))
164     result.clear();
165   return result;
166 }
167 
168 // Constructs a consistency/audit proof from a test vector.
169 // This is templated so that it can be used with both ConsistencyProofTestVector
170 // and AuditProofTestVector.
171 template <typename TestVectorType>
GetProof(const TestVectorType & test_vector)172 std::vector<std::string> GetProof(const TestVectorType& test_vector) {
173   std::vector<std::string> proof(test_vector.proof_length);
174   std::transform(test_vector.proof,
175                  test_vector.proof + test_vector.proof_length, proof.begin(),
176                  &HexToBytes);
177 
178   return proof;
179 }
180 
181 // Creates a ct::MerkleConsistencyProof from its arguments and returns the
182 // result of passing this to log.VerifyConsistencyProof().
VerifyConsistencyProof(const CTLogVerifier & log,size_t old_tree_size,const std::string & old_tree_root,size_t new_tree_size,const std::string & new_tree_root,const std::vector<std::string> & proof)183 bool VerifyConsistencyProof(const CTLogVerifier& log,
184                             size_t old_tree_size,
185                             const std::string& old_tree_root,
186                             size_t new_tree_size,
187                             const std::string& new_tree_root,
188                             const std::vector<std::string>& proof) {
189   return log.VerifyConsistencyProof(
190       ct::MerkleConsistencyProof(log.key_id(), proof, old_tree_size,
191                                  new_tree_size),
192       old_tree_root, new_tree_root);
193 }
194 
195 // Creates a ct::MerkleAuditProof from its arguments and returns the result of
196 // passing this to log.VerifyAuditProof().
VerifyAuditProof(const CTLogVerifier & log,size_t leaf,size_t tree_size,const std::vector<std::string> & proof,const std::string & tree_root,const std::string & leaf_hash)197 bool VerifyAuditProof(const CTLogVerifier& log,
198                       size_t leaf,
199                       size_t tree_size,
200                       const std::vector<std::string>& proof,
201                       const std::string& tree_root,
202                       const std::string& leaf_hash) {
203   return log.VerifyAuditProof(ct::MerkleAuditProof(leaf, tree_size, proof),
204                               tree_root, leaf_hash);
205 }
206 
207 class CTLogVerifierTest : public ::testing::Test {
208  public:
SetUp()209   void SetUp() override {
210     log_ = CTLogVerifier::Create(ct::GetTestPublicKey(), "testlog");
211 
212     ASSERT_TRUE(log_);
213     EXPECT_EQ(ct::GetTestPublicKeyId(), log_->key_id());
214   }
215 
216  protected:
217   scoped_refptr<const CTLogVerifier> log_;
218 };
219 
220 // Given an audit proof for a leaf in a Merkle tree, asserts that it verifies
221 // and no other combination of leaves, tree sizes and proof nodes verifies.
CheckVerifyAuditProof(const CTLogVerifier & log,size_t leaf,size_t tree_size,const std::vector<std::string> & proof,const std::string & root_hash,const std::string & leaf_hash)222 void CheckVerifyAuditProof(const CTLogVerifier& log,
223                            size_t leaf,
224                            size_t tree_size,
225                            const std::vector<std::string>& proof,
226                            const std::string& root_hash,
227                            const std::string& leaf_hash) {
228   EXPECT_TRUE(
229       VerifyAuditProof(log, leaf, tree_size, proof, root_hash, leaf_hash))
230       << "proof for leaf " << leaf << " did not pass verification";
231   EXPECT_FALSE(
232       VerifyAuditProof(log, leaf - 1, tree_size, proof, root_hash, leaf_hash))
233       << "proof passed verification with wrong leaf index";
234   EXPECT_FALSE(
235       VerifyAuditProof(log, leaf + 1, tree_size, proof, root_hash, leaf_hash))
236       << "proof passed verification with wrong leaf index";
237   EXPECT_FALSE(
238       VerifyAuditProof(log, leaf ^ 2, tree_size, proof, root_hash, leaf_hash))
239       << "proof passed verification with wrong leaf index";
240   EXPECT_FALSE(
241       VerifyAuditProof(log, leaf, tree_size * 2, proof, root_hash, leaf_hash))
242       << "proof passed verification with wrong tree height";
243   EXPECT_FALSE(VerifyAuditProof(log, leaf / 2, tree_size / 2, proof, root_hash,
244                                 leaf_hash))
245       << "proof passed verification with wrong leaf index and tree height";
246   EXPECT_FALSE(
247       VerifyAuditProof(log, leaf, tree_size / 2, proof, root_hash, leaf_hash))
248       << "proof passed verification with wrong tree height";
249   EXPECT_FALSE(VerifyAuditProof(log, leaf, tree_size, proof, GetEmptyTreeHash(),
250                                 leaf_hash))
251       << "proof passed verification with wrong root hash";
252 
253   std::vector<std::string> wrong_proof;
254 
255   // Modify a single element on the proof.
256   for (size_t j = 0; j < proof.size(); ++j) {
257     wrong_proof = proof;
258     wrong_proof[j] = GetEmptyTreeHash();
259     EXPECT_FALSE(VerifyAuditProof(log, leaf, tree_size, wrong_proof, root_hash,
260                                   leaf_hash))
261         << "proof passed verification with one wrong node (node " << j << ")";
262   }
263 
264   wrong_proof = proof;
265   wrong_proof.emplace_back();
266   EXPECT_FALSE(
267       VerifyAuditProof(log, leaf, tree_size, wrong_proof, root_hash, leaf_hash))
268       << "proof passed verification with an empty node appended";
269 
270   wrong_proof.back() = root_hash;
271   EXPECT_FALSE(
272       VerifyAuditProof(log, leaf, tree_size, wrong_proof, root_hash, leaf_hash))
273       << "proof passed verification with an incorrect node appended";
274   wrong_proof.pop_back();
275 
276   if (!wrong_proof.empty()) {
277     wrong_proof.pop_back();
278     EXPECT_FALSE(VerifyAuditProof(log, leaf, tree_size, wrong_proof, root_hash,
279                                   leaf_hash))
280         << "proof passed verification with the last node missing";
281   }
282 
283   wrong_proof.clear();
284   wrong_proof.emplace_back();
285   wrong_proof.insert(wrong_proof.end(), proof.begin(), proof.end());
286   EXPECT_FALSE(
287       VerifyAuditProof(log, leaf, tree_size, wrong_proof, root_hash, leaf_hash))
288       << "proof passed verification with an empty node prepended";
289 
290   wrong_proof[0] = root_hash;
291   EXPECT_FALSE(
292       VerifyAuditProof(log, leaf, tree_size, wrong_proof, root_hash, leaf_hash))
293       << "proof passed verification with an incorrect node prepended";
294 }
295 
296 // Given a consistency proof between two snapshots of the tree, asserts that it
297 // verifies and no other combination of tree sizes and proof nodes verifies.
CheckVerifyConsistencyProof(const CTLogVerifier & log,int old_tree_size,int new_tree_size,const std::string & old_root,const std::string & new_root,const std::vector<std::string> & proof)298 void CheckVerifyConsistencyProof(const CTLogVerifier& log,
299                                  int old_tree_size,
300                                  int new_tree_size,
301                                  const std::string& old_root,
302                                  const std::string& new_root,
303                                  const std::vector<std::string>& proof) {
304   // Verify the original consistency proof.
305   EXPECT_TRUE(VerifyConsistencyProof(log, old_tree_size, old_root,
306                                      new_tree_size, new_root, proof))
307       << "proof between trees of size " << old_tree_size << " and "
308       << new_tree_size << " did not pass verification";
309 
310   if (proof.empty()) {
311     // For simplicity test only non-trivial proofs that have old_root !=
312     // new_root
313     // old_tree_size != 0 and old_tree_size != new_tree_size.
314     return;
315   }
316 
317   // Wrong tree size: The proof checking code should not accept as a valid proof
318   // a proof for a tree size different than the original size it was produced
319   // for. Test that this is not the case for off-by-one changes.
320   EXPECT_FALSE(VerifyConsistencyProof(log, old_tree_size - 1, old_root,
321                                       new_tree_size, new_root, proof))
322       << "proof passed verification with old tree size - 1";
323   EXPECT_FALSE(VerifyConsistencyProof(log, old_tree_size + 1, old_root,
324                                       new_tree_size, new_root, proof))
325       << "proof passed verification with old tree size + 1";
326   EXPECT_FALSE(VerifyConsistencyProof(log, old_tree_size ^ 2, old_root,
327                                       new_tree_size, new_root, proof))
328       << "proof passed verification with old tree size ^ 2";
329 
330   EXPECT_FALSE(VerifyConsistencyProof(log, old_tree_size, old_root,
331                                       new_tree_size * 2, new_root, proof))
332       << "proof passed verification with new tree height + 1";
333   EXPECT_FALSE(VerifyConsistencyProof(log, old_tree_size, old_root,
334                                       new_tree_size / 2, new_root, proof))
335       << "proof passed verification with new tree height - 1";
336 
337   const std::string wrong_root("WrongRoot");
338   EXPECT_FALSE(VerifyConsistencyProof(log, old_tree_size, old_root,
339                                       new_tree_size, wrong_root, proof))
340       << "proof passed verification with wrong old root";
341   EXPECT_FALSE(VerifyConsistencyProof(log, old_tree_size, wrong_root,
342                                       new_tree_size, new_root, proof))
343       << "proof passed verification with wrong new root";
344   EXPECT_FALSE(VerifyConsistencyProof(log, old_tree_size, new_root,
345                                       new_tree_size, old_root, proof))
346       << "proof passed verification with old and new root swapped";
347 
348   // Variations of wrong proofs, all of which should be rejected.
349   std::vector<std::string> wrong_proof;
350   EXPECT_FALSE(VerifyConsistencyProof(log, old_tree_size, old_root,
351                                       new_tree_size, new_root, wrong_proof))
352       << "empty proof passed verification";
353 
354   // Modify a single element in the proof.
355   for (size_t j = 0; j < proof.size(); ++j) {
356     wrong_proof = proof;
357     wrong_proof[j] = GetEmptyTreeHash();
358     EXPECT_FALSE(VerifyConsistencyProof(log, old_tree_size, old_root,
359                                         new_tree_size, new_root, wrong_proof))
360         << "proof passed verification with incorrect node (node " << j << ")";
361   }
362 
363   wrong_proof = proof;
364   wrong_proof.emplace_back();
365   EXPECT_FALSE(VerifyConsistencyProof(log, old_tree_size, old_root,
366                                       new_tree_size, new_root, wrong_proof))
367       << "proof passed verification with empty node appended";
368 
369   wrong_proof.back() = proof.back();
370   EXPECT_FALSE(VerifyConsistencyProof(log, old_tree_size, old_root,
371                                       new_tree_size, new_root, wrong_proof))
372       << "proof passed verification with last node duplicated";
373   wrong_proof.pop_back();
374 
375   wrong_proof.pop_back();
376   EXPECT_FALSE(VerifyConsistencyProof(log, old_tree_size, old_root,
377                                       new_tree_size, new_root, wrong_proof))
378       << "proof passed verification with last node missing";
379 
380   wrong_proof.clear();
381   wrong_proof.emplace_back();
382   wrong_proof.insert(wrong_proof.end(), proof.begin(), proof.end());
383   EXPECT_FALSE(VerifyConsistencyProof(log, old_tree_size, old_root,
384                                       new_tree_size, new_root, wrong_proof))
385       << "proof passed verification with empty node prepended";
386 
387   wrong_proof[0] = proof[0];
388   EXPECT_FALSE(VerifyConsistencyProof(log, old_tree_size, old_root,
389                                       new_tree_size, new_root, wrong_proof))
390       << "proof passed verification with first node duplicated";
391 }
392 
TEST_F(CTLogVerifierTest,VerifiesCertSCT)393 TEST_F(CTLogVerifierTest, VerifiesCertSCT) {
394   ct::SignedEntryData cert_entry;
395   ct::GetX509CertSignedEntry(&cert_entry);
396 
397   scoped_refptr<ct::SignedCertificateTimestamp> cert_sct;
398   ct::GetX509CertSCT(&cert_sct);
399 
400   EXPECT_TRUE(log_->Verify(cert_entry, *cert_sct.get()));
401 }
402 
TEST_F(CTLogVerifierTest,VerifiesPrecertSCT)403 TEST_F(CTLogVerifierTest, VerifiesPrecertSCT) {
404   ct::SignedEntryData precert_entry;
405   ct::GetPrecertSignedEntry(&precert_entry);
406 
407   scoped_refptr<ct::SignedCertificateTimestamp> precert_sct;
408   ct::GetPrecertSCT(&precert_sct);
409 
410   EXPECT_TRUE(log_->Verify(precert_entry, *precert_sct.get()));
411 }
412 
TEST_F(CTLogVerifierTest,FailsInvalidTimestamp)413 TEST_F(CTLogVerifierTest, FailsInvalidTimestamp) {
414   ct::SignedEntryData cert_entry;
415   ct::GetX509CertSignedEntry(&cert_entry);
416 
417   scoped_refptr<ct::SignedCertificateTimestamp> cert_sct;
418   ct::GetX509CertSCT(&cert_sct);
419 
420   // Mangle the timestamp, so that it should fail signature validation.
421   cert_sct->timestamp = base::Time::Now();
422 
423   EXPECT_FALSE(log_->Verify(cert_entry, *cert_sct.get()));
424 }
425 
TEST_F(CTLogVerifierTest,FailsInvalidLogID)426 TEST_F(CTLogVerifierTest, FailsInvalidLogID) {
427   ct::SignedEntryData cert_entry;
428   ct::GetX509CertSignedEntry(&cert_entry);
429 
430   scoped_refptr<ct::SignedCertificateTimestamp> cert_sct;
431   ct::GetX509CertSCT(&cert_sct);
432 
433   // Mangle the log ID, which should cause it to match a different log before
434   // attempting signature validation.
435   cert_sct->log_id.assign(cert_sct->log_id.size(), '\0');
436 
437   EXPECT_FALSE(log_->Verify(cert_entry, *cert_sct.get()));
438 }
439 
TEST_F(CTLogVerifierTest,VerifiesValidSTH)440 TEST_F(CTLogVerifierTest, VerifiesValidSTH) {
441   ct::SignedTreeHead sth;
442   ASSERT_TRUE(ct::GetSampleSignedTreeHead(&sth));
443   EXPECT_TRUE(log_->VerifySignedTreeHead(sth));
444 }
445 
TEST_F(CTLogVerifierTest,DoesNotVerifyInvalidSTH)446 TEST_F(CTLogVerifierTest, DoesNotVerifyInvalidSTH) {
447   ct::SignedTreeHead sth;
448   ASSERT_TRUE(ct::GetSampleSignedTreeHead(&sth));
449   sth.sha256_root_hash[0] = '\x0';
450   EXPECT_FALSE(log_->VerifySignedTreeHead(sth));
451 }
452 
TEST_F(CTLogVerifierTest,VerifiesValidEmptySTH)453 TEST_F(CTLogVerifierTest, VerifiesValidEmptySTH) {
454   ct::SignedTreeHead sth;
455   ASSERT_TRUE(ct::GetSampleEmptySignedTreeHead(&sth));
456   EXPECT_TRUE(log_->VerifySignedTreeHead(sth));
457 }
458 
TEST_F(CTLogVerifierTest,DoesNotVerifyInvalidEmptySTH)459 TEST_F(CTLogVerifierTest, DoesNotVerifyInvalidEmptySTH) {
460   ct::SignedTreeHead sth;
461   ASSERT_TRUE(ct::GetBadEmptySignedTreeHead(&sth));
462   EXPECT_FALSE(log_->VerifySignedTreeHead(sth));
463 }
464 
465 // Test that excess data after the public key is rejected.
TEST_F(CTLogVerifierTest,ExcessDataInPublicKey)466 TEST_F(CTLogVerifierTest, ExcessDataInPublicKey) {
467   std::string key = ct::GetTestPublicKey();
468   key += "extra";
469 
470   scoped_refptr<const CTLogVerifier> log =
471       CTLogVerifier::Create(key, "testlog");
472   EXPECT_FALSE(log);
473 }
474 
TEST_F(CTLogVerifierTest,VerifiesConsistencyProofEdgeCases_EmptyProof)475 TEST_F(CTLogVerifierTest, VerifiesConsistencyProofEdgeCases_EmptyProof) {
476   std::vector<std::string> empty_proof;
477   std::string old_root(GetEmptyTreeHash()), new_root(GetEmptyTreeHash());
478 
479   // Tree snapshots that are always consistent, because the proofs are either
480   // from an empty tree to a non-empty one or for trees of the same size.
481   EXPECT_TRUE(
482       VerifyConsistencyProof(*log_, 0, old_root, 0, new_root, empty_proof));
483   EXPECT_TRUE(
484       VerifyConsistencyProof(*log_, 0, old_root, 1, new_root, empty_proof));
485   EXPECT_TRUE(
486       VerifyConsistencyProof(*log_, 1, old_root, 1, new_root, empty_proof));
487 
488   // Invalid consistency proofs.
489   // Time travel to the past.
490   EXPECT_FALSE(
491       VerifyConsistencyProof(*log_, 1, old_root, 0, new_root, empty_proof));
492   EXPECT_FALSE(
493       VerifyConsistencyProof(*log_, 2, old_root, 1, new_root, empty_proof));
494   // Proof between two trees of different size can never be empty.
495   EXPECT_FALSE(
496       VerifyConsistencyProof(*log_, 1, old_root, 2, new_root, empty_proof));
497 }
498 
TEST_F(CTLogVerifierTest,VerifiesConsistencyProofEdgeCases_MismatchingRoots)499 TEST_F(CTLogVerifierTest, VerifiesConsistencyProofEdgeCases_MismatchingRoots) {
500   const std::string old_root(GetEmptyTreeHash());
501   std::string new_root;
502   std::vector<std::string> empty_proof;
503 
504   // Roots don't match.
505   EXPECT_FALSE(
506       VerifyConsistencyProof(*log_, 0, old_root, 0, new_root, empty_proof));
507   EXPECT_FALSE(
508       VerifyConsistencyProof(*log_, 1, old_root, 1, new_root, empty_proof));
509 }
510 
TEST_F(CTLogVerifierTest,VerifiesConsistencyProofEdgeCases_MatchingRootsNonEmptyProof)511 TEST_F(CTLogVerifierTest,
512        VerifiesConsistencyProofEdgeCases_MatchingRootsNonEmptyProof) {
513   const std::string empty_tree_hash(GetEmptyTreeHash());
514 
515   std::vector<std::string> proof;
516   proof.push_back(empty_tree_hash);
517 
518   // Roots match and the tree size is either the same or the old tree size is 0,
519   // but the proof is not empty (the verification code should not accept
520   // proofs with redundant nodes in this case).
521   proof.push_back(empty_tree_hash);
522   EXPECT_FALSE(VerifyConsistencyProof(*log_, 0, empty_tree_hash, 0,
523                                       empty_tree_hash, proof));
524   EXPECT_FALSE(VerifyConsistencyProof(*log_, 0, empty_tree_hash, 1,
525                                       empty_tree_hash, proof));
526   EXPECT_FALSE(VerifyConsistencyProof(*log_, 1, empty_tree_hash, 1,
527                                       empty_tree_hash, proof));
528 }
529 
530 class CTLogVerifierConsistencyProofTest
531     : public CTLogVerifierTest,
532       public ::testing::WithParamInterface<size_t /* proof index */> {};
533 
534 // Checks that a sample set of valid consistency proofs verify successfully.
TEST_P(CTLogVerifierConsistencyProofTest,VerifiesValidConsistencyProof)535 TEST_P(CTLogVerifierConsistencyProofTest, VerifiesValidConsistencyProof) {
536   const ConsistencyProofTestVector& test_vector =
537       kConsistencyProofs[GetParam()];
538   const std::vector<std::string> proof = GetProof(test_vector);
539 
540   const char* const old_root = kRootHashes[test_vector.old_tree_size - 1];
541   const char* const new_root = kRootHashes[test_vector.new_tree_size - 1];
542   CheckVerifyConsistencyProof(*log_, test_vector.old_tree_size,
543                               test_vector.new_tree_size, HexToBytes(old_root),
544                               HexToBytes(new_root), proof);
545 }
546 
547 INSTANTIATE_TEST_SUITE_P(KnownGoodProofs,
548                          CTLogVerifierConsistencyProofTest,
549                          ::testing::Range(size_t(0),
550                                           std::size(kConsistencyProofs)));
551 
552 class CTLogVerifierAuditProofTest
553     : public CTLogVerifierTest,
554       public ::testing::WithParamInterface<size_t /* proof index */> {};
555 
556 // Checks that a sample set of valid audit proofs verify successfully.
TEST_P(CTLogVerifierAuditProofTest,VerifiesValidAuditProofs)557 TEST_P(CTLogVerifierAuditProofTest, VerifiesValidAuditProofs) {
558   const AuditProofTestVector& test_vector = kAuditProofs[GetParam()];
559   const std::vector<std::string> proof = GetProof(test_vector);
560 
561   const char* const root_hash = kRootHashes[test_vector.tree_size - 1];
562   CheckVerifyAuditProof(*log_, test_vector.leaf, test_vector.tree_size, proof,
563                         HexToBytes(root_hash),
564                         HexToBytes(kLeafHashes[test_vector.leaf]));
565 }
566 
567 INSTANTIATE_TEST_SUITE_P(KnownGoodProofs,
568                          CTLogVerifierAuditProofTest,
569                          ::testing::Range(size_t(0), std::size(kAuditProofs)));
570 
TEST_F(CTLogVerifierTest,VerifiesAuditProofEdgeCases_InvalidLeafIndex)571 TEST_F(CTLogVerifierTest, VerifiesAuditProofEdgeCases_InvalidLeafIndex) {
572   std::vector<std::string> proof;
573   EXPECT_FALSE(
574       VerifyAuditProof(*log_, 1, 0, proof, std::string(), std::string()));
575   EXPECT_FALSE(
576       VerifyAuditProof(*log_, 2, 1, proof, std::string(), std::string()));
577 
578   const std::string empty_hash = GetEmptyTreeHash();
579   EXPECT_FALSE(VerifyAuditProof(*log_, 1, 0, proof, empty_hash, std::string()));
580   EXPECT_FALSE(VerifyAuditProof(*log_, 2, 1, proof, empty_hash, std::string()));
581 }
582 
583 // Functions that implement algorithms from RFC6962 necessary for constructing
584 // Merkle trees and proofs. This allows tests to generate a variety of trees
585 // for exhaustive testing.
586 namespace rfc6962 {
587 
588 // Calculates the hash of a leaf in a Merkle tree, given its content.
589 // See RFC6962, section 2.1.
HashLeaf(const std::string & leaf)590 std::string HashLeaf(const std::string& leaf) {
591   const char kLeafPrefix[] = {'\x00'};
592 
593   SHA256HashValue sha256;
594   memset(sha256.data, 0, sizeof(sha256.data));
595 
596   std::unique_ptr<crypto::SecureHash> hash(
597       crypto::SecureHash::Create(crypto::SecureHash::SHA256));
598   hash->Update(kLeafPrefix, 1);
599   hash->Update(leaf.data(), leaf.size());
600   hash->Finish(sha256.data, sizeof(sha256.data));
601 
602   return std::string(reinterpret_cast<const char*>(sha256.data),
603                      sizeof(sha256.data));
604 }
605 
606 // Calculates the root hash of a Merkle tree, given its leaf data and size.
607 // See RFC6962, section 2.1.
HashTree(std::string leaves[],size_t tree_size)608 std::string HashTree(std::string leaves[], size_t tree_size) {
609   if (tree_size == 0)
610     return GetEmptyTreeHash();
611   if (tree_size == 1)
612     return HashLeaf(leaves[0]);
613 
614   // Find the index of the last leaf in the left sub-tree.
615   const size_t split = CalculateNearestPowerOfTwo(tree_size);
616 
617   // Hash the left and right sub-trees, then hash the results.
618   return ct::internal::HashNodes(HashTree(leaves, split),
619                                  HashTree(&leaves[split], tree_size - split));
620 }
621 
622 // Returns a Merkle audit proof for the leaf with index |leaf_index|.
623 // The tree consists of |leaves[0]| to |leaves[tree_size-1]|.
624 // If |leaf_index| is >= |tree_size|, an empty proof will be returned.
625 // See RFC6962, section 2.1.1, for more details.
CreateAuditProof(std::string leaves[],size_t tree_size,size_t leaf_index)626 std::vector<std::string> CreateAuditProof(std::string leaves[],
627                                           size_t tree_size,
628                                           size_t leaf_index) {
629   std::vector<std::string> proof;
630   if (leaf_index >= tree_size)
631     return proof;
632   if (tree_size == 1)
633     return proof;
634 
635   // Find the index of the first leaf in the right sub-tree.
636   const size_t split = CalculateNearestPowerOfTwo(tree_size);
637 
638   // Recurse down the correct branch of the tree (left or right) to reach the
639   // leaf with |leaf_index|. Add the hash of the branch not taken at each step
640   // on the way up to build the proof.
641   if (leaf_index < split) {
642     proof = CreateAuditProof(leaves, split, leaf_index);
643     proof.push_back(HashTree(&leaves[split], tree_size - split));
644   } else {
645     proof =
646         CreateAuditProof(&leaves[split], tree_size - split, leaf_index - split);
647     proof.push_back(HashTree(leaves, split));
648   }
649 
650   return proof;
651 }
652 
653 // Returns a Merkle consistency proof between two Merkle trees.
654 // The old tree contains |leaves[0]| to |leaves[old_tree_size-1]|.
655 // The new tree contains |leaves[0]| to |leaves[new_tree_size-1]|.
656 // Call with |contains_old_tree| = true.
657 // See RFC6962, section 2.1.2, for more details.
CreateConsistencyProof(std::string leaves[],size_t new_tree_size,size_t old_tree_size,bool contains_old_tree=true)658 std::vector<std::string> CreateConsistencyProof(std::string leaves[],
659                                                 size_t new_tree_size,
660                                                 size_t old_tree_size,
661                                                 bool contains_old_tree = true) {
662   std::vector<std::string> proof;
663   if (old_tree_size == 0 || old_tree_size > new_tree_size)
664     return proof;
665   if (old_tree_size == new_tree_size) {
666     // Consistency proof for two equal subtrees is empty.
667     if (!contains_old_tree) {
668       // Record the hash of this subtree unless it's the root for which
669       // the proof was originally requested. (This happens when the old tree is
670       // balanced).
671       proof.push_back(HashTree(leaves, old_tree_size));
672     }
673     return proof;
674   }
675 
676   // Find the index of the last leaf in the left sub-tree.
677   const size_t split = CalculateNearestPowerOfTwo(new_tree_size);
678 
679   if (old_tree_size <= split) {
680     // Root of the old tree is in the left subtree of the new tree.
681     // Prove that the left subtrees are consistent.
682     proof =
683         CreateConsistencyProof(leaves, split, old_tree_size, contains_old_tree);
684     // Record the hash of the right subtree (only present in the new tree).
685     proof.push_back(HashTree(&leaves[split], new_tree_size - split));
686   } else {
687     // The old tree root is at the same level as the new tree root.
688     // Prove that the right subtrees are consistent. The right subtree
689     // doesn't contain the root of the old tree, so set contains_old_tree =
690     // false.
691     proof = CreateConsistencyProof(&leaves[split], new_tree_size - split,
692                                    old_tree_size - split,
693                                    /* contains_old_tree = */ false);
694     // Record the hash of the left subtree (equal in both trees).
695     proof.push_back(HashTree(leaves, split));
696   }
697   return proof;
698 }
699 
700 }  // namespace rfc6962
701 
702 class CTLogVerifierTestUsingGenerator
703     : public CTLogVerifierTest,
704       public ::testing::WithParamInterface<size_t /* tree_size */> {};
705 
706 // Checks that valid consistency proofs for a range of generated Merkle trees
707 // verify successfully.
TEST_P(CTLogVerifierTestUsingGenerator,VerifiesValidConsistencyProof)708 TEST_P(CTLogVerifierTestUsingGenerator, VerifiesValidConsistencyProof) {
709   const size_t tree_size = GetParam();
710 
711   std::vector<std::string> tree_leaves(tree_size);
712   for (size_t i = 0; i < tree_size; ++i)
713     tree_leaves[i].push_back(static_cast<char>(i));
714 
715   const std::string tree_root =
716       rfc6962::HashTree(tree_leaves.data(), tree_size);
717 
718   // Check consistency proofs for every sub-tree.
719   for (size_t old_tree_size = 0; old_tree_size <= tree_size; ++old_tree_size) {
720     SCOPED_TRACE(old_tree_size);
721     const std::string old_tree_root =
722         rfc6962::HashTree(tree_leaves.data(), old_tree_size);
723     const std::vector<std::string> proof = rfc6962::CreateConsistencyProof(
724         tree_leaves.data(), tree_size, old_tree_size);
725     // Checks that the consistency proof verifies only with the correct tree
726     // sizes and root hashes.
727     CheckVerifyConsistencyProof(*log_, old_tree_size, tree_size, old_tree_root,
728                                 tree_root, proof);
729   }
730 }
731 
732 // Checks that valid audit proofs for a range of generated Merkle trees verify
733 // successfully.
TEST_P(CTLogVerifierTestUsingGenerator,VerifiesValidAuditProofs)734 TEST_P(CTLogVerifierTestUsingGenerator, VerifiesValidAuditProofs) {
735   const size_t tree_size = GetParam();
736 
737   std::vector<std::string> tree_leaves(tree_size);
738   for (size_t i = 0; i < tree_size; ++i)
739     tree_leaves[i].push_back(static_cast<char>(i));
740 
741   const std::string root = rfc6962::HashTree(tree_leaves.data(), tree_size);
742 
743   // Check audit proofs for every leaf in the tree.
744   for (size_t leaf = 0; leaf < tree_size; ++leaf) {
745     SCOPED_TRACE(leaf);
746     std::vector<std::string> proof =
747         rfc6962::CreateAuditProof(tree_leaves.data(), tree_size, leaf);
748     // Checks that the audit proof verifies only for this leaf data, index,
749     // hash, tree size and root hash.
750     CheckVerifyAuditProof(*log_, leaf, tree_size, proof, root,
751                           rfc6962::HashLeaf(tree_leaves[leaf]));
752   }
753 }
754 
755 // Test verification of consistency proofs and audit proofs for all tree sizes
756 // from 0 to 128.
757 INSTANTIATE_TEST_SUITE_P(RangeOfTreeSizes,
758                          CTLogVerifierTestUsingGenerator,
759                          testing::Range(size_t(0), size_t(129)));
760 
761 }  // namespace
762 
763 }  // namespace net
764