CTSerialization.cpp 16 KB

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