Index: net/cert/ct_serialization.cc |
diff --git a/net/cert/ct_serialization.cc b/net/cert/ct_serialization.cc |
index 235d37e65ad1fc8106a05d602c3c9f04b4e61a48..9608cb3ac2bcd9f3a00ad4dc55d7ec3b62f63ee2 100644 |
--- a/net/cert/ct_serialization.cc |
+++ b/net/cert/ct_serialization.cc |
@@ -9,6 +9,7 @@ |
#include <limits> |
#include "base/logging.h" |
+#include "base/numerics/safe_math.h" |
namespace net { |
@@ -66,14 +67,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; |
+ base::CheckedNumeric<size_t> checked_length = length; |
+ if (!checked_length.IsValid()) |
+ return false; |
+ *out = checked_length.ValueOrDie(); |
return true; |
} |
@@ -96,7 +101,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; |
if (!ReadLength(prefix_length, in, &length)) |
return false; |
return ReadFixedBytes(length, in, out); |
@@ -184,7 +189,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); |
} |
Ryan Sleevi
2016/01/13 02:44:32
What if we:
Delete both DCHECKs
DCHECK(length >=
|
} |
@@ -195,25 +200,32 @@ 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. |
Ryan Sleevi
2016/01/12 00:10:15
typo: represent
Rob Percival
2016/01/13 00:55:52
Done.
|
// |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. |
+ uint64_t input_size = input.size(); |
+ if (prefix_length > sizeof(input_size)) |
+ return false; |
+ |
+ uint64_t max_allowed_input_size = ((1 << (prefix_length * 8)) - 1); |
if (input_size > max_allowed_input_size) |
return false; |
Rob Percival
2016/01/20 20:20:33
It's not clear to me why WriteVariableBytes return
Ryan Sleevi
2016/01/20 20:56:37
I believe the logic was because WriteVariableBytes
|
- WriteUint(prefix_length, input.size(), output); |
+ WriteUint(prefix_length, input_size, output); |
WriteEncodedBytes(input, output); |
return true; |
@@ -291,6 +303,27 @@ 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; |
+ } |
+ |
+ base::CheckedNumeric<int64_t> time_since_epoch_signed = time_since_epoch; |
+ |
+ if (!time_since_epoch_signed.IsValid()) { |
+ DVLOG(1) << "Timestamp value too big to cast to int64_t: " |
+ << time_since_epoch; |
+ return false; |
+ } |
+ |
+ *output = |
+ base::Time::UnixEpoch() + |
+ base::TimeDelta::FromMilliseconds(time_since_epoch_signed.ValueOrDie()); |
+ |
+ return true; |
+} |
+ |
static void WriteTimeSinceEpoch(const base::Time& timestamp, |
std::string* output) { |
base::TimeDelta time_since_epoch = timestamp - base::Time::UnixEpoch(); |
@@ -351,28 +384,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 +403,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 |