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 #include "net/cert/ct_serialization.h"
6
7 #include "base/logging.h"
8 #include "base/numerics/checked_math.h"
9 #include "crypto/sha2.h"
10 #include "net/cert/merkle_tree_leaf.h"
11 #include "net/cert/signed_certificate_timestamp.h"
12 #include "net/cert/signed_tree_head.h"
13 #include "third_party/boringssl/src/include/openssl/bytestring.h"
14
15 namespace net::ct {
16
17 namespace {
18
19 const size_t kLogIdLength = crypto::kSHA256Length;
20
21 enum SignatureType {
22 SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP = 0,
23 TREE_HASH = 1,
24 };
25
26 // Reads a variable-length SCT list that has been TLS encoded.
27 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed)
28 // |max_list_length| contains the overall length of the encoded list.
29 // |max_item_length| contains the maximum length of a single item.
30 // On success, returns true and updates |*out| with the encoded list.
ReadSCTList(CBS * in,std::vector<base::StringPiece> * out)31 bool ReadSCTList(CBS* in, std::vector<base::StringPiece>* out) {
32 std::vector<base::StringPiece> result;
33
34 CBS sct_list_data;
35
36 if (!CBS_get_u16_length_prefixed(in, &sct_list_data))
37 return false;
38
39 while (CBS_len(&sct_list_data) != 0) {
40 CBS sct_list_item;
41 if (!CBS_get_u16_length_prefixed(&sct_list_data, &sct_list_item) ||
42 CBS_len(&sct_list_item) == 0) {
43 return false;
44 }
45
46 result.emplace_back(reinterpret_cast<const char*>(CBS_data(&sct_list_item)),
47 CBS_len(&sct_list_item));
48 }
49
50 result.swap(*out);
51 return true;
52 }
53
54 // Checks and converts a hash algorithm.
55 // |in| is the numeric representation of the algorithm.
56 // If the hash algorithm value is in a set of known values, fills in |out| and
57 // returns true. Otherwise, returns false.
ConvertHashAlgorithm(unsigned in,DigitallySigned::HashAlgorithm * out)58 bool ConvertHashAlgorithm(unsigned in, DigitallySigned::HashAlgorithm* out) {
59 switch (in) {
60 case DigitallySigned::HASH_ALGO_NONE:
61 case DigitallySigned::HASH_ALGO_MD5:
62 case DigitallySigned::HASH_ALGO_SHA1:
63 case DigitallySigned::HASH_ALGO_SHA224:
64 case DigitallySigned::HASH_ALGO_SHA256:
65 case DigitallySigned::HASH_ALGO_SHA384:
66 case DigitallySigned::HASH_ALGO_SHA512:
67 break;
68 default:
69 return false;
70 }
71 *out = static_cast<DigitallySigned::HashAlgorithm>(in);
72 return true;
73 }
74
75 // Checks and converts a signing algorithm.
76 // |in| is the numeric representation of the algorithm.
77 // If the signing algorithm value is in a set of known values, fills in |out|
78 // and returns true. Otherwise, returns false.
ConvertSignatureAlgorithm(unsigned in,DigitallySigned::SignatureAlgorithm * out)79 bool ConvertSignatureAlgorithm(
80 unsigned in,
81 DigitallySigned::SignatureAlgorithm* out) {
82 switch (in) {
83 case DigitallySigned::SIG_ALGO_ANONYMOUS:
84 case DigitallySigned::SIG_ALGO_RSA:
85 case DigitallySigned::SIG_ALGO_DSA:
86 case DigitallySigned::SIG_ALGO_ECDSA:
87 break;
88 default:
89 return false;
90 }
91 *out = static_cast<DigitallySigned::SignatureAlgorithm>(in);
92 return true;
93 }
94
95 // Writes a SignedEntryData of type X.509 cert to |*output|.
96 // |input| is the SignedEntryData containing the certificate.
97 // Returns true if the leaf_certificate in the SignedEntryData does not exceed
98 // kMaxAsn1CertificateLength and so can be written to |output|.
EncodeAsn1CertSignedEntry(const SignedEntryData & input,CBB * output)99 bool EncodeAsn1CertSignedEntry(const SignedEntryData& input, CBB* output) {
100 CBB child;
101 return CBB_add_u24_length_prefixed(output, &child) &&
102 CBB_add_bytes(
103 &child,
104 reinterpret_cast<const uint8_t*>(input.leaf_certificate.data()),
105 input.leaf_certificate.size()) &&
106 CBB_flush(output);
107 }
108
109 // Writes a SignedEntryData of type PreCertificate to |*output|.
110 // |input| is the SignedEntryData containing the TBSCertificate and issuer key
111 // hash. Returns true if the TBSCertificate component in the SignedEntryData
112 // does not exceed kMaxTbsCertificateLength and so can be written to |output|.
EncodePrecertSignedEntry(const SignedEntryData & input,CBB * output)113 bool EncodePrecertSignedEntry(const SignedEntryData& input, CBB* output) {
114 CBB child;
115 return CBB_add_bytes(
116 output,
117 reinterpret_cast<const uint8_t*>(input.issuer_key_hash.data),
118 kLogIdLength) &&
119 CBB_add_u24_length_prefixed(output, &child) &&
120 CBB_add_bytes(
121 &child,
122 reinterpret_cast<const uint8_t*>(input.tbs_certificate.data()),
123 input.tbs_certificate.size()) &&
124 CBB_flush(output);
125 }
126
127 } // namespace
128
EncodeDigitallySigned(const DigitallySigned & input,CBB * output_cbb)129 bool EncodeDigitallySigned(const DigitallySigned& input, CBB* output_cbb) {
130 CBB child;
131 return CBB_add_u8(output_cbb, input.hash_algorithm) &&
132 CBB_add_u8(output_cbb, input.signature_algorithm) &&
133 CBB_add_u16_length_prefixed(output_cbb, &child) &&
134 CBB_add_bytes(
135 &child,
136 reinterpret_cast<const uint8_t*>(input.signature_data.data()),
137 input.signature_data.size()) &&
138 CBB_flush(output_cbb);
139 }
140
EncodeDigitallySigned(const DigitallySigned & input,std::string * output)141 bool EncodeDigitallySigned(const DigitallySigned& input,
142 std::string* output) {
143 bssl::ScopedCBB output_cbb;
144 if (!CBB_init(output_cbb.get(), 64) ||
145 !EncodeDigitallySigned(input, output_cbb.get()) ||
146 !CBB_flush(output_cbb.get())) {
147 return false;
148 }
149
150 output->append(reinterpret_cast<const char*>(CBB_data(output_cbb.get())),
151 CBB_len(output_cbb.get()));
152 return true;
153 }
154
DecodeDigitallySigned(CBS * input,DigitallySigned * output)155 bool DecodeDigitallySigned(CBS* input, DigitallySigned* output) {
156 uint8_t hash_algo;
157 uint8_t sig_algo;
158 CBS sig_data;
159
160 if (!CBS_get_u8(input, &hash_algo) || !CBS_get_u8(input, &sig_algo) ||
161 !CBS_get_u16_length_prefixed(input, &sig_data)) {
162 return false;
163 }
164
165 DigitallySigned result;
166 if (!ConvertHashAlgorithm(hash_algo, &result.hash_algorithm) ||
167 !ConvertSignatureAlgorithm(sig_algo, &result.signature_algorithm)) {
168 return false;
169 }
170
171 result.signature_data.assign(
172 reinterpret_cast<const char*>(CBS_data(&sig_data)), CBS_len(&sig_data));
173
174 *output = result;
175 return true;
176 }
177
DecodeDigitallySigned(base::StringPiece * input,DigitallySigned * output)178 bool DecodeDigitallySigned(base::StringPiece* input, DigitallySigned* output) {
179 CBS input_cbs;
180 CBS_init(&input_cbs, reinterpret_cast<const uint8_t*>(input->data()),
181 input->size());
182 bool result = DecodeDigitallySigned(&input_cbs, output);
183 input->remove_prefix(input->size() - CBS_len(&input_cbs));
184 return result;
185 }
186
EncodeSignedEntry(const SignedEntryData & input,CBB * output)187 static bool EncodeSignedEntry(const SignedEntryData& input, CBB* output) {
188 if (!CBB_add_u16(output, input.type)) {
189 return false;
190 }
191 switch (input.type) {
192 case SignedEntryData::LOG_ENTRY_TYPE_X509:
193 return EncodeAsn1CertSignedEntry(input, output);
194 case SignedEntryData::LOG_ENTRY_TYPE_PRECERT:
195 return EncodePrecertSignedEntry(input, output);
196 }
197 return false;
198 }
199
EncodeSignedEntry(const SignedEntryData & input,std::string * output)200 bool EncodeSignedEntry(const SignedEntryData& input, std::string* output) {
201 bssl::ScopedCBB output_cbb;
202
203 if (!CBB_init(output_cbb.get(), 64) ||
204 !EncodeSignedEntry(input, output_cbb.get()) ||
205 !CBB_flush(output_cbb.get())) {
206 return false;
207 }
208
209 output->append(reinterpret_cast<const char*>(CBB_data(output_cbb.get())),
210 CBB_len(output_cbb.get()));
211 return true;
212 }
213
ReadTimeSinceEpoch(CBS * input,base::Time * output)214 static bool ReadTimeSinceEpoch(CBS* input, base::Time* output) {
215 uint64_t time_since_epoch = 0;
216 if (!CBS_get_u64(input, &time_since_epoch))
217 return false;
218
219 base::CheckedNumeric<int64_t> time_since_epoch_signed = time_since_epoch;
220
221 if (!time_since_epoch_signed.IsValid()) {
222 return false;
223 }
224
225 *output = base::Time::UnixEpoch() +
226 base::Milliseconds(int64_t{time_since_epoch_signed.ValueOrDie()});
227
228 return true;
229 }
230
WriteTimeSinceEpoch(const base::Time & timestamp,CBB * output)231 static bool WriteTimeSinceEpoch(const base::Time& timestamp, CBB* output) {
232 base::TimeDelta time_since_epoch = timestamp - base::Time::UnixEpoch();
233 return CBB_add_u64(output, time_since_epoch.InMilliseconds());
234 }
235
EncodeTreeLeaf(const MerkleTreeLeaf & leaf,std::string * output)236 bool EncodeTreeLeaf(const MerkleTreeLeaf& leaf, std::string* output) {
237 bssl::ScopedCBB output_cbb;
238 CBB child;
239 if (!CBB_init(output_cbb.get(), 64) ||
240 !CBB_add_u8(output_cbb.get(), 0) || // version: 1
241 !CBB_add_u8(output_cbb.get(), 0) || // type: timestamped entry
242 !WriteTimeSinceEpoch(leaf.timestamp, output_cbb.get()) ||
243 !EncodeSignedEntry(leaf.signed_entry, output_cbb.get()) ||
244 !CBB_add_u16_length_prefixed(output_cbb.get(), &child) ||
245 !CBB_add_bytes(&child,
246 reinterpret_cast<const uint8_t*>(leaf.extensions.data()),
247 leaf.extensions.size()) ||
248 !CBB_flush(output_cbb.get())) {
249 return false;
250 }
251 output->append(reinterpret_cast<const char*>(CBB_data(output_cbb.get())),
252 CBB_len(output_cbb.get()));
253 return true;
254 }
255
EncodeV1SCTSignedData(const base::Time & timestamp,const std::string & serialized_log_entry,const std::string & extensions,std::string * output)256 bool EncodeV1SCTSignedData(const base::Time& timestamp,
257 const std::string& serialized_log_entry,
258 const std::string& extensions,
259 std::string* output) {
260 bssl::ScopedCBB output_cbb;
261 CBB child;
262 if (!CBB_init(output_cbb.get(), 64) ||
263 !CBB_add_u8(output_cbb.get(), SignedCertificateTimestamp::V1) ||
264 !CBB_add_u8(output_cbb.get(), SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP) ||
265 !WriteTimeSinceEpoch(timestamp, output_cbb.get()) ||
266 // NOTE: serialized_log_entry must already be serialized and contain the
267 // length as the prefix.
268 !CBB_add_bytes(
269 output_cbb.get(),
270 reinterpret_cast<const uint8_t*>(serialized_log_entry.data()),
271 serialized_log_entry.size()) ||
272 !CBB_add_u16_length_prefixed(output_cbb.get(), &child) ||
273 !CBB_add_bytes(&child,
274 reinterpret_cast<const uint8_t*>(extensions.data()),
275 extensions.size()) ||
276 !CBB_flush(output_cbb.get())) {
277 return false;
278 }
279 output->append(reinterpret_cast<const char*>(CBB_data(output_cbb.get())),
280 CBB_len(output_cbb.get()));
281 return true;
282 }
283
EncodeTreeHeadSignature(const SignedTreeHead & signed_tree_head,std::string * output)284 bool EncodeTreeHeadSignature(const SignedTreeHead& signed_tree_head,
285 std::string* output) {
286 bssl::ScopedCBB output_cbb;
287 if (!CBB_init(output_cbb.get(), 64) ||
288 !CBB_add_u8(output_cbb.get(), signed_tree_head.version) ||
289 !CBB_add_u8(output_cbb.get(), TREE_HASH) ||
290 !WriteTimeSinceEpoch(signed_tree_head.timestamp, output_cbb.get()) ||
291 !CBB_add_u64(output_cbb.get(), signed_tree_head.tree_size) ||
292 !CBB_add_bytes(
293 output_cbb.get(),
294 reinterpret_cast<const uint8_t*>(signed_tree_head.sha256_root_hash),
295 kSthRootHashLength)) {
296 return false;
297 }
298 output->append(reinterpret_cast<const char*>(CBB_data(output_cbb.get())),
299 CBB_len(output_cbb.get()));
300 return true;
301 }
302
DecodeSCTList(base::StringPiece input,std::vector<base::StringPiece> * output)303 bool DecodeSCTList(base::StringPiece input,
304 std::vector<base::StringPiece>* output) {
305 std::vector<base::StringPiece> result;
306 CBS input_cbs;
307 CBS_init(&input_cbs, reinterpret_cast<const uint8_t*>(input.data()),
308 input.size());
309 if (!ReadSCTList(&input_cbs, &result) || CBS_len(&input_cbs) != 0 ||
310 result.empty()) {
311 return false;
312 }
313
314 output->swap(result);
315 return true;
316 }
317
DecodeSignedCertificateTimestamp(base::StringPiece * input,scoped_refptr<SignedCertificateTimestamp> * output)318 bool DecodeSignedCertificateTimestamp(
319 base::StringPiece* input,
320 scoped_refptr<SignedCertificateTimestamp>* output) {
321 auto result = base::MakeRefCounted<SignedCertificateTimestamp>();
322 uint8_t version;
323 CBS input_cbs;
324 CBS_init(&input_cbs, reinterpret_cast<const uint8_t*>(input->data()),
325 input->size());
326 if (!CBS_get_u8(&input_cbs, &version) ||
327 version != SignedCertificateTimestamp::V1) {
328 return false;
329 }
330
331 result->version = SignedCertificateTimestamp::V1;
332 CBS log_id;
333 CBS extensions;
334 if (!CBS_get_bytes(&input_cbs, &log_id, kLogIdLength) ||
335 !ReadTimeSinceEpoch(&input_cbs, &result->timestamp) ||
336 !CBS_get_u16_length_prefixed(&input_cbs, &extensions) ||
337 !DecodeDigitallySigned(&input_cbs, &result->signature)) {
338 return false;
339 }
340
341 result->log_id.assign(reinterpret_cast<const char*>(CBS_data(&log_id)),
342 CBS_len(&log_id));
343 result->extensions.assign(
344 reinterpret_cast<const char*>(CBS_data(&extensions)),
345 CBS_len(&extensions));
346 output->swap(result);
347 input->remove_prefix(input->size() - CBS_len(&input_cbs));
348 return true;
349 }
350
EncodeSignedCertificateTimestamp(const scoped_refptr<ct::SignedCertificateTimestamp> & input,std::string * output)351 bool EncodeSignedCertificateTimestamp(
352 const scoped_refptr<ct::SignedCertificateTimestamp>& input,
353 std::string* output) {
354 // This function only supports serialization of V1 SCTs.
355 DCHECK_EQ(SignedCertificateTimestamp::V1, input->version);
356 DCHECK_EQ(kLogIdLength, input->log_id.size());
357
358 bssl::ScopedCBB output_cbb;
359 CBB child;
360 if (!CBB_init(output_cbb.get(), 64) ||
361 !CBB_add_u8(output_cbb.get(), input->version) ||
362 !CBB_add_bytes(output_cbb.get(),
363 reinterpret_cast<const uint8_t*>(input->log_id.data()),
364 kLogIdLength) ||
365 !WriteTimeSinceEpoch(input->timestamp, output_cbb.get()) ||
366 !CBB_add_u16_length_prefixed(output_cbb.get(), &child) ||
367 !CBB_add_bytes(&child,
368 reinterpret_cast<const uint8_t*>(input->extensions.data()),
369 input->extensions.size()) ||
370 !EncodeDigitallySigned(input->signature, output_cbb.get()) ||
371 !CBB_flush(output_cbb.get())) {
372 return false;
373 }
374 output->append(reinterpret_cast<const char*>(CBB_data(output_cbb.get())),
375 CBB_len(output_cbb.get()));
376 return true;
377 }
378
EncodeSCTListForTesting(base::StringPiece sct,std::string * output)379 bool EncodeSCTListForTesting(base::StringPiece sct, std::string* output) {
380 bssl::ScopedCBB encoded_sct, output_cbb;
381 CBB encoded_sct_child, output_child;
382 if (!CBB_init(encoded_sct.get(), 64) || !CBB_init(output_cbb.get(), 64) ||
383 !CBB_add_u16_length_prefixed(encoded_sct.get(), &encoded_sct_child) ||
384 !CBB_add_bytes(&encoded_sct_child,
385 reinterpret_cast<const uint8_t*>(sct.data()),
386 sct.size()) ||
387 !CBB_flush(encoded_sct.get()) ||
388 !CBB_add_u16_length_prefixed(output_cbb.get(), &output_child) ||
389 !CBB_add_bytes(&output_child, CBB_data(encoded_sct.get()),
390 CBB_len(encoded_sct.get())) ||
391 !CBB_flush(output_cbb.get())) {
392 return false;
393 }
394
395 output->append(reinterpret_cast<const char*>(CBB_data(output_cbb.get())),
396 CBB_len(output_cbb.get()));
397 return true;
398 }
399
400 } // namespace net::ct
401