LCOV - code coverage report
Current view: top level - security/certverifier - CTSerialization.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 223 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 35 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13