/src/mozilla-central/security/certverifier/CTSerialization.cpp
Line | Count | Source (jump to first uncovered line) |
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 "CTUtils.h" |
9 | | |
10 | | #include <stdint.h> |
11 | | |
12 | | #include "mozilla/Assertions.h" |
13 | | #include "mozilla/Move.h" |
14 | | #include "mozilla/TypeTraits.h" |
15 | | |
16 | | namespace mozilla { namespace ct { |
17 | | |
18 | | using namespace mozilla::pkix; |
19 | | |
20 | | typedef mozilla::pkix::Result Result; |
21 | | |
22 | | // Note: length is always specified in bytes. |
23 | | // Signed Certificate Timestamp (SCT) Version length |
24 | | static const size_t kVersionLength = 1; |
25 | | |
26 | | // Members of a V1 SCT |
27 | | static const size_t kLogIdLength = 32; |
28 | | static const size_t kTimestampLength = 8; |
29 | | static const size_t kExtensionsLengthBytes = 2; |
30 | | static const size_t kHashAlgorithmLength = 1; |
31 | | static const size_t kSigAlgorithmLength = 1; |
32 | | static const size_t kSignatureLengthBytes = 2; |
33 | | |
34 | | // Members of the digitally-signed struct of a V1 SCT |
35 | | static const size_t kSignatureTypeLength = 1; |
36 | | static const size_t kLogEntryTypeLength = 2; |
37 | | static const size_t kAsn1CertificateLengthBytes = 3; |
38 | | static const size_t kTbsCertificateLengthBytes = 3; |
39 | | |
40 | | static const size_t kSCTListLengthBytes = 2; |
41 | | static const size_t kSerializedSCTLengthBytes = 2; |
42 | | |
43 | | // Members of digitally-signed struct of a STH |
44 | | static const size_t kTreeSizeLength = 8; |
45 | | |
46 | | // Length of sha256RootHash buffer of SignedTreeHead |
47 | | static const size_t kSthRootHashLength = 32; |
48 | | |
49 | | enum class SignatureType { |
50 | | CertificateTimestamp = 0, |
51 | | TreeHash = 1, |
52 | | }; |
53 | | |
54 | | // Reads a TLS-encoded variable length unsigned integer from |in|. |
55 | | // The integer is expected to be in big-endian order, which is used by TLS. |
56 | | // Note: does not check if the output parameter overflows while reading. |
57 | | // |length| indicates the size (in bytes) of the serialized integer. |
58 | | static Result |
59 | | UncheckedReadUint(size_t length, Reader& in, uint64_t& out) |
60 | 0 | { |
61 | 0 | uint64_t result = 0; |
62 | 0 | for (size_t i = 0; i < length; ++i) { |
63 | 0 | uint8_t value; |
64 | 0 | Result rv = in.Read(value); |
65 | 0 | if (rv != Success) { |
66 | 0 | return rv; |
67 | 0 | } |
68 | 0 | result = (result << 8) | value; |
69 | 0 | } |
70 | 0 | out = result; |
71 | 0 | return Success; |
72 | 0 | } |
73 | | |
74 | | // Performs overflow sanity checks and calls UncheckedReadUint. |
75 | | template <size_t length, typename T> |
76 | | Result |
77 | | ReadUint(Reader& in, T& out) |
78 | 0 | { |
79 | 0 | uint64_t value; |
80 | 0 | static_assert(mozilla::IsUnsigned<T>::value, "T must be unsigned"); |
81 | 0 | static_assert(length <= 8, "At most 8 byte integers can be read"); |
82 | 0 | static_assert(sizeof(T) >= length, "T must be able to hold <length> bytes"); |
83 | 0 | Result rv = UncheckedReadUint(length, in, value); |
84 | 0 | if (rv != Success) { |
85 | 0 | return rv; |
86 | 0 | } |
87 | 0 | out = static_cast<T>(value); |
88 | 0 | return Success; |
89 | 0 | } Unexecuted instantiation: mozilla::pkix::Result mozilla::ct::ReadUint<1ul, unsigned int>(mozilla::pkix::Reader&, unsigned int&) Unexecuted instantiation: mozilla::pkix::Result mozilla::ct::ReadUint<1ul, unsigned long>(mozilla::pkix::Reader&, unsigned long&) Unexecuted instantiation: mozilla::pkix::Result mozilla::ct::ReadUint<8ul, unsigned long>(mozilla::pkix::Reader&, unsigned long&) Unexecuted instantiation: mozilla::pkix::Result mozilla::ct::ReadUint<2ul, unsigned long>(mozilla::pkix::Reader&, unsigned long&) |
90 | | |
91 | | // Reads |length| bytes from |in|. |
92 | | static Result |
93 | | ReadFixedBytes(size_t length, Reader& in, Input& out) |
94 | 0 | { |
95 | 0 | return in.Skip(length, out); |
96 | 0 | } |
97 | | |
98 | | // Reads a length-prefixed variable amount of bytes from |in|, updating |out| |
99 | | // on success. |prefixLength| indicates the number of bytes needed to represent |
100 | | // the length. |
101 | | template <size_t prefixLength> |
102 | | Result |
103 | | ReadVariableBytes(Reader& in, Input& out) |
104 | 0 | { |
105 | 0 | size_t length; |
106 | 0 | Result rv = ReadUint<prefixLength>(in, length); |
107 | 0 | if (rv != Success) { |
108 | 0 | return rv; |
109 | 0 | } |
110 | 0 | return ReadFixedBytes(length, in, out); |
111 | 0 | } Unexecuted instantiation: mozilla::pkix::Result mozilla::ct::ReadVariableBytes<1ul>(mozilla::pkix::Reader&, mozilla::pkix::Input&) Unexecuted instantiation: mozilla::pkix::Result mozilla::ct::ReadVariableBytes<2ul>(mozilla::pkix::Reader&, mozilla::pkix::Input&) |
112 | | |
113 | | // Reads a serialized hash algorithm. |
114 | | static Result |
115 | | ReadHashAlgorithm(Reader& in, DigitallySigned::HashAlgorithm& out) |
116 | 0 | { |
117 | 0 | unsigned int value; |
118 | 0 | Result rv = ReadUint<kHashAlgorithmLength>(in, value); |
119 | 0 | if (rv != Success) { |
120 | 0 | return rv; |
121 | 0 | } |
122 | 0 | DigitallySigned::HashAlgorithm algo = |
123 | 0 | static_cast<DigitallySigned::HashAlgorithm>(value); |
124 | 0 | switch (algo) { |
125 | 0 | case DigitallySigned::HashAlgorithm::None: |
126 | 0 | case DigitallySigned::HashAlgorithm::MD5: |
127 | 0 | case DigitallySigned::HashAlgorithm::SHA1: |
128 | 0 | case DigitallySigned::HashAlgorithm::SHA224: |
129 | 0 | case DigitallySigned::HashAlgorithm::SHA256: |
130 | 0 | case DigitallySigned::HashAlgorithm::SHA384: |
131 | 0 | case DigitallySigned::HashAlgorithm::SHA512: |
132 | 0 | out = algo; |
133 | 0 | return Success; |
134 | 0 | } |
135 | 0 | return Result::ERROR_BAD_DER; |
136 | 0 | } |
137 | | |
138 | | // Reads a serialized signature algorithm. |
139 | | static Result |
140 | | ReadSignatureAlgorithm(Reader& in, DigitallySigned::SignatureAlgorithm& out) |
141 | 0 | { |
142 | 0 | unsigned int value; |
143 | 0 | Result rv = ReadUint<kSigAlgorithmLength>(in, value); |
144 | 0 | if (rv != Success) { |
145 | 0 | return rv; |
146 | 0 | } |
147 | 0 | DigitallySigned::SignatureAlgorithm algo = |
148 | 0 | static_cast<DigitallySigned::SignatureAlgorithm>(value); |
149 | 0 | switch (algo) { |
150 | 0 | case DigitallySigned::SignatureAlgorithm::Anonymous: |
151 | 0 | case DigitallySigned::SignatureAlgorithm::RSA: |
152 | 0 | case DigitallySigned::SignatureAlgorithm::DSA: |
153 | 0 | case DigitallySigned::SignatureAlgorithm::ECDSA: |
154 | 0 | out = algo; |
155 | 0 | return Success; |
156 | 0 | } |
157 | 0 | return Result::ERROR_BAD_DER; |
158 | 0 | } |
159 | | |
160 | | // Reads a serialized version enum. |
161 | | static Result |
162 | | ReadVersion(Reader& in, SignedCertificateTimestamp::Version& out) |
163 | 0 | { |
164 | 0 | unsigned int value; |
165 | 0 | Result rv = ReadUint<kVersionLength>(in, value); |
166 | 0 | if (rv != Success) { |
167 | 0 | return rv; |
168 | 0 | } |
169 | 0 | SignedCertificateTimestamp::Version version = |
170 | 0 | static_cast<SignedCertificateTimestamp::Version>(value); |
171 | 0 | switch (version) { |
172 | 0 | case SignedCertificateTimestamp::Version::V1: |
173 | 0 | out = version; |
174 | 0 | return Success; |
175 | 0 | } |
176 | 0 | return Result::ERROR_BAD_DER; |
177 | 0 | } |
178 | | |
179 | | // Writes a TLS-encoded variable length unsigned integer to |output|. |
180 | | // Note: range/overflow checks are not performed on the input parameters. |
181 | | // |length| indicates the size (in bytes) of the integer to be written. |
182 | | // |value| the value itself to be written. |
183 | | static Result |
184 | | UncheckedWriteUint(size_t length, uint64_t value, Buffer& output) |
185 | 0 | { |
186 | 0 | if (!output.reserve(length + output.length())) { |
187 | 0 | return Result::FATAL_ERROR_NO_MEMORY; |
188 | 0 | } |
189 | 0 | for (; length > 0; --length) { |
190 | 0 | uint8_t nextByte = (value >> ((length - 1) * 8)) & 0xFF; |
191 | 0 | output.infallibleAppend(nextByte); |
192 | 0 | } |
193 | 0 | return Success; |
194 | 0 | } |
195 | | |
196 | | // Performs sanity checks on T and calls UncheckedWriteUint. |
197 | | template <size_t length, typename T> |
198 | | static inline Result |
199 | | WriteUint(T value, Buffer& output) |
200 | 0 | { |
201 | 0 | static_assert(length <= 8, "At most 8 byte integers can be written"); |
202 | 0 | static_assert(sizeof(T) >= length, "T must be able to hold <length> bytes"); |
203 | 0 | if (mozilla::IsSigned<T>::value) { |
204 | 0 | // We accept signed integer types assuming the actual value is non-negative. |
205 | 0 | if (value < 0) { |
206 | 0 | return Result::FATAL_ERROR_INVALID_ARGS; |
207 | 0 | } |
208 | 0 | } |
209 | 0 | if (sizeof(T) > length) { |
210 | 0 | // We allow the value variable to take more bytes than is written, |
211 | 0 | // but the unwritten bytes must be zero. |
212 | 0 | // Note: when "sizeof(T) == length" holds, "value >> (length * 8)" is |
213 | 0 | // undefined since the shift is too big. On some compilers, this would |
214 | 0 | // produce a warning even though the actual code is unreachable. |
215 | 0 | if (value >> (length * 8 - 1) > 1) { |
216 | 0 | return Result::FATAL_ERROR_INVALID_ARGS; |
217 | 0 | } |
218 | 0 | } |
219 | 0 | return UncheckedWriteUint(length, static_cast<uint64_t>(value), output); |
220 | 0 | } Unexecuted instantiation: Unified_cpp_certverifier0.cpp:mozilla::pkix::Result mozilla::ct::WriteUint<3ul, unsigned long>(unsigned long, mozilla::Vector<unsigned char, 0ul, mozilla::MallocAllocPolicy>&) Unexecuted instantiation: Unified_cpp_certverifier0.cpp:mozilla::pkix::Result mozilla::ct::WriteUint<1ul, unsigned int>(unsigned int, mozilla::Vector<unsigned char, 0ul, mozilla::MallocAllocPolicy>&) Unexecuted instantiation: Unified_cpp_certverifier0.cpp:mozilla::pkix::Result mozilla::ct::WriteUint<2ul, unsigned int>(unsigned int, mozilla::Vector<unsigned char, 0ul, mozilla::MallocAllocPolicy>&) Unexecuted instantiation: Unified_cpp_certverifier0.cpp:mozilla::pkix::Result mozilla::ct::WriteUint<8ul, unsigned long>(unsigned long, mozilla::Vector<unsigned char, 0ul, mozilla::MallocAllocPolicy>&) Unexecuted instantiation: Unified_cpp_certverifier0.cpp:mozilla::pkix::Result mozilla::ct::WriteUint<2ul, unsigned long>(unsigned long, mozilla::Vector<unsigned char, 0ul, mozilla::MallocAllocPolicy>&) |
221 | | |
222 | | // Writes an array to |output| from |input|. |
223 | | // Should be used in one of two cases: |
224 | | // * The length of |input| has already been encoded into the |output| stream. |
225 | | // * The length of |input| is fixed and the reader is expected to specify that |
226 | | // length when reading. |
227 | | // If the length of |input| is dynamic and data is expected to follow it, |
228 | | // WriteVariableBytes must be used. |
229 | | static Result |
230 | | WriteEncodedBytes(Input input, Buffer& output) |
231 | 0 | { |
232 | 0 | if (!output.append(input.UnsafeGetData(), input.GetLength())) { |
233 | 0 | return Result::FATAL_ERROR_NO_MEMORY; |
234 | 0 | } |
235 | 0 | return Success; |
236 | 0 | } |
237 | | |
238 | | // Same as above, but the source data is in a Buffer. |
239 | | static Result |
240 | | WriteEncodedBytes(const Buffer& source, Buffer& output) |
241 | 0 | { |
242 | 0 | if (!output.appendAll(source)) { |
243 | 0 | return Result::FATAL_ERROR_NO_MEMORY; |
244 | 0 | } |
245 | 0 | return Success; |
246 | 0 | } |
247 | | |
248 | | // A variable-length byte array is prefixed by its length when serialized. |
249 | | // This writes the length prefix. |
250 | | // |prefixLength| indicates the number of bytes needed to represent the length. |
251 | | // |dataLength| is the length of the byte array following the prefix. |
252 | | // Fails if |dataLength| is more than 2^|prefixLength| - 1. |
253 | | template <size_t prefixLength> |
254 | | static Result |
255 | | WriteVariableBytesPrefix(size_t dataLength, Buffer& output) |
256 | 0 | { |
257 | 0 | const size_t maxAllowedInputSize = |
258 | 0 | static_cast<size_t>(((1 << (prefixLength * 8)) - 1)); |
259 | 0 | if (dataLength > maxAllowedInputSize) { |
260 | 0 | return Result::FATAL_ERROR_INVALID_ARGS; |
261 | 0 | } |
262 | 0 | |
263 | 0 | return WriteUint<prefixLength>(dataLength, output); |
264 | 0 | } Unexecuted instantiation: Unified_cpp_certverifier0.cpp:mozilla::pkix::Result mozilla::ct::WriteVariableBytesPrefix<3ul>(unsigned long, mozilla::Vector<unsigned char, 0ul, mozilla::MallocAllocPolicy>&) Unexecuted instantiation: Unified_cpp_certverifier0.cpp:mozilla::pkix::Result mozilla::ct::WriteVariableBytesPrefix<2ul>(unsigned long, mozilla::Vector<unsigned char, 0ul, mozilla::MallocAllocPolicy>&) |
265 | | |
266 | | // Writes a variable-length array to |output|. |
267 | | // |prefixLength| indicates the number of bytes needed to represent the length. |
268 | | // |input| is the array itself. |
269 | | // Fails if the size of |input| is more than 2^|prefixLength| - 1. |
270 | | template <size_t prefixLength> |
271 | | static Result |
272 | | WriteVariableBytes(Input input, Buffer& output) |
273 | 0 | { |
274 | 0 | Result rv = WriteVariableBytesPrefix<prefixLength>(input.GetLength(), output); |
275 | 0 | if (rv != Success) { |
276 | 0 | return rv; |
277 | 0 | } |
278 | 0 | return WriteEncodedBytes(input, output); |
279 | 0 | } Unexecuted instantiation: Unified_cpp_certverifier0.cpp:mozilla::pkix::Result mozilla::ct::WriteVariableBytes<3ul>(mozilla::pkix::Input, mozilla::Vector<unsigned char, 0ul, mozilla::MallocAllocPolicy>&) Unexecuted instantiation: Unified_cpp_certverifier0.cpp:mozilla::pkix::Result mozilla::ct::WriteVariableBytes<2ul>(mozilla::pkix::Input, mozilla::Vector<unsigned char, 0ul, mozilla::MallocAllocPolicy>&) |
280 | | |
281 | | // Same as above, but the source data is in a Buffer. |
282 | | template <size_t prefixLength> |
283 | | static Result |
284 | | WriteVariableBytes(const Buffer& source, Buffer& output) |
285 | 0 | { |
286 | 0 | Input input; |
287 | 0 | Result rv = BufferToInput(source, input); |
288 | 0 | if (rv != Success) { |
289 | 0 | return rv; |
290 | 0 | } |
291 | 0 | return WriteVariableBytes<prefixLength>(input, output); |
292 | 0 | } Unexecuted instantiation: Unified_cpp_certverifier0.cpp:mozilla::pkix::Result mozilla::ct::WriteVariableBytes<3ul>(mozilla::Vector<unsigned char, 0ul, mozilla::MallocAllocPolicy> const&, mozilla::Vector<unsigned char, 0ul, mozilla::MallocAllocPolicy>&) Unexecuted instantiation: Unified_cpp_certverifier0.cpp:mozilla::pkix::Result mozilla::ct::WriteVariableBytes<2ul>(mozilla::Vector<unsigned char, 0ul, mozilla::MallocAllocPolicy> const&, mozilla::Vector<unsigned char, 0ul, mozilla::MallocAllocPolicy>&) |
293 | | |
294 | | // Writes a LogEntry of type X.509 cert to |output|. |
295 | | // |input| is the LogEntry containing the certificate. |
296 | | static Result |
297 | | EncodeAsn1CertLogEntry(const LogEntry& entry, Buffer& output) |
298 | 0 | { |
299 | 0 | return WriteVariableBytes<kAsn1CertificateLengthBytes>(entry.leafCertificate, |
300 | 0 | output); |
301 | 0 | } |
302 | | |
303 | | // Writes a LogEntry of type PreCertificate to |output|. |
304 | | // |input| is the LogEntry containing the TBSCertificate and issuer key hash. |
305 | | static Result |
306 | | EncodePrecertLogEntry(const LogEntry& entry, Buffer& output) |
307 | 0 | { |
308 | 0 | if (entry.issuerKeyHash.length() != kLogIdLength) { |
309 | 0 | return Result::FATAL_ERROR_INVALID_ARGS; |
310 | 0 | } |
311 | 0 | Result rv = WriteEncodedBytes(entry.issuerKeyHash, output); |
312 | 0 | if (rv != Success) { |
313 | 0 | return rv; |
314 | 0 | } |
315 | 0 | return WriteVariableBytes<kTbsCertificateLengthBytes>(entry.tbsCertificate, |
316 | 0 | output); |
317 | 0 | } |
318 | | |
319 | | |
320 | | Result |
321 | | EncodeDigitallySigned(const DigitallySigned& data, Buffer& output) |
322 | 0 | { |
323 | 0 | Result rv = WriteUint<kHashAlgorithmLength>( |
324 | 0 | static_cast<unsigned int>(data.hashAlgorithm), output); |
325 | 0 | if (rv != Success) { |
326 | 0 | return rv; |
327 | 0 | } |
328 | 0 | rv = WriteUint<kSigAlgorithmLength>( |
329 | 0 | static_cast<unsigned int>(data.signatureAlgorithm), output); |
330 | 0 | if (rv != Success) { |
331 | 0 | return rv; |
332 | 0 | } |
333 | 0 | return WriteVariableBytes<kSignatureLengthBytes>(data.signatureData, output); |
334 | 0 | } |
335 | | |
336 | | Result |
337 | | DecodeDigitallySigned(Reader& reader, DigitallySigned& output) |
338 | 0 | { |
339 | 0 | DigitallySigned result; |
340 | 0 |
|
341 | 0 | Result rv = ReadHashAlgorithm(reader, result.hashAlgorithm); |
342 | 0 | if (rv != Success) { |
343 | 0 | return rv; |
344 | 0 | } |
345 | 0 | rv = ReadSignatureAlgorithm(reader, result.signatureAlgorithm); |
346 | 0 | if (rv != Success) { |
347 | 0 | return rv; |
348 | 0 | } |
349 | 0 | |
350 | 0 | Input signatureData; |
351 | 0 | rv = ReadVariableBytes<kSignatureLengthBytes>(reader, signatureData); |
352 | 0 | if (rv != Success) { |
353 | 0 | return rv; |
354 | 0 | } |
355 | 0 | rv = InputToBuffer(signatureData, result.signatureData); |
356 | 0 | if (rv != Success) { |
357 | 0 | return rv; |
358 | 0 | } |
359 | 0 | |
360 | 0 | output = std::move(result); |
361 | 0 | return Success; |
362 | 0 | } |
363 | | |
364 | | Result |
365 | | EncodeLogEntry(const LogEntry& entry, Buffer& output) |
366 | 0 | { |
367 | 0 | Result rv = WriteUint<kLogEntryTypeLength>( |
368 | 0 | static_cast<unsigned int>(entry.type), output); |
369 | 0 | if (rv != Success) { |
370 | 0 | return rv; |
371 | 0 | } |
372 | 0 | switch (entry.type) { |
373 | 0 | case LogEntry::Type::X509: |
374 | 0 | return EncodeAsn1CertLogEntry(entry, output); |
375 | 0 | case LogEntry::Type::Precert: |
376 | 0 | return EncodePrecertLogEntry(entry, output); |
377 | 0 | default: |
378 | 0 | MOZ_ASSERT_UNREACHABLE("Unexpected LogEntry type"); |
379 | 0 | } |
380 | 0 | return Result::ERROR_BAD_DER; |
381 | 0 | } |
382 | | |
383 | | static Result |
384 | | WriteTimeSinceEpoch(uint64_t timestamp, Buffer& output) |
385 | 0 | { |
386 | 0 | return WriteUint<kTimestampLength>(timestamp, output); |
387 | 0 | } |
388 | | |
389 | | Result |
390 | | EncodeV1SCTSignedData(uint64_t timestamp, Input serializedLogEntry, |
391 | | Input extensions, Buffer& output) |
392 | 0 | { |
393 | 0 | Result rv = WriteUint<kVersionLength>(static_cast<unsigned int>( |
394 | 0 | SignedCertificateTimestamp::Version::V1), output); |
395 | 0 | if (rv != Success) { |
396 | 0 | return rv; |
397 | 0 | } |
398 | 0 | rv = WriteUint<kSignatureTypeLength>(static_cast<unsigned int>( |
399 | 0 | SignatureType::CertificateTimestamp), output); |
400 | 0 | if (rv != Success) { |
401 | 0 | return rv; |
402 | 0 | } |
403 | 0 | rv = WriteTimeSinceEpoch(timestamp, output); |
404 | 0 | if (rv != Success) { |
405 | 0 | return rv; |
406 | 0 | } |
407 | 0 | // NOTE: serializedLogEntry must already be serialized and contain the |
408 | 0 | // length as the prefix. |
409 | 0 | rv = WriteEncodedBytes(serializedLogEntry, output); |
410 | 0 | if (rv != Success) { |
411 | 0 | return rv; |
412 | 0 | } |
413 | 0 | return WriteVariableBytes<kExtensionsLengthBytes>(extensions, output); |
414 | 0 | } |
415 | | |
416 | | Result |
417 | | EncodeTreeHeadSignature(const SignedTreeHead& signedTreeHead, |
418 | | Buffer& output) |
419 | 0 | { |
420 | 0 | Result rv = WriteUint<kVersionLength>( |
421 | 0 | static_cast<unsigned int>(signedTreeHead.version), output); |
422 | 0 | if (rv != Success) { |
423 | 0 | return rv; |
424 | 0 | } |
425 | 0 | rv = WriteUint<kSignatureTypeLength>( |
426 | 0 | static_cast<unsigned int>(SignatureType::TreeHash), output); |
427 | 0 | if (rv != Success) { |
428 | 0 | return rv; |
429 | 0 | } |
430 | 0 | rv = WriteTimeSinceEpoch(signedTreeHead.timestamp, output); |
431 | 0 | if (rv != Success) { |
432 | 0 | return rv; |
433 | 0 | } |
434 | 0 | rv = WriteUint<kTreeSizeLength>(signedTreeHead.treeSize, output); |
435 | 0 | if (rv != Success) { |
436 | 0 | return rv; |
437 | 0 | } |
438 | 0 | if (signedTreeHead.sha256RootHash.length() != kSthRootHashLength) { |
439 | 0 | return Result::FATAL_ERROR_INVALID_ARGS; |
440 | 0 | } |
441 | 0 | return WriteEncodedBytes(signedTreeHead.sha256RootHash, output); |
442 | 0 | } |
443 | | |
444 | | Result |
445 | | DecodeSCTList(Input input, Reader& listReader) |
446 | 0 | { |
447 | 0 | Reader inputReader(input); |
448 | 0 | Input listData; |
449 | 0 | Result rv = ReadVariableBytes<kSCTListLengthBytes>(inputReader, listData); |
450 | 0 | if (rv != Success) { |
451 | 0 | return rv; |
452 | 0 | } |
453 | 0 | return listReader.Init(listData); |
454 | 0 | } |
455 | | |
456 | | Result |
457 | | ReadSCTListItem(Reader& listReader, Input& output) |
458 | 0 | { |
459 | 0 | if (listReader.AtEnd()) { |
460 | 0 | return Result::FATAL_ERROR_INVALID_ARGS; |
461 | 0 | } |
462 | 0 | |
463 | 0 | Result rv = ReadVariableBytes<kSerializedSCTLengthBytes>(listReader, output); |
464 | 0 | if (rv != Success) { |
465 | 0 | return rv; |
466 | 0 | } |
467 | 0 | if (output.GetLength() == 0) { |
468 | 0 | return Result::ERROR_BAD_DER; |
469 | 0 | } |
470 | 0 | return Success; |
471 | 0 | } |
472 | | |
473 | | Result |
474 | | DecodeSignedCertificateTimestamp(Reader& reader, |
475 | | SignedCertificateTimestamp& output) |
476 | 0 | { |
477 | 0 | SignedCertificateTimestamp result; |
478 | 0 |
|
479 | 0 | Result rv = ReadVersion(reader, result.version); |
480 | 0 | if (rv != Success) { |
481 | 0 | return rv; |
482 | 0 | } |
483 | 0 | |
484 | 0 | uint64_t timestamp; |
485 | 0 | Input logId; |
486 | 0 | Input extensions; |
487 | 0 |
|
488 | 0 | rv = ReadFixedBytes(kLogIdLength, reader, logId); |
489 | 0 | if (rv != Success) { |
490 | 0 | return rv; |
491 | 0 | } |
492 | 0 | rv = ReadUint<kTimestampLength>(reader, timestamp); |
493 | 0 | if (rv != Success) { |
494 | 0 | return rv; |
495 | 0 | } |
496 | 0 | rv = ReadVariableBytes<kExtensionsLengthBytes>(reader, extensions); |
497 | 0 | if (rv != Success) { |
498 | 0 | return rv; |
499 | 0 | } |
500 | 0 | rv = DecodeDigitallySigned(reader, result.signature); |
501 | 0 | if (rv != Success) { |
502 | 0 | return rv; |
503 | 0 | } |
504 | 0 | |
505 | 0 | rv = InputToBuffer(logId, result.logId); |
506 | 0 | if (rv != Success) { |
507 | 0 | return rv; |
508 | 0 | } |
509 | 0 | rv = InputToBuffer(extensions, result.extensions); |
510 | 0 | if (rv != Success) { |
511 | 0 | return rv; |
512 | 0 | } |
513 | 0 | result.timestamp = timestamp; |
514 | 0 |
|
515 | 0 | output = std::move(result); |
516 | 0 | return Success; |
517 | 0 | } |
518 | | |
519 | | Result |
520 | | EncodeSCTList(const Vector<pkix::Input>& scts, Buffer& output) |
521 | 0 | { |
522 | 0 | // Find out the total size of the SCT list to be written so we can |
523 | 0 | // write the prefix for the list before writing its contents. |
524 | 0 | size_t sctListLength = 0; |
525 | 0 | for (auto& sct : scts) { |
526 | 0 | sctListLength += |
527 | 0 | /* data size */ sct.GetLength() + |
528 | 0 | /* length prefix size */ kSerializedSCTLengthBytes; |
529 | 0 | } |
530 | 0 |
|
531 | 0 | if (!output.reserve(kSCTListLengthBytes + sctListLength)) { |
532 | 0 | return Result::FATAL_ERROR_NO_MEMORY; |
533 | 0 | } |
534 | 0 | |
535 | 0 | // Write the prefix for the SCT list. |
536 | 0 | Result rv = WriteVariableBytesPrefix<kSCTListLengthBytes>(sctListLength, |
537 | 0 | output); |
538 | 0 | if (rv != Success) { |
539 | 0 | return rv; |
540 | 0 | } |
541 | 0 | // Now write each SCT from the list. |
542 | 0 | for (auto& sct : scts) { |
543 | 0 | rv = WriteVariableBytes<kSerializedSCTLengthBytes>(sct, output); |
544 | 0 | if (rv != Success) { |
545 | 0 | return rv; |
546 | 0 | } |
547 | 0 | } |
548 | 0 | return Success; |
549 | 0 | } |
550 | | |
551 | | } } // namespace mozilla::ct |