• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 #include "net/cert/ct_log_response_parser.h"
6 
7 #include <memory>
8 #include <string>
9 
10 #include "base/base64.h"
11 #include "base/json/json_reader.h"
12 #include "base/time/time.h"
13 #include "base/values.h"
14 #include "net/cert/ct_serialization.h"
15 #include "net/cert/signed_tree_head.h"
16 #include "net/test/ct_test_util.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 
19 namespace net::ct {
20 
TEST(CTLogResponseParserTest,ParsesValidJsonSTH)21 TEST(CTLogResponseParserTest, ParsesValidJsonSTH) {
22   absl::optional<base::Value> sample_sth_json =
23       base::JSONReader::Read(GetSampleSTHAsJson());
24   SignedTreeHead tree_head;
25   EXPECT_TRUE(FillSignedTreeHead(*sample_sth_json, &tree_head));
26 
27   SignedTreeHead sample_sth;
28   ASSERT_TRUE(GetSampleSignedTreeHead(&sample_sth));
29 
30   ASSERT_EQ(SignedTreeHead::V1, tree_head.version);
31   ASSERT_EQ(sample_sth.timestamp, tree_head.timestamp);
32   ASSERT_EQ(sample_sth.tree_size, tree_head.tree_size);
33 
34   // Copy the field from the SignedTreeHead because it's not null terminated
35   // there and ASSERT_STREQ expects null-terminated strings.
36   char actual_hash[kSthRootHashLength + 1];
37   memcpy(actual_hash, tree_head.sha256_root_hash, kSthRootHashLength);
38   actual_hash[kSthRootHashLength] = '\0';
39   std::string expected_sha256_root_hash = GetSampleSTHSHA256RootHash();
40   ASSERT_STREQ(expected_sha256_root_hash.c_str(), actual_hash);
41 
42   const DigitallySigned& expected_signature(sample_sth.signature);
43 
44   ASSERT_EQ(tree_head.signature.hash_algorithm,
45             expected_signature.hash_algorithm);
46   ASSERT_EQ(tree_head.signature.signature_algorithm,
47             expected_signature.signature_algorithm);
48   ASSERT_EQ(tree_head.signature.signature_data,
49             expected_signature.signature_data);
50 }
51 
TEST(CTLogResponseParserTest,FailsToParseMissingFields)52 TEST(CTLogResponseParserTest, FailsToParseMissingFields) {
53   absl::optional<base::Value> missing_signature_sth = base::JSONReader::Read(
54       CreateSignedTreeHeadJsonString(1 /* tree_size */, 123456u /* timestamp */,
55                                      GetSampleSTHSHA256RootHash(), ""));
56 
57   SignedTreeHead tree_head;
58   ASSERT_FALSE(FillSignedTreeHead(*missing_signature_sth, &tree_head));
59 
60   absl::optional<base::Value> missing_root_hash_sth = base::JSONReader::Read(
61       CreateSignedTreeHeadJsonString(1 /* tree_size */, 123456u /* timestamp */,
62                                      "", GetSampleSTHTreeHeadSignature()));
63   ASSERT_FALSE(FillSignedTreeHead(*missing_root_hash_sth, &tree_head));
64 }
65 
TEST(CTLogResponseParserTest,FailsToParseIncorrectLengthRootHash)66 TEST(CTLogResponseParserTest, FailsToParseIncorrectLengthRootHash) {
67   SignedTreeHead tree_head;
68 
69   std::string too_long_hash;
70   base::Base64Decode(
71       base::StringPiece("/WHFMgXtI/umKKuACJIN0Bb73TcILm9WkeU6qszvoArK\n"),
72       &too_long_hash);
73   absl::optional<base::Value> too_long_hash_json =
74       base::JSONReader::Read(CreateSignedTreeHeadJsonString(
75           1 /* tree_size */, 123456u /* timestamp */,
76           GetSampleSTHSHA256RootHash(), too_long_hash));
77   ASSERT_FALSE(FillSignedTreeHead(*too_long_hash_json, &tree_head));
78 
79   std::string too_short_hash;
80   base::Base64Decode(
81       base::StringPiece("/WHFMgXtI/umKKuACJIN0Bb73TcILm9WkeU6qszvoA==\n"),
82       &too_short_hash);
83   absl::optional<base::Value> too_short_hash_json =
84       base::JSONReader::Read(CreateSignedTreeHeadJsonString(
85           1 /* tree_size */, 123456u /* timestamp */,
86           GetSampleSTHSHA256RootHash(), too_short_hash));
87   ASSERT_FALSE(FillSignedTreeHead(*too_short_hash_json, &tree_head));
88 }
89 
TEST(CTLogResponseParserTest,ParsesJsonSTHWithLargeTimestamp)90 TEST(CTLogResponseParserTest, ParsesJsonSTHWithLargeTimestamp) {
91   SignedTreeHead tree_head;
92 
93   absl::optional<base::Value> large_timestamp_json =
94       base::JSONReader::Read(CreateSignedTreeHeadJsonString(
95           100, INT64_C(1) << 34, GetSampleSTHSHA256RootHash(),
96           GetSampleSTHTreeHeadSignature()));
97 
98   ASSERT_TRUE(FillSignedTreeHead(*large_timestamp_json, &tree_head));
99 
100   base::Time expected_time =
101       base::Time::UnixEpoch() + base::Milliseconds(INT64_C(1) << 34);
102 
103   EXPECT_EQ(tree_head.timestamp, expected_time);
104 }
105 
TEST(CTLogResponseParserTest,ParsesConsistencyProofSuccessfully)106 TEST(CTLogResponseParserTest, ParsesConsistencyProofSuccessfully) {
107   std::string first(32, 'a');
108   std::string second(32, 'b');
109   std::string third(32, 'c');
110 
111   std::vector<std::string> raw_nodes;
112   raw_nodes.push_back(first);
113   raw_nodes.push_back(second);
114   raw_nodes.push_back(third);
115   absl::optional<base::Value> sample_consistency_proof =
116       base::JSONReader::Read(CreateConsistencyProofJsonString(raw_nodes));
117 
118   std::vector<std::string> output;
119 
120   ASSERT_TRUE(FillConsistencyProof(*sample_consistency_proof, &output));
121 
122   EXPECT_EQ(output[0], first);
123   EXPECT_EQ(output[1], second);
124   EXPECT_EQ(output[2], third);
125 }
126 
TEST(CTLogResponseParserTest,FailsOnInvalidProofJson)127 TEST(CTLogResponseParserTest, FailsOnInvalidProofJson) {
128   std::vector<std::string> output;
129 
130   absl::optional<base::Value> badly_encoded =
131       base::JSONReader::Read(std::string("{\"consistency\": [\"notbase64\"]}"));
132   EXPECT_FALSE(FillConsistencyProof(*badly_encoded, &output));
133 
134   absl::optional<base::Value> not_a_string =
135       base::JSONReader::Read(std::string("{\"consistency\": [42, 16]}"));
136   EXPECT_FALSE(FillConsistencyProof(*badly_encoded, &output));
137 
138   absl::optional<base::Value> missing_consistency =
139       base::JSONReader::Read(std::string("{}"));
140   EXPECT_FALSE(FillConsistencyProof(*missing_consistency, &output));
141 
142   absl::optional<base::Value> not_a_dict =
143       base::JSONReader::Read(std::string("[]"));
144   EXPECT_FALSE(FillConsistencyProof(*not_a_dict, &output));
145 }
146 
TEST(CTLogResponseParserTest,ParsesProofJsonWithExtraFields)147 TEST(CTLogResponseParserTest, ParsesProofJsonWithExtraFields) {
148   std::vector<std::string> output;
149 
150   absl::optional<base::Value> badly_encoded = base::JSONReader::Read(
151       std::string("{\"consistency\": [], \"somethingelse\": 3}"));
152   EXPECT_TRUE(FillConsistencyProof(*badly_encoded, &output));
153 }
154 
155 }  // namespace net::ct
156