Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(596)

Unified Diff: net/cert/ct_serialization.cc

Issue 1575543002: Minor improvements to ct_serialization.cc (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addresses review comments Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/cert/ct_serialization.cc
diff --git a/net/cert/ct_serialization.cc b/net/cert/ct_serialization.cc
index 235d37e65ad1fc8106a05d602c3c9f04b4e61a48..9da4b73cf8506739a00b872db0cbcdeb950dbbe5 100644
--- a/net/cert/ct_serialization.cc
+++ b/net/cert/ct_serialization.cc
@@ -6,9 +6,11 @@
#include <stdint.h>
+#include <algorithm>
#include <limits>
#include "base/logging.h"
+#include "base/numerics/safe_math.h"
namespace net {
@@ -45,6 +47,18 @@ enum SignatureType {
TREE_HASH = 1,
};
+// Returns the maximum value of an unsigned integer that is |length| bytes long.
+// |length| can be up to 8.
+uint64_t GetUintMaxValue(size_t length) {
+ DCHECK_LE(length, 8u);
+
+ // If length == 8, we can't calculate the max value because that would involve
+ // shifting a uint64_t left by 64 bits, which invokes undefined behaviour (see
+ // https://www.securecoding.cert.org/confluence/x/IRE). Instead, we just hard-
+ // 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.
+ return length == 8 ? 0xffffffffffffffff : (uint64_t(1) << (length * 8)) - 1;
+}
+
// Reads a TLS-encoded variable length unsigned integer from |in|.
// The integer is expected to be in big-endian order, which is used by TLS.
// The bytes read from |in| are discarded (i.e. |in|'s prefix removed)
@@ -54,11 +68,15 @@ template <typename T>
bool ReadUint(size_t length, base::StringPiece* in, T* out) {
if (in->size() < length)
return false;
+ DCHECK_NE(length, 0u);
DCHECK_LE(length, sizeof(T));
- T result = 0;
- for (size_t i = 0; i < length; ++i) {
- result = (result << 8) | static_cast<unsigned char>((*in)[i]);
+ T result = static_cast<uint8_t>((*in)[0]);
+ // This loop only executes if sizeof(T) > 1, because the first operation is
+ // to shift left by 1 byte, which is undefined behaviour if T is a 1 byte
+ // integer.
+ for (size_t i = 1; i < length; ++i) {
+ result = (result << 8) | static_cast<uint8_t>((*in)[i]);
}
in->remove_prefix(length);
*out = result;
@@ -66,14 +84,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 +118,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);
@@ -176,15 +198,15 @@ bool ConvertSignatureAlgorithm(
}
// Writes a TLS-encoded variable length unsigned integer to |output|.
-// |length| indicates the size (in bytes) of the integer.
+// |length| indicates the size (in bytes) of the integer. This must be able to
+// accomodate |value|.
// |value| the value itself to be written.
-template <typename T>
-void WriteUint(size_t length, T value, std::string* output) {
- DCHECK_LE(length, sizeof(T));
- DCHECK(length == sizeof(T) || value >> (length * 8) == 0);
+void WriteUint(size_t length, uint64_t value, std::string* output) {
+ // Check that |value| fits into |length| bytes.
+ DCHECK(length >= sizeof(value) || 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 +217,29 @@ 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.
+// |prefix_length| indicates the number of bytes needed to represent 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));
- if (input_size > max_allowed_input_size)
+ size_t max_input_size =
+ 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.
+
+ if (input_size > max_input_size)
return false;
- WriteUint(prefix_length, input.size(), output);
+ WriteUint(prefix_length, input_size, output);
WriteEncodedBytes(input, output);
return true;
@@ -291,6 +317,27 @@ bool EncodeLogEntry(const LogEntry& input, std::string* output) {
return false;
}
+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
+ uint64_t time_since_epoch = 0;
+ if (!ReadUint(kTimestampLength, input, &time_since_epoch)) {
+ return false;
+ }
Ryan Sleevi 2016/01/22 23:32:16 no braces
Rob Percival 2016/01/25 16:42:29 Done.
+
+ 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 +398,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, &timestamp) ||
- !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 +417,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
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698