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, ×tamp) || 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