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 enum SignatureType { 38 SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP = 0, 39 TREE_HASH = 1, 40 }; 41 42 // Reads a TLS-encoded variable length unsigned integer from |in|. 43 // The integer is expected to be in big-endian order, which is used by TLS. 44 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) 45 // |length| indicates the size (in bytes) of the integer. On success, returns 46 // true and stores the result in |*out|. 47 template <typename T> 48 bool ReadUint(size_t length, base::StringPiece* in, T* out) { 49 if (in->size() < length) 50 return false; 51 DCHECK_LE(length, sizeof(T)); 52 53 T result = 0; 54 for (size_t i = 0; i < length; ++i) { 55 result = (result << 8) | static_cast<unsigned char>((*in)[i]); 56 } 57 in->remove_prefix(length); 58 *out = result; 59 return true; 60 } 61 62 // Reads a TLS-encoded field length from |in|. 63 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) 64 // |prefix_length| indicates the bytes needed to represent the length (e.g. 3) 65 // success, returns true and stores the result in |*out|. 66 bool ReadLength(size_t prefix_length, base::StringPiece* in, size_t* out) { 67 size_t length; 68 if (!ReadUint(prefix_length, in, &length)) 69 return false; 70 *out = length; 71 return true; 72 } 73 74 // Reads |length| bytes from |*in|. If |*in| is too small, returns false. 75 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) 76 bool ReadFixedBytes(size_t length, 77 base::StringPiece* in, 78 base::StringPiece* out) { 79 if (in->length() < length) 80 return false; 81 out->set(in->data(), length); 82 in->remove_prefix(length); 83 return true; 84 } 85 86 // Reads a length-prefixed variable amount of bytes from |in|, updating |out| 87 // on success. |prefix_length| indicates the number of bytes needed to represent 88 // the length. 89 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) 90 bool ReadVariableBytes(size_t prefix_length, 91 base::StringPiece* in, 92 base::StringPiece* out) { 93 size_t length; 94 if (!ReadLength(prefix_length, in, &length)) 95 return false; 96 return ReadFixedBytes(length, in, out); 97 } 98 99 // Reads a variable-length list that has been TLS encoded. 100 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) 101 // |max_list_length| contains the overall length of the encoded list. 102 // |max_item_length| contains the maximum length of a single item. 103 // On success, returns true and updates |*out| with the encoded list. 104 bool ReadList(size_t max_list_length, 105 size_t max_item_length, 106 base::StringPiece* in, 107 std::vector<base::StringPiece>* out) { 108 std::vector<base::StringPiece> result; 109 110 base::StringPiece list_data; 111 if (!ReadVariableBytes(max_list_length, in, &list_data)) 112 return false; 113 114 while (!list_data.empty()) { 115 base::StringPiece list_item; 116 if (!ReadVariableBytes(max_item_length, &list_data, &list_item)) { 117 DVLOG(1) << "Failed to read item in list."; 118 return false; 119 } 120 if (list_item.empty()) { 121 DVLOG(1) << "Empty item in list"; 122 return false; 123 } 124 result.push_back(list_item); 125 } 126 127 result.swap(*out); 128 return true; 129 } 130 131 // Checks and converts a hash algorithm. 132 // |in| is the numeric representation of the algorithm. 133 // If the hash algorithm value is in a set of known values, fills in |out| and 134 // returns true. Otherwise, returns false. 135 bool ConvertHashAlgorithm(unsigned in, DigitallySigned::HashAlgorithm* out) { 136 switch (in) { 137 case DigitallySigned::HASH_ALGO_NONE: 138 case DigitallySigned::HASH_ALGO_MD5: 139 case DigitallySigned::HASH_ALGO_SHA1: 140 case DigitallySigned::HASH_ALGO_SHA224: 141 case DigitallySigned::HASH_ALGO_SHA256: 142 case DigitallySigned::HASH_ALGO_SHA384: 143 case DigitallySigned::HASH_ALGO_SHA512: 144 break; 145 default: 146 return false; 147 } 148 *out = static_cast<DigitallySigned::HashAlgorithm>(in); 149 return true; 150 } 151 152 // Checks and converts a signing algorithm. 153 // |in| is the numeric representation of the algorithm. 154 // If the signing algorithm value is in a set of known values, fills in |out| 155 // and returns true. Otherwise, returns false. 156 bool ConvertSignatureAlgorithm( 157 unsigned in, 158 DigitallySigned::SignatureAlgorithm* out) { 159 switch (in) { 160 case DigitallySigned::SIG_ALGO_ANONYMOUS: 161 case DigitallySigned::SIG_ALGO_RSA: 162 case DigitallySigned::SIG_ALGO_DSA: 163 case DigitallySigned::SIG_ALGO_ECDSA: 164 break; 165 default: 166 return false; 167 } 168 *out = static_cast<DigitallySigned::SignatureAlgorithm>(in); 169 return true; 170 } 171 172 // Writes a TLS-encoded variable length unsigned integer to |output|. 173 // |length| indicates the size (in bytes) of the integer. 174 // |value| the value itself to be written. 175 template <typename T> 176 void WriteUint(size_t length, T value, std::string* output) { 177 DCHECK_LE(length, sizeof(T)); 178 DCHECK(length == sizeof(T) || value >> (length * 8) == 0); 179 180 for (; length > 0; --length) { 181 output->push_back((value >> ((length - 1)* 8)) & 0xFF); 182 } 183 } 184 185 // Writes an array to |output| from |input|. 186 // Should be used in one of two cases: 187 // * The length of |input| has already been encoded into the |output| stream. 188 // * The length of |input| is fixed and the reader is expected to specify that 189 // length when reading. 190 // If the length of |input| is dynamic and data is expected to follow it, 191 // WriteVariableBytes must be used. 192 void WriteEncodedBytes(const base::StringPiece& input, std::string* output) { 193 input.AppendToString(output); 194 } 195 196 // Writes a variable-length array to |output|. 197 // |prefix_length| indicates the number of bytes needed to represnt the length. 198 // |input| is the array itself. 199 // If the size of |input| is less than 2^|prefix_length| - 1, encode the 200 // length and data and return true. Otherwise, return false. 201 bool WriteVariableBytes(size_t prefix_length, 202 const base::StringPiece& input, 203 std::string* output) { 204 size_t input_size = input.size(); 205 size_t max_allowed_input_size = 206 static_cast<size_t>(((1 << (prefix_length * 8)) - 1)); 207 if (input_size > max_allowed_input_size) 208 return false; 209 210 WriteUint(prefix_length, input.size(), output); 211 WriteEncodedBytes(input, output); 212 213 return true; 214 } 215 216 // Writes a LogEntry of type X.509 cert to |output|. 217 // |input| is the LogEntry containing the certificate. 218 // Returns true if the leaf_certificate in the LogEntry does not exceed 219 // kMaxAsn1CertificateLength and so can be written to |output|. 220 bool EncodeAsn1CertLogEntry(const LogEntry& input, std::string* output) { 221 return WriteVariableBytes(kAsn1CertificateLengthBytes, 222 input.leaf_certificate, output); 223 } 224 225 // Writes a LogEntry of type PreCertificate to |output|. 226 // |input| is the LogEntry containing the TBSCertificate and issuer key hash. 227 // Returns true if the TBSCertificate component in the LogEntry does not 228 // exceed kMaxTbsCertificateLength and so can be written to |output|. 229 bool EncodePrecertLogEntry(const LogEntry& input, std::string* output) { 230 WriteEncodedBytes( 231 base::StringPiece( 232 reinterpret_cast<const char*>(input.issuer_key_hash.data), 233 kLogIdLength), 234 output); 235 return WriteVariableBytes(kTbsCertificateLengthBytes, 236 input.tbs_certificate, output); 237 } 238 239 } // namespace 240 241 bool EncodeDigitallySigned(const DigitallySigned& input, 242 std::string* output) { 243 WriteUint(kHashAlgorithmLength, input.hash_algorithm, output); 244 WriteUint(kSigAlgorithmLength, input.signature_algorithm, 245 output); 246 return WriteVariableBytes(kSignatureLengthBytes, input.signature_data, 247 output); 248 } 249 250 bool DecodeDigitallySigned(base::StringPiece* input, 251 DigitallySigned* output) { 252 unsigned hash_algo; 253 unsigned sig_algo; 254 base::StringPiece sig_data; 255 256 if (!ReadUint(kHashAlgorithmLength, input, &hash_algo) || 257 !ReadUint(kSigAlgorithmLength, input, &sig_algo) || 258 !ReadVariableBytes(kSignatureLengthBytes, input, &sig_data)) { 259 return false; 260 } 261 262 DigitallySigned result; 263 if (!ConvertHashAlgorithm(hash_algo, &result.hash_algorithm)) { 264 DVLOG(1) << "Invalid hash algorithm " << hash_algo; 265 return false; 266 } 267 if (!ConvertSignatureAlgorithm(sig_algo, &result.signature_algorithm)) { 268 DVLOG(1) << "Invalid signature algorithm " << sig_algo; 269 return false; 270 } 271 sig_data.CopyToString(&result.signature_data); 272 273 *output = result; 274 return true; 275 } 276 277 bool EncodeLogEntry(const LogEntry& input, std::string* output) { 278 WriteUint(kLogEntryTypeLength, input.type, output); 279 switch (input.type) { 280 case LogEntry::LOG_ENTRY_TYPE_X509: 281 return EncodeAsn1CertLogEntry(input, output); 282 case LogEntry::LOG_ENTRY_TYPE_PRECERT: 283 return EncodePrecertLogEntry(input, output); 284 } 285 return false; 286 } 287 288 bool EncodeV1SCTSignedData(const base::Time& timestamp, 289 const std::string& serialized_log_entry, 290 const std::string& extensions, 291 std::string* output) { 292 WriteUint(kVersionLength, SignedCertificateTimestamp::SCT_VERSION_1, 293 output); 294 WriteUint(kSignatureTypeLength, SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP, 295 output); 296 base::TimeDelta time_since_epoch = timestamp - base::Time::UnixEpoch(); 297 WriteUint(kTimestampLength, time_since_epoch.InMilliseconds(), 298 output); 299 // NOTE: serialized_log_entry must already be serialized and contain the 300 // length as the prefix. 301 WriteEncodedBytes(serialized_log_entry, output); 302 return WriteVariableBytes(kExtensionsLengthBytes, extensions, output); 303 } 304 305 bool DecodeSCTList(base::StringPiece* input, 306 std::vector<base::StringPiece>* output) { 307 std::vector<base::StringPiece> result; 308 if (!ReadList(kSCTListLengthBytes, kSerializedSCTLengthBytes, 309 input, &result)) { 310 return false; 311 } 312 313 if (!input->empty() || result.empty()) 314 return false; 315 output->swap(result); 316 return true; 317 } 318 319 bool DecodeSignedCertificateTimestamp( 320 base::StringPiece* input, 321 scoped_refptr<SignedCertificateTimestamp>* output) { 322 scoped_refptr<SignedCertificateTimestamp> result( 323 new SignedCertificateTimestamp()); 324 unsigned version; 325 if (!ReadUint(kVersionLength, input, &version)) 326 return false; 327 if (version != SignedCertificateTimestamp::SCT_VERSION_1) { 328 DVLOG(1) << "Unsupported/invalid version " << version; 329 return false; 330 } 331 332 result->version = SignedCertificateTimestamp::SCT_VERSION_1; 333 uint64 timestamp; 334 base::StringPiece log_id; 335 base::StringPiece extensions; 336 if (!ReadFixedBytes(kLogIdLength, input, &log_id) || 337 !ReadUint(kTimestampLength, input, ×tamp) || 338 !ReadVariableBytes(kExtensionsLengthBytes, input, 339 &extensions) || 340 !DecodeDigitallySigned(input, &result->signature)) { 341 return false; 342 } 343 344 if (timestamp > static_cast<uint64>(kint64max)) { 345 DVLOG(1) << "Timestamp value too big to cast to int64: " << timestamp; 346 return false; 347 } 348 349 log_id.CopyToString(&result->log_id); 350 extensions.CopyToString(&result->extensions); 351 result->timestamp = 352 base::Time::UnixEpoch() + 353 base::TimeDelta::FromMilliseconds(static_cast<int64>(timestamp)); 354 355 output->swap(result); 356 return true; 357 } 358 359 bool EncodeSCTListForTesting(const base::StringPiece& sct, 360 std::string* output) { 361 std::string encoded_sct; 362 return WriteVariableBytes(kSerializedSCTLengthBytes, sct, &encoded_sct) && 363 WriteVariableBytes(kSCTListLengthBytes, encoded_sct, output); 364 } 365 366 } // namespace ct 367 368 } // namespace net 369