Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/cert/ct_serialization.h" | 5 #include "net/cert/ct_serialization.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <algorithm> | |
| 9 #include <limits> | 10 #include <limits> |
| 10 | 11 |
| 11 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/numerics/safe_math.h" | |
| 12 | 14 |
| 13 namespace net { | 15 namespace net { |
| 14 | 16 |
| 15 namespace ct { | 17 namespace ct { |
| 16 | 18 |
| 17 namespace { | 19 namespace { |
| 18 | 20 |
| 19 // Note: length is always specified in bytes. | 21 // Note: length is always specified in bytes. |
| 20 // Signed Certificate Timestamp (SCT) Version length | 22 // Signed Certificate Timestamp (SCT) Version length |
| 21 const size_t kVersionLength = 1; | 23 const size_t kVersionLength = 1; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 38 const size_t kSerializedSCTLengthBytes = 2; | 40 const size_t kSerializedSCTLengthBytes = 2; |
| 39 | 41 |
| 40 // Members of digitally-signed struct of a STH | 42 // Members of digitally-signed struct of a STH |
| 41 const size_t kTreeSizeLength = 8; | 43 const size_t kTreeSizeLength = 8; |
| 42 | 44 |
| 43 enum SignatureType { | 45 enum SignatureType { |
| 44 SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP = 0, | 46 SIGNATURE_TYPE_CERTIFICATE_TIMESTAMP = 0, |
| 45 TREE_HASH = 1, | 47 TREE_HASH = 1, |
| 46 }; | 48 }; |
| 47 | 49 |
| 50 // Returns the maximum value of an unsigned integer that is |length| bytes long. | |
| 51 // |length| can be up to 8. | |
| 52 uint64_t GetUintMaxValue(size_t length) { | |
| 53 DCHECK_LE(length, 8u); | |
| 54 | |
| 55 // If length == 8, we can't calculate the max value because that would involve | |
| 56 // shifting a uint64_t left by 64 bits, which invokes undefined behaviour (see | |
| 57 // https://www.securecoding.cert.org/confluence/x/IRE). Instead, we just hard- | |
| 58 // code the result for that case. | |
|
Ryan Sleevi
2016/01/22 23:32:16
https://groups.google.com/a/chromium.org/forum/#!t
Rob Percival
2016/01/25 16:42:29
Acknowledged.
| |
| 59 return length == 8 ? 0xffffffffffffffff : (uint64_t(1) << (length * 8)) - 1; | |
| 60 } | |
| 61 | |
| 48 // Reads a TLS-encoded variable length unsigned integer from |in|. | 62 // Reads a TLS-encoded variable length unsigned integer from |in|. |
| 49 // The integer is expected to be in big-endian order, which is used by TLS. | 63 // The integer is expected to be in big-endian order, which is used by TLS. |
| 50 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) | 64 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) |
| 51 // |length| indicates the size (in bytes) of the integer. On success, returns | 65 // |length| indicates the size (in bytes) of the integer. On success, returns |
| 52 // true and stores the result in |*out|. | 66 // true and stores the result in |*out|. |
| 53 template <typename T> | 67 template <typename T> |
| 54 bool ReadUint(size_t length, base::StringPiece* in, T* out) { | 68 bool ReadUint(size_t length, base::StringPiece* in, T* out) { |
| 55 if (in->size() < length) | 69 if (in->size() < length) |
| 56 return false; | 70 return false; |
| 71 DCHECK_NE(length, 0u); | |
| 57 DCHECK_LE(length, sizeof(T)); | 72 DCHECK_LE(length, sizeof(T)); |
| 58 | 73 |
| 59 T result = 0; | 74 T result = static_cast<uint8_t>((*in)[0]); |
| 60 for (size_t i = 0; i < length; ++i) { | 75 // This loop only executes if sizeof(T) > 1, because the first operation is |
| 61 result = (result << 8) | static_cast<unsigned char>((*in)[i]); | 76 // to shift left by 1 byte, which is undefined behaviour if T is a 1 byte |
| 77 // integer. | |
| 78 for (size_t i = 1; i < length; ++i) { | |
| 79 result = (result << 8) | static_cast<uint8_t>((*in)[i]); | |
| 62 } | 80 } |
| 63 in->remove_prefix(length); | 81 in->remove_prefix(length); |
| 64 *out = result; | 82 *out = result; |
| 65 return true; | 83 return true; |
| 66 } | 84 } |
| 67 | 85 |
| 68 // Reads a TLS-encoded field length from |in|. | 86 // Reads a TLS-encoded field length from |in|. |
| 69 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) | 87 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed). |
| 70 // |prefix_length| indicates the bytes needed to represent the length (e.g. 3) | 88 // |prefix_length| indicates the bytes needed to represent the length (e.g. 3). |
| 89 // Max |prefix_length| is 8. | |
| 71 // success, returns true and stores the result in |*out|. | 90 // success, returns true and stores the result in |*out|. |
| 72 bool ReadLength(size_t prefix_length, base::StringPiece* in, size_t* out) { | 91 bool ReadLength(size_t prefix_length, base::StringPiece* in, size_t* out) { |
| 73 size_t length; | 92 uint64_t length = 0; |
| 74 if (!ReadUint(prefix_length, in, &length)) | 93 if (!ReadUint(prefix_length, in, &length)) |
| 75 return false; | 94 return false; |
| 76 *out = length; | 95 base::CheckedNumeric<size_t> checked_length = length; |
| 96 if (!checked_length.IsValid()) | |
| 97 return false; | |
| 98 *out = checked_length.ValueOrDie(); | |
| 77 return true; | 99 return true; |
| 78 } | 100 } |
| 79 | 101 |
| 80 // Reads |length| bytes from |*in|. If |*in| is too small, returns false. | 102 // Reads |length| bytes from |*in|. If |*in| is too small, returns false. |
| 81 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) | 103 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) |
| 82 bool ReadFixedBytes(size_t length, | 104 bool ReadFixedBytes(size_t length, |
| 83 base::StringPiece* in, | 105 base::StringPiece* in, |
| 84 base::StringPiece* out) { | 106 base::StringPiece* out) { |
| 85 if (in->length() < length) | 107 if (in->length() < length) |
| 86 return false; | 108 return false; |
| 87 out->set(in->data(), length); | 109 out->set(in->data(), length); |
| 88 in->remove_prefix(length); | 110 in->remove_prefix(length); |
| 89 return true; | 111 return true; |
| 90 } | 112 } |
| 91 | 113 |
| 92 // Reads a length-prefixed variable amount of bytes from |in|, updating |out| | 114 // Reads a length-prefixed variable amount of bytes from |in|, updating |out| |
| 93 // on success. |prefix_length| indicates the number of bytes needed to represent | 115 // on success. |prefix_length| indicates the number of bytes needed to represent |
| 94 // the length. | 116 // the length. |
| 95 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) | 117 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) |
| 96 bool ReadVariableBytes(size_t prefix_length, | 118 bool ReadVariableBytes(size_t prefix_length, |
| 97 base::StringPiece* in, | 119 base::StringPiece* in, |
| 98 base::StringPiece* out) { | 120 base::StringPiece* out) { |
| 99 size_t length; | 121 size_t length = 0; |
| 100 if (!ReadLength(prefix_length, in, &length)) | 122 if (!ReadLength(prefix_length, in, &length)) |
| 101 return false; | 123 return false; |
| 102 return ReadFixedBytes(length, in, out); | 124 return ReadFixedBytes(length, in, out); |
| 103 } | 125 } |
| 104 | 126 |
| 105 // Reads a variable-length list that has been TLS encoded. | 127 // Reads a variable-length list that has been TLS encoded. |
| 106 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) | 128 // The bytes read from |in| are discarded (i.e. |in|'s prefix removed) |
| 107 // |max_list_length| contains the overall length of the encoded list. | 129 // |max_list_length| contains the overall length of the encoded list. |
| 108 // |max_item_length| contains the maximum length of a single item. | 130 // |max_item_length| contains the maximum length of a single item. |
| 109 // On success, returns true and updates |*out| with the encoded list. | 131 // On success, returns true and updates |*out| with the encoded list. |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 169 case DigitallySigned::SIG_ALGO_ECDSA: | 191 case DigitallySigned::SIG_ALGO_ECDSA: |
| 170 break; | 192 break; |
| 171 default: | 193 default: |
| 172 return false; | 194 return false; |
| 173 } | 195 } |
| 174 *out = static_cast<DigitallySigned::SignatureAlgorithm>(in); | 196 *out = static_cast<DigitallySigned::SignatureAlgorithm>(in); |
| 175 return true; | 197 return true; |
| 176 } | 198 } |
| 177 | 199 |
| 178 // Writes a TLS-encoded variable length unsigned integer to |output|. | 200 // Writes a TLS-encoded variable length unsigned integer to |output|. |
| 179 // |length| indicates the size (in bytes) of the integer. | 201 // |length| indicates the size (in bytes) of the integer. This must be able to |
| 202 // accomodate |value|. | |
| 180 // |value| the value itself to be written. | 203 // |value| the value itself to be written. |
| 181 template <typename T> | 204 void WriteUint(size_t length, uint64_t value, std::string* output) { |
| 182 void WriteUint(size_t length, T value, std::string* output) { | 205 // Check that |value| fits into |length| bytes. |
| 183 DCHECK_LE(length, sizeof(T)); | 206 DCHECK(length >= sizeof(value) || value >> (length * 8) == 0); |
| 184 DCHECK(length == sizeof(T) || value >> (length * 8) == 0); | |
| 185 | 207 |
| 186 for (; length > 0; --length) { | 208 for (; length > 0; --length) { |
| 187 output->push_back((value >> ((length - 1)* 8)) & 0xFF); | 209 output->push_back((value >> ((length - 1) * 8)) & 0xFF); |
| 188 } | 210 } |
| 189 } | 211 } |
| 190 | 212 |
| 191 // Writes an array to |output| from |input|. | 213 // Writes an array to |output| from |input|. |
| 192 // Should be used in one of two cases: | 214 // Should be used in one of two cases: |
| 193 // * The length of |input| has already been encoded into the |output| stream. | 215 // * The length of |input| has already been encoded into the |output| stream. |
| 194 // * The length of |input| is fixed and the reader is expected to specify that | 216 // * The length of |input| is fixed and the reader is expected to specify that |
| 195 // length when reading. | 217 // length when reading. |
| 196 // If the length of |input| is dynamic and data is expected to follow it, | 218 // If the length of |input| is dynamic and data is expected to follow it, |
| 197 // WriteVariableBytes must be used. | 219 // WriteVariableBytes must be used. |
| 198 void WriteEncodedBytes(const base::StringPiece& input, std::string* output) { | 220 // Returns the number of bytes written (the length of |input|). |
| 221 size_t WriteEncodedBytes(const base::StringPiece& input, std::string* output) { | |
| 199 input.AppendToString(output); | 222 input.AppendToString(output); |
| 223 return input.size(); | |
| 200 } | 224 } |
| 201 | 225 |
| 202 // Writes a variable-length array to |output|. | 226 // Writes a variable-length array to |output|. |
| 203 // |prefix_length| indicates the number of bytes needed to represnt the length. | 227 // |prefix_length| indicates the number of bytes needed to represent the length. |
| 204 // |input| is the array itself. | 228 // |input| is the array itself. |
| 205 // If the size of |input| is less than 2^|prefix_length| - 1, encode the | 229 // If 1 <= |prefix_length| <= 8 and the size of |input| is less than |
| 206 // length and data and return true. Otherwise, return false. | 230 // 2^|prefix_length| - 1, encode the length and data and return true. |
| 231 // Otherwise, return false. | |
| 207 bool WriteVariableBytes(size_t prefix_length, | 232 bool WriteVariableBytes(size_t prefix_length, |
| 208 const base::StringPiece& input, | 233 const base::StringPiece& input, |
| 209 std::string* output) { | 234 std::string* output) { |
| 210 size_t input_size = input.size(); | 235 size_t input_size = input.size(); |
| 211 size_t max_allowed_input_size = | 236 size_t max_input_size = |
| 212 static_cast<size_t>(((1 << (prefix_length * 8)) - 1)); | 237 GetUintMaxValue(std::min(sizeof(size_t), prefix_length)); |
|
Ryan Sleevi
2016/01/22 23:32:16
I don't see why this is necessary. You already kno
Rob Percival
2016/01/25 16:42:29
Done.
| |
| 213 if (input_size > max_allowed_input_size) | 238 |
| 239 if (input_size > max_input_size) | |
| 214 return false; | 240 return false; |
| 215 | 241 |
| 216 WriteUint(prefix_length, input.size(), output); | 242 WriteUint(prefix_length, input_size, output); |
| 217 WriteEncodedBytes(input, output); | 243 WriteEncodedBytes(input, output); |
| 218 | 244 |
| 219 return true; | 245 return true; |
| 220 } | 246 } |
| 221 | 247 |
| 222 // Writes a LogEntry of type X.509 cert to |output|. | 248 // Writes a LogEntry of type X.509 cert to |output|. |
| 223 // |input| is the LogEntry containing the certificate. | 249 // |input| is the LogEntry containing the certificate. |
| 224 // Returns true if the leaf_certificate in the LogEntry does not exceed | 250 // Returns true if the leaf_certificate in the LogEntry does not exceed |
| 225 // kMaxAsn1CertificateLength and so can be written to |output|. | 251 // kMaxAsn1CertificateLength and so can be written to |output|. |
| 226 bool EncodeAsn1CertLogEntry(const LogEntry& input, std::string* output) { | 252 bool EncodeAsn1CertLogEntry(const LogEntry& input, std::string* output) { |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 284 WriteUint(kLogEntryTypeLength, input.type, output); | 310 WriteUint(kLogEntryTypeLength, input.type, output); |
| 285 switch (input.type) { | 311 switch (input.type) { |
| 286 case LogEntry::LOG_ENTRY_TYPE_X509: | 312 case LogEntry::LOG_ENTRY_TYPE_X509: |
| 287 return EncodeAsn1CertLogEntry(input, output); | 313 return EncodeAsn1CertLogEntry(input, output); |
| 288 case LogEntry::LOG_ENTRY_TYPE_PRECERT: | 314 case LogEntry::LOG_ENTRY_TYPE_PRECERT: |
| 289 return EncodePrecertLogEntry(input, output); | 315 return EncodePrecertLogEntry(input, output); |
| 290 } | 316 } |
| 291 return false; | 317 return false; |
| 292 } | 318 } |
| 293 | 319 |
| 320 static bool ReadTimeSinceEpoch(base::StringPiece* input, base::Time* output) { | |
|
Ryan Sleevi
2016/01/22 23:32:16
Is this abstraction necessary? Will it ever be reu
Rob Percival
2016/01/25 16:42:29
Yes, it is reused in one of my next patches: https
| |
| 321 uint64_t time_since_epoch = 0; | |
| 322 if (!ReadUint(kTimestampLength, input, &time_since_epoch)) { | |
| 323 return false; | |
| 324 } | |
|
Ryan Sleevi
2016/01/22 23:32:16
no braces
Rob Percival
2016/01/25 16:42:29
Done.
| |
| 325 | |
| 326 base::CheckedNumeric<int64_t> time_since_epoch_signed = time_since_epoch; | |
| 327 | |
| 328 if (!time_since_epoch_signed.IsValid()) { | |
| 329 DVLOG(1) << "Timestamp value too big to cast to int64_t: " | |
| 330 << time_since_epoch; | |
| 331 return false; | |
| 332 } | |
| 333 | |
| 334 *output = | |
| 335 base::Time::UnixEpoch() + | |
| 336 base::TimeDelta::FromMilliseconds(time_since_epoch_signed.ValueOrDie()); | |
| 337 | |
| 338 return true; | |
| 339 } | |
| 340 | |
| 294 static void WriteTimeSinceEpoch(const base::Time& timestamp, | 341 static void WriteTimeSinceEpoch(const base::Time& timestamp, |
| 295 std::string* output) { | 342 std::string* output) { |
| 296 base::TimeDelta time_since_epoch = timestamp - base::Time::UnixEpoch(); | 343 base::TimeDelta time_since_epoch = timestamp - base::Time::UnixEpoch(); |
| 297 WriteUint(kTimestampLength, time_since_epoch.InMilliseconds(), output); | 344 WriteUint(kTimestampLength, time_since_epoch.InMilliseconds(), output); |
| 298 } | 345 } |
| 299 | 346 |
| 300 bool EncodeV1SCTSignedData(const base::Time& timestamp, | 347 bool EncodeV1SCTSignedData(const base::Time& timestamp, |
| 301 const std::string& serialized_log_entry, | 348 const std::string& serialized_log_entry, |
| 302 const std::string& extensions, | 349 const std::string& extensions, |
| 303 std::string* output) { | 350 std::string* output) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 344 new SignedCertificateTimestamp()); | 391 new SignedCertificateTimestamp()); |
| 345 unsigned version; | 392 unsigned version; |
| 346 if (!ReadUint(kVersionLength, input, &version)) | 393 if (!ReadUint(kVersionLength, input, &version)) |
| 347 return false; | 394 return false; |
| 348 if (version != SignedCertificateTimestamp::SCT_VERSION_1) { | 395 if (version != SignedCertificateTimestamp::SCT_VERSION_1) { |
| 349 DVLOG(1) << "Unsupported/invalid version " << version; | 396 DVLOG(1) << "Unsupported/invalid version " << version; |
| 350 return false; | 397 return false; |
| 351 } | 398 } |
| 352 | 399 |
| 353 result->version = SignedCertificateTimestamp::SCT_VERSION_1; | 400 result->version = SignedCertificateTimestamp::SCT_VERSION_1; |
| 354 uint64_t timestamp; | |
| 355 base::StringPiece log_id; | 401 base::StringPiece log_id; |
| 356 base::StringPiece extensions; | 402 base::StringPiece extensions; |
| 357 if (!ReadFixedBytes(kLogIdLength, input, &log_id) || | 403 if (!ReadFixedBytes(kLogIdLength, input, &log_id) || |
| 358 !ReadUint(kTimestampLength, input, ×tamp) || | 404 !ReadTimeSinceEpoch(input, &result->timestamp) || |
| 359 !ReadVariableBytes(kExtensionsLengthBytes, input, | 405 !ReadVariableBytes(kExtensionsLengthBytes, input, &extensions) || |
| 360 &extensions) || | |
| 361 !DecodeDigitallySigned(input, &result->signature)) { | 406 !DecodeDigitallySigned(input, &result->signature)) { |
| 362 return false; | 407 return false; |
| 363 } | 408 } |
| 364 | 409 |
| 365 if (timestamp > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) { | |
| 366 DVLOG(1) << "Timestamp value too big to cast to int64_t: " << timestamp; | |
| 367 return false; | |
| 368 } | |
| 369 | |
| 370 log_id.CopyToString(&result->log_id); | 410 log_id.CopyToString(&result->log_id); |
| 371 extensions.CopyToString(&result->extensions); | 411 extensions.CopyToString(&result->extensions); |
| 372 result->timestamp = | |
| 373 base::Time::UnixEpoch() + | |
| 374 base::TimeDelta::FromMilliseconds(static_cast<int64_t>(timestamp)); | |
| 375 | |
| 376 output->swap(result); | 412 output->swap(result); |
| 377 return true; | 413 return true; |
| 378 } | 414 } |
| 379 | 415 |
| 380 bool EncodeSCTListForTesting(const base::StringPiece& sct, | 416 bool EncodeSCTListForTesting(const base::StringPiece& sct, |
| 381 std::string* output) { | 417 std::string* output) { |
| 382 std::string encoded_sct; | 418 std::string encoded_sct; |
| 383 return WriteVariableBytes(kSerializedSCTLengthBytes, sct, &encoded_sct) && | 419 return WriteVariableBytes(kSerializedSCTLengthBytes, sct, &encoded_sct) && |
| 384 WriteVariableBytes(kSCTListLengthBytes, encoded_sct, output); | 420 WriteVariableBytes(kSCTListLengthBytes, encoded_sct, output); |
| 385 } | 421 } |
| 386 | 422 |
| 387 } // namespace ct | 423 } // namespace ct |
| 388 | 424 |
| 389 } // namespace net | 425 } // namespace net |
| OLD | NEW |