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[] =
CBORReader::CBORReader(base::span<const uint8_t>::const_iterator it,
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() {}
// static
......@@ -65,7 +69,8 @@ base::Optional<CBORValue> CBORReader::Read(base::span<uint8_t const> data,
DecoderError* error_code_out,
int max_nesting_level) {
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)
reader.CheckExtraneousData();
......@@ -77,7 +82,29 @@ base::Optional<CBORValue> CBORReader::Read(base::span<uint8_t const> data,
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) {
error_code_ = DecoderError::TOO_MUCH_NESTING;
return base::nullopt;
......@@ -224,7 +251,8 @@ base::Optional<CBORValue> CBORReader::ReadCBORArray(uint64_t length,
int max_nesting_level) {
CBORValue::ArrayValue cbor_array;
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())
return base::nullopt;
cbor_array.push_back(std::move(cbor_element.value()));
......@@ -236,8 +264,10 @@ base::Optional<CBORValue> CBORReader::ReadCBORMap(uint64_t length,
int max_nesting_level) {
CBORValue::MapValue cbor_map;
while (length-- > 0) {
base::Optional<CBORValue> key = DecodeCBOR(max_nesting_level - 1);
base::Optional<CBORValue> value = DecodeCBOR(max_nesting_level - 1);
base::Optional<CBORValue> key =
DecodeCompleteDataItem(max_nesting_level - 1);
base::Optional<CBORValue> value =
DecodeCompleteDataItem(max_nesting_level - 1);
if (!key.has_value() || !value.has_value())
return base::nullopt;
......
......@@ -79,17 +79,27 @@ class CBOR_EXPORT CBORReader {
// CBOR data- then an empty optional is returned. Optional |error_code_out|
// can be provided by the caller to obtain additional information about
// 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,
DecoderError* error_code_out = nullptr,
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.
static const char* ErrorCodeToString(DecoderError error_code);
private:
CBORReader(base::span<const uint8_t>::const_iterator it,
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> DecodeValueToUnsigned(uint64_t value);
base::Optional<CBORValue> ReadSimpleValue(uint8_t additional_info,
......@@ -109,6 +119,9 @@ class CBOR_EXPORT CBORReader {
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_;
const base::span<const uint8_t>::const_iterator end_;
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