Commit 7367cae6 authored by Kouhei Ueno's avatar Kouhei Ueno Committed by Commit Bot

CBORReader: Add alternate ::Read() which allows extraneous data

Before this CL, CBORReader::Read() rejected CBOR-encoded data with extra bytes
at the end, and reported CBORReader::DecoderError::EXTRANEOUS_DATA.

This CL introduces alternative CBORReader::Read() which allows extraneous data
following CBOR-encoded data. Callers can tell the size of the CBOR-encoded data
via |num_consumed_bytes|.

Bug: 803774
Change-Id: I154534f5049e94f3d20e67c4889e711332b1726f
Reviewed-on: https://chromium-review.googlesource.com/920802
Commit-Queue: Kouhei Ueno <kouhei@chromium.org>
Reviewed-by: default avatarBalazs Engedy <engedy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#537699}
parent a03d2fe5
...@@ -57,7 +57,11 @@ const char kOutOfRangeIntegerValue[] = ...@@ -57,7 +57,11 @@ const char kOutOfRangeIntegerValue[] =
CBORReader::CBORReader(base::span<const uint8_t>::const_iterator it, CBORReader::CBORReader(base::span<const uint8_t>::const_iterator it,
const base::span<const uint8_t>::const_iterator end) const base::span<const uint8_t>::const_iterator end)
: it_(it), end_(end), error_code_(DecoderError::CBOR_NO_ERROR) {} : begin_(it),
it_(it),
end_(end),
error_code_(DecoderError::CBOR_NO_ERROR) {}
CBORReader::~CBORReader() {} CBORReader::~CBORReader() {}
// static // static
...@@ -65,7 +69,8 @@ base::Optional<CBORValue> CBORReader::Read(base::span<uint8_t const> data, ...@@ -65,7 +69,8 @@ base::Optional<CBORValue> CBORReader::Read(base::span<uint8_t const> data,
DecoderError* error_code_out, DecoderError* error_code_out,
int max_nesting_level) { int max_nesting_level) {
CBORReader reader(data.cbegin(), data.cend()); CBORReader reader(data.cbegin(), data.cend());
base::Optional<CBORValue> decoded_cbor = reader.DecodeCBOR(max_nesting_level); base::Optional<CBORValue> decoded_cbor =
reader.DecodeCompleteDataItem(max_nesting_level);
if (decoded_cbor) if (decoded_cbor)
reader.CheckExtraneousData(); reader.CheckExtraneousData();
...@@ -77,7 +82,29 @@ base::Optional<CBORValue> CBORReader::Read(base::span<uint8_t const> data, ...@@ -77,7 +82,29 @@ base::Optional<CBORValue> CBORReader::Read(base::span<uint8_t const> data,
return decoded_cbor; return decoded_cbor;
} }
base::Optional<CBORValue> CBORReader::DecodeCBOR(int max_nesting_level) { // static
base::Optional<CBORValue> CBORReader::Read(base::span<uint8_t const> data,
size_t* num_bytes_consumed,
DecoderError* error_code_out,
int max_nesting_level) {
CBORReader reader(data.cbegin(), data.cend());
base::Optional<CBORValue> decoded_cbor =
reader.DecodeCompleteDataItem(max_nesting_level);
if (error_code_out)
*error_code_out = reader.GetErrorCode();
if (reader.GetErrorCode() != DecoderError::CBOR_NO_ERROR) {
*num_bytes_consumed = 0;
return base::nullopt;
}
*num_bytes_consumed = reader.num_bytes_consumed();
return decoded_cbor;
}
base::Optional<CBORValue> CBORReader::DecodeCompleteDataItem(
int max_nesting_level) {
if (max_nesting_level < 0 || max_nesting_level > kCBORMaxDepth) { if (max_nesting_level < 0 || max_nesting_level > kCBORMaxDepth) {
error_code_ = DecoderError::TOO_MUCH_NESTING; error_code_ = DecoderError::TOO_MUCH_NESTING;
return base::nullopt; return base::nullopt;
...@@ -224,7 +251,8 @@ base::Optional<CBORValue> CBORReader::ReadCBORArray(uint64_t length, ...@@ -224,7 +251,8 @@ base::Optional<CBORValue> CBORReader::ReadCBORArray(uint64_t length,
int max_nesting_level) { int max_nesting_level) {
CBORValue::ArrayValue cbor_array; CBORValue::ArrayValue cbor_array;
while (length-- > 0) { while (length-- > 0) {
base::Optional<CBORValue> cbor_element = DecodeCBOR(max_nesting_level - 1); base::Optional<CBORValue> cbor_element =
DecodeCompleteDataItem(max_nesting_level - 1);
if (!cbor_element.has_value()) if (!cbor_element.has_value())
return base::nullopt; return base::nullopt;
cbor_array.push_back(std::move(cbor_element.value())); cbor_array.push_back(std::move(cbor_element.value()));
...@@ -236,8 +264,10 @@ base::Optional<CBORValue> CBORReader::ReadCBORMap(uint64_t length, ...@@ -236,8 +264,10 @@ base::Optional<CBORValue> CBORReader::ReadCBORMap(uint64_t length,
int max_nesting_level) { int max_nesting_level) {
CBORValue::MapValue cbor_map; CBORValue::MapValue cbor_map;
while (length-- > 0) { while (length-- > 0) {
base::Optional<CBORValue> key = DecodeCBOR(max_nesting_level - 1); base::Optional<CBORValue> key =
base::Optional<CBORValue> value = DecodeCBOR(max_nesting_level - 1); DecodeCompleteDataItem(max_nesting_level - 1);
base::Optional<CBORValue> value =
DecodeCompleteDataItem(max_nesting_level - 1);
if (!key.has_value() || !value.has_value()) if (!key.has_value() || !value.has_value())
return base::nullopt; return base::nullopt;
......
...@@ -79,17 +79,27 @@ class CBOR_EXPORT CBORReader { ...@@ -79,17 +79,27 @@ class CBOR_EXPORT CBORReader {
// CBOR data- then an empty optional is returned. Optional |error_code_out| // CBOR data- then an empty optional is returned. Optional |error_code_out|
// can be provided by the caller to obtain additional information about // can be provided by the caller to obtain additional information about
// decoding failures. // decoding failures.
//
// Fails if not all the data was consumed and sets |error_code_out| to
// EXTRANEOUS_DATA in this case.
static base::Optional<CBORValue> Read(base::span<const uint8_t> input_data, static base::Optional<CBORValue> Read(base::span<const uint8_t> input_data,
DecoderError* error_code_out = nullptr, DecoderError* error_code_out = nullptr,
int max_nesting_level = kCBORMaxDepth); int max_nesting_level = kCBORMaxDepth);
// Never fails with EXTRANEOUS_DATA, but informs the caller of how many bytes
// were consumed through |num_bytes_consumed|.
static base::Optional<CBORValue> Read(base::span<const uint8_t> input_data,
size_t* num_bytes_consumed,
DecoderError* error_code_out = nullptr,
int max_nesting_level = kCBORMaxDepth);
// Translates errors to human-readable error messages. // Translates errors to human-readable error messages.
static const char* ErrorCodeToString(DecoderError error_code); static const char* ErrorCodeToString(DecoderError error_code);
private: private:
CBORReader(base::span<const uint8_t>::const_iterator it, CBORReader(base::span<const uint8_t>::const_iterator it,
const base::span<const uint8_t>::const_iterator end); const base::span<const uint8_t>::const_iterator end);
base::Optional<CBORValue> DecodeCBOR(int max_nesting_level); base::Optional<CBORValue> DecodeCompleteDataItem(int max_nesting_level);
base::Optional<CBORValue> DecodeValueToNegative(uint64_t value); base::Optional<CBORValue> DecodeValueToNegative(uint64_t value);
base::Optional<CBORValue> DecodeValueToUnsigned(uint64_t value); base::Optional<CBORValue> DecodeValueToUnsigned(uint64_t value);
base::Optional<CBORValue> ReadSimpleValue(uint8_t additional_info, base::Optional<CBORValue> ReadSimpleValue(uint8_t additional_info,
...@@ -109,6 +119,9 @@ class CBOR_EXPORT CBORReader { ...@@ -109,6 +119,9 @@ class CBOR_EXPORT CBORReader {
DecoderError GetErrorCode(); DecoderError GetErrorCode();
size_t num_bytes_consumed() const { return it_ - begin_; }
const base::span<const uint8_t>::const_iterator begin_;
base::span<const uint8_t>::const_iterator it_; base::span<const uint8_t>::const_iterator it_;
const base::span<const uint8_t>::const_iterator end_; const base::span<const uint8_t>::const_iterator end_;
DecoderError error_code_; DecoderError error_code_;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment