Home | History | Annotate | Download | only in cert
      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.
      4 
      5 #include "net/cert/ct_serialization.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/logging.h"
      9 
     10 namespace net {
     11 
     12 namespace ct {
     13 
     14 namespace {
     15 
     16 // Note: length is always specified in bytes.
     17 // Signed Certificate Timestamp (SCT) Version length
     18 const size_t kVersionLength = 1;
     19 
     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;
     27 
     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;
     33 
     34 const size_t kSCTListLengthBytes = 2;
     35 const size_t kSerializedSCTLengthBytes = 2;
     36 
     37 // Members of digitally-signed struct of a STH
     38 const size_t kTreeSizeLength = 8;
     39 
     40 enum SignatureType {
     41   SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP = 0,
     42   TREE_HASH = 1,
     43 };
     44 
     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|.
     50 template <typename T>
     51 bool ReadUint(size_t length, base::StringPiece* in, T* out) {
     52   if (in->size() < length)
     53     return false;
     54   DCHECK_LE(length, sizeof(T));
     55 
     56   T result = 0;
     57   for (size_t i = 0; i < length; ++i) {
     58     result = (result << 8) | static_cast<unsigned char>((*in)[i]);
     59   }
     60   in->remove_prefix(length);
     61   *out = result;
     62   return true;
     63 }
     64 
     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) {
     70   size_t length;
     71   if (!ReadUint(prefix_length, in, &length))
     72     return false;
     73   *out = length;
     74   return true;
     75 }
     76 
     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)
     83     return false;
     84   out->set(in->data(), length);
     85   in->remove_prefix(length);
     86   return true;
     87 }
     88 
     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
     91 // the length.
     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) {
     96   size_t length;
     97   if (!ReadLength(prefix_length, in, &length))
     98     return false;
     99   return ReadFixedBytes(length, in, out);
    100 }
    101 
    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;
    112 
    113   base::StringPiece list_data;
    114   if (!ReadVariableBytes(max_list_length, in, &list_data))
    115     return false;
    116 
    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.";
    121       return false;
    122     }
    123     if (list_item.empty()) {
    124       DVLOG(1) << "Empty item in list";
    125       return false;
    126     }
    127     result.push_back(list_item);
    128   }
    129 
    130   result.swap(*out);
    131   return true;
    132 }
    133 
    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) {
    139   switch (in) {
    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:
    147       break;
    148     default:
    149       return false;
    150   }
    151   *out = static_cast<DigitallySigned::HashAlgorithm>(in);
    152   return true;
    153 }
    154 
    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(
    160     unsigned in,
    161     DigitallySigned::SignatureAlgorithm* out) {
    162   switch (in) {
    163     case DigitallySigned::SIG_ALGO_ANONYMOUS:
    164     case DigitallySigned::SIG_ALGO_RSA:
    165     case DigitallySigned::SIG_ALGO_DSA:
    166     case DigitallySigned::SIG_ALGO_ECDSA:
    167       break;
    168     default:
    169       return false;
    170   }
    171   *out = static_cast<DigitallySigned::SignatureAlgorithm>(in);
    172   return true;
    173 }
    174 
    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);
    182 
    183   for (; length > 0; --length) {
    184     output->push_back((value >> ((length - 1)* 8)) & 0xFF);
    185   }
    186 }
    187 
    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);
    197 }
    198 
    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)
    211     return false;
    212 
    213   WriteUint(prefix_length, input.size(), output);
    214   WriteEncodedBytes(input, output);
    215 
    216   return true;
    217 }
    218 
    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);
    226 }
    227 
    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) {
    233   WriteEncodedBytes(
    234       base::StringPiece(
    235           reinterpret_cast<const char*>(input.issuer_key_hash.data),
    236           kLogIdLength),
    237       output);
    238   return WriteVariableBytes(kTbsCertificateLengthBytes,
    239                             input.tbs_certificate, output);
    240 }
    241 
    242 }  // namespace
    243 
    244 bool EncodeDigitallySigned(const DigitallySigned& input,
    245                            std::string* output) {
    246   WriteUint(kHashAlgorithmLength, input.hash_algorithm, output);
    247   WriteUint(kSigAlgorithmLength, input.signature_algorithm,
    248             output);
    249   return WriteVariableBytes(kSignatureLengthBytes, input.signature_data,
    250                             output);
    251 }
    252 
    253 bool DecodeDigitallySigned(base::StringPiece* input,
    254                            DigitallySigned* output) {
    255   unsigned hash_algo;
    256   unsigned sig_algo;
    257   base::StringPiece sig_data;
    258 
    259   if (!ReadUint(kHashAlgorithmLength, input, &hash_algo) ||
    260       !ReadUint(kSigAlgorithmLength, input, &sig_algo) ||
    261       !ReadVariableBytes(kSignatureLengthBytes, input, &sig_data)) {
    262     return false;
    263   }
    264 
    265   DigitallySigned result;
    266   if (!ConvertHashAlgorithm(hash_algo, &result.hash_algorithm)) {
    267     DVLOG(1) << "Invalid hash algorithm " << hash_algo;
    268     return false;
    269   }
    270   if (!ConvertSignatureAlgorithm(sig_algo, &result.signature_algorithm)) {
    271     DVLOG(1) << "Invalid signature algorithm " << sig_algo;
    272     return false;
    273   }
    274   sig_data.CopyToString(&result.signature_data);
    275 
    276   *output = result;
    277   return true;
    278 }
    279 
    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);
    287   }
    288   return false;
    289 }
    290 
    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);
    295 }
    296 
    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,
    302             output);
    303   WriteUint(kSignatureTypeLength, SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP,
    304             output);
    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);
    310 }
    311 
    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);
    318   WriteEncodedBytes(
    319       base::StringPiece(signed_tree_head.sha256_root_hash, kSthRootHashLength),
    320       output);
    321 }
    322 
    323 bool DecodeSCTList(base::StringPiece* input,
    324                    std::vector<base::StringPiece>* output) {
    325   std::vector<base::StringPiece> result;
    326   if (!ReadList(kSCTListLengthBytes, kSerializedSCTLengthBytes,
    327                 input, &result)) {
    328     return false;
    329   }
    330 
    331   if (!input->empty() || result.empty())
    332     return false;
    333   output->swap(result);
    334   return true;
    335 }
    336 
    337 bool DecodeSignedCertificateTimestamp(
    338     base::StringPiece* input,
    339     scoped_refptr<SignedCertificateTimestamp>* output) {
    340   scoped_refptr<SignedCertificateTimestamp> result(
    341       new SignedCertificateTimestamp());
    342   unsigned version;
    343   if (!ReadUint(kVersionLength, input, &version))
    344     return false;
    345   if (version != SignedCertificateTimestamp::SCT_VERSION_1) {
    346     DVLOG(1) << "Unsupported/invalid version " << version;
    347     return false;
    348   }
    349 
    350   result->version = SignedCertificateTimestamp::SCT_VERSION_1;
    351   uint64 timestamp;
    352   base::StringPiece log_id;
    353   base::StringPiece extensions;
    354   if (!ReadFixedBytes(kLogIdLength, input, &log_id) ||
    355       !ReadUint(kTimestampLength, input, &timestamp) ||
    356       !ReadVariableBytes(kExtensionsLengthBytes, input,
    357                          &extensions) ||
    358       !DecodeDigitallySigned(input, &result->signature)) {
    359     return false;
    360   }
    361 
    362   if (timestamp > static_cast<uint64>(kint64max)) {
    363     DVLOG(1) << "Timestamp value too big to cast to int64: " << timestamp;
    364     return false;
    365   }
    366 
    367   log_id.CopyToString(&result->log_id);
    368   extensions.CopyToString(&result->extensions);
    369   result->timestamp =
    370       base::Time::UnixEpoch() +
    371       base::TimeDelta::FromMilliseconds(static_cast<int64>(timestamp));
    372 
    373   output->swap(result);
    374   return true;
    375 }
    376 
    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);
    382 }
    383 
    384 }  // namespace ct
    385 
    386 }  // namespace net
    387