Chromium Code Reviews| Index: net/cert/ct_serialization.cc |
| diff --git a/net/cert/ct_serialization.cc b/net/cert/ct_serialization.cc |
| index 235d37e65ad1fc8106a05d602c3c9f04b4e61a48..ebeda1fd234f000ee933f47f21c7595adecbf3e4 100644 |
| --- a/net/cert/ct_serialization.cc |
| +++ b/net/cert/ct_serialization.cc |
| @@ -4,8 +4,7 @@ |
| #include "net/cert/ct_serialization.h" |
| -#include <stdint.h> |
| - |
| +#include <cstdint> |
|
Ryan Sleevi
2016/01/08 19:46:31
Chromium code recommends stdint.h (and, in general
Rob Percival
2016/01/10 03:48:56
No, I just wasn't aware of that recommendation - I
|
| #include <limits> |
| #include "base/logging.h" |
| @@ -66,14 +65,18 @@ bool ReadUint(size_t length, base::StringPiece* in, T* out) { |
| } |
| // Reads a TLS-encoded field length from |in|. |
| -// The bytes read from |in| are discarded (i.e. |in|'s prefix removed) |
| -// |prefix_length| indicates the bytes needed to represent the length (e.g. 3) |
| +// The bytes read from |in| are discarded (i.e. |in|'s prefix removed). |
| +// |prefix_length| indicates the bytes needed to represent the length (e.g. 3). |
| +// Max |prefix_length| is 8. |
| // success, returns true and stores the result in |*out|. |
| bool ReadLength(size_t prefix_length, base::StringPiece* in, size_t* out) { |
| - size_t length; |
| + uint64_t length = 0; |
| if (!ReadUint(prefix_length, in, &length)) |
| return false; |
| - *out = length; |
| + if (length > std::numeric_limits<size_t>::max()) { |
| + return false; |
| + } |
|
Ryan Sleevi
2016/01/08 19:46:31
CONSISTENCY: No braces for one-line conditionals
Rob Percival
2016/01/10 03:48:56
Done.
|
| + *out = static_cast<size_t>(length); |
| return true; |
| } |
| @@ -96,7 +99,7 @@ bool ReadFixedBytes(size_t length, |
| bool ReadVariableBytes(size_t prefix_length, |
| base::StringPiece* in, |
| base::StringPiece* out) { |
| - size_t length; |
| + size_t length = 0; |
|
Ryan Sleevi
2016/01/08 19:46:31
Why? (I mean, on a mere pedantry that adds an extr
Rob Percival
2016/01/10 03:48:56
It's a little more defensive against bugs than tru
|
| if (!ReadLength(prefix_length, in, &length)) |
| return false; |
| return ReadFixedBytes(length, in, out); |
| @@ -184,7 +187,7 @@ void WriteUint(size_t length, T value, std::string* output) { |
| DCHECK(length == sizeof(T) || value >> (length * 8) == 0); |
| for (; length > 0; --length) { |
| - output->push_back((value >> ((length - 1)* 8)) & 0xFF); |
| + output->push_back((value >> ((length - 1) * 8)) & 0xFF); |
| } |
| } |
| @@ -195,25 +198,33 @@ void WriteUint(size_t length, T value, std::string* output) { |
| // length when reading. |
| // If the length of |input| is dynamic and data is expected to follow it, |
| // WriteVariableBytes must be used. |
| -void WriteEncodedBytes(const base::StringPiece& input, std::string* output) { |
| +// Returns the number of bytes written (the length of |input|). |
| +size_t WriteEncodedBytes(const base::StringPiece& input, std::string* output) { |
| input.AppendToString(output); |
| + return input.size(); |
| } |
| // Writes a variable-length array to |output|. |
| // |prefix_length| indicates the number of bytes needed to represnt the length. |
| // |input| is the array itself. |
| -// If the size of |input| is less than 2^|prefix_length| - 1, encode the |
| -// length and data and return true. Otherwise, return false. |
| +// If 1 <= |prefix_length| <= 8 and the size of |input| is less than |
| +// 2^|prefix_length| - 1, encode the length and data and return true. |
| +// Otherwise, return false. |
| bool WriteVariableBytes(size_t prefix_length, |
| const base::StringPiece& input, |
| std::string* output) { |
| - size_t input_size = input.size(); |
| - size_t max_allowed_input_size = |
| - static_cast<size_t>(((1 << (prefix_length * 8)) - 1)); |
| + // Use uint64_t instead of size_t to allow a |prefix_length| up to 8 bytes, |
| + // even on 32-bit builds. |
|
Ryan Sleevi
2016/01/08 19:46:31
Why? input.size() will never exceed 4 bytes on 32-
Rob Percival
2016/01/10 03:48:56
The catch here is that WriteUint (below) is a temp
Ryan Sleevi
2016/01/12 00:10:15
Isn't this moreso a bug in line 186/187 having bad
Rob Percival
2016/01/13 00:55:52
How about we replace the preconditions of WriteUin
|
| + uint64_t input_size = input.size(); |
| + if (prefix_length > sizeof(input_size)) { |
| + return false; |
| + } |
|
Ryan Sleevi
2016/01/08 19:46:31
Consistency: Braces
Rob Percival
2016/01/10 03:48:56
Done.
|
| + |
| + uint64_t max_allowed_input_size = ((1 << (prefix_length * 8)) - 1); |
| if (input_size > max_allowed_input_size) |
| return false; |
| - WriteUint(prefix_length, input.size(), output); |
| + WriteUint(prefix_length, input_size, output); |
| WriteEncodedBytes(input, output); |
| return true; |
| @@ -291,6 +302,26 @@ bool EncodeLogEntry(const LogEntry& input, std::string* output) { |
| return false; |
| } |
| +static bool ReadTimeSinceEpoch(base::StringPiece* input, base::Time* output) { |
| + uint64_t time_since_epoch = 0; |
| + if (!ReadUint(kTimestampLength, input, &time_since_epoch)) { |
| + return false; |
| + } |
| + |
| + if (time_since_epoch > |
| + static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) { |
|
Ryan Sleevi
2016/01/08 19:46:31
There's stuff in base/safe_numerics to help with t
Rob Percival
2016/01/10 03:48:56
Done.
|
| + DVLOG(1) << "Timestamp value too big to cast to int64_t: " |
| + << time_since_epoch; |
| + return false; |
| + } |
| + |
| + *output = |
| + base::Time::UnixEpoch() + |
| + base::TimeDelta::FromMilliseconds(static_cast<int64_t>(time_since_epoch)); |
| + |
| + return true; |
| +} |
| + |
| static void WriteTimeSinceEpoch(const base::Time& timestamp, |
| std::string* output) { |
| base::TimeDelta time_since_epoch = timestamp - base::Time::UnixEpoch(); |
| @@ -351,28 +382,17 @@ bool DecodeSignedCertificateTimestamp( |
| } |
| result->version = SignedCertificateTimestamp::SCT_VERSION_1; |
| - uint64_t timestamp; |
| base::StringPiece log_id; |
| base::StringPiece extensions; |
| if (!ReadFixedBytes(kLogIdLength, input, &log_id) || |
| - !ReadUint(kTimestampLength, input, ×tamp) || |
| - !ReadVariableBytes(kExtensionsLengthBytes, input, |
| - &extensions) || |
| + !ReadTimeSinceEpoch(input, &result->timestamp) || |
| + !ReadVariableBytes(kExtensionsLengthBytes, input, &extensions) || |
| !DecodeDigitallySigned(input, &result->signature)) { |
| return false; |
| } |
| - if (timestamp > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) { |
| - DVLOG(1) << "Timestamp value too big to cast to int64_t: " << timestamp; |
| - return false; |
| - } |
| - |
| log_id.CopyToString(&result->log_id); |
| extensions.CopyToString(&result->extensions); |
| - result->timestamp = |
| - base::Time::UnixEpoch() + |
| - base::TimeDelta::FromMilliseconds(static_cast<int64_t>(timestamp)); |
| - |
| output->swap(result); |
| return true; |
| } |
| @@ -381,7 +401,7 @@ bool EncodeSCTListForTesting(const base::StringPiece& sct, |
| std::string* output) { |
| std::string encoded_sct; |
| return WriteVariableBytes(kSerializedSCTLengthBytes, sct, &encoded_sct) && |
| - WriteVariableBytes(kSCTListLengthBytes, encoded_sct, output); |
| + WriteVariableBytes(kSCTListLengthBytes, encoded_sct, output); |
| } |
| } // namespace ct |