summaryrefslogtreecommitdiff
path: root/chromium/components/cbor
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-01-31 16:33:43 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-02-06 16:33:22 +0000
commitda51f56cc21233c2d30f0fe0d171727c3102b2e0 (patch)
tree4e579ab70ce4b19bee7984237f3ce05a96d59d83 /chromium/components/cbor
parentc8c2d1901aec01e934adf561a9fdf0cc776cdef8 (diff)
downloadqtwebengine-chromium-da51f56cc21233c2d30f0fe0d171727c3102b2e0.tar.gz
BASELINE: Update Chromium to 65.0.3525.40
Also imports missing submodules Change-Id: I36901b7c6a325cda3d2c10cedb2186c25af3b79b Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/components/cbor')
-rw-r--r--chromium/components/cbor/BUILD.gn51
-rw-r--r--chromium/components/cbor/OWNERS2
-rw-r--r--chromium/components/cbor/cbor_binary.h35
-rw-r--r--chromium/components/cbor/cbor_export.h29
-rw-r--r--chromium/components/cbor/cbor_reader.cc349
-rw-r--r--chromium/components/cbor/cbor_reader.h120
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer.cc30
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor0bin0 -> 1 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor11
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor101
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor11bin0 -> 11 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor121
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor13bin0 -> 11 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor141
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor151
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor161
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor171
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor18bin0 -> 3 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor19bin0 -> 3 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor21
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor20bin0 -> 3 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor211
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor22bin0 -> 3 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor231
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor24bin0 -> 5 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor251
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor26bin0 -> 9 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor27bin0 -> 3 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor28bin0 -> 3 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor29bin0 -> 3 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor31
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor301
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor31bin0 -> 3 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor32bin0 -> 3 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor33bin0 -> 3 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor34bin0 -> 5 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor35bin0 -> 5 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor36bin0 -> 5 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor37bin0 -> 9 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor38bin0 -> 9 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor39bin0 -> 9 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor41
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor401
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor411
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor421
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor431
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor441
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor451
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor461
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor471
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor481
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor49bin0 -> 10 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor51
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor501
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor511
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor521
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor531
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor541
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor551
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor561
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor571
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor581
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor591
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor61
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor601
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor611
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor621
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor631
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor641
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor652
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor661
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor671
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor681
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor691
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor71
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor701
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor711
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor721
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor731
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor741
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor751
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor761
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor771
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor782
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor791
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor8bin0 -> 5 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor801
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor811
-rw-r--r--chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor9bin0 -> 9 bytes
-rw-r--r--chromium/components/cbor/cbor_reader_unittest.cc821
-rw-r--r--chromium/components/cbor/cbor_values.cc226
-rw-r--r--chromium/components/cbor/cbor_values.h171
-rw-r--r--chromium/components/cbor/cbor_values_unittest.cc354
-rw-r--r--chromium/components/cbor/cbor_writer.cc176
-rw-r--r--chromium/components/cbor/cbor_writer.h100
-rw-r--r--chromium/components/cbor/cbor_writer_unittest.cc431
96 files changed, 2955 insertions, 0 deletions
diff --git a/chromium/components/cbor/BUILD.gn b/chromium/components/cbor/BUILD.gn
new file mode 100644
index 00000000000..ae9ec5b2260
--- /dev/null
+++ b/chromium/components/cbor/BUILD.gn
@@ -0,0 +1,51 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//testing/libfuzzer/fuzzer_test.gni")
+
+component("cbor") {
+ sources = [
+ "cbor_binary.h",
+ "cbor_reader.cc",
+ "cbor_reader.h",
+ "cbor_values.cc",
+ "cbor_values.h",
+ "cbor_writer.cc",
+ "cbor_writer.h",
+ ]
+
+ defines = [ "CBOR_IMPLEMENTATION" ]
+
+ deps = [
+ "//base",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "cbor_reader_unittest.cc",
+ "cbor_values_unittest.cc",
+ "cbor_writer_unittest.cc",
+ ]
+
+ deps = [
+ ":cbor",
+ "//base",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
+
+fuzzer_test("cbor_reader_fuzzer") {
+ sources = [
+ "cbor_reader_fuzzer.cc",
+ ]
+ deps = [
+ ":cbor",
+ "//base",
+ ]
+ seed_corpus = "cbor_reader_fuzzer_corpus/"
+ libfuzzer_options = [ "max_len=65535" ]
+}
diff --git a/chromium/components/cbor/OWNERS b/chromium/components/cbor/OWNERS
new file mode 100644
index 00000000000..85cda96ded9
--- /dev/null
+++ b/chromium/components/cbor/OWNERS
@@ -0,0 +1,2 @@
+jochen@chromium.org
+engedy@chromium.org
diff --git a/chromium/components/cbor/cbor_binary.h b/chromium/components/cbor/cbor_binary.h
new file mode 100644
index 00000000000..f1790658a92
--- /dev/null
+++ b/chromium/components/cbor/cbor_binary.h
@@ -0,0 +1,35 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdint.h>
+
+#ifndef COMPONENTS_CBOR_CBOR_BINARY_H_
+#define COMPONENTS_CBOR_CBOR_BINARY_H_
+
+namespace cbor {
+namespace constants {
+
+// Mask selecting the low-order 5 bits of the "initial byte", which is where
+// the additional information is encoded.
+static constexpr uint8_t kAdditionalInformationMask = 0x1F;
+// Mask selecting the high-order 3 bits of the "initial byte", which indicates
+// the major type of the encoded value.
+static constexpr uint8_t kMajorTypeMask = 0xE0;
+// Indicates the number of bits the "initial byte" needs to be shifted to the
+// right after applying |kMajorTypeMask| to produce the major type in the
+// lowermost bits.
+static constexpr uint8_t kMajorTypeBitShift = 5u;
+// Indicates the integer is in the following byte.
+static constexpr uint8_t kAdditionalInformation1Byte = 24u;
+// Indicates the integer is in the next 2 bytes.
+static constexpr uint8_t kAdditionalInformation2Bytes = 25u;
+// Indicates the integer is in the next 4 bytes.
+static constexpr uint8_t kAdditionalInformation4Bytes = 26u;
+// Indicates the integer is in the next 8 bytes.
+static constexpr uint8_t kAdditionalInformation8Bytes = 27u;
+
+} // namespace constants
+} // namespace cbor
+
+#endif // COMPONENTS_CBOR_CBOR_BINARY_H_
diff --git a/chromium/components/cbor/cbor_export.h b/chromium/components/cbor/cbor_export.h
new file mode 100644
index 00000000000..1b932e68111
--- /dev/null
+++ b/chromium/components/cbor/cbor_export.h
@@ -0,0 +1,29 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_CBOR_CBOR_EXPORT_H_
+#define COMPONENTS_CBOR_CBOR_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(CBOR_IMPLEMENTATION)
+#define CBOR_EXPORT __declspec(dllexport)
+#else
+#define CBOR_EXPORT __declspec(dllimport)
+#endif // defined(CBOR_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(CBOR_IMPLEMENTATION)
+#define CBOR_EXPORT __attribute__((visibility("default")))
+#else
+#define CBOR_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define CBOR_EXPORT
+#endif
+
+#endif // COMPONENTS_CBOR_CBOR_EXPORT_H_
diff --git a/chromium/components/cbor/cbor_reader.cc b/chromium/components/cbor/cbor_reader.cc
new file mode 100644
index 00000000000..c21f4df3cb9
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader.cc
@@ -0,0 +1,349 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/cbor/cbor_reader.h"
+
+#include <math.h>
+#include <utility>
+
+#include "base/numerics/checked_math.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "components/cbor/cbor_binary.h"
+
+namespace cbor {
+
+namespace {
+
+CBORValue::Type GetMajorType(uint8_t initial_data_byte) {
+ return static_cast<CBORValue::Type>(
+ (initial_data_byte & constants::kMajorTypeMask) >>
+ constants::kMajorTypeBitShift);
+}
+
+uint8_t GetAdditionalInfo(uint8_t initial_data_byte) {
+ return initial_data_byte & constants::kAdditionalInformationMask;
+}
+
+// Error messages that correspond to each of the error codes.
+const char kNoError[] = "Successfully deserialized to a CBOR value.";
+const char kUnsupportedMajorType[] = "Unsupported major type.";
+const char kUnknownAdditionalInfo[] =
+ "Unknown additional info format in the first byte.";
+const char kIncompleteCBORData[] =
+ "Prematurely terminated CBOR data byte array.";
+const char kIncorrectMapKeyType[] =
+ "Map keys other than utf-8 encoded strings are not allowed.";
+const char kTooMuchNesting[] = "Too much nesting.";
+const char kInvalidUTF8[] = "String encoding other than utf8 are not allowed.";
+const char kExtraneousData[] = "Trailing data bytes are not allowed.";
+const char kDuplicateKey[] = "Duplicate map keys are not allowed.";
+const char kMapKeyOutOfOrder[] =
+ "Map keys must be sorted by byte length and then by byte-wise lexical "
+ "order.";
+const char kNonMinimalCBOREncoding[] =
+ "Unsigned integers must be encoded with minimum number of bytes.";
+const char kUnsupportedSimpleValue[] =
+ "Unsupported or unassigned simple value.";
+const char kUnsupportedFloatingPointValue[] =
+ "Floating point numbers are not supported.";
+const char kOutOfRangeIntegerValue[] =
+ "Integer values must be between INT64_MIN and INT64_MAX.";
+
+} // namespace
+
+CBORReader::CBORReader(Bytes::const_iterator it, Bytes::const_iterator end)
+ : it_(it), end_(end), error_code_(DecoderError::CBOR_NO_ERROR) {}
+CBORReader::~CBORReader() {}
+
+// static
+base::Optional<CBORValue> CBORReader::Read(const Bytes& data,
+ DecoderError* error_code_out,
+ int max_nesting_level) {
+ CBORReader reader(data.begin(), data.end());
+ base::Optional<CBORValue> decoded_cbor = reader.DecodeCBOR(max_nesting_level);
+
+ if (decoded_cbor)
+ reader.CheckExtraneousData();
+ if (error_code_out)
+ *error_code_out = reader.GetErrorCode();
+
+ if (reader.GetErrorCode() != DecoderError::CBOR_NO_ERROR)
+ return base::nullopt;
+ return decoded_cbor;
+}
+
+base::Optional<CBORValue> CBORReader::DecodeCBOR(int max_nesting_level) {
+ if (max_nesting_level < 0 || max_nesting_level > kCBORMaxDepth) {
+ error_code_ = DecoderError::TOO_MUCH_NESTING;
+ return base::nullopt;
+ }
+
+ if (!CanConsume(1)) {
+ error_code_ = DecoderError::INCOMPLETE_CBOR_DATA;
+ return base::nullopt;
+ }
+
+ const uint8_t initial_byte = *it_++;
+ const auto major_type = GetMajorType(initial_byte);
+ const uint8_t additional_info = GetAdditionalInfo(initial_byte);
+
+ uint64_t value;
+ if (!ReadVariadicLengthInteger(additional_info, &value))
+ return base::nullopt;
+
+ switch (major_type) {
+ case CBORValue::Type::UNSIGNED:
+ return DecodeValueToUnsigned(value);
+ case CBORValue::Type::NEGATIVE:
+ return DecodeValueToNegative(value);
+ case CBORValue::Type::BYTE_STRING:
+ return ReadBytes(value);
+ case CBORValue::Type::STRING:
+ return ReadString(value);
+ case CBORValue::Type::ARRAY:
+ return ReadCBORArray(value, max_nesting_level);
+ case CBORValue::Type::MAP:
+ return ReadCBORMap(value, max_nesting_level);
+ case CBORValue::Type::SIMPLE_VALUE:
+ return ReadSimpleValue(additional_info, value);
+ case CBORValue::Type::NONE:
+ break;
+ }
+
+ error_code_ = DecoderError::UNSUPPORTED_MAJOR_TYPE;
+ return base::nullopt;
+}
+
+bool CBORReader::ReadVariadicLengthInteger(uint8_t additional_info,
+ uint64_t* value) {
+ uint8_t additional_bytes = 0;
+ if (additional_info < 24) {
+ *value = additional_info;
+ return true;
+ } else if (additional_info == 24) {
+ additional_bytes = 1;
+ } else if (additional_info == 25) {
+ additional_bytes = 2;
+ } else if (additional_info == 26) {
+ additional_bytes = 4;
+ } else if (additional_info == 27) {
+ additional_bytes = 8;
+ } else {
+ error_code_ = DecoderError::UNKNOWN_ADDITIONAL_INFO;
+ return false;
+ }
+
+ if (!CanConsume(additional_bytes)) {
+ error_code_ = DecoderError::INCOMPLETE_CBOR_DATA;
+ return false;
+ }
+
+ uint64_t int_data = 0;
+ for (uint8_t i = 0; i < additional_bytes; ++i) {
+ int_data <<= 8;
+ int_data |= *it_++;
+ }
+
+ *value = int_data;
+ return CheckMinimalEncoding(additional_bytes, int_data);
+}
+
+base::Optional<CBORValue> CBORReader::DecodeValueToNegative(uint64_t value) {
+ auto negative_value = -base::CheckedNumeric<int64_t>(value) - 1;
+ if (!negative_value.IsValid()) {
+ error_code_ = DecoderError::OUT_OF_RANGE_INTEGER_VALUE;
+ return base::nullopt;
+ }
+ return CBORValue(negative_value.ValueOrDie());
+}
+
+base::Optional<CBORValue> CBORReader::DecodeValueToUnsigned(uint64_t value) {
+ auto unsigned_value = base::CheckedNumeric<int64_t>(value);
+ if (!unsigned_value.IsValid()) {
+ error_code_ = DecoderError::OUT_OF_RANGE_INTEGER_VALUE;
+ return base::nullopt;
+ }
+ return CBORValue(unsigned_value.ValueOrDie());
+}
+
+base::Optional<CBORValue> CBORReader::ReadSimpleValue(uint8_t additional_info,
+ uint64_t value) {
+ // Floating point numbers are not supported.
+ if (additional_info > 24 && additional_info < 28) {
+ error_code_ = DecoderError::UNSUPPORTED_FLOATING_POINT_VALUE;
+ return base::nullopt;
+ }
+
+ CHECK_LE(value, 255u);
+ CBORValue::SimpleValue possibly_unsupported_simple_value =
+ static_cast<CBORValue::SimpleValue>(static_cast<int>(value));
+ switch (possibly_unsupported_simple_value) {
+ case CBORValue::SimpleValue::FALSE_VALUE:
+ case CBORValue::SimpleValue::TRUE_VALUE:
+ case CBORValue::SimpleValue::NULL_VALUE:
+ case CBORValue::SimpleValue::UNDEFINED:
+ return CBORValue(possibly_unsupported_simple_value);
+ }
+
+ error_code_ = DecoderError::UNSUPPORTED_SIMPLE_VALUE;
+ return base::nullopt;
+}
+
+base::Optional<CBORValue> CBORReader::ReadString(uint64_t num_bytes) {
+ if (!CanConsume(num_bytes)) {
+ error_code_ = DecoderError::INCOMPLETE_CBOR_DATA;
+ return base::nullopt;
+ }
+
+ std::string cbor_string(it_, it_ + num_bytes);
+ it_ += num_bytes;
+
+ return HasValidUTF8Format(cbor_string)
+ ? base::make_optional<CBORValue>(CBORValue(std::move(cbor_string)))
+ : base::nullopt;
+}
+
+base::Optional<CBORValue> CBORReader::ReadBytes(uint64_t num_bytes) {
+ if (!CanConsume(num_bytes)) {
+ error_code_ = DecoderError::INCOMPLETE_CBOR_DATA;
+ return base::nullopt;
+ }
+
+ Bytes cbor_byte_string(it_, it_ + num_bytes);
+ it_ += num_bytes;
+
+ return CBORValue(std::move(cbor_byte_string));
+}
+
+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);
+ if (!cbor_element.has_value())
+ return base::nullopt;
+ cbor_array.push_back(std::move(cbor_element.value()));
+ }
+ return CBORValue(std::move(cbor_array));
+}
+
+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);
+ if (!key.has_value() || !value.has_value())
+ return base::nullopt;
+
+ // Only CBOR maps with integer or string type keys are allowed.
+ if (key.value().type() != CBORValue::Type::STRING &&
+ key.value().type() != CBORValue::Type::UNSIGNED) {
+ error_code_ = DecoderError::INCORRECT_MAP_KEY_TYPE;
+ return base::nullopt;
+ }
+ if (!CheckDuplicateKey(key.value(), &cbor_map) ||
+ !CheckOutOfOrderKey(key.value(), &cbor_map)) {
+ return base::nullopt;
+ }
+
+ cbor_map.insert_or_assign(std::move(key.value()), std::move(value.value()));
+ }
+ return CBORValue(std::move(cbor_map));
+}
+
+bool CBORReader::CanConsume(uint64_t bytes) {
+ if (base::checked_cast<uint64_t>(std::distance(it_, end_)) >= bytes) {
+ return true;
+ }
+ error_code_ = DecoderError::INCOMPLETE_CBOR_DATA;
+ return false;
+}
+
+bool CBORReader::CheckMinimalEncoding(uint8_t additional_bytes,
+ uint64_t uint_data) {
+ if ((additional_bytes == 1 && uint_data < 24) ||
+ uint_data <= (1ULL << 8 * (additional_bytes >> 1)) - 1) {
+ error_code_ = DecoderError::NON_MINIMAL_CBOR_ENCODING;
+ return false;
+ }
+ return true;
+}
+
+void CBORReader::CheckExtraneousData() {
+ if (it_ != end_)
+ error_code_ = DecoderError::EXTRANEOUS_DATA;
+}
+
+bool CBORReader::CheckDuplicateKey(const CBORValue& new_key,
+ CBORValue::MapValue* map) {
+ if (base::ContainsKey(*map, new_key)) {
+ error_code_ = DecoderError::DUPLICATE_KEY;
+ return false;
+ }
+ return true;
+}
+
+bool CBORReader::HasValidUTF8Format(const std::string& string_data) {
+ if (!base::IsStringUTF8(string_data)) {
+ error_code_ = DecoderError::INVALID_UTF8;
+ return false;
+ }
+ return true;
+}
+
+bool CBORReader::CheckOutOfOrderKey(const CBORValue& new_key,
+ CBORValue::MapValue* map) {
+ auto comparator = map->key_comp();
+ if (!map->empty() && comparator(new_key, map->rbegin()->first)) {
+ error_code_ = DecoderError::OUT_OF_ORDER_KEY;
+ return false;
+ }
+ return true;
+}
+
+CBORReader::DecoderError CBORReader::GetErrorCode() {
+ return error_code_;
+}
+
+// static
+const char* CBORReader::ErrorCodeToString(DecoderError error) {
+ switch (error) {
+ case DecoderError::CBOR_NO_ERROR:
+ return kNoError;
+ case DecoderError::UNSUPPORTED_MAJOR_TYPE:
+ return kUnsupportedMajorType;
+ case DecoderError::UNKNOWN_ADDITIONAL_INFO:
+ return kUnknownAdditionalInfo;
+ case DecoderError::INCOMPLETE_CBOR_DATA:
+ return kIncompleteCBORData;
+ case DecoderError::INCORRECT_MAP_KEY_TYPE:
+ return kIncorrectMapKeyType;
+ case DecoderError::TOO_MUCH_NESTING:
+ return kTooMuchNesting;
+ case DecoderError::INVALID_UTF8:
+ return kInvalidUTF8;
+ case DecoderError::EXTRANEOUS_DATA:
+ return kExtraneousData;
+ case DecoderError::DUPLICATE_KEY:
+ return kDuplicateKey;
+ case DecoderError::OUT_OF_ORDER_KEY:
+ return kMapKeyOutOfOrder;
+ case DecoderError::NON_MINIMAL_CBOR_ENCODING:
+ return kNonMinimalCBOREncoding;
+ case DecoderError::UNSUPPORTED_SIMPLE_VALUE:
+ return kUnsupportedSimpleValue;
+ case DecoderError::UNSUPPORTED_FLOATING_POINT_VALUE:
+ return kUnsupportedFloatingPointValue;
+ case DecoderError::OUT_OF_RANGE_INTEGER_VALUE:
+ return kOutOfRangeIntegerValue;
+ default:
+ NOTREACHED();
+ return "Unknown error code.";
+ }
+}
+
+} // namespace cbor
diff --git a/chromium/components/cbor/cbor_reader.h b/chromium/components/cbor/cbor_reader.h
new file mode 100644
index 00000000000..35558891a45
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader.h
@@ -0,0 +1,120 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_CBOR_CBOR_READER_H_
+#define COMPONENTS_CBOR_CBOR_READER_H_
+
+#include <stddef.h>
+#include <string>
+#include <vector>
+
+#include "base/optional.h"
+#include "components/cbor/cbor_export.h"
+#include "components/cbor/cbor_values.h"
+
+// Concise Binary Object Representation (CBOR) decoder as defined by
+// https://tools.ietf.org/html/rfc7049. This decoder only accepts canonical
+// CBOR as defined by section 3.9.
+// Supported:
+// * Major types:
+// * 0: Unsigned integers, up to 64-bit.
+// * 2: Byte strings.
+// * 3: UTF-8 strings.
+// * 4: Definite-length arrays.
+// * 5: Definite-length maps.
+// * 7: Simple values.
+//
+// Requirements for canonical CBOR representation:
+// - Duplicate keys for map are not allowed.
+// - Keys for map must be sorted first by length and then by byte-wise
+// lexical order.
+//
+// Known limitations and interpretations of the RFC:
+// - Does not support negative integers, indefinite data streams and tagging.
+// - Floating point representations and BREAK stop code in major
+// type 7 are not supported.
+// - Non-character codepoint are not supported for Major type 3.
+// - Incomplete CBOR data items are treated as syntax errors.
+// - Trailing data bytes are treated as errors.
+// - Unknown additional information formats are treated as syntax errors.
+// - Callers can decode CBOR values with at most 16 nested depth layer. More
+// strict restrictions on nesting layer size of CBOR values can be enforced
+// by setting |max_nesting_level|.
+// - Only CBOR maps with integer or string type keys are supported due to the
+// cost of serialization when sorting map keys.
+// - Simple values that are unassigned/reserved as per RFC 7049 are not
+// supported and treated as errors.
+
+namespace cbor {
+
+class CBOR_EXPORT CBORReader {
+ public:
+ using Bytes = std::vector<uint8_t>;
+
+ enum class DecoderError {
+ CBOR_NO_ERROR = 0,
+ UNSUPPORTED_MAJOR_TYPE,
+ UNKNOWN_ADDITIONAL_INFO,
+ INCOMPLETE_CBOR_DATA,
+ INCORRECT_MAP_KEY_TYPE,
+ TOO_MUCH_NESTING,
+ INVALID_UTF8,
+ EXTRANEOUS_DATA,
+ DUPLICATE_KEY,
+ OUT_OF_ORDER_KEY,
+ NON_MINIMAL_CBOR_ENCODING,
+ UNSUPPORTED_SIMPLE_VALUE,
+ UNSUPPORTED_FLOATING_POINT_VALUE,
+ OUT_OF_RANGE_INTEGER_VALUE,
+ };
+
+ // CBOR nested depth sufficient for most use cases.
+ static const int kCBORMaxDepth = 16;
+
+ ~CBORReader();
+
+ // Reads and parses |input_data| into a CBORValue. If any one of the syntax
+ // formats is violated -including unknown additional info and incomplete
+ // 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.
+ static base::Optional<CBORValue> Read(const Bytes& input_data,
+ 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(Bytes::const_iterator it, const Bytes::const_iterator end);
+ base::Optional<CBORValue> DecodeCBOR(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,
+ uint64_t value);
+ bool ReadVariadicLengthInteger(uint8_t additional_info, uint64_t* value);
+ base::Optional<CBORValue> ReadBytes(uint64_t num_bytes);
+ base::Optional<CBORValue> ReadString(uint64_t num_bytes);
+ base::Optional<CBORValue> ReadCBORArray(uint64_t length,
+ int max_nesting_level);
+ base::Optional<CBORValue> ReadCBORMap(uint64_t length, int max_nesting_level);
+ bool CanConsume(uint64_t bytes);
+ void CheckExtraneousData();
+ bool CheckDuplicateKey(const CBORValue& new_key, CBORValue::MapValue* map);
+ bool HasValidUTF8Format(const std::string& string_data);
+ bool CheckOutOfOrderKey(const CBORValue& new_key, CBORValue::MapValue* map);
+ bool CheckMinimalEncoding(uint8_t additional_bytes, uint64_t uint_data);
+
+ DecoderError GetErrorCode();
+
+ Bytes::const_iterator it_;
+ const Bytes::const_iterator end_;
+ DecoderError error_code_;
+
+ DISALLOW_COPY_AND_ASSIGN(CBORReader);
+};
+
+} // namespace cbor
+
+#endif // COMPONENTS_CBOR_CBOR_READER_H_
diff --git a/chromium/components/cbor/cbor_reader_fuzzer.cc b/chromium/components/cbor/cbor_reader_fuzzer.cc
new file mode 100644
index 00000000000..4809e704adb
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer.cc
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdint.h>
+#include <algorithm>
+
+#include "components/cbor/cbor_reader.h" // nogncheck
+#include "components/cbor/cbor_writer.h" // nogncheck
+
+namespace cbor {
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ std::vector<uint8_t> input(data, data + size);
+ base::Optional<CBORValue> cbor = CBORReader::Read(input);
+
+ if (cbor.has_value()) {
+ base::Optional<std::vector<uint8_t>> serialized_cbor =
+ CBORWriter::Write(cbor.value());
+ CHECK(serialized_cbor.has_value());
+ if (serialized_cbor.has_value()) {
+ CHECK(serialized_cbor.value().size() == input.size());
+ CHECK(memcmp(serialized_cbor.value().data(), input.data(),
+ input.size()) == 0);
+ }
+ }
+ return 0;
+}
+
+} // namespace cbor
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor0 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor0
new file mode 100644
index 00000000000..f76dd238ade
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor0
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor1 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor1
new file mode 100644
index 00000000000..6b2aaa76407
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor1
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor10 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor10
new file mode 100644
index 00000000000..fed1e13fcfa
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor10
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor11 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor11
new file mode 100644
index 00000000000..00a3f0c5362
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor11
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor12 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor12
new file mode 100644
index 00000000000..077457ad259
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor12
@@ -0,0 +1 @@
+; \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor13 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor13
new file mode 100644
index 00000000000..b4818a3b38b
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor13
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor14 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor14
new file mode 100644
index 00000000000..0519ecba6ea
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor14
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor15 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor15
new file mode 100644
index 00000000000..e8a0f87653d
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor15
@@ -0,0 +1 @@
+) \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor16 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor16
new file mode 100644
index 00000000000..bfefdad18c4
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor16
@@ -0,0 +1 @@
+8c \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor17 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor17
new file mode 100644
index 00000000000..5de255544fc
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor17
@@ -0,0 +1 @@
+9 \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor18 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor18
new file mode 100644
index 00000000000..e43ae5af822
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor18
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor19 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor19
new file mode 100644
index 00000000000..6935671d0de
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor19
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor2 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor2
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor2
@@ -0,0 +1 @@
+
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor20 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor20
new file mode 100644
index 00000000000..ed788bb3a4c
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor20
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor21 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor21
new file mode 100644
index 00000000000..fc9ea00d188
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor21
@@ -0,0 +1 @@
+?񙙙 \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor22 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor22
new file mode 100644
index 00000000000..5ac3929dea8
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor22
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor23 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor23
new file mode 100644
index 00000000000..735f4675f10
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor23
@@ -0,0 +1 @@
+{ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor24 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor24
new file mode 100644
index 00000000000..f36a086ed50
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor24
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor25 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor25
new file mode 100644
index 00000000000..16f3345724b
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor25
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor26 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor26
new file mode 100644
index 00000000000..8e79bf519fe
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor26
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor27 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor27
new file mode 100644
index 00000000000..8e144ff3cd2
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor27
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor28 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor28
new file mode 100644
index 00000000000..16b0d43402f
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor28
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor29 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor29
new file mode 100644
index 00000000000..e5b8b4d8adb
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor29
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor3 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor3
new file mode 100644
index 00000000000..c96ab3cc70e
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor3
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor30 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor30
new file mode 100644
index 00000000000..815adc3e417
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor30
@@ -0,0 +1 @@
+ffffff \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor31 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor31
new file mode 100644
index 00000000000..2b119eb6592
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor31
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor32 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor32
new file mode 100644
index 00000000000..d73f58e36a2
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor32
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor33 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor33
new file mode 100644
index 00000000000..7c2eb64047e
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor33
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor34 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor34
new file mode 100644
index 00000000000..82965f3b13a
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor34
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor35 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor35
new file mode 100644
index 00000000000..2a9ccaec94a
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor35
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor36 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor36
new file mode 100644
index 00000000000..a9e0eebe00c
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor36
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor37 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor37
new file mode 100644
index 00000000000..c90d682d848
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor37
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor38 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor38
new file mode 100644
index 00000000000..802efe1966e
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor38
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor39 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor39
new file mode 100644
index 00000000000..7a1f61c5343
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor39
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor4 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor4
new file mode 100644
index 00000000000..a1910b3f6cc
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor4
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor40 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor40
new file mode 100644
index 00000000000..3a6e607aa5a
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor40
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor41 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor41
new file mode 100644
index 00000000000..bb7d13c5e9a
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor41
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor42 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor42
new file mode 100644
index 00000000000..f7a8cadeb57
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor42
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor43 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor43
new file mode 100644
index 00000000000..009080e8e0b
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor43
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor44 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor44
new file mode 100644
index 00000000000..04f7b5be698
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor44
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor45 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor45
new file mode 100644
index 00000000000..33c4e29de19
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor45
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor46 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor46
new file mode 100644
index 00000000000..a61a4624f2c
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor46
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor47 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor47
new file mode 100644
index 00000000000..d2fbff8927a
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor47
@@ -0,0 +1 @@
+t2013-03-21T20:04:00Z \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor48 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor48
new file mode 100644
index 00000000000..4ecf94681e9
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor48
@@ -0,0 +1 @@
+QKg \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor49 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor49
new file mode 100644
index 00000000000..c5c79cf7779
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor49
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor5 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor5
new file mode 100644
index 00000000000..d4e634a6b50
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor5
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor50 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor50
new file mode 100644
index 00000000000..7d0120d5bff
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor50
@@ -0,0 +1 @@
+D \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor51 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor51
new file mode 100644
index 00000000000..2784fd87e9b
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor51
@@ -0,0 +1 @@
+EdIETF \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor52 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor52
new file mode 100644
index 00000000000..b7d2601ab13
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor52
@@ -0,0 +1 @@
+ vhttp://www.example.com \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor53 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor53
new file mode 100644
index 00000000000..b516b2c489f
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor53
@@ -0,0 +1 @@
+@ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor54 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor54
new file mode 100644
index 00000000000..352e89a8017
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor54
@@ -0,0 +1 @@
+D \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor55 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor55
new file mode 100644
index 00000000000..64845fb7679
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor55
@@ -0,0 +1 @@
+` \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor56 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor56
new file mode 100644
index 00000000000..7ec9a4b774e
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor56
@@ -0,0 +1 @@
+aa \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor57 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor57
new file mode 100644
index 00000000000..743669bb19c
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor57
@@ -0,0 +1 @@
+dIETF \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor58 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor58
new file mode 100644
index 00000000000..cce6615381d
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor58
@@ -0,0 +1 @@
+b"\ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor59 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor59
new file mode 100644
index 00000000000..9055a92aa61
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor59
@@ -0,0 +1 @@
+bü \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor6 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor6
new file mode 100644
index 00000000000..3b5c90718af
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor6
@@ -0,0 +1 @@
+d \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor60 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor60
new file mode 100644
index 00000000000..0868c9a4288
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor60
@@ -0,0 +1 @@
+c水 \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor61 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor61
new file mode 100644
index 00000000000..8ea48a07a27
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor61
@@ -0,0 +1 @@
+d𐅑 \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor62 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor62
new file mode 100644
index 00000000000..5416677bc7d
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor62
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor63 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor63
new file mode 100644
index 00000000000..4cdf6ce18a8
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor63
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor64 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor64
new file mode 100644
index 00000000000..80fd3949e51
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor64
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor65 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor65
new file mode 100644
index 00000000000..b4495842ec6
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor65
@@ -0,0 +1,2 @@
+
+  \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor66 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor66
new file mode 100644
index 00000000000..eea1bf0c31f
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor66
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor67 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor67
new file mode 100644
index 00000000000..abc169a8cc5
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor67
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor68 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor68
new file mode 100644
index 00000000000..81e38473ff6
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor68
@@ -0,0 +1 @@
+aaab \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor69 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor69
new file mode 100644
index 00000000000..9b1d08caf44
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor69
@@ -0,0 +1 @@
+aaabac \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor7 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor7
new file mode 100644
index 00000000000..fda74fd9c88
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor7
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor70 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor70
new file mode 100644
index 00000000000..05bb07fc9d1
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor70
@@ -0,0 +1 @@
+aaaAabaBacaCadaDaeaE \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor71 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor71
new file mode 100644
index 00000000000..2681a857cb7
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor71
@@ -0,0 +1 @@
+_BC \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor72 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor72
new file mode 100644
index 00000000000..d0daf282398
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor72
@@ -0,0 +1 @@
+estreadming \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor73 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor73
new file mode 100644
index 00000000000..422ce24eaac
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor73
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor74 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor74
new file mode 100644
index 00000000000..f67cd5703a8
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor74
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor75 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor75
new file mode 100644
index 00000000000..78343ed40e3
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor75
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor76 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor76
new file mode 100644
index 00000000000..a0f1ea25969
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor76
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor77 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor77
new file mode 100644
index 00000000000..dbbf8e51a3f
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor77
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor78 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor78
new file mode 100644
index 00000000000..81c9910e824
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor78
@@ -0,0 +1,2 @@
+
+  \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor79 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor79
new file mode 100644
index 00000000000..018602c1e13
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor79
@@ -0,0 +1 @@
+aaab \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor8 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor8
new file mode 100644
index 00000000000..916281951cd
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor8
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor80 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor80
new file mode 100644
index 00000000000..151c13e53d3
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor80
@@ -0,0 +1 @@
+aaabac \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor81 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor81
new file mode 100644
index 00000000000..c0f4fd5eb32
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor81
@@ -0,0 +1 @@
+cFuncAmt! \ No newline at end of file
diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor9 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor9
new file mode 100644
index 00000000000..4cdcd7ccc3f
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor9
Binary files differ
diff --git a/chromium/components/cbor/cbor_reader_unittest.cc b/chromium/components/cbor/cbor_reader_unittest.cc
new file mode 100644
index 00000000000..e9819bf9498
--- /dev/null
+++ b/chromium/components/cbor/cbor_reader_unittest.cc
@@ -0,0 +1,821 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+#include <utility>
+
+#include "components/cbor/cbor_reader.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+/* Leveraging RFC 7049 examples from
+ https://github.com/cbor/test-vectors/blob/master/appendix_a.json. */
+namespace cbor {
+
+TEST(CBORReaderTest, TestReadUint) {
+ struct UintTestCase {
+ const int64_t value;
+ const std::vector<uint8_t> cbor_data;
+ };
+
+ static const UintTestCase kUintTestCases[] = {
+ {0, {0x00}},
+ {1, {0x01}},
+ {23, {0x17}},
+ {24, {0x18, 0x18}},
+ {std::numeric_limits<uint8_t>::max(), {0x18, 0xff}},
+ {1LL << 8, {0x19, 0x01, 0x00}},
+ {std::numeric_limits<uint16_t>::max(), {0x19, 0xff, 0xff}},
+ {1LL << 16, {0x1a, 0x00, 0x01, 0x00, 0x00}},
+ {std::numeric_limits<uint32_t>::max(), {0x1a, 0xff, 0xff, 0xff, 0xff}},
+ {1LL << 32, {0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}},
+ {std::numeric_limits<int64_t>::max(),
+ {0x1b, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ };
+
+ for (const UintTestCase& test_case : kUintTestCases) {
+ SCOPED_TRACE(testing::Message() << "testing uint: " << test_case.value);
+
+ base::Optional<CBORValue> cbor = CBORReader::Read(test_case.cbor_data);
+ ASSERT_TRUE(cbor.has_value());
+ ASSERT_EQ(cbor.value().type(), CBORValue::Type::UNSIGNED);
+ EXPECT_EQ(cbor.value().GetInteger(), test_case.value);
+ }
+}
+
+TEST(CBORReaderTest, TestUintEncodedWithNonMinimumByteLength) {
+ static const std::vector<uint8_t> non_minimal_uint_encodings[] = {
+ // Uint 23 encoded with 1 byte.
+ {0x18, 0x17},
+ // Uint 255 encoded with 2 bytes.
+ {0x19, 0x00, 0xff},
+ // Uint 65535 encoded with 4 byte.
+ {0x1a, 0x00, 0x00, 0xff, 0xff},
+ // Uint 4294967295 encoded with 8 byte.
+ {0x1b, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff},
+
+ // When decoding byte has more than one syntax error, the first syntax
+ // error encountered during deserialization is returned as the error code.
+ {
+ 0xa2, // map with non-minimally encoded key
+ 0x17, // key 24
+ 0x61, 0x42, // value :"B"
+
+ 0x18, 0x17, // key 23 encoded with extra byte
+ 0x61, 0x45 // value "E"
+ },
+ {
+ 0xa2, // map with out of order and non-minimally encoded key
+ 0x18, 0x17, // key 23 encoded with extra byte
+ 0x61, 0x45, // value "E"
+ 0x17, // key 23
+ 0x61, 0x42 // value :"B"
+ },
+ {
+ 0xa2, // map with duplicate non-minimally encoded key
+ 0x18, 0x17, // key 23 encoded with extra byte
+ 0x61, 0x45, // value "E"
+ 0x18, 0x17, // key 23 encoded with extra byte
+ 0x61, 0x42 // value :"B"
+ },
+ };
+
+ int test_case_index = 0;
+ CBORReader::DecoderError error_code;
+ for (const auto& non_minimal_uint : non_minimal_uint_encodings) {
+ SCOPED_TRACE(testing::Message()
+ << "testing element at index : " << test_case_index++);
+
+ base::Optional<CBORValue> cbor =
+ CBORReader::Read(non_minimal_uint, &error_code);
+ EXPECT_FALSE(cbor.has_value());
+ EXPECT_EQ(error_code, CBORReader::DecoderError::NON_MINIMAL_CBOR_ENCODING);
+ }
+}
+
+TEST(CBORReaderTest, TestReadNegativeInt) {
+ struct NegativeIntTestCase {
+ const int64_t negative_int;
+ const std::vector<uint8_t> cbor_data;
+ };
+
+ static const NegativeIntTestCase kNegativeIntTestCases[] = {
+ {-1LL, {0x20}},
+ {-24LL, {0x37}},
+ {-25LL, {0x38, 0x18}},
+ {-256LL, {0x38, 0xff}},
+ {-1000LL, {0x39, 0x03, 0xe7}},
+ {-1000000LL, {0x3a, 0x00, 0x0f, 0x42, 0x3f}},
+ {-4294967296LL, {0x3a, 0xff, 0xff, 0xff, 0xff}},
+ {std::numeric_limits<int64_t>::min(),
+ {0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}};
+
+ for (const NegativeIntTestCase& test_case : kNegativeIntTestCases) {
+ SCOPED_TRACE(testing::Message()
+ << "testing negative int : " << test_case.negative_int);
+
+ base::Optional<CBORValue> cbor = CBORReader::Read(test_case.cbor_data);
+ ASSERT_TRUE(cbor.has_value());
+ ASSERT_EQ(cbor.value().type(), CBORValue::Type::NEGATIVE);
+ EXPECT_EQ(cbor.value().GetInteger(), test_case.negative_int);
+ }
+}
+
+TEST(CBORReaderTest, TestReadBytes) {
+ struct ByteTestCase {
+ const std::vector<uint8_t> value;
+ const std::vector<uint8_t> cbor_data;
+ };
+
+ static const ByteTestCase kByteStringTestCases[] = {
+ // clang-format off
+ {{}, {0x40}},
+ {{0x01, 0x02, 0x03, 0x04}, {0x44, 0x01, 0x02, 0x03, 0x04}},
+ // clang-format on
+ };
+
+ int element_index = 0;
+ for (const ByteTestCase& test_case : kByteStringTestCases) {
+ SCOPED_TRACE(testing::Message()
+ << "testing string test case at : " << element_index++);
+
+ base::Optional<CBORValue> cbor = CBORReader::Read(test_case.cbor_data);
+ ASSERT_TRUE(cbor.has_value());
+ ASSERT_EQ(cbor.value().type(), CBORValue::Type::BYTE_STRING);
+ EXPECT_EQ(cbor.value().GetBytestring(), test_case.value);
+ }
+}
+
+TEST(CBORReaderTest, TestReadString) {
+ struct StringTestCase {
+ const std::string value;
+ const std::vector<uint8_t> cbor_data;
+ };
+
+ static const StringTestCase kStringTestCases[] = {
+ {"", {0x60}},
+ {"a", {0x61, 0x61}},
+ {"IETF", {0x64, 0x49, 0x45, 0x54, 0x46}},
+ {"\"\\", {0x62, 0x22, 0x5c}},
+ {"\xc3\xbc", {0x62, 0xc3, 0xbc}},
+ {"\xe6\xb0\xb4", {0x63, 0xe6, 0xb0, 0xb4}},
+ {"\xf0\x90\x85\x91", {0x64, 0xf0, 0x90, 0x85, 0x91}},
+ };
+
+ for (const StringTestCase& test_case : kStringTestCases) {
+ SCOPED_TRACE(testing::Message()
+ << "testing string value : " << test_case.value);
+
+ base::Optional<CBORValue> cbor = CBORReader::Read(test_case.cbor_data);
+ ASSERT_TRUE(cbor.has_value());
+ ASSERT_EQ(cbor.value().type(), CBORValue::Type::STRING);
+ EXPECT_EQ(cbor.value().GetString(), test_case.value);
+ }
+}
+
+TEST(CBORReaderTest, TestReadStringWithNUL) {
+ static const struct {
+ const std::string value;
+ const std::vector<uint8_t> cbor_data;
+ } kStringTestCases[] = {
+ {std::string("string_without_nul"),
+ {0x72, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x5F, 0x77, 0x69, 0x74, 0x68,
+ 0x6F, 0x75, 0x74, 0x5F, 0x6E, 0x75, 0x6C}},
+ {std::string("nul_terminated_string\0", 22),
+ {0x76, 0x6E, 0x75, 0x6C, 0x5F, 0x74, 0x65, 0x72, 0x6D, 0x69, 0x6E, 0x61,
+ 0x74, 0x65, 0x64, 0x5F, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x00}},
+ {std::string("embedded\0nul", 12),
+ {0x6C, 0x65, 0x6D, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x00, 0x6E, 0x75,
+ 0x6C}},
+ {std::string("trailing_nuls\0\0", 15),
+ {0x6F, 0x74, 0x72, 0x61, 0x69, 0x6C, 0x69, 0x6E, 0x67, 0x5F, 0x6E, 0x75,
+ 0x6C, 0x73, 0x00, 0x00}},
+ };
+
+ for (const auto& test_case : kStringTestCases) {
+ SCOPED_TRACE(testing::Message()
+ << "testing string with nul bytes :" << test_case.value);
+
+ base::Optional<CBORValue> cbor = CBORReader::Read(test_case.cbor_data);
+ ASSERT_TRUE(cbor.has_value());
+ ASSERT_EQ(cbor.value().type(), CBORValue::Type::STRING);
+ EXPECT_EQ(cbor.value().GetString(), test_case.value);
+ }
+}
+
+TEST(CBORReaderTest, TestReadStringWithInvalidByteSequenceAfterNUL) {
+ // UTF-8 validation should not stop at the first NUL character in the string.
+ // That is, a string with an invalid byte sequence should fail UTF-8
+ // validation even if the invalid character is located after one or more NUL
+ // characters. Here, 0xA6 is an unexpected continuation byte.
+ static const std::vector<uint8_t> string_with_invalid_continuation_byte = {
+ 0x63, 0x00, 0x00, 0xA6};
+ CBORReader::DecoderError error_code;
+ base::Optional<CBORValue> cbor =
+ CBORReader::Read(string_with_invalid_continuation_byte, &error_code);
+ EXPECT_FALSE(cbor.has_value());
+ EXPECT_EQ(error_code, CBORReader::DecoderError::INVALID_UTF8);
+}
+
+TEST(CBORReaderTest, TestReadArray) {
+ static const std::vector<uint8_t> kArrayTestCaseCbor = {
+ // clang-format off
+ 0x98, 0x19, // array of 25 elements
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+ 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x18, 0x18, 0x19,
+ // clang-format on
+ };
+
+ base::Optional<CBORValue> cbor = CBORReader::Read(kArrayTestCaseCbor);
+ ASSERT_TRUE(cbor.has_value());
+ const CBORValue cbor_array = std::move(cbor.value());
+ ASSERT_EQ(cbor_array.type(), CBORValue::Type::ARRAY);
+ ASSERT_THAT(cbor_array.GetArray(), testing::SizeIs(25));
+
+ std::vector<CBORValue> array;
+ for (int i = 0; i < 25; i++) {
+ SCOPED_TRACE(testing::Message() << "testing array element at index " << i);
+
+ ASSERT_EQ(cbor_array.GetArray()[i].type(), CBORValue::Type::UNSIGNED);
+ EXPECT_EQ(cbor_array.GetArray()[i].GetInteger(),
+ static_cast<int64_t>(i + 1));
+ }
+}
+
+TEST(CBORReaderTest, TestReadMapWithMapValue) {
+ static const std::vector<uint8_t> kMapTestCaseCbor = {
+ // clang-format off
+ 0xa4, // map with 4 key value pairs:
+ 0x18, 0x18, // 24
+ 0x63, 0x61, 0x62, 0x63, // "abc"
+
+ 0x60, // ""
+ 0x61, 0x2e, // "."
+
+ 0x61, 0x62, // "b"
+ 0x61, 0x42, // "B"
+
+ 0x62, 0x61, 0x61, // "aa"
+ 0x62, 0x41, 0x41, // "AA"
+ // clang-format on
+ };
+
+ base::Optional<CBORValue> cbor = CBORReader::Read(kMapTestCaseCbor);
+ ASSERT_TRUE(cbor.has_value());
+ const CBORValue cbor_val = std::move(cbor.value());
+ ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP);
+ ASSERT_EQ(cbor_val.GetMap().size(), 4u);
+
+ const CBORValue key_uint(24);
+ ASSERT_EQ(cbor_val.GetMap().count(key_uint), 1u);
+ ASSERT_EQ(cbor_val.GetMap().find(key_uint)->second.type(),
+ CBORValue::Type::STRING);
+ EXPECT_EQ(cbor_val.GetMap().find(key_uint)->second.GetString(), "abc");
+
+ const CBORValue key_empty_string("");
+ ASSERT_EQ(cbor_val.GetMap().count(key_empty_string), 1u);
+ ASSERT_EQ(cbor_val.GetMap().find(key_empty_string)->second.type(),
+ CBORValue::Type::STRING);
+ EXPECT_EQ(cbor_val.GetMap().find(key_empty_string)->second.GetString(), ".");
+
+ const CBORValue key_b("b");
+ ASSERT_EQ(cbor_val.GetMap().count(key_b), 1u);
+ ASSERT_EQ(cbor_val.GetMap().find(key_b)->second.type(),
+ CBORValue::Type::STRING);
+ EXPECT_EQ(cbor_val.GetMap().find(key_b)->second.GetString(), "B");
+
+ const CBORValue key_aa("aa");
+ ASSERT_EQ(cbor_val.GetMap().count(key_aa), 1u);
+ ASSERT_EQ(cbor_val.GetMap().find(key_aa)->second.type(),
+ CBORValue::Type::STRING);
+ EXPECT_EQ(cbor_val.GetMap().find(key_aa)->second.GetString(), "AA");
+}
+
+TEST(CBORReaderTest, TestReadMapWithIntegerKeys) {
+ static const std::vector<uint8_t> kMapWithIntegerKeyCbor = {
+ // clang-format off
+ 0xA4, // map with 4 key value pairs
+ 0x01, // key : 1
+ 0x61, 0x61, // value : "a"
+
+ 0x09, // key : 9
+ 0x61, 0x62, // value : "b"
+
+ 0x19, 0x03, 0xE7, // key : 999
+ 0x61, 0x63, // value "c"
+
+ 0x19, 0x04, 0x57, // key : 1111
+ 0x61, 0x64, // value : "d"
+ // clang-format on
+ };
+
+ base::Optional<CBORValue> cbor = CBORReader::Read(kMapWithIntegerKeyCbor);
+ ASSERT_TRUE(cbor.has_value());
+ const CBORValue cbor_val = std::move(cbor.value());
+ ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP);
+ ASSERT_EQ(cbor_val.GetMap().size(), 4u);
+
+ const CBORValue key_1(1);
+ ASSERT_EQ(cbor_val.GetMap().count(key_1), 1u);
+ ASSERT_EQ(cbor_val.GetMap().find(key_1)->second.type(),
+ CBORValue::Type::STRING);
+ EXPECT_EQ(cbor_val.GetMap().find(key_1)->second.GetString(), "a");
+
+ const CBORValue key_9(9);
+ ASSERT_EQ(cbor_val.GetMap().count(key_9), 1u);
+ ASSERT_EQ(cbor_val.GetMap().find(key_9)->second.type(),
+ CBORValue::Type::STRING);
+ EXPECT_EQ(cbor_val.GetMap().find(key_9)->second.GetString(), "b");
+
+ const CBORValue key_999(999);
+ ASSERT_EQ(cbor_val.GetMap().count(key_999), 1u);
+ ASSERT_EQ(cbor_val.GetMap().find(key_999)->second.type(),
+ CBORValue::Type::STRING);
+ EXPECT_EQ(cbor_val.GetMap().find(key_999)->second.GetString(), "c");
+
+ const CBORValue key_1111(1111);
+ ASSERT_EQ(cbor_val.GetMap().count(key_1111), 1u);
+ ASSERT_EQ(cbor_val.GetMap().find(key_1111)->second.type(),
+ CBORValue::Type::STRING);
+ EXPECT_EQ(cbor_val.GetMap().find(key_1111)->second.GetString(), "d");
+}
+
+TEST(CBORReaderTest, TestReadMapWithArray) {
+ static const std::vector<uint8_t> kMapArrayTestCaseCbor = {
+ // clang-format off
+ 0xa2, // map of 2 pairs
+ 0x61, 0x61, // "a"
+ 0x01,
+
+ 0x61, 0x62, // "b"
+ 0x82, // array with 2 elements
+ 0x02,
+ 0x03,
+ // clang-format on
+ };
+
+ base::Optional<CBORValue> cbor = CBORReader::Read(kMapArrayTestCaseCbor);
+ ASSERT_TRUE(cbor.has_value());
+ const CBORValue cbor_val = std::move(cbor.value());
+ ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP);
+ ASSERT_EQ(cbor_val.GetMap().size(), 2u);
+
+ const CBORValue key_a("a");
+ ASSERT_EQ(cbor_val.GetMap().count(key_a), 1u);
+ ASSERT_EQ(cbor_val.GetMap().find(key_a)->second.type(),
+ CBORValue::Type::UNSIGNED);
+ EXPECT_EQ(cbor_val.GetMap().find(key_a)->second.GetInteger(), 1u);
+
+ const CBORValue key_b("b");
+ ASSERT_EQ(cbor_val.GetMap().count(key_b), 1u);
+ ASSERT_EQ(cbor_val.GetMap().find(key_b)->second.type(),
+ CBORValue::Type::ARRAY);
+
+ const CBORValue nested_array = cbor_val.GetMap().find(key_b)->second.Clone();
+ ASSERT_EQ(nested_array.GetArray().size(), 2u);
+ for (int i = 0; i < 2; i++) {
+ ASSERT_THAT(nested_array.GetArray()[i].type(), CBORValue::Type::UNSIGNED);
+ EXPECT_EQ(nested_array.GetArray()[i].GetInteger(),
+ static_cast<int64_t>(i + 2));
+ }
+}
+
+TEST(CBORReaderTest, TestReadNestedMap) {
+ static const std::vector<uint8_t> kNestedMapTestCase = {
+ // clang-format off
+ 0xa2, // map of 2 pairs
+ 0x61, 0x61, // "a"
+ 0x01,
+
+ 0x61, 0x62, // "b"
+ 0xa2, // map of 2 pairs
+ 0x61, 0x63, // "c"
+ 0x02,
+
+ 0x61, 0x64, // "d"
+ 0x03,
+ // clang-format on
+ };
+
+ base::Optional<CBORValue> cbor = CBORReader::Read(kNestedMapTestCase);
+ ASSERT_TRUE(cbor.has_value());
+ const CBORValue cbor_val = std::move(cbor.value());
+ ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP);
+ ASSERT_EQ(cbor_val.GetMap().size(), 2u);
+
+ const CBORValue key_a("a");
+ ASSERT_EQ(cbor_val.GetMap().count(key_a), 1u);
+ ASSERT_EQ(cbor_val.GetMap().find(key_a)->second.type(),
+ CBORValue::Type::UNSIGNED);
+ EXPECT_EQ(cbor_val.GetMap().find(key_a)->second.GetInteger(), 1u);
+
+ const CBORValue key_b("b");
+ ASSERT_EQ(cbor_val.GetMap().count(key_b), 1u);
+ const CBORValue nested_map = cbor_val.GetMap().find(key_b)->second.Clone();
+ ASSERT_EQ(nested_map.type(), CBORValue::Type::MAP);
+ ASSERT_EQ(nested_map.GetMap().size(), 2u);
+
+ const CBORValue key_c("c");
+ ASSERT_EQ(nested_map.GetMap().count(key_c), 1u);
+ ASSERT_EQ(nested_map.GetMap().find(key_c)->second.type(),
+ CBORValue::Type::UNSIGNED);
+ EXPECT_EQ(nested_map.GetMap().find(key_c)->second.GetInteger(), 2u);
+
+ const CBORValue key_d("d");
+ ASSERT_EQ(nested_map.GetMap().count(key_d), 1u);
+ ASSERT_EQ(nested_map.GetMap().find(key_d)->second.type(),
+ CBORValue::Type::UNSIGNED);
+ EXPECT_EQ(nested_map.GetMap().find(key_d)->second.GetInteger(), 3u);
+}
+
+TEST(CBORReaderTest, TestIntegerRange) {
+ static const std::vector<uint8_t> kMaxPositiveInt = {
+ 0x1b, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+ static const std::vector<uint8_t> kMinNegativeInt = {
+ 0x3b, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+ base::Optional<CBORValue> max_positive_int =
+ CBORReader::Read(kMaxPositiveInt);
+ ASSERT_TRUE(max_positive_int.has_value());
+ EXPECT_EQ(max_positive_int.value().GetInteger(), INT64_MAX);
+
+ base::Optional<CBORValue> min_negative_int =
+ CBORReader::Read(kMinNegativeInt);
+ ASSERT_TRUE(min_negative_int.has_value());
+ EXPECT_EQ(min_negative_int.value().GetInteger(), INT64_MIN);
+}
+
+TEST(CBORReaderTest, TestIntegerOutOfRangeError) {
+ static const std::vector<uint8_t> kOutOfRangePositiveInt = {
+ 0x1b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ static const std::vector<uint8_t> kOutOfRangeNegativeInt = {
+ 0x3b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ CBORReader::DecoderError error_code;
+ base::Optional<CBORValue> positive_int_out_of_range_cbor =
+ CBORReader::Read(kOutOfRangePositiveInt, &error_code);
+ EXPECT_FALSE(positive_int_out_of_range_cbor.has_value());
+ EXPECT_EQ(error_code, CBORReader::DecoderError::OUT_OF_RANGE_INTEGER_VALUE);
+
+ base::Optional<CBORValue> negative_int_out_of_range_cbor =
+ CBORReader::Read(kOutOfRangeNegativeInt, &error_code);
+ EXPECT_FALSE(negative_int_out_of_range_cbor.has_value());
+ EXPECT_EQ(error_code, CBORReader::DecoderError::OUT_OF_RANGE_INTEGER_VALUE);
+}
+
+TEST(CBORReaderTest, TestReadSimpleValue) {
+ static const struct {
+ const CBORValue::SimpleValue value;
+ const std::vector<uint8_t> cbor_data;
+ } kSimpleValueTestCases[] = {
+ {CBORValue::SimpleValue::FALSE_VALUE, {0xf4}},
+ {CBORValue::SimpleValue::TRUE_VALUE, {0xf5}},
+ {CBORValue::SimpleValue::NULL_VALUE, {0xf6}},
+ {CBORValue::SimpleValue::UNDEFINED, {0xf7}},
+ };
+
+ int test_element_index = 0;
+ for (const auto& test_case : kSimpleValueTestCases) {
+ SCOPED_TRACE(testing::Message()
+ << "testing simple value at index : " << test_element_index++);
+
+ base::Optional<CBORValue> cbor = CBORReader::Read(test_case.cbor_data);
+ ASSERT_TRUE(cbor.has_value());
+ ASSERT_EQ(cbor.value().type(), CBORValue::Type::SIMPLE_VALUE);
+ EXPECT_EQ(cbor.value().GetSimpleValue(), test_case.value);
+ }
+}
+
+TEST(CBORReaderTest, TestReadUnsupportedFloatingPointNumbers) {
+ static const std::vector<uint8_t> floating_point_cbors[] = {
+ // 16 bit floating point value.
+ {0xf9, 0x10, 0x00},
+ // 32 bit floating point value.
+ {0xfa, 0x10, 0x00, 0x00, 0x00},
+ // 64 bit floating point value.
+ {0xfb, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+
+ for (const auto& unsupported_floating_point : floating_point_cbors) {
+ SCOPED_TRACE(testing::Message()
+ << "testing unsupported floating point : "
+ << testing::PrintToString(unsupported_floating_point));
+ CBORReader::DecoderError error_code;
+ base::Optional<CBORValue> cbor =
+ CBORReader::Read(unsupported_floating_point, &error_code);
+ EXPECT_FALSE(cbor.has_value());
+ EXPECT_EQ(error_code,
+ CBORReader::DecoderError::UNSUPPORTED_FLOATING_POINT_VALUE);
+ }
+}
+
+TEST(CBORReaderTest, TestIncompleteCBORDataError) {
+ static const std::vector<uint8_t> incomplete_cbor_list[] = {
+ // Additional info byte corresponds to unsigned int that corresponds
+ // to 2 additional bytes. But actual data encoded in one byte.
+ {0x19, 0x03},
+ // CBOR bytestring of length 3 encoded with additional info of length 4.
+ {0x44, 0x01, 0x02, 0x03},
+ // CBOR string data "IETF" of length 4 encoded with additional info of
+ // length 5.
+ {0x65, 0x49, 0x45, 0x54, 0x46},
+ // CBOR array of length 1 encoded with additional info of length 2.
+ {0x82, 0x02},
+ // CBOR map with single key value pair encoded with additional info of
+ // length 2.
+ {0xa2, 0x61, 0x61, 0x01},
+ };
+
+ int test_element_index = 0;
+ for (const auto& incomplete_data : incomplete_cbor_list) {
+ SCOPED_TRACE(testing::Message() << "testing incomplete data at index : "
+ << test_element_index++);
+
+ CBORReader::DecoderError error_code;
+ base::Optional<CBORValue> cbor =
+ CBORReader::Read(incomplete_data, &error_code);
+ EXPECT_FALSE(cbor.has_value());
+ EXPECT_EQ(error_code, CBORReader::DecoderError::INCOMPLETE_CBOR_DATA);
+ }
+}
+
+// While RFC 7049 allows CBOR map keys with all types, current decoder only
+// supports unsigned integer and string keys.
+TEST(CBORReaderTest, TestUnsupportedMapKeyFormatError) {
+ static const std::vector<uint8_t> kMapWithUintKey = {
+ // clang-format off
+ 0xa2, // map of 2 pairs
+
+ 0x82, 0x01, 0x02, // invalid key : [1, 2]
+ 0x02, // value : 2
+
+ 0x61, 0x64, // key : "d"
+ 0x03, // value : 3
+ // clang-format on
+ };
+
+ CBORReader::DecoderError error_code;
+ base::Optional<CBORValue> cbor =
+ CBORReader::Read(kMapWithUintKey, &error_code);
+ EXPECT_FALSE(cbor.has_value());
+ EXPECT_EQ(error_code, CBORReader::DecoderError::INCORRECT_MAP_KEY_TYPE);
+}
+
+TEST(CBORReaderTest, TestUnknownAdditionalInfoError) {
+ static const std::vector<uint8_t> kUnknownAdditionalInfoList[] = {
+ // "IETF" encoded with major type 3 and additional info of 28.
+ {0x7C, 0x49, 0x45, 0x54, 0x46},
+ // "\"\\" encoded with major type 3 and additional info of 29.
+ {0x7D, 0x22, 0x5c},
+ // "\xc3\xbc" encoded with major type 3 and additional info of 30.
+ {0x7E, 0xc3, 0xbc},
+ // "\xe6\xb0\xb4" encoded with major type 3 and additional info of 31.
+ {0x7F, 0xe6, 0xb0, 0xb4},
+ // Major type 7, additional information 28: unassigned.
+ {0xFC},
+ // Major type 7, additional information 29: unassigned.
+ {0xFD},
+ // Major type 7, additional information 30: unassigned.
+ {0xFE},
+ // Major type 7, additional information 31: "break" stop code for
+ // indefinite-length items.
+ {0xFF},
+ };
+
+ int test_element_index = 0;
+ for (const auto& incorrect_cbor : kUnknownAdditionalInfoList) {
+ SCOPED_TRACE(testing::Message()
+ << "testing data at index : " << test_element_index++);
+
+ CBORReader::DecoderError error_code;
+ base::Optional<CBORValue> cbor =
+ CBORReader::Read(incorrect_cbor, &error_code);
+ EXPECT_FALSE(cbor.has_value());
+ EXPECT_EQ(error_code, CBORReader::DecoderError::UNKNOWN_ADDITIONAL_INFO);
+ }
+}
+
+TEST(CBORReaderTest, TestTooMuchNestingError) {
+ static const std::vector<uint8_t> kZeroDepthCBORList[] = {
+ // Unsigned int with value 100.
+ {0x18, 0x64},
+ // CBOR bytestring of length 4.
+ {0x44, 0x01, 0x02, 0x03, 0x04},
+ // CBOR string of corresponding to "IETF.
+ {0x64, 0x49, 0x45, 0x54, 0x46},
+ // Empty CBOR array.
+ {0x80},
+ // Empty CBOR Map
+ {0xa0},
+ };
+
+ int test_element_index = 0;
+ for (const auto& zero_depth_data : kZeroDepthCBORList) {
+ SCOPED_TRACE(testing::Message()
+ << "testing zero nested data : " << test_element_index++);
+ CBORReader::DecoderError error_code;
+ base::Optional<CBORValue> cbor =
+ CBORReader::Read(zero_depth_data, &error_code, 0);
+ EXPECT_TRUE(cbor.has_value());
+ EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+ }
+
+ // Corresponds to a CBOR structure with a nesting depth of 2:
+ // {"a": 1,
+ // "b": [2, 3]}
+ static const std::vector<uint8_t> kNestedCBORData = {
+ // clang-format off
+ 0xa2, // map of 2 pairs
+ 0x61, 0x61, // "a"
+ 0x01,
+
+ 0x61, 0x62, // "b"
+ 0x82, // array with 2 elements
+ 0x02,
+ 0x03,
+ // clang-format on
+ };
+
+ CBORReader::DecoderError error_code;
+ base::Optional<CBORValue> cbor_single_layer_max =
+ CBORReader::Read(kNestedCBORData, &error_code, 1);
+ EXPECT_FALSE(cbor_single_layer_max.has_value());
+ EXPECT_EQ(error_code, CBORReader::DecoderError::TOO_MUCH_NESTING);
+
+ base::Optional<CBORValue> cbor_double_layer_max =
+ CBORReader::Read(kNestedCBORData, &error_code, 2);
+ EXPECT_TRUE(cbor_double_layer_max.has_value());
+ EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+}
+
+TEST(CBORReaderTest, TestOutOfOrderKeyError) {
+ static const std::vector<uint8_t> kMapsWithUnsortedKeys[] = {
+ // clang-format off
+ {0xa2, // map with 2 keys with same major type and length
+ 0x61, 0x62, // key "b"
+ 0x61, 0x42, // value :"B"
+
+ 0x61, 0x61, // key "a" (out of order byte-wise lexically)
+ 0x61, 0x45 // value "E"
+ },
+ {0xa2, // map with 2 keys with different major type
+ 0x61, 0x62, // key "b"
+ 0x02, // value 2
+
+ // key 1000 (out of order since lower major type sorts first)
+ 0x19, 0x03, 0xe8,
+ 0x61, 0x61, // value a
+ },
+ {0xa2, // map with 2 keys with same major type
+ 0x19, 0x03, 0xe8, // key 1000 (out of order due to longer length)
+ 0x61, 0x61, //value "a"
+
+ 0x0a, // key 10
+ 0x61, 0x62}, // value "b"
+ //clang-format on
+ };
+
+ int test_element_index = 0;
+ CBORReader::DecoderError error_code;
+ for (const auto& unsorted_map : kMapsWithUnsortedKeys) {
+ testing::Message scope_message;
+ scope_message << "testing unsorted map : " << test_element_index++;
+ SCOPED_TRACE(scope_message);
+
+ base::Optional<CBORValue> cbor =
+ CBORReader::Read(unsorted_map, &error_code);
+ EXPECT_FALSE(cbor.has_value());
+ EXPECT_EQ(error_code, CBORReader::DecoderError::OUT_OF_ORDER_KEY);
+ }
+}
+
+TEST(CBORReaderTest, TestDuplicateKeyError) {
+ static const std::vector<uint8_t> kMapWithDuplicateKey = {
+ // clang-format off
+ 0xa6, // map of 6 pairs:
+ 0x60, // ""
+ 0x61, 0x2e, // "."
+
+ 0x61, 0x62, // "b"
+ 0x61, 0x42, // "B"
+
+ 0x61, 0x62, // "b" (Duplicate key)
+ 0x61, 0x43, // "C"
+
+ 0x61, 0x64, // "d"
+ 0x61, 0x44, // "D"
+
+ 0x61, 0x65, // "e"
+ 0x61, 0x44, // "D"
+
+ 0x62, 0x61, 0x61, // "aa"
+ 0x62, 0x41, 0x41, // "AA"
+ // clang-format on
+ };
+
+ CBORReader::DecoderError error_code;
+
+ base::Optional<CBORValue> cbor =
+ CBORReader::Read(kMapWithDuplicateKey, &error_code);
+ EXPECT_FALSE(cbor.has_value());
+ EXPECT_EQ(error_code, CBORReader::DecoderError::DUPLICATE_KEY);
+}
+
+// Leveraging Markus Kuhn’s UTF-8 decoder stress test. See
+// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt for details.
+TEST(CBORReaderTest, TestIncorrectStringEncodingError) {
+ static const std::vector<uint8_t> utf8_character_encodings[] = {
+ // Corresponds to utf8 encoding of "퟿" (section 2.3.1 of stress test).
+ {0x63, 0xED, 0x9F, 0xBF},
+ // Corresponds to utf8 encoding of "" (section 2.3.2 of stress test).
+ {0x63, 0xEE, 0x80, 0x80},
+ // Corresponds to utf8 encoding of "�" (section 2.3.3 of stress test).
+ {0x63, 0xEF, 0xBF, 0xBD},
+ };
+
+ int test_element_index = 0;
+ CBORReader::DecoderError error_code;
+ for (const auto& cbor_byte : utf8_character_encodings) {
+ SCOPED_TRACE(testing::Message() << "testing cbor data utf8 encoding : "
+ << test_element_index++);
+
+ base::Optional<CBORValue> correctly_encoded_cbor =
+ CBORReader::Read(cbor_byte, &error_code);
+ EXPECT_TRUE(correctly_encoded_cbor.has_value());
+ EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+ }
+
+ // Incorrect UTF8 encoding referenced by section 3.5.3 of the stress test.
+ std::vector<uint8_t> impossible_utf_byte{0x64, 0xfe, 0xfe, 0xff, 0xff};
+ base::Optional<CBORValue> incorrectly_encoded_cbor =
+ CBORReader::Read(impossible_utf_byte, &error_code);
+ EXPECT_FALSE(incorrectly_encoded_cbor.has_value());
+ EXPECT_EQ(error_code, CBORReader::DecoderError::INVALID_UTF8);
+}
+
+TEST(CBORReaderTest, TestExtraneousCBORDataError) {
+ static const std::vector<uint8_t> zero_padded_cbor_list[] = {
+ // 1 extra byte after a 2-byte unsigned int.
+ {0x19, 0x03, 0x05, 0x00},
+ // 1 extra byte after a 4-byte cbor byte array.
+ {0x44, 0x01, 0x02, 0x03, 0x04, 0x00},
+ // 1 extra byte after a 4-byte string.
+ {0x64, 0x49, 0x45, 0x54, 0x46, 0x00},
+ // 1 extra byte after CBOR array of length 2.
+ {0x82, 0x01, 0x02, 0x00},
+ // 1 extra key value pair after CBOR map of size 2.
+ {0xa1, 0x61, 0x63, 0x02, 0x61, 0x64, 0x03},
+ };
+
+ int test_element_index = 0;
+ for (const auto& extraneous_cbor_data : zero_padded_cbor_list) {
+ SCOPED_TRACE(testing::Message()
+ << "testing cbor extraneous data : " << test_element_index++);
+
+ CBORReader::DecoderError error_code;
+ base::Optional<CBORValue> cbor =
+ CBORReader::Read(extraneous_cbor_data, &error_code);
+ EXPECT_FALSE(cbor.has_value());
+ EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA);
+ }
+}
+
+TEST(CBORReaderTest, TestUnsupportedSimplevalue) {
+ static const std::vector<uint8_t> unsupported_simple_values[] = {
+ // Simple value (0, unassigned)
+ {0xE0},
+ // Simple value (19, unassigned)
+ {0xF3},
+ // Simple value (24, reserved)
+ {0xF8, 0x18},
+ // Simple value (28, reserved)
+ {0xF8, 0x1C},
+ // Simple value (29, reserved)
+ {0xF8, 0x1D},
+ // Simple value (30, reserved)
+ {0xF8, 0x1E},
+ // Simple value (31, reserved)
+ {0xF8, 0x1F},
+ // Simple value (32, unassigned)
+ {0xF8, 0x20},
+ // Simple value (255, unassigned)
+ {0xF8, 0xFF},
+ };
+
+ for (const auto& unsupported_simple_val : unsupported_simple_values) {
+ SCOPED_TRACE(testing::Message()
+ << "testing unsupported cbor simple value : "
+ << ::testing::PrintToString(unsupported_simple_val));
+
+ CBORReader::DecoderError error_code;
+ base::Optional<CBORValue> cbor =
+ CBORReader::Read(unsupported_simple_val, &error_code);
+ EXPECT_FALSE(cbor.has_value());
+ EXPECT_EQ(error_code, CBORReader::DecoderError::UNSUPPORTED_SIMPLE_VALUE);
+ }
+}
+
+} // namespace cbor
diff --git a/chromium/components/cbor/cbor_values.cc b/chromium/components/cbor/cbor_values.cc
new file mode 100644
index 00000000000..b4517650b45
--- /dev/null
+++ b/chromium/components/cbor/cbor_values.cc
@@ -0,0 +1,226 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/cbor/cbor_values.h"
+
+#include <new>
+#include <utility>
+
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_util.h"
+
+namespace cbor {
+
+CBORValue::CBORValue() noexcept : type_(Type::NONE) {}
+
+CBORValue::CBORValue(CBORValue&& that) noexcept {
+ InternalMoveConstructFrom(std::move(that));
+}
+
+CBORValue::CBORValue(Type type) : type_(type) {
+ // Initialize with the default value.
+ switch (type_) {
+ case Type::UNSIGNED:
+ case Type::NEGATIVE:
+ integer_value_ = 0;
+ return;
+ case Type::BYTE_STRING:
+ new (&bytestring_value_) BinaryValue();
+ return;
+ case Type::STRING:
+ new (&string_value_) std::string();
+ return;
+ case Type::ARRAY:
+ new (&array_value_) ArrayValue();
+ return;
+ case Type::MAP:
+ new (&map_value_) MapValue();
+ return;
+ case Type::SIMPLE_VALUE:
+ simple_value_ = CBORValue::SimpleValue::UNDEFINED;
+ return;
+ case Type::NONE:
+ return;
+ }
+ NOTREACHED();
+}
+
+CBORValue::CBORValue(int integer_value)
+ : CBORValue(base::checked_cast<int64_t>(integer_value)) {}
+
+CBORValue::CBORValue(int64_t integer_value) : integer_value_(integer_value) {
+ type_ = integer_value >= 0 ? Type::UNSIGNED : Type::NEGATIVE;
+}
+
+CBORValue::CBORValue(const BinaryValue& in_bytes)
+ : type_(Type::BYTE_STRING), bytestring_value_(in_bytes) {}
+
+CBORValue::CBORValue(BinaryValue&& in_bytes) noexcept
+ : type_(Type::BYTE_STRING), bytestring_value_(std::move(in_bytes)) {}
+
+CBORValue::CBORValue(const char* in_string)
+ : CBORValue(std::string(in_string)) {}
+
+CBORValue::CBORValue(std::string&& in_string) noexcept
+ : type_(Type::STRING), string_value_(std::move(in_string)) {
+ DCHECK(base::IsStringUTF8(string_value_));
+}
+
+CBORValue::CBORValue(base::StringPiece in_string)
+ : CBORValue(in_string.as_string()) {}
+
+CBORValue::CBORValue(const ArrayValue& in_array)
+ : type_(Type::ARRAY), array_value_() {
+ array_value_.reserve(in_array.size());
+ for (const auto& val : in_array)
+ array_value_.emplace_back(val.Clone());
+}
+
+CBORValue::CBORValue(ArrayValue&& in_array) noexcept
+ : type_(Type::ARRAY), array_value_(std::move(in_array)) {}
+
+CBORValue::CBORValue(const MapValue& in_map) : type_(Type::MAP), map_value_() {
+ map_value_.reserve(in_map.size());
+ for (const auto& it : in_map)
+ map_value_.emplace_hint(map_value_.end(), it.first.Clone(),
+ it.second.Clone());
+}
+
+CBORValue::CBORValue(MapValue&& in_map) noexcept
+ : type_(Type::MAP), map_value_(std::move(in_map)) {}
+
+CBORValue::CBORValue(SimpleValue in_simple)
+ : type_(Type::SIMPLE_VALUE), simple_value_(in_simple) {
+ CHECK(static_cast<int>(in_simple) >= 20 && static_cast<int>(in_simple) <= 23);
+}
+
+CBORValue& CBORValue::operator=(CBORValue&& that) noexcept {
+ InternalCleanup();
+ InternalMoveConstructFrom(std::move(that));
+
+ return *this;
+}
+
+CBORValue::~CBORValue() {
+ InternalCleanup();
+}
+
+CBORValue CBORValue::Clone() const {
+ switch (type_) {
+ case Type::NONE:
+ return CBORValue();
+ case Type::UNSIGNED:
+ case Type::NEGATIVE:
+ return CBORValue(integer_value_);
+ case Type::BYTE_STRING:
+ return CBORValue(bytestring_value_);
+ case Type::STRING:
+ return CBORValue(string_value_);
+ case Type::ARRAY:
+ return CBORValue(array_value_);
+ case Type::MAP:
+ return CBORValue(map_value_);
+ case Type::SIMPLE_VALUE:
+ return CBORValue(simple_value_);
+ }
+
+ NOTREACHED();
+ return CBORValue();
+}
+
+const int64_t& CBORValue::GetInteger() const {
+ CHECK(is_integer());
+ return integer_value_;
+}
+
+const int64_t& CBORValue::GetUnsigned() const {
+ CHECK(is_unsigned());
+ CHECK_GE(integer_value_, 0);
+ return integer_value_;
+}
+
+const int64_t& CBORValue::GetNegative() const {
+ CHECK(is_negative());
+ CHECK_LT(integer_value_, 0);
+ return integer_value_;
+}
+
+const std::string& CBORValue::GetString() const {
+ CHECK(is_string());
+ return string_value_;
+}
+
+const CBORValue::BinaryValue& CBORValue::GetBytestring() const {
+ CHECK(is_bytestring());
+ return bytestring_value_;
+}
+
+const CBORValue::ArrayValue& CBORValue::GetArray() const {
+ CHECK(is_array());
+ return array_value_;
+}
+
+const CBORValue::MapValue& CBORValue::GetMap() const {
+ CHECK(is_map());
+ return map_value_;
+}
+
+CBORValue::SimpleValue CBORValue::GetSimpleValue() const {
+ CHECK(is_simple());
+ return simple_value_;
+}
+
+void CBORValue::InternalMoveConstructFrom(CBORValue&& that) {
+ type_ = that.type_;
+
+ switch (type_) {
+ case Type::UNSIGNED:
+ case Type::NEGATIVE:
+ integer_value_ = that.integer_value_;
+ return;
+ case Type::BYTE_STRING:
+ new (&bytestring_value_) BinaryValue(std::move(that.bytestring_value_));
+ return;
+ case Type::STRING:
+ new (&string_value_) std::string(std::move(that.string_value_));
+ return;
+ case Type::ARRAY:
+ new (&array_value_) ArrayValue(std::move(that.array_value_));
+ return;
+ case Type::MAP:
+ new (&map_value_) MapValue(std::move(that.map_value_));
+ return;
+ case Type::SIMPLE_VALUE:
+ simple_value_ = that.simple_value_;
+ return;
+ case Type::NONE:
+ return;
+ }
+ NOTREACHED();
+}
+
+void CBORValue::InternalCleanup() {
+ switch (type_) {
+ case Type::BYTE_STRING:
+ bytestring_value_.~BinaryValue();
+ break;
+ case Type::STRING:
+ string_value_.~basic_string();
+ break;
+ case Type::ARRAY:
+ array_value_.~ArrayValue();
+ break;
+ case Type::MAP:
+ map_value_.~MapValue();
+ break;
+ case Type::NONE:
+ case Type::UNSIGNED:
+ case Type::NEGATIVE:
+ case Type::SIMPLE_VALUE:
+ break;
+ }
+ type_ = Type::NONE;
+}
+
+} // namespace cbor
diff --git a/chromium/components/cbor/cbor_values.h b/chromium/components/cbor/cbor_values.h
new file mode 100644
index 00000000000..53eea212a0c
--- /dev/null
+++ b/chromium/components/cbor/cbor_values.h
@@ -0,0 +1,171 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_CBOR_CBOR_VALUES_H_
+#define COMPONENTS_CBOR_CBOR_VALUES_H_
+
+#include <stdint.h>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include "base/containers/flat_map.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "components/cbor/cbor_export.h"
+
+namespace cbor {
+
+// A class for Concise Binary Object Representation (CBOR) values.
+// This does not support:
+// * Floating-point numbers.
+// * Indefinite-length encodings.
+class CBOR_EXPORT CBORValue {
+ public:
+ struct CTAPLess {
+ // Comparison predicate to order keys in a dictionary as required by the
+ // Client-to-Authenticator Protocol (CTAP) spec 2.0.
+ //
+ // The sort order defined in CTAP is:
+ // • If the major types are different, the one with the lower value in
+ // numerical order sorts earlier.
+ // • If two keys have different lengths, the shorter one sorts earlier.
+ // • If two keys have the same length, the one with the lower value in
+ // (byte-wise) lexical order sorts earlier.
+ //
+ // See section 6 of https://fidoalliance.org/specs/fido-v2.0-rd-20170927/
+ // fido-client-to-authenticator-protocol-v2.0-rd-20170927.html.
+ //
+ // THE CTAP SORT ORDER IMPLEMENTED HERE DIFFERS FROM THE CANONICAL CBOR
+ // ORDER defined in https://tools.ietf.org/html/rfc7049#section-3.9, in that
+ // the latter sorts purely by serialised key and doesn't specify that major
+ // types are compared first. Thus the shortest key sorts first by the RFC
+ // rules (irrespective of the major type), but may not by CTAP rules.
+ bool operator()(const CBORValue& a, const CBORValue& b) const {
+ DCHECK((a.is_integer() || a.is_string()) &&
+ (b.is_integer() || b.is_string()));
+ if (a.type() != b.type())
+ return a.type() < b.type();
+ switch (a.type()) {
+ case Type::UNSIGNED:
+ return a.GetInteger() < b.GetInteger();
+ case Type::NEGATIVE:
+ return a.GetInteger() > b.GetInteger();
+ case Type::STRING: {
+ const auto& a_str = a.GetString();
+ const size_t a_length = a_str.size();
+ const auto& b_str = b.GetString();
+ const size_t b_length = b_str.size();
+ return std::tie(a_length, a_str) < std::tie(b_length, b_str);
+ }
+ default:
+ break;
+ }
+
+ NOTREACHED();
+ return false;
+ }
+
+ using is_transparent = void;
+ };
+
+ using BinaryValue = std::vector<uint8_t>;
+ using ArrayValue = std::vector<CBORValue>;
+ using MapValue = base::flat_map<CBORValue, CBORValue, CTAPLess>;
+
+ enum class Type {
+ UNSIGNED = 0,
+ NEGATIVE = 1,
+ BYTE_STRING = 2,
+ STRING = 3,
+ ARRAY = 4,
+ MAP = 5,
+ SIMPLE_VALUE = 7,
+ NONE = -1,
+ };
+
+ enum class SimpleValue {
+ FALSE_VALUE = 20,
+ TRUE_VALUE = 21,
+ NULL_VALUE = 22,
+ UNDEFINED = 23,
+ };
+
+ CBORValue(CBORValue&& that) noexcept;
+ CBORValue() noexcept; // A NONE value.
+
+ explicit CBORValue(Type type);
+ explicit CBORValue(int integer_value);
+ explicit CBORValue(int64_t integer_value);
+ explicit CBORValue(uint64_t integer_value) = delete;
+
+ explicit CBORValue(const BinaryValue& in_bytes);
+ explicit CBORValue(BinaryValue&& in_bytes) noexcept;
+
+ explicit CBORValue(const char* in_string);
+ explicit CBORValue(std::string&& in_string) noexcept;
+ explicit CBORValue(base::StringPiece in_string);
+
+ explicit CBORValue(const ArrayValue& in_array);
+ explicit CBORValue(ArrayValue&& in_array) noexcept;
+
+ explicit CBORValue(const MapValue& in_map);
+ explicit CBORValue(MapValue&& in_map) noexcept;
+
+ explicit CBORValue(SimpleValue in_simple);
+
+ CBORValue& operator=(CBORValue&& that) noexcept;
+
+ ~CBORValue();
+
+ // CBORValue's copy constructor and copy assignment operator are deleted.
+ // Use this to obtain a deep copy explicitly.
+ CBORValue Clone() const;
+
+ // Returns the type of the value stored by the current Value object.
+ Type type() const { return type_; }
+
+ // Returns true if the current object represents a given type.
+ bool is_type(Type type) const { return type == type_; }
+ bool is_none() const { return type() == Type::NONE; }
+ bool is_unsigned() const { return type() == Type::UNSIGNED; }
+ bool is_negative() const { return type() == Type::NEGATIVE; }
+ bool is_integer() const { return is_unsigned() || is_negative(); }
+ bool is_bytestring() const { return type() == Type::BYTE_STRING; }
+ bool is_string() const { return type() == Type::STRING; }
+ bool is_array() const { return type() == Type::ARRAY; }
+ bool is_map() const { return type() == Type::MAP; }
+ bool is_simple() const { return type() == Type::SIMPLE_VALUE; }
+
+ // These will all fatally assert if the type doesn't match.
+ SimpleValue GetSimpleValue() const;
+ const int64_t& GetInteger() const;
+ const int64_t& GetUnsigned() const;
+ const int64_t& GetNegative() const;
+ const BinaryValue& GetBytestring() const;
+ // Returned string may contain NUL characters.
+ const std::string& GetString() const;
+ const ArrayValue& GetArray() const;
+ const MapValue& GetMap() const;
+
+ private:
+ Type type_;
+
+ union {
+ SimpleValue simple_value_;
+ int64_t integer_value_;
+ BinaryValue bytestring_value_;
+ std::string string_value_;
+ ArrayValue array_value_;
+ MapValue map_value_;
+ };
+
+ void InternalMoveConstructFrom(CBORValue&& that);
+ void InternalCleanup();
+
+ DISALLOW_COPY_AND_ASSIGN(CBORValue);
+};
+} // namespace cbor
+
+#endif // COMPONENTS_CBOR_CBOR_VALUES_H_
diff --git a/chromium/components/cbor/cbor_values_unittest.cc b/chromium/components/cbor/cbor_values_unittest.cc
new file mode 100644
index 00000000000..b003e83be9b
--- /dev/null
+++ b/chromium/components/cbor/cbor_values_unittest.cc
@@ -0,0 +1,354 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/cbor/cbor_values.h"
+
+#include <string>
+#include <utility>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cbor {
+
+TEST(CBORValuesTest, TestNothrow) {
+ static_assert(std::is_nothrow_move_constructible<CBORValue>::value,
+ "IsNothrowMoveConstructible");
+ static_assert(std::is_nothrow_default_constructible<CBORValue>::value,
+ "IsNothrowDefaultConstructible");
+ static_assert(std::is_nothrow_constructible<CBORValue, std::string&&>::value,
+ "IsNothrowMoveConstructibleFromString");
+ static_assert(
+ std::is_nothrow_constructible<CBORValue, CBORValue::BinaryValue&&>::value,
+ "IsNothrowMoveConstructibleFromBytestring");
+ static_assert(
+ std::is_nothrow_constructible<CBORValue, CBORValue::ArrayValue&&>::value,
+ "IsNothrowMoveConstructibleFromArray");
+ static_assert(std::is_nothrow_move_assignable<CBORValue>::value,
+ "IsNothrowMoveAssignable");
+}
+
+// Test constructors
+TEST(CBORValuesTest, ConstructUnsigned) {
+ CBORValue value(37);
+ ASSERT_EQ(CBORValue::Type::UNSIGNED, value.type());
+ EXPECT_EQ(37u, value.GetInteger());
+}
+
+TEST(CBORValuesTest, ConstructNegative) {
+ CBORValue value(-1);
+ ASSERT_EQ(CBORValue::Type::NEGATIVE, value.type());
+ EXPECT_EQ(-1, value.GetInteger());
+}
+
+TEST(CBORValuesTest, ConstructStringFromConstCharPtr) {
+ const char* str = "foobar";
+ CBORValue value(str);
+ ASSERT_EQ(CBORValue::Type::STRING, value.type());
+ EXPECT_EQ("foobar", value.GetString());
+}
+
+TEST(CBORValuesTest, ConstructStringFromStdStringConstRef) {
+ std::string str = "foobar";
+ CBORValue value(str);
+ ASSERT_EQ(CBORValue::Type::STRING, value.type());
+ EXPECT_EQ("foobar", value.GetString());
+}
+
+TEST(CBORValuesTest, ConstructStringFromStdStringRefRef) {
+ std::string str = "foobar";
+ CBORValue value(std::move(str));
+ ASSERT_EQ(CBORValue::Type::STRING, value.type());
+ EXPECT_EQ("foobar", value.GetString());
+}
+
+TEST(CBORValuesTest, ConstructBytestring) {
+ CBORValue value(CBORValue::BinaryValue({0xF, 0x0, 0x0, 0xB, 0xA, 0x2}));
+ ASSERT_EQ(CBORValue::Type::BYTE_STRING, value.type());
+ EXPECT_EQ(CBORValue::BinaryValue({0xF, 0x0, 0x0, 0xB, 0xA, 0x2}),
+ value.GetBytestring());
+}
+
+TEST(CBORValuesTest, ConstructArray) {
+ CBORValue::ArrayValue array;
+ array.emplace_back(CBORValue("foo"));
+ {
+ CBORValue value(array);
+ ASSERT_EQ(CBORValue::Type::ARRAY, value.type());
+ ASSERT_EQ(1u, value.GetArray().size());
+ ASSERT_EQ(CBORValue::Type::STRING, value.GetArray()[0].type());
+ EXPECT_EQ("foo", value.GetArray()[0].GetString());
+ }
+
+ array.back() = CBORValue("bar");
+ {
+ CBORValue value(std::move(array));
+ ASSERT_EQ(CBORValue::Type::ARRAY, value.type());
+ ASSERT_EQ(1u, value.GetArray().size());
+ ASSERT_EQ(CBORValue::Type::STRING, value.GetArray()[0].type());
+ EXPECT_EQ("bar", value.GetArray()[0].GetString());
+ }
+}
+
+TEST(CBORValuesTest, ConstructMap) {
+ CBORValue::MapValue map;
+ const CBORValue key_foo("foo");
+ map[CBORValue("foo")] = CBORValue("bar");
+ {
+ CBORValue value(map);
+ ASSERT_EQ(CBORValue::Type::MAP, value.type());
+ ASSERT_EQ(value.GetMap().count(key_foo), 1u);
+ ASSERT_EQ(CBORValue::Type::STRING,
+ value.GetMap().find(key_foo)->second.type());
+ EXPECT_EQ("bar", value.GetMap().find(key_foo)->second.GetString());
+ }
+
+ map[CBORValue("foo")] = CBORValue("baz");
+ {
+ CBORValue value(std::move(map));
+ ASSERT_EQ(CBORValue::Type::MAP, value.type());
+ ASSERT_EQ(value.GetMap().count(key_foo), 1u);
+ ASSERT_EQ(CBORValue::Type::STRING,
+ value.GetMap().find(key_foo)->second.type());
+ EXPECT_EQ("baz", value.GetMap().find(key_foo)->second.GetString());
+ }
+}
+
+TEST(CBORValuesTest, ConstructSimpleValue) {
+ CBORValue false_value(CBORValue::SimpleValue::FALSE_VALUE);
+ ASSERT_EQ(CBORValue::Type::SIMPLE_VALUE, false_value.type());
+ EXPECT_EQ(CBORValue::SimpleValue::FALSE_VALUE, false_value.GetSimpleValue());
+
+ CBORValue true_value(CBORValue::SimpleValue::TRUE_VALUE);
+ ASSERT_EQ(CBORValue::Type::SIMPLE_VALUE, true_value.type());
+ EXPECT_EQ(CBORValue::SimpleValue::TRUE_VALUE, true_value.GetSimpleValue());
+
+ CBORValue null_value(CBORValue::SimpleValue::NULL_VALUE);
+ ASSERT_EQ(CBORValue::Type::SIMPLE_VALUE, null_value.type());
+ EXPECT_EQ(CBORValue::SimpleValue::NULL_VALUE, null_value.GetSimpleValue());
+
+ CBORValue undefined_value(CBORValue::SimpleValue::UNDEFINED);
+ ASSERT_EQ(CBORValue::Type::SIMPLE_VALUE, undefined_value.type());
+ EXPECT_EQ(CBORValue::SimpleValue::UNDEFINED,
+ undefined_value.GetSimpleValue());
+}
+
+// Test copy constructors
+TEST(CBORValuesTest, CopyUnsigned) {
+ CBORValue value(74);
+ CBORValue copied_value(value.Clone());
+ ASSERT_EQ(value.type(), copied_value.type());
+ EXPECT_EQ(value.GetInteger(), copied_value.GetInteger());
+
+ CBORValue blank;
+
+ blank = value.Clone();
+ ASSERT_EQ(value.type(), blank.type());
+ EXPECT_EQ(value.GetInteger(), blank.GetInteger());
+}
+
+TEST(CBORValuesTest, CopyNegativeInt) {
+ CBORValue value(-74);
+ CBORValue copied_value(value.Clone());
+ ASSERT_EQ(value.type(), copied_value.type());
+ EXPECT_EQ(value.GetInteger(), copied_value.GetInteger());
+
+ CBORValue blank;
+
+ blank = value.Clone();
+ ASSERT_EQ(value.type(), blank.type());
+ EXPECT_EQ(value.GetInteger(), blank.GetInteger());
+}
+
+TEST(CBORValuesTest, CopyString) {
+ CBORValue value("foobar");
+ CBORValue copied_value(value.Clone());
+ ASSERT_EQ(value.type(), copied_value.type());
+ EXPECT_EQ(value.GetString(), copied_value.GetString());
+
+ CBORValue blank;
+
+ blank = value.Clone();
+ ASSERT_EQ(value.type(), blank.type());
+ EXPECT_EQ(value.GetString(), blank.GetString());
+}
+
+TEST(CBORValuesTest, CopyBytestring) {
+ CBORValue value(CBORValue::BinaryValue({0xF, 0x0, 0x0, 0xB, 0xA, 0x2}));
+ CBORValue copied_value(value.Clone());
+ ASSERT_EQ(value.type(), copied_value.type());
+ EXPECT_EQ(value.GetBytestring(), copied_value.GetBytestring());
+
+ CBORValue blank;
+
+ blank = value.Clone();
+ ASSERT_EQ(value.type(), blank.type());
+ EXPECT_EQ(value.GetBytestring(), blank.GetBytestring());
+}
+
+TEST(CBORValuesTest, CopyArray) {
+ CBORValue::ArrayValue array;
+ array.emplace_back(123);
+ CBORValue value(std::move(array));
+
+ CBORValue copied_value(value.Clone());
+ ASSERT_EQ(1u, copied_value.GetArray().size());
+ ASSERT_TRUE(copied_value.GetArray()[0].is_unsigned());
+ EXPECT_EQ(value.GetArray()[0].GetInteger(),
+ copied_value.GetArray()[0].GetInteger());
+
+ CBORValue blank;
+ blank = value.Clone();
+ EXPECT_EQ(1u, blank.GetArray().size());
+}
+
+TEST(CBORValuesTest, CopyMap) {
+ CBORValue::MapValue map;
+ CBORValue key_a("a");
+ map[CBORValue("a")] = CBORValue(123);
+ CBORValue value(std::move(map));
+
+ CBORValue copied_value(value.Clone());
+ EXPECT_EQ(1u, copied_value.GetMap().size());
+ ASSERT_EQ(value.GetMap().count(key_a), 1u);
+ ASSERT_EQ(copied_value.GetMap().count(key_a), 1u);
+ ASSERT_TRUE(copied_value.GetMap().find(key_a)->second.is_unsigned());
+ EXPECT_EQ(value.GetMap().find(key_a)->second.GetInteger(),
+ copied_value.GetMap().find(key_a)->second.GetInteger());
+
+ CBORValue blank;
+ blank = value.Clone();
+ EXPECT_EQ(1u, blank.GetMap().size());
+ ASSERT_EQ(blank.GetMap().count(key_a), 1u);
+ ASSERT_TRUE(blank.GetMap().find(key_a)->second.is_unsigned());
+ EXPECT_EQ(value.GetMap().find(key_a)->second.GetInteger(),
+ blank.GetMap().find(key_a)->second.GetInteger());
+}
+
+TEST(CBORValuesTest, CopySimpleValue) {
+ CBORValue value(CBORValue::SimpleValue::TRUE_VALUE);
+ CBORValue copied_value(value.Clone());
+ EXPECT_EQ(value.type(), copied_value.type());
+ EXPECT_EQ(value.GetSimpleValue(), copied_value.GetSimpleValue());
+
+ CBORValue blank;
+
+ blank = value.Clone();
+ EXPECT_EQ(value.type(), blank.type());
+ EXPECT_EQ(value.GetSimpleValue(), blank.GetSimpleValue());
+}
+
+// Test move constructors and move-assignment
+TEST(CBORValuesTest, MoveUnsigned) {
+ CBORValue value(74);
+ CBORValue moved_value(std::move(value));
+ EXPECT_EQ(CBORValue::Type::UNSIGNED, moved_value.type());
+ EXPECT_EQ(74u, moved_value.GetInteger());
+
+ CBORValue blank;
+
+ blank = CBORValue(654);
+ EXPECT_EQ(CBORValue::Type::UNSIGNED, blank.type());
+ EXPECT_EQ(654u, blank.GetInteger());
+}
+
+TEST(CBORValuesTest, MoveNegativeInteger) {
+ CBORValue value(-74);
+ CBORValue moved_value(std::move(value));
+ EXPECT_EQ(CBORValue::Type::NEGATIVE, moved_value.type());
+ EXPECT_EQ(-74, moved_value.GetInteger());
+
+ CBORValue blank;
+
+ blank = CBORValue(-654);
+ EXPECT_EQ(CBORValue::Type::NEGATIVE, blank.type());
+ EXPECT_EQ(-654, blank.GetInteger());
+}
+
+TEST(CBORValuesTest, MoveString) {
+ CBORValue value("foobar");
+ CBORValue moved_value(std::move(value));
+ EXPECT_EQ(CBORValue::Type::STRING, moved_value.type());
+ EXPECT_EQ("foobar", moved_value.GetString());
+
+ CBORValue blank;
+
+ blank = CBORValue("foobar");
+ EXPECT_EQ(CBORValue::Type::STRING, blank.type());
+ EXPECT_EQ("foobar", blank.GetString());
+}
+
+TEST(CBORValuesTest, MoveBytestring) {
+ const CBORValue::BinaryValue bytes({0xF, 0x0, 0x0, 0xB, 0xA, 0x2});
+ CBORValue value(bytes);
+ CBORValue moved_value(std::move(value));
+ EXPECT_EQ(CBORValue::Type::BYTE_STRING, moved_value.type());
+ EXPECT_EQ(bytes, moved_value.GetBytestring());
+
+ CBORValue blank;
+
+ blank = CBORValue(bytes);
+ EXPECT_EQ(CBORValue::Type::BYTE_STRING, blank.type());
+ EXPECT_EQ(bytes, blank.GetBytestring());
+}
+
+TEST(CBORValuesTest, MoveConstructMap) {
+ CBORValue::MapValue map;
+ const CBORValue key_a("a");
+ map[CBORValue("a")] = CBORValue(123);
+
+ CBORValue value(std::move(map));
+ CBORValue moved_value(std::move(value));
+ ASSERT_EQ(CBORValue::Type::MAP, moved_value.type());
+ ASSERT_EQ(moved_value.GetMap().count(key_a), 1u);
+ ASSERT_TRUE(moved_value.GetMap().find(key_a)->second.is_unsigned());
+ EXPECT_EQ(123u, moved_value.GetMap().find(key_a)->second.GetInteger());
+}
+
+TEST(CBORValuesTest, MoveAssignMap) {
+ CBORValue::MapValue map;
+ const CBORValue key_a("a");
+ map[CBORValue("a")] = CBORValue(123);
+
+ CBORValue blank;
+ blank = CBORValue(std::move(map));
+ ASSERT_TRUE(blank.is_map());
+ ASSERT_EQ(blank.GetMap().count(key_a), 1u);
+ ASSERT_TRUE(blank.GetMap().find(key_a)->second.is_unsigned());
+ EXPECT_EQ(123u, blank.GetMap().find(key_a)->second.GetInteger());
+}
+
+TEST(CBORValuesTest, MoveArray) {
+ CBORValue::ArrayValue array;
+ array.emplace_back(123);
+ CBORValue value(array);
+ CBORValue moved_value(std::move(value));
+ EXPECT_EQ(CBORValue::Type::ARRAY, moved_value.type());
+ EXPECT_EQ(123u, moved_value.GetArray().back().GetInteger());
+
+ CBORValue blank;
+ blank = CBORValue(std::move(array));
+ EXPECT_EQ(CBORValue::Type::ARRAY, blank.type());
+ EXPECT_EQ(123u, blank.GetArray().back().GetInteger());
+}
+
+TEST(CBORValuesTest, MoveSimpleValue) {
+ CBORValue value(CBORValue::SimpleValue::UNDEFINED);
+ CBORValue moved_value(std::move(value));
+ EXPECT_EQ(CBORValue::Type::SIMPLE_VALUE, moved_value.type());
+ EXPECT_EQ(CBORValue::SimpleValue::UNDEFINED, moved_value.GetSimpleValue());
+
+ CBORValue blank;
+
+ blank = CBORValue(CBORValue::SimpleValue::UNDEFINED);
+ EXPECT_EQ(CBORValue::Type::SIMPLE_VALUE, blank.type());
+ EXPECT_EQ(CBORValue::SimpleValue::UNDEFINED, blank.GetSimpleValue());
+}
+
+TEST(CBORValuesTest, SelfSwap) {
+ CBORValue test(1);
+ std::swap(test, test);
+ EXPECT_EQ(test.GetInteger(), 1u);
+}
+
+} // namespace cbor
diff --git a/chromium/components/cbor/cbor_writer.cc b/chromium/components/cbor/cbor_writer.cc
new file mode 100644
index 00000000000..d6e09fa54af
--- /dev/null
+++ b/chromium/components/cbor/cbor_writer.cc
@@ -0,0 +1,176 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/cbor/cbor_writer.h"
+
+#include <string>
+
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_piece.h"
+#include "components/cbor/cbor_binary.h"
+
+namespace cbor {
+
+CBORWriter::~CBORWriter() {}
+
+// static
+base::Optional<std::vector<uint8_t>> CBORWriter::Write(
+ const CBORValue& node,
+ size_t max_nesting_level) {
+ std::vector<uint8_t> cbor;
+ CBORWriter writer(&cbor);
+ if (writer.EncodeCBOR(node, base::checked_cast<int>(max_nesting_level)))
+ return cbor;
+ return base::nullopt;
+}
+
+CBORWriter::CBORWriter(std::vector<uint8_t>* cbor) : encoded_cbor_(cbor) {}
+
+bool CBORWriter::EncodeCBOR(const CBORValue& node, int max_nesting_level) {
+ if (max_nesting_level < 0)
+ return false;
+
+ switch (node.type()) {
+ case CBORValue::Type::NONE: {
+ StartItem(CBORValue::Type::BYTE_STRING, 0);
+ return true;
+ }
+
+ // Represents unsigned integers.
+ case CBORValue::Type::UNSIGNED: {
+ int64_t value = node.GetUnsigned();
+ StartItem(CBORValue::Type::UNSIGNED, static_cast<uint64_t>(value));
+ return true;
+ }
+
+ // Represents negative integers.
+ case CBORValue::Type::NEGATIVE: {
+ int64_t value = node.GetNegative();
+ StartItem(CBORValue::Type::NEGATIVE, static_cast<uint64_t>(-(value + 1)));
+ return true;
+ }
+
+ // Represents a byte string.
+ case CBORValue::Type::BYTE_STRING: {
+ const CBORValue::BinaryValue& bytes = node.GetBytestring();
+ StartItem(CBORValue::Type::BYTE_STRING,
+ base::strict_cast<uint64_t>(bytes.size()));
+ // Add the bytes.
+ encoded_cbor_->insert(encoded_cbor_->end(), bytes.begin(), bytes.end());
+ return true;
+ }
+
+ case CBORValue::Type::STRING: {
+ base::StringPiece string = node.GetString();
+ StartItem(CBORValue::Type::STRING,
+ base::strict_cast<uint64_t>(string.size()));
+
+ // Add the characters.
+ encoded_cbor_->insert(encoded_cbor_->end(), string.begin(), string.end());
+ return true;
+ }
+
+ // Represents an array.
+ case CBORValue::Type::ARRAY: {
+ const CBORValue::ArrayValue& array = node.GetArray();
+ StartItem(CBORValue::Type::ARRAY, array.size());
+ for (const auto& value : array) {
+ if (!EncodeCBOR(value, max_nesting_level - 1))
+ return false;
+ }
+ return true;
+ }
+
+ // Represents a map.
+ case CBORValue::Type::MAP: {
+ const CBORValue::MapValue& map = node.GetMap();
+ StartItem(CBORValue::Type::MAP, map.size());
+
+ for (const auto& value : map) {
+ if (!EncodeCBOR(value.first, max_nesting_level - 1))
+ return false;
+ if (!EncodeCBOR(value.second, max_nesting_level - 1))
+ return false;
+ }
+ return true;
+ }
+
+ // Represents a simple value.
+ case CBORValue::Type::SIMPLE_VALUE: {
+ const CBORValue::SimpleValue simple_value = node.GetSimpleValue();
+ StartItem(CBORValue::Type::SIMPLE_VALUE,
+ base::checked_cast<uint64_t>(simple_value));
+ return true;
+ }
+
+ default:
+ break;
+ }
+ NOTREACHED();
+ return false;
+}
+
+void CBORWriter::StartItem(CBORValue::Type type, uint64_t size) {
+ encoded_cbor_->push_back(base::checked_cast<uint8_t>(
+ static_cast<unsigned>(type) << constants::kMajorTypeBitShift));
+ SetUint(size);
+}
+
+void CBORWriter::SetAdditionalInformation(uint8_t additional_information) {
+ DCHECK(!encoded_cbor_->empty());
+ DCHECK_EQ(additional_information & constants::kAdditionalInformationMask,
+ additional_information);
+ encoded_cbor_->back() |=
+ (additional_information & constants::kAdditionalInformationMask);
+}
+
+void CBORWriter::SetUint(uint64_t value) {
+ size_t count = GetNumUintBytes(value);
+ int shift = -1;
+ // Values under 24 are encoded directly in the initial byte.
+ // Otherwise, the last 5 bits of the initial byte contains the length
+ // of unsigned integer, which is encoded in following bytes.
+ switch (count) {
+ case 0:
+ SetAdditionalInformation(base::checked_cast<uint8_t>(value));
+ break;
+ case 1:
+ SetAdditionalInformation(constants::kAdditionalInformation1Byte);
+ shift = 0;
+ break;
+ case 2:
+ SetAdditionalInformation(constants::kAdditionalInformation2Bytes);
+ shift = 1;
+ break;
+ case 4:
+ SetAdditionalInformation(constants::kAdditionalInformation4Bytes);
+ shift = 3;
+ break;
+ case 8:
+ SetAdditionalInformation(constants::kAdditionalInformation8Bytes);
+ shift = 7;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ for (; shift >= 0; shift--) {
+ encoded_cbor_->push_back(0xFF & (value >> (shift * 8)));
+ }
+}
+
+size_t CBORWriter::GetNumUintBytes(uint64_t value) {
+ if (value < 24) {
+ return 0;
+ } else if (value <= 0xFF) {
+ return 1;
+ } else if (value <= 0xFFFF) {
+ return 2;
+ } else if (value <= 0xFFFFFFFF) {
+ return 4;
+ }
+ return 8;
+}
+
+} // namespace cbor
diff --git a/chromium/components/cbor/cbor_writer.h b/chromium/components/cbor/cbor_writer.h
new file mode 100644
index 00000000000..89e24da742e
--- /dev/null
+++ b/chromium/components/cbor/cbor_writer.h
@@ -0,0 +1,100 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_CBOR_CBOR_WRITER_H_
+#define COMPONENTS_CBOR_CBOR_WRITER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <vector>
+
+#include "base/optional.h"
+#include "components/cbor/cbor_export.h"
+#include "components/cbor/cbor_values.h"
+
+// A basic Concise Binary Object Representation (CBOR) encoder as defined by
+// https://tools.ietf.org/html/rfc7049. This is a generic encoder that supplies
+// canonical, well-formed CBOR values but does not guarantee their validity
+// (see https://tools.ietf.org/html/rfc7049#section-3.2).
+// Supported:
+// * Major types:
+// * 0: Unsigned integers, up to INT64_MAX.
+// * 1: Negative integers, to INT64_MIN.
+// * 2: Byte strings.
+// * 3: UTF-8 strings.
+// * 4: Arrays, with the number of elements known at the start.
+// * 5: Maps, with the number of elements known at the start
+// of the container.
+// * 7: Simple values.
+//
+// Unsupported:
+// * Floating-point numbers.
+// * Indefinite-length encodings.
+// * Parsing.
+//
+// Requirements for canonical CBOR as suggested by RFC 7049 are:
+// 1) All major data types for the CBOR values must be as short as possible.
+// * Unsigned integer between 0 to 23 must be expressed in same byte as
+// the major type.
+// * 24 to 255 must be expressed only with an additional uint8_t.
+// * 256 to 65535 must be expressed only with an additional uint16_t.
+// * 65536 to 4294967295 must be expressed only with an additional
+// uint32_t. * The rules for expression of length in major types
+// 2 to 5 follow the above rule for integers.
+// 2) Keys in every map must be sorted (first by major type, then by key
+// length, then by value in byte-wise lexical order).
+// 3) Indefinite length items must be converted to definite length items.
+// 4) All maps must not have duplicate keys.
+//
+// Current implementation of CBORWriter encoder meets all the requirements of
+// canonical CBOR.
+
+namespace cbor {
+
+class CBOR_EXPORT CBORWriter {
+ public:
+ // Default that should be sufficiently large for most use cases.
+ static constexpr size_t kDefaultMaxNestingDepth = 16;
+
+ ~CBORWriter();
+
+ // Returns the CBOR byte string representation of |node|, unless its nesting
+ // depth is greater than |max_nesting_depth|, in which case an empty optional
+ // value is returned. The nesting depth of |node| is defined as the number of
+ // arrays/maps that has to be traversed to reach the most nested CBORValue
+ // contained in |node|. Primitive values and empty containers have nesting
+ // depths of 0.
+ static base::Optional<std::vector<uint8_t>> Write(
+ const CBORValue& node,
+ size_t max_nesting_level = kDefaultMaxNestingDepth);
+
+ private:
+ explicit CBORWriter(std::vector<uint8_t>* cbor);
+
+ // Called recursively to build the CBOR bytestring. When completed,
+ // |encoded_cbor_| will contain the CBOR.
+ bool EncodeCBOR(const CBORValue& node, int max_nesting_level);
+
+ // Encodes the type and size of the data being added.
+ void StartItem(CBORValue::Type type, uint64_t size);
+
+ // Encodes the additional information for the data.
+ void SetAdditionalInformation(uint8_t additional_information);
+
+ // Encodes an unsigned integer value. This is used to both write
+ // unsigned integers and to encode the lengths of other major types.
+ void SetUint(uint64_t value);
+
+ // Get the number of bytes needed to store the unsigned integer.
+ size_t GetNumUintBytes(uint64_t value);
+
+ // Holds the encoded CBOR data.
+ std::vector<uint8_t>* encoded_cbor_;
+
+ DISALLOW_COPY_AND_ASSIGN(CBORWriter);
+};
+
+} // namespace cbor
+
+#endif // COMPONENTS_CBOR_CBOR_WRITER_H_
diff --git a/chromium/components/cbor/cbor_writer_unittest.cc b/chromium/components/cbor/cbor_writer_unittest.cc
new file mode 100644
index 00000000000..5b047b6d2f4
--- /dev/null
+++ b/chromium/components/cbor/cbor_writer_unittest.cc
@@ -0,0 +1,431 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/cbor/cbor_writer.h"
+
+#include <limits>
+#include <string>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+/* Leveraging RFC 7049 examples from
+ https://github.com/cbor/test-vectors/blob/master/appendix_a.json. */
+namespace cbor {
+
+TEST(CBORWriterTest, TestWriteUint) {
+ typedef struct {
+ const int64_t value;
+ const base::StringPiece cbor;
+ } UintTestCase;
+
+ static const UintTestCase kUintTestCases[] = {
+ // Reminder: must specify length when creating string pieces
+ // with null bytes, else the string will truncate prematurely.
+ {0, base::StringPiece("\x00", 1)},
+ {1, base::StringPiece("\x01")},
+ {10, base::StringPiece("\x0a")},
+ {23, base::StringPiece("\x17")},
+ {24, base::StringPiece("\x18\x18")},
+ {25, base::StringPiece("\x18\x19")},
+ {100, base::StringPiece("\x18\x64")},
+ {1000, base::StringPiece("\x19\x03\xe8")},
+ {1000000, base::StringPiece("\x1a\x00\x0f\x42\x40", 5)},
+ {0xFFFFFFFF, base::StringPiece("\x1a\xff\xff\xff\xff")},
+ {0x100000000,
+ base::StringPiece("\x1b\x00\x00\x00\x01\x00\x00\x00\x00", 9)},
+ {std::numeric_limits<int64_t>::max(),
+ base::StringPiece("\x1b\x7f\xff\xff\xff\xff\xff\xff\xff")}};
+
+ for (const UintTestCase& test_case : kUintTestCases) {
+ auto cbor = CBORWriter::Write(CBORValue(test_case.value));
+ ASSERT_TRUE(cbor.has_value());
+ EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor));
+ }
+}
+
+TEST(CBORWriterTest, TestWriteNegativeInteger) {
+ static const struct {
+ const int64_t negative_int;
+ const base::StringPiece cbor;
+ } kNegativeIntTestCases[] = {
+ {-1LL, base::StringPiece("\x20")},
+ {-10LL, base::StringPiece("\x29")},
+ {-23LL, base::StringPiece("\x36")},
+ {-24LL, base::StringPiece("\x37")},
+ {-25LL, base::StringPiece("\x38\x18")},
+ {-100LL, base::StringPiece("\x38\x63")},
+ {-1000LL, base::StringPiece("\x39\x03\xe7")},
+ {-4294967296LL, base::StringPiece("\x3a\xff\xff\xff\xff")},
+ {-4294967297LL,
+ base::StringPiece("\x3b\x00\x00\x00\x01\x00\x00\x00\x00", 9)},
+ {std::numeric_limits<int64_t>::min(),
+ base::StringPiece("\x3b\x7f\xff\xff\xff\xff\xff\xff\xff")},
+ };
+
+ for (const auto& test_case : kNegativeIntTestCases) {
+ SCOPED_TRACE(testing::Message() << "testing negative int at index: "
+ << test_case.negative_int);
+
+ auto cbor = CBORWriter::Write(CBORValue(test_case.negative_int));
+ ASSERT_TRUE(cbor.has_value());
+ EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor));
+ }
+}
+
+TEST(CBORWriterTest, TestWriteBytes) {
+ typedef struct {
+ const std::vector<uint8_t> bytes;
+ const base::StringPiece cbor;
+ } BytesTestCase;
+
+ static const BytesTestCase kBytesTestCases[] = {
+ {{}, base::StringPiece("\x40")},
+ {{0x01, 0x02, 0x03, 0x04}, base::StringPiece("\x44\x01\x02\x03\x04")},
+ };
+
+ for (const BytesTestCase& test_case : kBytesTestCases) {
+ auto cbor = CBORWriter::Write(CBORValue(test_case.bytes));
+ ASSERT_TRUE(cbor.has_value());
+ EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor));
+ }
+}
+
+TEST(CBORWriterTest, TestWriteString) {
+ typedef struct {
+ const std::string string;
+ const base::StringPiece cbor;
+ } StringTestCase;
+
+ static const StringTestCase kStringTestCases[] = {
+ {"", base::StringPiece("\x60")},
+ {"a", base::StringPiece("\x61\x61")},
+ {"IETF", base::StringPiece("\x64\x49\x45\x54\x46")},
+ {"\"\\", base::StringPiece("\x62\x22\x5c")},
+ {"\xc3\xbc", base::StringPiece("\x62\xc3\xbc")},
+ {"\xe6\xb0\xb4", base::StringPiece("\x63\xe6\xb0\xb4")},
+ {"\xf0\x90\x85\x91", base::StringPiece("\x64\xf0\x90\x85\x91")}};
+
+ for (const StringTestCase& test_case : kStringTestCases) {
+ SCOPED_TRACE(testing::Message()
+ << "testing encoding string : " << test_case.string);
+
+ auto cbor = CBORWriter::Write(CBORValue(test_case.string));
+ ASSERT_TRUE(cbor.has_value());
+ EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor));
+ }
+}
+
+TEST(CBORWriterTest, TestWriteArray) {
+ static const uint8_t kArrayTestCaseCbor[] = {
+ // clang-format off
+ 0x98, 0x19, // array of 25 elements
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+ 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x18, 0x18, 0x19,
+ // clang-format on
+ };
+ std::vector<CBORValue> array;
+ for (int64_t i = 1; i <= 25; i++) {
+ array.push_back(CBORValue(i));
+ }
+ auto cbor = CBORWriter::Write(CBORValue(array));
+ ASSERT_TRUE(cbor.has_value());
+ EXPECT_THAT(cbor.value(),
+ testing::ElementsAreArray(kArrayTestCaseCbor,
+ arraysize(kArrayTestCaseCbor)));
+}
+
+TEST(CBORWriterTest, TestWriteMapWithMapValue) {
+ static const uint8_t kMapTestCaseCbor[] = {
+ // clang-format off
+ 0xb6, // map of 8 pairs:
+ 0x00, // key 0
+ 0x61, 0x61, // value "a"
+
+ 0x17, // key 23
+ 0x61, 0x62, // value "b"
+
+ 0x18, 0x18, // key 24
+ 0x61, 0x63, // value "c"
+
+ 0x18, 0xFF, // key 255
+ 0x61, 0x64, // value "d"
+
+ 0x19, 0x01, 0x00, // key 256
+ 0x61, 0x65, // value "e"
+
+ 0x19, 0xFF, 0xFF, // key 65535
+ 0x61, 0x66, // value "f"
+
+ 0x1A, 0x00, 0x01, 0x00, 0x00, // key 65536
+ 0x61, 0x67, // value "g"
+
+ 0x1A, 0xFF, 0xFF, 0xFF, 0xFF, // key 4294967295
+ 0x61, 0x68, // value "h"
+
+ // key 4294967296
+ 0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x61, 0x69, // value "i"
+
+ // key INT64_MAX
+ 0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x61, 0x6a, // value "j"
+
+ 0x20, // key -1
+ 0x61, 0x6b, // value "k"
+
+ 0x37, // key -24
+ 0x61, 0x6c, // value "l"
+
+ 0x38, 0x18, // key -25
+ 0x61, 0x6d, // value "m"
+
+ 0x38, 0xFF, // key -256
+ 0x61, 0x6e, // value "n"
+
+ 0x39, 0x01, 0x00, // key -257
+ 0x61, 0x6f, // value "o"
+
+ 0x3A, 0x00, 0x01, 0x00, 0x00, // key -65537
+ 0x61, 0x70, // value "p"
+
+ 0x3A, 0xFF, 0xFF, 0xFF, 0xFF, // key -4294967296
+ 0x61, 0x71, // value "q"
+
+ // key -4294967297
+ 0x3B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x61, 0x72, // value "r"
+
+ // key INT64_MIN
+ 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x61, 0x73, // value "s"
+
+ 0x60, // key ""
+ 0x61, 0x2e, // value "."
+
+ 0x61, 0x65, // key "e"
+ 0x61, 0x45, // value "E"
+
+ 0x62, 0x61, 0x61, // key "aa"
+ 0x62, 0x41, 0x41, // value "AA"
+ // clang-format on
+ };
+ CBORValue::MapValue map;
+ // Shorter strings sort first in CTAP, thus the “aa” value should be
+ // serialised last in the map.
+ map[CBORValue("aa")] = CBORValue("AA");
+ map[CBORValue("e")] = CBORValue("E");
+ // The empty string is shorter than all others, so should appear first among
+ // the strings.
+ map[CBORValue("")] = CBORValue(".");
+ // Map keys are sorted by major type, by byte length, and then by
+ // byte-wise lexical order. So all integer type keys should appear before
+ // key "" and all positive integer keys should appear before negative integer
+ // keys.
+ map[CBORValue(-1)] = CBORValue("k");
+ map[CBORValue(-24)] = CBORValue("l");
+ map[CBORValue(-25)] = CBORValue("m");
+ map[CBORValue(-256)] = CBORValue("n");
+ map[CBORValue(-257)] = CBORValue("o");
+ map[CBORValue(-65537)] = CBORValue("p");
+ map[CBORValue(int64_t(-4294967296))] = CBORValue("q");
+ map[CBORValue(int64_t(-4294967297))] = CBORValue("r");
+ map[CBORValue(std::numeric_limits<int64_t>::min())] = CBORValue("s");
+ map[CBORValue(0)] = CBORValue("a");
+ map[CBORValue(23)] = CBORValue("b");
+ map[CBORValue(24)] = CBORValue("c");
+ map[CBORValue(std::numeric_limits<uint8_t>::max())] = CBORValue("d");
+ map[CBORValue(256)] = CBORValue("e");
+ map[CBORValue(std::numeric_limits<uint16_t>::max())] = CBORValue("f");
+ map[CBORValue(65536)] = CBORValue("g");
+ map[CBORValue(int64_t(std::numeric_limits<uint32_t>::max()))] =
+ CBORValue("h");
+ map[CBORValue(int64_t(4294967296))] = CBORValue("i");
+ map[CBORValue(std::numeric_limits<int64_t>::max())] = CBORValue("j");
+ auto cbor = CBORWriter::Write(CBORValue(map));
+ ASSERT_TRUE(cbor.has_value());
+ EXPECT_THAT(cbor.value(), testing::ElementsAreArray(
+ kMapTestCaseCbor, arraysize(kMapTestCaseCbor)));
+}
+
+TEST(CBORWriterTest, TestWriteMapWithArray) {
+ static const uint8_t kMapArrayTestCaseCbor[] = {
+ // clang-format off
+ 0xa2, // map of 2 pairs
+ 0x61, 0x61, // "a"
+ 0x01,
+
+ 0x61, 0x62, // "b"
+ 0x82, // array with 2 elements
+ 0x02,
+ 0x03,
+ // clang-format on
+ };
+ CBORValue::MapValue map;
+ map[CBORValue("a")] = CBORValue(1);
+ CBORValue::ArrayValue array;
+ array.push_back(CBORValue(2));
+ array.push_back(CBORValue(3));
+ map[CBORValue("b")] = CBORValue(array);
+ auto cbor = CBORWriter::Write(CBORValue(map));
+ ASSERT_TRUE(cbor.has_value());
+ EXPECT_THAT(cbor.value(),
+ testing::ElementsAreArray(kMapArrayTestCaseCbor,
+ arraysize(kMapArrayTestCaseCbor)));
+}
+
+TEST(CBORWriterTest, TestWriteNestedMap) {
+ static const uint8_t kNestedMapTestCase[] = {
+ // clang-format off
+ 0xa2, // map of 2 pairs
+ 0x61, 0x61, // "a"
+ 0x01,
+
+ 0x61, 0x62, // "b"
+ 0xa2, // map of 2 pairs
+ 0x61, 0x63, // "c"
+ 0x02,
+
+ 0x61, 0x64, // "d"
+ 0x03,
+ // clang-format on
+ };
+ CBORValue::MapValue map;
+ map[CBORValue("a")] = CBORValue(1);
+ CBORValue::MapValue nested_map;
+ nested_map[CBORValue("c")] = CBORValue(2);
+ nested_map[CBORValue("d")] = CBORValue(3);
+ map[CBORValue("b")] = CBORValue(nested_map);
+ auto cbor = CBORWriter::Write(CBORValue(map));
+ ASSERT_TRUE(cbor.has_value());
+ EXPECT_THAT(cbor.value(),
+ testing::ElementsAreArray(kNestedMapTestCase,
+ arraysize(kNestedMapTestCase)));
+}
+
+TEST(CBORWriterTest, TestWriteSimpleValue) {
+ static const struct {
+ CBORValue::SimpleValue simple_value;
+ const base::StringPiece cbor;
+ } kSimpleTestCase[] = {
+ {CBORValue::SimpleValue::FALSE_VALUE, base::StringPiece("\xf4")},
+ {CBORValue::SimpleValue::TRUE_VALUE, base::StringPiece("\xf5")},
+ {CBORValue::SimpleValue::NULL_VALUE, base::StringPiece("\xf6")},
+ {CBORValue::SimpleValue::UNDEFINED, base::StringPiece("\xf7")}};
+
+ for (const auto& test_case : kSimpleTestCase) {
+ auto cbor = CBORWriter::Write(CBORValue(test_case.simple_value));
+ ASSERT_TRUE(cbor.has_value());
+ EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor));
+ }
+}
+
+// For major type 0, 2, 3, empty CBOR array, and empty CBOR map, the nesting
+// depth is expected to be 0 since the CBOR decoder does not need to parse
+// any nested CBOR value elements.
+TEST(CBORWriterTest, TestWriteSingleLayer) {
+ const CBORValue simple_uint = CBORValue(1);
+ const CBORValue simple_string = CBORValue("a");
+ const std::vector<uint8_t> byte_data = {0x01, 0x02, 0x03, 0x04};
+ const CBORValue simple_bytestring = CBORValue(byte_data);
+ CBORValue::ArrayValue empty_cbor_array;
+ CBORValue::MapValue empty_cbor_map;
+ const CBORValue empty_array_value = CBORValue(empty_cbor_array);
+ const CBORValue empty_map_value = CBORValue(empty_cbor_map);
+ CBORValue::ArrayValue simple_array;
+ simple_array.push_back(CBORValue(2));
+ CBORValue::MapValue simple_map;
+ simple_map[CBORValue("b")] = CBORValue(3);
+ const CBORValue single_layer_cbor_map = CBORValue(simple_map);
+ const CBORValue single_layer_cbor_array = CBORValue(simple_array);
+
+ EXPECT_TRUE(CBORWriter::Write(simple_uint, 0).has_value());
+ EXPECT_TRUE(CBORWriter::Write(simple_string, 0).has_value());
+ EXPECT_TRUE(CBORWriter::Write(simple_bytestring, 0).has_value());
+
+ EXPECT_TRUE(CBORWriter::Write(empty_array_value, 0).has_value());
+ EXPECT_TRUE(CBORWriter::Write(empty_map_value, 0).has_value());
+
+ EXPECT_FALSE(CBORWriter::Write(single_layer_cbor_array, 0).has_value());
+ EXPECT_TRUE(CBORWriter::Write(single_layer_cbor_array, 1).has_value());
+
+ EXPECT_FALSE(CBORWriter::Write(single_layer_cbor_map, 0).has_value());
+ EXPECT_TRUE(CBORWriter::Write(single_layer_cbor_map, 1).has_value());
+}
+
+// Major type 5 nested CBOR map value with following structure.
+// {"a": 1,
+// "b": {"c": 2,
+// "d": 3}}
+TEST(CBORWriterTest, NestedMaps) {
+ CBORValue::MapValue cbor_map;
+ cbor_map[CBORValue("a")] = CBORValue(1);
+ CBORValue::MapValue nested_map;
+ nested_map[CBORValue("c")] = CBORValue(2);
+ nested_map[CBORValue("d")] = CBORValue(3);
+ cbor_map[CBORValue("b")] = CBORValue(nested_map);
+ EXPECT_TRUE(CBORWriter::Write(CBORValue(cbor_map), 2).has_value());
+ EXPECT_FALSE(CBORWriter::Write(CBORValue(cbor_map), 1).has_value());
+}
+
+// Testing Write() function for following CBOR structure with depth of 3.
+// [1,
+// 2,
+// 3,
+// {"a": 1,
+// "b": {"c": 2,
+// "d": 3}}]
+TEST(CBORWriterTest, UnbalancedNestedContainers) {
+ CBORValue::ArrayValue cbor_array;
+ CBORValue::MapValue cbor_map;
+ CBORValue::MapValue nested_map;
+
+ cbor_map[CBORValue("a")] = CBORValue(1);
+ nested_map[CBORValue("c")] = CBORValue(2);
+ nested_map[CBORValue("d")] = CBORValue(3);
+ cbor_map[CBORValue("b")] = CBORValue(nested_map);
+ cbor_array.push_back(CBORValue(1));
+ cbor_array.push_back(CBORValue(2));
+ cbor_array.push_back(CBORValue(3));
+ cbor_array.push_back(CBORValue(cbor_map));
+
+ EXPECT_TRUE(CBORWriter::Write(CBORValue(cbor_array), 3).has_value());
+ EXPECT_FALSE(CBORWriter::Write(CBORValue(cbor_array), 2).has_value());
+}
+
+// Testing Write() function for following CBOR structure.
+// {"a": 1,
+// "b": {"c": 2,
+// "d": 3
+// "h": { "e": 4,
+// "f": 5,
+// "g": [6, 7, [8]]}}}
+// Since above CBOR contains 5 nesting levels. Thus, Write() is expected to
+// return empty optional object when maximum nesting layer size is set to 4.
+TEST(CBORWriterTest, OverlyNestedCBOR) {
+ CBORValue::MapValue map;
+ CBORValue::MapValue nested_map;
+ CBORValue::MapValue inner_nested_map;
+ CBORValue::ArrayValue inner_array;
+ CBORValue::ArrayValue array;
+
+ map[CBORValue("a")] = CBORValue(1);
+ nested_map[CBORValue("c")] = CBORValue(2);
+ nested_map[CBORValue("d")] = CBORValue(3);
+ inner_nested_map[CBORValue("e")] = CBORValue(4);
+ inner_nested_map[CBORValue("f")] = CBORValue(5);
+ inner_array.push_back(CBORValue(6));
+ array.push_back(CBORValue(6));
+ array.push_back(CBORValue(7));
+ array.push_back(CBORValue(inner_array));
+ inner_nested_map[CBORValue("g")] = CBORValue(array);
+ nested_map[CBORValue("h")] = CBORValue(inner_nested_map);
+ map[CBORValue("b")] = CBORValue(nested_map);
+
+ EXPECT_TRUE(CBORWriter::Write(CBORValue(map), 5).has_value());
+ EXPECT_FALSE(CBORWriter::Write(CBORValue(map), 4).has_value());
+}
+
+} // namespace cbor