1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "CTSerialization.h"
8 #include "CTTestUtils.h"
9 #include "gtest/gtest.h"
10 #include "mozilla/Move.h"
11
12 namespace mozilla { namespace ct {
13
14 using namespace pkix;
15
16 class CTSerializationTest : public ::testing::Test
17 {
18 public:
SetUp()19 void SetUp() override
20 {
21 mTestDigitallySigned = GetTestDigitallySigned();
22 mTestSignatureData = GetTestDigitallySignedData();
23 }
24
25 protected:
26 Buffer mTestDigitallySigned;
27 Buffer mTestSignatureData;
28 };
29
TEST_F(CTSerializationTest,DecodesDigitallySigned)30 TEST_F(CTSerializationTest, DecodesDigitallySigned)
31 {
32 Input digitallySigned = InputForBuffer(mTestDigitallySigned);
33 Reader digitallySignedReader(digitallySigned);
34
35 DigitallySigned parsed;
36 ASSERT_EQ(Success,
37 DecodeDigitallySigned(digitallySignedReader, parsed));
38 EXPECT_TRUE(digitallySignedReader.AtEnd());
39
40 EXPECT_EQ(DigitallySigned::HashAlgorithm::SHA256,
41 parsed.hashAlgorithm);
42 EXPECT_EQ(DigitallySigned::SignatureAlgorithm::ECDSA,
43 parsed.signatureAlgorithm);
44 EXPECT_EQ(mTestSignatureData, parsed.signatureData);
45 }
46
TEST_F(CTSerializationTest,FailsToDecodePartialDigitallySigned)47 TEST_F(CTSerializationTest, FailsToDecodePartialDigitallySigned)
48 {
49 Input partial;
50 ASSERT_EQ(Success,
51 partial.Init(mTestDigitallySigned.begin(),
52 mTestDigitallySigned.length() - 5));
53 Reader partialReader(partial);
54
55 DigitallySigned parsed;
56
57 EXPECT_NE(Success, DecodeDigitallySigned(partialReader, parsed));
58 }
59
TEST_F(CTSerializationTest,EncodesDigitallySigned)60 TEST_F(CTSerializationTest, EncodesDigitallySigned)
61 {
62 DigitallySigned digitallySigned;
63 digitallySigned.hashAlgorithm =
64 DigitallySigned::HashAlgorithm::SHA256;
65 digitallySigned.signatureAlgorithm =
66 DigitallySigned::SignatureAlgorithm::ECDSA;
67 digitallySigned.signatureData = cloneBuffer(mTestSignatureData);
68
69 Buffer encoded;
70
71 ASSERT_EQ(Success, EncodeDigitallySigned(digitallySigned, encoded));
72 EXPECT_EQ(mTestDigitallySigned, encoded);
73 }
74
TEST_F(CTSerializationTest,EncodesLogEntryForX509Cert)75 TEST_F(CTSerializationTest, EncodesLogEntryForX509Cert)
76 {
77 LogEntry entry;
78 GetX509CertLogEntry(entry);
79
80 Buffer encoded;
81 ASSERT_EQ(Success, EncodeLogEntry(entry, encoded));
82 EXPECT_EQ((718U + 5U), encoded.length());
83 // First two bytes are log entry type. Next, length:
84 // Length is 718 which is 512 + 206, which is 0x2ce
85 Buffer expectedPrefix;
86 MOZ_RELEASE_ASSERT(expectedPrefix.append("\0\0\0\x2\xCE", 5));
87 Buffer encodedPrefix;
88 MOZ_RELEASE_ASSERT(encodedPrefix.
89 append(encoded.begin(), encoded.begin() + 5));
90 EXPECT_EQ(expectedPrefix, encodedPrefix);
91 }
92
TEST_F(CTSerializationTest,EncodesLogEntryForPrecert)93 TEST_F(CTSerializationTest, EncodesLogEntryForPrecert)
94 {
95 LogEntry entry;
96 GetPrecertLogEntry(entry);
97
98 Buffer encoded;
99 ASSERT_EQ(Success, EncodeLogEntry(entry, encoded));
100 // log entry type + issuer key + length + tbsCertificate
101 EXPECT_EQ((2U + 32U + 3U + entry.tbsCertificate.length()), encoded.length());
102
103 // First two bytes are log entry type.
104 Buffer expectedPrefix;
105 MOZ_RELEASE_ASSERT(expectedPrefix.append("\0\x1", 2));
106 Buffer encodedPrefix;
107 MOZ_RELEASE_ASSERT(encodedPrefix.
108 append(encoded.begin(), encoded.begin() + 2));
109 EXPECT_EQ(expectedPrefix, encodedPrefix);
110
111 // Next is the issuer key (32 bytes).
112 Buffer encodedKeyHash;
113 MOZ_RELEASE_ASSERT(encodedKeyHash.
114 append(encoded.begin() + 2, encoded.begin() + 2 + 32));
115 EXPECT_EQ(GetDefaultIssuerKeyHash(), encodedKeyHash);
116 }
117
TEST_F(CTSerializationTest,EncodesV1SCTSignedData)118 TEST_F(CTSerializationTest, EncodesV1SCTSignedData)
119 {
120 uint64_t timestamp = UINT64_C(0x139fe353cf5);
121 const uint8_t DUMMY_BYTES[] = { 0x61, 0x62, 0x63 }; // abc
122 Input dummyEntry(DUMMY_BYTES);
123 Input emptyExtensions;
124 Buffer encoded;
125 ASSERT_EQ(Success, EncodeV1SCTSignedData(
126 timestamp, dummyEntry, emptyExtensions, encoded));
127 EXPECT_EQ((size_t) 15, encoded.length());
128
129 const uint8_t EXPECTED_BYTES[] = {
130 0x00, // version
131 0x00, // signature type
132 0x00, 0x00, 0x01, 0x39, 0xFE, 0x35, 0x3C, 0xF5, // timestamp
133 0x61, 0x62, 0x63, // log signature
134 0x00, 0x00 // extensions (empty)
135 };
136 Buffer expectedBuffer;
137 MOZ_RELEASE_ASSERT(
138 expectedBuffer.append(EXPECTED_BYTES, sizeof(EXPECTED_BYTES)));
139 EXPECT_EQ(expectedBuffer, encoded);
140 }
141
TEST_F(CTSerializationTest,DecodesSCTList)142 TEST_F(CTSerializationTest, DecodesSCTList)
143 {
144 // Two items in the list: "abc", "def"
145 const uint8_t ENCODED[] = {
146 0x00, 0x0a, 0x00, 0x03, 0x61, 0x62, 0x63, 0x00, 0x03, 0x64, 0x65, 0x66
147 };
148 const uint8_t DECODED_1[] = { 0x61, 0x62, 0x63 };
149 const uint8_t DECODED_2[] = { 0x64, 0x65, 0x66 };
150
151 Reader listReader;
152 ASSERT_EQ(Success, DecodeSCTList(Input(ENCODED), listReader));
153
154 Input decoded1;
155 ASSERT_EQ(Success, ReadSCTListItem(listReader, decoded1));
156
157 Input decoded2;
158 ASSERT_EQ(Success, ReadSCTListItem(listReader, decoded2));
159
160 EXPECT_TRUE(listReader.AtEnd());
161 EXPECT_TRUE(InputsAreEqual(decoded1, Input(DECODED_1)));
162 EXPECT_TRUE(InputsAreEqual(decoded2, Input(DECODED_2)));
163 }
164
TEST_F(CTSerializationTest,FailsDecodingInvalidSCTList)165 TEST_F(CTSerializationTest, FailsDecodingInvalidSCTList)
166 {
167 // A list with one item that's too short (the second one)
168 const uint8_t ENCODED[] = {
169 0x00, 0x0a, 0x00, 0x03, 0x61, 0x62, 0x63, 0x00, 0x05, 0x64, 0x65, 0x66
170 };
171
172 Reader listReader;
173 ASSERT_EQ(Success, DecodeSCTList(Input(ENCODED), listReader));
174 Input decoded1;
175 EXPECT_EQ(Success, ReadSCTListItem(listReader, decoded1));
176 Input decoded2;
177 EXPECT_NE(Success, ReadSCTListItem(listReader, decoded2));
178 }
179
TEST_F(CTSerializationTest,EncodesSCTList)180 TEST_F(CTSerializationTest, EncodesSCTList)
181 {
182 const uint8_t SCT_1[] = { 0x61, 0x62, 0x63 };
183 const uint8_t SCT_2[] = { 0x64, 0x65, 0x66 };
184
185 Vector<Input> list;
186 ASSERT_TRUE(list.append(Move(Input(SCT_1))));
187 ASSERT_TRUE(list.append(Move(Input(SCT_2))));
188
189 Buffer encodedList;
190 ASSERT_EQ(Success, EncodeSCTList(list, encodedList));
191
192 Reader listReader;
193 ASSERT_EQ(Success, DecodeSCTList(InputForBuffer(encodedList), listReader));
194
195 Input decoded1;
196 ASSERT_EQ(Success, ReadSCTListItem(listReader, decoded1));
197 EXPECT_TRUE(InputsAreEqual(decoded1, Input(SCT_1)));
198
199 Input decoded2;
200 ASSERT_EQ(Success, ReadSCTListItem(listReader, decoded2));
201 EXPECT_TRUE(InputsAreEqual(decoded2, Input(SCT_2)));
202
203 EXPECT_TRUE(listReader.AtEnd());
204 }
205
TEST_F(CTSerializationTest,DecodesSignedCertificateTimestamp)206 TEST_F(CTSerializationTest, DecodesSignedCertificateTimestamp)
207 {
208 Buffer encodedSctBuffer = GetTestSignedCertificateTimestamp();
209 Input encodedSctInput = InputForBuffer(encodedSctBuffer);
210 Reader encodedSctReader(encodedSctInput);
211
212 SignedCertificateTimestamp sct;
213 ASSERT_EQ(Success,
214 DecodeSignedCertificateTimestamp(encodedSctReader, sct));
215 EXPECT_EQ(SignedCertificateTimestamp::Version::V1, sct.version);
216 EXPECT_EQ(GetTestPublicKeyId(), sct.logId);
217 const uint64_t expectedTime = 1365181456089;
218 EXPECT_EQ(expectedTime, sct.timestamp);
219 const size_t expectedSignatureLength = 71;
220 EXPECT_EQ(expectedSignatureLength, sct.signature.signatureData.length());
221 EXPECT_TRUE(sct.extensions.empty());
222 }
223
TEST_F(CTSerializationTest,FailsDecodingInvalidSignedCertificateTimestamp)224 TEST_F(CTSerializationTest, FailsDecodingInvalidSignedCertificateTimestamp)
225 {
226 SignedCertificateTimestamp sct;
227
228 // Invalid version
229 const uint8_t INVALID_VERSION_BYTES[] = { 0x02, 0x00 };
230 Input invalidVersionSctInput(INVALID_VERSION_BYTES);
231 Reader invalidVersionSctReader(invalidVersionSctInput);
232 EXPECT_EQ(Result::ERROR_BAD_DER,
233 DecodeSignedCertificateTimestamp(invalidVersionSctReader, sct));
234
235 // Valid version, invalid length (missing data)
236 const uint8_t INVALID_LENGTH_BYTES[] = { 0x00, 0x0a, 0x0b, 0x0c };
237 Input invalidLengthSctInput(INVALID_LENGTH_BYTES);
238 Reader invalidLengthSctReader(invalidLengthSctInput);
239 EXPECT_EQ(Result::ERROR_BAD_DER,
240 DecodeSignedCertificateTimestamp(invalidLengthSctReader, sct));
241 }
242
TEST_F(CTSerializationTest,EncodesValidSignedTreeHead)243 TEST_F(CTSerializationTest, EncodesValidSignedTreeHead)
244 {
245 SignedTreeHead signedTreeHead;
246 GetSampleSignedTreeHead(signedTreeHead);
247
248 Buffer encoded;
249 ASSERT_EQ(Success,
250 EncodeTreeHeadSignature(signedTreeHead, encoded));
251 // Expected size is 50 bytes:
252 // Byte 0 is version, byte 1 is signature type
253 // Bytes 2-9 are timestamp
254 // Bytes 10-17 are tree size
255 // Bytes 18-49 are sha256 root hash
256 ASSERT_EQ(50u, encoded.length());
257 const uint8_t EXPECTED_BYTES_PREFIX[] = {
258 0x00, // version
259 0x01, // signature type
260 0x00, 0x00, 0x01, 0x45, 0x3c, 0x5f, 0xb8, 0x35, // timestamp
261 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15 // tree size
262 // sha256 root hash should follow
263 };
264 Buffer expectedBuffer;
265 MOZ_RELEASE_ASSERT(expectedBuffer.append(EXPECTED_BYTES_PREFIX, 18));
266 Buffer hash = GetSampleSTHSHA256RootHash();
267 MOZ_RELEASE_ASSERT(expectedBuffer.append(hash.begin(), hash.length()));
268 EXPECT_EQ(expectedBuffer, encoded);
269 }
270
271 } } // namespace mozilla::ct
272