1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/cert/ct_serialization.h"
7 #include "base/basictypes.h"
8 #include "base/logging.h"
16 // Note: length is always specified in bytes.
17 // Signed Certificate Timestamp (SCT) Version length
18 const size_t kVersionLength
= 1;
20 // Members of a V1 SCT
21 const size_t kLogIdLength
= 32;
22 const size_t kTimestampLength
= 8;
23 const size_t kExtensionsLengthBytes
= 2;
24 const size_t kHashAlgorithmLength
= 1;
25 const size_t kSigAlgorithmLength
= 1;
26 const size_t kSignatureLengthBytes
= 2;
28 // Members of the digitally-signed struct of a V1 SCT
29 const size_t kSignatureTypeLength
= 1;
30 const size_t kLogEntryTypeLength
= 2;
31 const size_t kAsn1CertificateLengthBytes
= 3;
32 const size_t kTbsCertificateLengthBytes
= 3;
34 const size_t kSCTListLengthBytes
= 2;
35 const size_t kSerializedSCTLengthBytes
= 2;
37 // Members of digitally-signed struct of a STH
38 const size_t kTreeSizeLength
= 8;
41 SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP
= 0,
45 // Reads a TLS-encoded variable length unsigned integer from |in|.
46 // The integer is expected to be in big-endian order, which is used by TLS.
47 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed)
48 // |length| indicates the size (in bytes) of the integer. On success, returns
49 // true and stores the result in |*out|.
51 bool ReadUint(size_t length
, base::StringPiece
* in
, T
* out
) {
52 if (in
->size() < length
)
54 DCHECK_LE(length
, sizeof(T
));
57 for (size_t i
= 0; i
< length
; ++i
) {
58 result
= (result
<< 8) | static_cast<unsigned char>((*in
)[i
]);
60 in
->remove_prefix(length
);
65 // Reads a TLS-encoded field length from |in|.
66 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed)
67 // |prefix_length| indicates the bytes needed to represent the length (e.g. 3)
68 // success, returns true and stores the result in |*out|.
69 bool ReadLength(size_t prefix_length
, base::StringPiece
* in
, size_t* out
) {
71 if (!ReadUint(prefix_length
, in
, &length
))
77 // Reads |length| bytes from |*in|. If |*in| is too small, returns false.
78 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed)
79 bool ReadFixedBytes(size_t length
,
80 base::StringPiece
* in
,
81 base::StringPiece
* out
) {
82 if (in
->length() < length
)
84 out
->set(in
->data(), length
);
85 in
->remove_prefix(length
);
89 // Reads a length-prefixed variable amount of bytes from |in|, updating |out|
90 // on success. |prefix_length| indicates the number of bytes needed to represent
92 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed)
93 bool ReadVariableBytes(size_t prefix_length
,
94 base::StringPiece
* in
,
95 base::StringPiece
* out
) {
97 if (!ReadLength(prefix_length
, in
, &length
))
99 return ReadFixedBytes(length
, in
, out
);
102 // Reads a variable-length list that has been TLS encoded.
103 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed)
104 // |max_list_length| contains the overall length of the encoded list.
105 // |max_item_length| contains the maximum length of a single item.
106 // On success, returns true and updates |*out| with the encoded list.
107 bool ReadList(size_t max_list_length
,
108 size_t max_item_length
,
109 base::StringPiece
* in
,
110 std::vector
<base::StringPiece
>* out
) {
111 std::vector
<base::StringPiece
> result
;
113 base::StringPiece list_data
;
114 if (!ReadVariableBytes(max_list_length
, in
, &list_data
))
117 while (!list_data
.empty()) {
118 base::StringPiece list_item
;
119 if (!ReadVariableBytes(max_item_length
, &list_data
, &list_item
)) {
120 DVLOG(1) << "Failed to read item in list.";
123 if (list_item
.empty()) {
124 DVLOG(1) << "Empty item in list";
127 result
.push_back(list_item
);
134 // Checks and converts a hash algorithm.
135 // |in| is the numeric representation of the algorithm.
136 // If the hash algorithm value is in a set of known values, fills in |out| and
137 // returns true. Otherwise, returns false.
138 bool ConvertHashAlgorithm(unsigned in
, DigitallySigned::HashAlgorithm
* out
) {
140 case DigitallySigned::HASH_ALGO_NONE
:
141 case DigitallySigned::HASH_ALGO_MD5
:
142 case DigitallySigned::HASH_ALGO_SHA1
:
143 case DigitallySigned::HASH_ALGO_SHA224
:
144 case DigitallySigned::HASH_ALGO_SHA256
:
145 case DigitallySigned::HASH_ALGO_SHA384
:
146 case DigitallySigned::HASH_ALGO_SHA512
:
151 *out
= static_cast<DigitallySigned::HashAlgorithm
>(in
);
155 // Checks and converts a signing algorithm.
156 // |in| is the numeric representation of the algorithm.
157 // If the signing algorithm value is in a set of known values, fills in |out|
158 // and returns true. Otherwise, returns false.
159 bool ConvertSignatureAlgorithm(
161 DigitallySigned::SignatureAlgorithm
* out
) {
163 case DigitallySigned::SIG_ALGO_ANONYMOUS
:
164 case DigitallySigned::SIG_ALGO_RSA
:
165 case DigitallySigned::SIG_ALGO_DSA
:
166 case DigitallySigned::SIG_ALGO_ECDSA
:
171 *out
= static_cast<DigitallySigned::SignatureAlgorithm
>(in
);
175 // Writes a TLS-encoded variable length unsigned integer to |output|.
176 // |length| indicates the size (in bytes) of the integer.
177 // |value| the value itself to be written.
178 template <typename T
>
179 void WriteUint(size_t length
, T value
, std::string
* output
) {
180 DCHECK_LE(length
, sizeof(T
));
181 DCHECK(length
== sizeof(T
) || value
>> (length
* 8) == 0);
183 for (; length
> 0; --length
) {
184 output
->push_back((value
>> ((length
- 1)* 8)) & 0xFF);
188 // Writes an array to |output| from |input|.
189 // Should be used in one of two cases:
190 // * The length of |input| has already been encoded into the |output| stream.
191 // * The length of |input| is fixed and the reader is expected to specify that
192 // length when reading.
193 // If the length of |input| is dynamic and data is expected to follow it,
194 // WriteVariableBytes must be used.
195 void WriteEncodedBytes(const base::StringPiece
& input
, std::string
* output
) {
196 input
.AppendToString(output
);
199 // Writes a variable-length array to |output|.
200 // |prefix_length| indicates the number of bytes needed to represnt the length.
201 // |input| is the array itself.
202 // If the size of |input| is less than 2^|prefix_length| - 1, encode the
203 // length and data and return true. Otherwise, return false.
204 bool WriteVariableBytes(size_t prefix_length
,
205 const base::StringPiece
& input
,
206 std::string
* output
) {
207 size_t input_size
= input
.size();
208 size_t max_allowed_input_size
=
209 static_cast<size_t>(((1 << (prefix_length
* 8)) - 1));
210 if (input_size
> max_allowed_input_size
)
213 WriteUint(prefix_length
, input
.size(), output
);
214 WriteEncodedBytes(input
, output
);
219 // Writes a LogEntry of type X.509 cert to |output|.
220 // |input| is the LogEntry containing the certificate.
221 // Returns true if the leaf_certificate in the LogEntry does not exceed
222 // kMaxAsn1CertificateLength and so can be written to |output|.
223 bool EncodeAsn1CertLogEntry(const LogEntry
& input
, std::string
* output
) {
224 return WriteVariableBytes(kAsn1CertificateLengthBytes
,
225 input
.leaf_certificate
, output
);
228 // Writes a LogEntry of type PreCertificate to |output|.
229 // |input| is the LogEntry containing the TBSCertificate and issuer key hash.
230 // Returns true if the TBSCertificate component in the LogEntry does not
231 // exceed kMaxTbsCertificateLength and so can be written to |output|.
232 bool EncodePrecertLogEntry(const LogEntry
& input
, std::string
* output
) {
235 reinterpret_cast<const char*>(input
.issuer_key_hash
.data
),
238 return WriteVariableBytes(kTbsCertificateLengthBytes
,
239 input
.tbs_certificate
, output
);
244 bool EncodeDigitallySigned(const DigitallySigned
& input
,
245 std::string
* output
) {
246 WriteUint(kHashAlgorithmLength
, input
.hash_algorithm
, output
);
247 WriteUint(kSigAlgorithmLength
, input
.signature_algorithm
,
249 return WriteVariableBytes(kSignatureLengthBytes
, input
.signature_data
,
253 bool DecodeDigitallySigned(base::StringPiece
* input
,
254 DigitallySigned
* output
) {
257 base::StringPiece sig_data
;
259 if (!ReadUint(kHashAlgorithmLength
, input
, &hash_algo
) ||
260 !ReadUint(kSigAlgorithmLength
, input
, &sig_algo
) ||
261 !ReadVariableBytes(kSignatureLengthBytes
, input
, &sig_data
)) {
265 DigitallySigned result
;
266 if (!ConvertHashAlgorithm(hash_algo
, &result
.hash_algorithm
)) {
267 DVLOG(1) << "Invalid hash algorithm " << hash_algo
;
270 if (!ConvertSignatureAlgorithm(sig_algo
, &result
.signature_algorithm
)) {
271 DVLOG(1) << "Invalid signature algorithm " << sig_algo
;
274 sig_data
.CopyToString(&result
.signature_data
);
280 bool EncodeLogEntry(const LogEntry
& input
, std::string
* output
) {
281 WriteUint(kLogEntryTypeLength
, input
.type
, output
);
282 switch (input
.type
) {
283 case LogEntry::LOG_ENTRY_TYPE_X509
:
284 return EncodeAsn1CertLogEntry(input
, output
);
285 case LogEntry::LOG_ENTRY_TYPE_PRECERT
:
286 return EncodePrecertLogEntry(input
, output
);
291 static void WriteTimeSinceEpoch(const base::Time
& timestamp
,
292 std::string
* output
) {
293 base::TimeDelta time_since_epoch
= timestamp
- base::Time::UnixEpoch();
294 WriteUint(kTimestampLength
, time_since_epoch
.InMilliseconds(), output
);
297 bool EncodeV1SCTSignedData(const base::Time
& timestamp
,
298 const std::string
& serialized_log_entry
,
299 const std::string
& extensions
,
300 std::string
* output
) {
301 WriteUint(kVersionLength
, SignedCertificateTimestamp::SCT_VERSION_1
,
303 WriteUint(kSignatureTypeLength
, SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP
,
305 WriteTimeSinceEpoch(timestamp
, output
);
306 // NOTE: serialized_log_entry must already be serialized and contain the
307 // length as the prefix.
308 WriteEncodedBytes(serialized_log_entry
, output
);
309 return WriteVariableBytes(kExtensionsLengthBytes
, extensions
, output
);
312 void EncodeTreeHeadSignature(const SignedTreeHead
& signed_tree_head
,
313 std::string
* output
) {
314 WriteUint(kVersionLength
, signed_tree_head
.version
, output
);
315 WriteUint(kSignatureTypeLength
, TREE_HASH
, output
);
316 WriteTimeSinceEpoch(signed_tree_head
.timestamp
, output
);
317 WriteUint(kTreeSizeLength
, signed_tree_head
.tree_size
, output
);
319 base::StringPiece(signed_tree_head
.sha256_root_hash
, kSthRootHashLength
),
323 bool DecodeSCTList(base::StringPiece
* input
,
324 std::vector
<base::StringPiece
>* output
) {
325 std::vector
<base::StringPiece
> result
;
326 if (!ReadList(kSCTListLengthBytes
, kSerializedSCTLengthBytes
,
331 if (!input
->empty() || result
.empty())
333 output
->swap(result
);
337 bool DecodeSignedCertificateTimestamp(
338 base::StringPiece
* input
,
339 scoped_refptr
<SignedCertificateTimestamp
>* output
) {
340 scoped_refptr
<SignedCertificateTimestamp
> result(
341 new SignedCertificateTimestamp());
343 if (!ReadUint(kVersionLength
, input
, &version
))
345 if (version
!= SignedCertificateTimestamp::SCT_VERSION_1
) {
346 DVLOG(1) << "Unsupported/invalid version " << version
;
350 result
->version
= SignedCertificateTimestamp::SCT_VERSION_1
;
352 base::StringPiece log_id
;
353 base::StringPiece extensions
;
354 if (!ReadFixedBytes(kLogIdLength
, input
, &log_id
) ||
355 !ReadUint(kTimestampLength
, input
, ×tamp
) ||
356 !ReadVariableBytes(kExtensionsLengthBytes
, input
,
358 !DecodeDigitallySigned(input
, &result
->signature
)) {
362 if (timestamp
> static_cast<uint64
>(kint64max
)) {
363 DVLOG(1) << "Timestamp value too big to cast to int64: " << timestamp
;
367 log_id
.CopyToString(&result
->log_id
);
368 extensions
.CopyToString(&result
->extensions
);
370 base::Time::UnixEpoch() +
371 base::TimeDelta::FromMilliseconds(static_cast<int64
>(timestamp
));
373 output
->swap(result
);
377 bool EncodeSCTListForTesting(const base::StringPiece
& sct
,
378 std::string
* output
) {
379 std::string encoded_sct
;
380 return WriteVariableBytes(kSerializedSCTLengthBytes
, sct
, &encoded_sct
) &&
381 WriteVariableBytes(kSCTListLengthBytes
, encoded_sct
, output
);