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