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/. */
7 #include "CTSerialization.h"
11 #include <type_traits>
16 using namespace mozilla::pkix
;
18 typedef mozilla::pkix::Result Result
;
20 // Note: length is always specified in bytes.
21 // Signed Certificate Timestamp (SCT) Version length
22 static const size_t kVersionLength
= 1;
24 // Members of a V1 SCT
25 static const size_t kLogIdLength
= 32;
26 static const size_t kTimestampLength
= 8;
27 static const size_t kExtensionsLengthBytes
= 2;
28 static const size_t kHashAlgorithmLength
= 1;
29 static const size_t kSigAlgorithmLength
= 1;
30 static const size_t kSignatureLengthBytes
= 2;
32 // Members of the digitally-signed struct of a V1 SCT
33 static const size_t kSignatureTypeLength
= 1;
34 static const size_t kLogEntryTypeLength
= 2;
35 static const size_t kAsn1CertificateLengthBytes
= 3;
36 static const size_t kTbsCertificateLengthBytes
= 3;
38 static const size_t kSCTListLengthBytes
= 2;
39 static const size_t kSerializedSCTLengthBytes
= 2;
41 // Length of sha256RootHash buffer of SignedTreeHead
42 static const size_t kSthRootHashLength
= 32;
44 enum class SignatureType
{
45 CertificateTimestamp
= 0,
49 // Reads a TLS-encoded variable length unsigned integer from |in|.
50 // The integer is expected to be in big-endian order, which is used by TLS.
51 // Note: does not check if the output parameter overflows while reading.
52 // |length| indicates the size (in bytes) of the serialized integer.
53 static Result
UncheckedReadUint(size_t length
, Reader
& in
, uint64_t& out
) {
55 for (size_t i
= 0; i
< length
; ++i
) {
57 Result rv
= in
.Read(value
);
61 result
= (result
<< 8) | value
;
67 // Performs overflow sanity checks and calls UncheckedReadUint.
68 template <size_t length
, typename T
>
69 Result
ReadUint(Reader
& in
, T
& out
) {
71 static_assert(std::is_unsigned
<T
>::value
, "T must be unsigned");
72 static_assert(length
<= 8, "At most 8 byte integers can be read");
73 static_assert(sizeof(T
) >= length
, "T must be able to hold <length> bytes");
74 Result rv
= UncheckedReadUint(length
, in
, value
);
78 out
= static_cast<T
>(value
);
82 // Reads |length| bytes from |in|.
83 static Result
ReadFixedBytes(size_t length
, Reader
& in
, Input
& out
) {
84 return in
.Skip(length
, out
);
87 // Reads a length-prefixed variable amount of bytes from |in|, updating |out|
88 // on success. |prefixLength| indicates the number of bytes needed to represent
90 template <size_t prefixLength
>
91 Result
ReadVariableBytes(Reader
& in
, Input
& out
) {
93 Result rv
= ReadUint
<prefixLength
>(in
, length
);
97 return ReadFixedBytes(length
, in
, out
);
100 // Reads a serialized hash algorithm.
101 static Result
ReadHashAlgorithm(Reader
& in
,
102 DigitallySigned::HashAlgorithm
& out
) {
104 Result rv
= ReadUint
<kHashAlgorithmLength
>(in
, value
);
108 DigitallySigned::HashAlgorithm algo
=
109 static_cast<DigitallySigned::HashAlgorithm
>(value
);
111 case DigitallySigned::HashAlgorithm::None
:
112 case DigitallySigned::HashAlgorithm::MD5
:
113 case DigitallySigned::HashAlgorithm::SHA1
:
114 case DigitallySigned::HashAlgorithm::SHA224
:
115 case DigitallySigned::HashAlgorithm::SHA256
:
116 case DigitallySigned::HashAlgorithm::SHA384
:
117 case DigitallySigned::HashAlgorithm::SHA512
:
121 return Result::ERROR_BAD_DER
;
124 // Reads a serialized signature algorithm.
125 static Result
ReadSignatureAlgorithm(Reader
& in
,
126 DigitallySigned::SignatureAlgorithm
& out
) {
128 Result rv
= ReadUint
<kSigAlgorithmLength
>(in
, value
);
132 DigitallySigned::SignatureAlgorithm algo
=
133 static_cast<DigitallySigned::SignatureAlgorithm
>(value
);
135 case DigitallySigned::SignatureAlgorithm::Anonymous
:
136 case DigitallySigned::SignatureAlgorithm::RSA
:
137 case DigitallySigned::SignatureAlgorithm::DSA
:
138 case DigitallySigned::SignatureAlgorithm::ECDSA
:
142 return Result::ERROR_BAD_DER
;
145 // Reads a serialized version enum.
146 static Result
ReadVersion(Reader
& in
,
147 SignedCertificateTimestamp::Version
& out
) {
149 Result rv
= ReadUint
<kVersionLength
>(in
, value
);
153 SignedCertificateTimestamp::Version version
=
154 static_cast<SignedCertificateTimestamp::Version
>(value
);
156 case SignedCertificateTimestamp::Version::V1
:
160 return Result::ERROR_BAD_DER
;
163 // Writes a TLS-encoded variable length unsigned integer to |output|.
164 // Note: range/overflow checks are not performed on the input parameters.
165 // |length| indicates the size (in bytes) of the integer to be written.
166 // |value| the value itself to be written.
167 static Result
UncheckedWriteUint(size_t length
, uint64_t value
,
169 output
.reserve(length
+ output
.size());
170 for (; length
> 0; --length
) {
171 uint8_t nextByte
= (value
>> ((length
- 1) * 8)) & 0xFF;
172 output
.push_back(nextByte
);
177 // Performs sanity checks on T and calls UncheckedWriteUint.
178 template <size_t length
, typename T
>
179 static inline Result
WriteUint(T value
, Buffer
& output
) {
180 static_assert(length
<= 8, "At most 8 byte integers can be written");
181 static_assert(sizeof(T
) >= length
, "T must be able to hold <length> bytes");
182 if (std::is_signed
<T
>::value
) {
183 // We accept signed integer types assuming the actual value is non-negative.
185 return Result::FATAL_ERROR_INVALID_ARGS
;
188 if (sizeof(T
) > length
) {
189 // We allow the value variable to take more bytes than is written,
190 // but the unwritten bytes must be zero.
191 // Note: when "sizeof(T) == length" holds, "value >> (length * 8)" is
192 // undefined since the shift is too big. On some compilers, this would
193 // produce a warning even though the actual code is unreachable.
194 if (value
>> (length
* 8 - 1) > 1) {
195 return Result::FATAL_ERROR_INVALID_ARGS
;
198 return UncheckedWriteUint(length
, static_cast<uint64_t>(value
), output
);
201 // Writes an array to |output| from |input|.
202 // Should be used in one of two cases:
203 // * The length of |input| has already been encoded into the |output| stream.
204 // * The length of |input| is fixed and the reader is expected to specify that
205 // length when reading.
206 // If the length of |input| is dynamic and data is expected to follow it,
207 // WriteVariableBytes must be used.
208 static void WriteEncodedBytes(Input input
, Buffer
& output
) {
209 output
.insert(output
.end(), input
.UnsafeGetData(),
210 input
.UnsafeGetData() + input
.GetLength());
213 // Same as above, but the source data is in a Buffer.
214 static void WriteEncodedBytes(const Buffer
& source
, Buffer
& output
) {
215 output
.insert(output
.end(), source
.begin(), source
.end());
218 // A variable-length byte array is prefixed by its length when serialized.
219 // This writes the length prefix.
220 // |prefixLength| indicates the number of bytes needed to represent the length.
221 // |dataLength| is the length of the byte array following the prefix.
222 // Fails if |dataLength| is more than 2^|prefixLength| - 1.
223 template <size_t prefixLength
>
224 static Result
WriteVariableBytesPrefix(size_t dataLength
, Buffer
& output
) {
225 const size_t maxAllowedInputSize
=
226 static_cast<size_t>(((1 << (prefixLength
* 8)) - 1));
227 if (dataLength
> maxAllowedInputSize
) {
228 return Result::FATAL_ERROR_INVALID_ARGS
;
231 return WriteUint
<prefixLength
>(dataLength
, output
);
234 // Writes a variable-length array to |output|.
235 // |prefixLength| indicates the number of bytes needed to represent the length.
236 // |input| is the array itself.
237 // Fails if the size of |input| is more than 2^|prefixLength| - 1.
238 template <size_t prefixLength
>
239 static Result
WriteVariableBytes(Input input
, Buffer
& output
) {
240 Result rv
= WriteVariableBytesPrefix
<prefixLength
>(input
.GetLength(), output
);
244 WriteEncodedBytes(input
, output
);
248 // Same as above, but the source data is in a Buffer.
249 template <size_t prefixLength
>
250 static Result
WriteVariableBytes(const Buffer
& source
, Buffer
& output
) {
252 Result rv
= BufferToInput(source
, input
);
256 return WriteVariableBytes
<prefixLength
>(input
, output
);
259 // Writes a LogEntry of type X.509 cert to |output|.
260 // |input| is the LogEntry containing the certificate.
261 static Result
EncodeAsn1CertLogEntry(const LogEntry
& entry
, Buffer
& output
) {
262 return WriteVariableBytes
<kAsn1CertificateLengthBytes
>(entry
.leafCertificate
,
266 // Writes a LogEntry of type PreCertificate to |output|.
267 // |input| is the LogEntry containing the TBSCertificate and issuer key hash.
268 static Result
EncodePrecertLogEntry(const LogEntry
& entry
, Buffer
& output
) {
269 if (entry
.issuerKeyHash
.size() != kLogIdLength
) {
270 return Result::FATAL_ERROR_INVALID_ARGS
;
272 WriteEncodedBytes(entry
.issuerKeyHash
, output
);
273 return WriteVariableBytes
<kTbsCertificateLengthBytes
>(entry
.tbsCertificate
,
277 Result
EncodeDigitallySigned(const DigitallySigned
& data
, Buffer
& output
) {
278 Result rv
= WriteUint
<kHashAlgorithmLength
>(
279 static_cast<unsigned int>(data
.hashAlgorithm
), output
);
283 rv
= WriteUint
<kSigAlgorithmLength
>(
284 static_cast<unsigned int>(data
.signatureAlgorithm
), output
);
288 return WriteVariableBytes
<kSignatureLengthBytes
>(data
.signatureData
, output
);
291 Result
DecodeDigitallySigned(Reader
& reader
, DigitallySigned
& output
) {
292 DigitallySigned result
;
294 Result rv
= ReadHashAlgorithm(reader
, result
.hashAlgorithm
);
298 rv
= ReadSignatureAlgorithm(reader
, result
.signatureAlgorithm
);
304 rv
= ReadVariableBytes
<kSignatureLengthBytes
>(reader
, signatureData
);
308 InputToBuffer(signatureData
, result
.signatureData
);
310 output
= std::move(result
);
314 Result
EncodeLogEntry(const LogEntry
& entry
, Buffer
& output
) {
315 Result rv
= WriteUint
<kLogEntryTypeLength
>(
316 static_cast<unsigned int>(entry
.type
), output
);
320 switch (entry
.type
) {
321 case LogEntry::Type::X509
:
322 return EncodeAsn1CertLogEntry(entry
, output
);
323 case LogEntry::Type::Precert
:
324 return EncodePrecertLogEntry(entry
, output
);
328 return Result::ERROR_BAD_DER
;
331 static Result
WriteTimeSinceEpoch(uint64_t timestamp
, Buffer
& output
) {
332 return WriteUint
<kTimestampLength
>(timestamp
, output
);
335 Result
EncodeV1SCTSignedData(uint64_t timestamp
, Input serializedLogEntry
,
336 Input extensions
, Buffer
& output
) {
337 Result rv
= WriteUint
<kVersionLength
>(
338 static_cast<unsigned int>(SignedCertificateTimestamp::Version::V1
),
343 rv
= WriteUint
<kSignatureTypeLength
>(
344 static_cast<unsigned int>(SignatureType::CertificateTimestamp
), output
);
348 rv
= WriteTimeSinceEpoch(timestamp
, output
);
352 // NOTE: serializedLogEntry must already be serialized and contain the
353 // length as the prefix.
354 WriteEncodedBytes(serializedLogEntry
, output
);
355 return WriteVariableBytes
<kExtensionsLengthBytes
>(extensions
, output
);
358 Result
DecodeSCTList(Input input
, Reader
& listReader
) {
359 Reader
inputReader(input
);
361 Result rv
= ReadVariableBytes
<kSCTListLengthBytes
>(inputReader
, listData
);
365 return listReader
.Init(listData
);
368 Result
ReadSCTListItem(Reader
& listReader
, Input
& output
) {
369 if (listReader
.AtEnd()) {
370 return Result::FATAL_ERROR_INVALID_ARGS
;
373 Result rv
= ReadVariableBytes
<kSerializedSCTLengthBytes
>(listReader
, output
);
377 if (output
.GetLength() == 0) {
378 return Result::ERROR_BAD_DER
;
383 Result
DecodeSignedCertificateTimestamp(Reader
& reader
,
384 SignedCertificateTimestamp
& output
) {
385 SignedCertificateTimestamp result
;
387 Result rv
= ReadVersion(reader
, result
.version
);
396 rv
= ReadFixedBytes(kLogIdLength
, reader
, logId
);
400 rv
= ReadUint
<kTimestampLength
>(reader
, timestamp
);
404 rv
= ReadVariableBytes
<kExtensionsLengthBytes
>(reader
, extensions
);
408 rv
= DecodeDigitallySigned(reader
, result
.signature
);
413 InputToBuffer(logId
, result
.logId
);
414 InputToBuffer(extensions
, result
.extensions
);
415 result
.timestamp
= timestamp
;
417 output
= std::move(result
);
421 Result
EncodeSCTList(const std::vector
<pkix::Input
>& scts
, Buffer
& output
) {
422 // Find out the total size of the SCT list to be written so we can
423 // write the prefix for the list before writing its contents.
424 size_t sctListLength
= 0;
425 for (auto& sct
: scts
) {
427 /* data size */ sct
.GetLength() +
428 /* length prefix size */ kSerializedSCTLengthBytes
;
431 output
.reserve(kSCTListLengthBytes
+ sctListLength
);
433 // Write the prefix for the SCT list.
435 WriteVariableBytesPrefix
<kSCTListLengthBytes
>(sctListLength
, output
);
439 // Now write each SCT from the list.
440 for (auto& sct
: scts
) {
441 rv
= WriteVariableBytes
<kSerializedSCTLengthBytes
>(sct
, output
);
450 } // namespace mozilla