| OLD | NEW |
| (Empty) |
| 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 | |
| OLD | NEW |