// 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 #include #include "components/cbor/reader.h" #include "base/containers/span.h" #include "base/stl_util.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 { namespace { std::vector WithExtraneousData(base::span original) { std::vector ret(original.begin(), original.end()); // Add a valid one byte long CBOR data item, namely, an unsigned integer // with value "1". ret.push_back(0x01); return ret; } } // namespace TEST(CBORReaderTest, TestReadUint) { struct UintTestCase { const int64_t value; const std::vector cbor_data; }; static const UintTestCase kUintTestCases[] = { {0, {0x00}}, {1, {0x01}}, {23, {0x17}}, {24, {0x18, 0x18}}, {std::numeric_limits::max(), {0x18, 0xff}}, {1LL << 8, {0x19, 0x01, 0x00}}, {std::numeric_limits::max(), {0x19, 0xff, 0xff}}, {1LL << 16, {0x1a, 0x00, 0x01, 0x00, 0x00}}, {std::numeric_limits::max(), {0x1a, 0xff, 0xff, 0xff, 0xff}}, {1LL << 32, {0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, {std::numeric_limits::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 cbor = Reader::Read(test_case.cbor_data); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor.value().type(), Value::Type::UNSIGNED); EXPECT_EQ(cbor.value().GetInteger(), test_case.value); auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); Reader::DecoderError error_code; cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); size_t num_bytes_consumed; cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor.value().type(), Value::Type::UNSIGNED); EXPECT_EQ(cbor.value().GetInteger(), test_case.value); EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); } } TEST(CBORReaderTest, TestUintEncodedWithNonMinimumByteLength) { static const std::vector 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; Reader::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 cbor = Reader::Read(non_minimal_uint, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::NON_MINIMAL_CBOR_ENCODING); } } TEST(CBORReaderTest, TestReadNegativeInt) { struct NegativeIntTestCase { const int64_t negative_int; const std::vector 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::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 cbor = Reader::Read(test_case.cbor_data); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor.value().type(), Value::Type::NEGATIVE); EXPECT_EQ(cbor.value().GetInteger(), test_case.negative_int); auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); Reader::DecoderError error_code; cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); size_t num_bytes_consumed; cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor.value().type(), Value::Type::NEGATIVE); EXPECT_EQ(cbor.value().GetInteger(), test_case.negative_int); EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); } } TEST(CBORReaderTest, TestReadBytes) { struct ByteTestCase { const std::vector value; const std::vector 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 cbor = Reader::Read(test_case.cbor_data); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor.value().type(), Value::Type::BYTE_STRING); EXPECT_EQ(cbor.value().GetBytestring(), test_case.value); auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); Reader::DecoderError error_code; cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); size_t num_bytes_consumed; cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor.value().type(), Value::Type::BYTE_STRING); EXPECT_EQ(cbor.value().GetBytestring(), test_case.value); EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); } } TEST(CBORReaderTest, TestReadString) { struct StringTestCase { const std::string value; const std::vector 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 cbor = Reader::Read(test_case.cbor_data); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor.value().type(), Value::Type::STRING); EXPECT_EQ(cbor.value().GetString(), test_case.value); auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); Reader::DecoderError error_code; cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); size_t num_bytes_consumed; cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor.value().type(), Value::Type::STRING); EXPECT_EQ(cbor.value().GetString(), test_case.value); EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); } } TEST(CBORReaderTest, TestReadStringWithNUL) { static const struct { const std::string value; const std::vector 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 cbor = Reader::Read(test_case.cbor_data); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor.value().type(), Value::Type::STRING); EXPECT_EQ(cbor.value().GetString(), test_case.value); auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); Reader::DecoderError error_code; cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); size_t num_bytes_consumed; cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor.value().type(), Value::Type::STRING); EXPECT_EQ(cbor.value().GetString(), test_case.value); EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); } } 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 string_with_invalid_continuation_byte = { 0x63, 0x00, 0x00, 0xA6}; Reader::DecoderError error_code; base::Optional cbor = Reader::Read(string_with_invalid_continuation_byte, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::INVALID_UTF8); } TEST(CBORReaderTest, TestReadArray) { static const std::vector 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 cbor = Reader::Read(kArrayTestCaseCbor); ASSERT_TRUE(cbor.has_value()); const Value cbor_array = std::move(cbor.value()); ASSERT_EQ(cbor_array.type(), Value::Type::ARRAY); ASSERT_THAT(cbor_array.GetArray(), testing::SizeIs(25)); std::vector 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(), Value::Type::UNSIGNED); EXPECT_EQ(cbor_array.GetArray()[i].GetInteger(), static_cast(i + 1)); } auto cbor_data_with_extra_byte = WithExtraneousData(kArrayTestCaseCbor); Reader::DecoderError error_code; cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); size_t num_bytes_consumed; cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor_array.type(), Value::Type::ARRAY); ASSERT_THAT(cbor_array.GetArray(), testing::SizeIs(25)); EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); EXPECT_EQ(num_bytes_consumed, kArrayTestCaseCbor.size()); } TEST(CBORReaderTest, TestReadMapWithMapValue) { static const std::vector 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 cbor = Reader::Read(kMapTestCaseCbor); ASSERT_TRUE(cbor.has_value()); const Value cbor_val = std::move(cbor.value()); ASSERT_EQ(cbor_val.type(), Value::Type::MAP); ASSERT_EQ(cbor_val.GetMap().size(), 4u); const Value key_uint(24); ASSERT_EQ(cbor_val.GetMap().count(key_uint), 1u); ASSERT_EQ(cbor_val.GetMap().find(key_uint)->second.type(), Value::Type::STRING); EXPECT_EQ(cbor_val.GetMap().find(key_uint)->second.GetString(), "abc"); const Value key_empty_string(""); ASSERT_EQ(cbor_val.GetMap().count(key_empty_string), 1u); ASSERT_EQ(cbor_val.GetMap().find(key_empty_string)->second.type(), Value::Type::STRING); EXPECT_EQ(cbor_val.GetMap().find(key_empty_string)->second.GetString(), "."); const Value key_b("b"); ASSERT_EQ(cbor_val.GetMap().count(key_b), 1u); ASSERT_EQ(cbor_val.GetMap().find(key_b)->second.type(), Value::Type::STRING); EXPECT_EQ(cbor_val.GetMap().find(key_b)->second.GetString(), "B"); const Value key_aa("aa"); ASSERT_EQ(cbor_val.GetMap().count(key_aa), 1u); ASSERT_EQ(cbor_val.GetMap().find(key_aa)->second.type(), Value::Type::STRING); EXPECT_EQ(cbor_val.GetMap().find(key_aa)->second.GetString(), "AA"); auto cbor_data_with_extra_byte = WithExtraneousData(kMapTestCaseCbor); Reader::DecoderError error_code; cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); size_t num_bytes_consumed; cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor_val.type(), Value::Type::MAP); ASSERT_EQ(cbor_val.GetMap().size(), 4u); EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); EXPECT_EQ(num_bytes_consumed, kMapTestCaseCbor.size()); } TEST(CBORReaderTest, TestReadMapWithIntegerKeys) { static const std::vector 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 cbor = Reader::Read(kMapWithIntegerKeyCbor); ASSERT_TRUE(cbor.has_value()); const Value cbor_val = std::move(cbor.value()); ASSERT_EQ(cbor_val.type(), Value::Type::MAP); ASSERT_EQ(cbor_val.GetMap().size(), 4u); const Value key_1(1); ASSERT_EQ(cbor_val.GetMap().count(key_1), 1u); ASSERT_EQ(cbor_val.GetMap().find(key_1)->second.type(), Value::Type::STRING); EXPECT_EQ(cbor_val.GetMap().find(key_1)->second.GetString(), "a"); const Value key_9(9); ASSERT_EQ(cbor_val.GetMap().count(key_9), 1u); ASSERT_EQ(cbor_val.GetMap().find(key_9)->second.type(), Value::Type::STRING); EXPECT_EQ(cbor_val.GetMap().find(key_9)->second.GetString(), "b"); const Value key_999(999); ASSERT_EQ(cbor_val.GetMap().count(key_999), 1u); ASSERT_EQ(cbor_val.GetMap().find(key_999)->second.type(), Value::Type::STRING); EXPECT_EQ(cbor_val.GetMap().find(key_999)->second.GetString(), "c"); const Value key_1111(1111); ASSERT_EQ(cbor_val.GetMap().count(key_1111), 1u); ASSERT_EQ(cbor_val.GetMap().find(key_1111)->second.type(), Value::Type::STRING); EXPECT_EQ(cbor_val.GetMap().find(key_1111)->second.GetString(), "d"); auto cbor_data_with_extra_byte = WithExtraneousData(kMapWithIntegerKeyCbor); Reader::DecoderError error_code; cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); size_t num_bytes_consumed; cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor_val.type(), Value::Type::MAP); ASSERT_EQ(cbor_val.GetMap().size(), 4u); EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); EXPECT_EQ(num_bytes_consumed, kMapWithIntegerKeyCbor.size()); } TEST(CBORReaderTest, TestReadMapWithNegativeIntegersKeys) { static const std::vector kMapWithIntegerKeyCbor = { // clang-format off 0xA3, // map with 3 key value pairs 0x20, // key : -1 0x01, 0x21, // key : -2 0x02, 0x38, 0x63, // key : -100 0x03, // clang-format on }; base::Optional cbor = Reader::Read(kMapWithIntegerKeyCbor); ASSERT_TRUE(cbor.has_value()); const Value cbor_val = std::move(cbor.value()); ASSERT_EQ(cbor_val.type(), Value::Type::MAP); ASSERT_EQ(cbor_val.GetMap().size(), 3u); const Value key_1(-1); ASSERT_EQ(cbor_val.GetMap().count(key_1), 1u); ASSERT_EQ(cbor_val.GetMap().find(key_1)->second.type(), Value::Type::UNSIGNED); EXPECT_EQ(cbor_val.GetMap().find(key_1)->second.GetInteger(), 1); const Value key_2(-2); ASSERT_EQ(cbor_val.GetMap().count(key_2), 1u); ASSERT_EQ(cbor_val.GetMap().find(key_2)->second.type(), Value::Type::UNSIGNED); EXPECT_EQ(cbor_val.GetMap().find(key_2)->second.GetInteger(), 2); const Value key_100(-100); ASSERT_EQ(cbor_val.GetMap().count(key_100), 1u); ASSERT_EQ(cbor_val.GetMap().find(key_100)->second.type(), Value::Type::UNSIGNED); EXPECT_EQ(cbor_val.GetMap().find(key_100)->second.GetInteger(), 3); auto cbor_data_with_extra_byte = WithExtraneousData(kMapWithIntegerKeyCbor); Reader::DecoderError error_code; cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); size_t num_bytes_consumed; cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor_val.type(), Value::Type::MAP); ASSERT_EQ(cbor_val.GetMap().size(), 3u); EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); EXPECT_EQ(num_bytes_consumed, kMapWithIntegerKeyCbor.size()); } TEST(CBORReaderTest, TestReadMapWithArray) { static const std::vector 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 cbor = Reader::Read(kMapArrayTestCaseCbor); ASSERT_TRUE(cbor.has_value()); const Value cbor_val = std::move(cbor.value()); ASSERT_EQ(cbor_val.type(), Value::Type::MAP); ASSERT_EQ(cbor_val.GetMap().size(), 2u); const Value key_a("a"); ASSERT_EQ(cbor_val.GetMap().count(key_a), 1u); ASSERT_EQ(cbor_val.GetMap().find(key_a)->second.type(), Value::Type::UNSIGNED); EXPECT_EQ(cbor_val.GetMap().find(key_a)->second.GetInteger(), 1u); const Value key_b("b"); ASSERT_EQ(cbor_val.GetMap().count(key_b), 1u); ASSERT_EQ(cbor_val.GetMap().find(key_b)->second.type(), Value::Type::ARRAY); const Value 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(), Value::Type::UNSIGNED); EXPECT_EQ(nested_array.GetArray()[i].GetInteger(), static_cast(i + 2)); } auto cbor_data_with_extra_byte = WithExtraneousData(kMapArrayTestCaseCbor); Reader::DecoderError error_code; cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); size_t num_bytes_consumed; cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor_val.type(), Value::Type::MAP); ASSERT_EQ(cbor_val.GetMap().size(), 2u); EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); EXPECT_EQ(num_bytes_consumed, kMapArrayTestCaseCbor.size()); } TEST(CBORReaderTest, TestReadMapWithTextStringKeys) { static const std::vector kMapTestCase{ // clang-format off 0xa2, // map of 2 pairs 0x61, 'k', // text string "k" 0x61, 'v', 0x63, 'f', 'o', 'o', // text string "foo" 0x63, 'b', 'a', 'r', // clang-format on }; Reader::DecoderError error_code; base::Optional cbor = Reader::Read(kMapTestCase, &error_code); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor->type(), Value::Type::MAP); ASSERT_EQ(cbor->GetMap().size(), 2u); const Value key_k("k"); ASSERT_EQ(cbor->GetMap().count(key_k), 1u); ASSERT_EQ(cbor->GetMap().find(key_k)->second.type(), Value::Type::STRING); EXPECT_EQ(cbor->GetMap().find(key_k)->second.GetString(), "v"); const Value key_foo("foo"); ASSERT_EQ(cbor->GetMap().count(key_foo), 1u); ASSERT_EQ(cbor->GetMap().find(key_foo)->second.type(), Value::Type::STRING); EXPECT_EQ(cbor->GetMap().find(key_foo)->second.GetString(), "bar"); auto cbor_data_with_extra_byte = WithExtraneousData(kMapTestCase); cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); size_t num_bytes_consumed; cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor->type(), Value::Type::MAP); ASSERT_EQ(cbor->GetMap().size(), 2u); EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); EXPECT_EQ(num_bytes_consumed, kMapTestCase.size()); } TEST(CBORReaderTest, TestReadMapWithByteStringKeys) { static const std::vector kMapTestCase{ // clang-format off 0xa2, // map of 2 pairs 0x41, 'k', // byte string "k" 0x41, 'v', 0x43, 'f', 'o', 'o', // byte string "foo" 0x43, 'b', 'a', 'r', // clang-format on }; Reader::DecoderError error_code; base::Optional cbor = Reader::Read(kMapTestCase, &error_code); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor->type(), Value::Type::MAP); ASSERT_EQ(cbor->GetMap().size(), 2u); const Value key_k(std::vector{'k'}); ASSERT_EQ(cbor->GetMap().count(key_k), 1u); ASSERT_EQ(cbor->GetMap().find(key_k)->second.type(), Value::Type::BYTE_STRING); EXPECT_EQ(cbor->GetMap().find(key_k)->second.GetBytestring(), std::vector{'v'}); const Value key_foo(std::vector{'f', 'o', 'o'}); ASSERT_EQ(cbor->GetMap().count(key_foo), 1u); ASSERT_EQ(cbor->GetMap().find(key_foo)->second.type(), Value::Type::BYTE_STRING); static const std::vector kBarBytes{'b', 'a', 'r'}; EXPECT_EQ(cbor->GetMap().find(key_foo)->second.GetBytestring(), kBarBytes); auto cbor_data_with_extra_byte = WithExtraneousData(kMapTestCase); cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); size_t num_bytes_consumed; cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor->type(), Value::Type::MAP); ASSERT_EQ(cbor->GetMap().size(), 2u); EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); EXPECT_EQ(num_bytes_consumed, kMapTestCase.size()); } TEST(CBORReaderTest, TestReadMapWithMixedKeys) { // Example adopted from: // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html static const uint8_t kMapTestCase[] = { // clang-format off 0xa6, // map of 6 pairs 0x0a, // 10 0x00, 0x18, 0x64, // 100 0x01, 0x20, // -1 0x02, // This entry is not in the example, but added to test byte string key 0x42, 'x', 'y', // byte string "xy" 0x03, 0x61, 'z', // text string "z" 0x04, 0x62, 'a', 'a', // text string "aa" 0x05, /* 0x81, 0x18, 0x64, // [100] (array as map key is not yet supported) 0x06, 0x81, 0x20, // [-1] (array as map key is not yet supported) 0x07, 0xf4, // false (boolean as map key is not yet supported) 0x08, */ // clang-format on }; Reader::DecoderError error_code; base::Optional cbor = Reader::Read(kMapTestCase, &error_code); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor->type(), Value::Type::MAP); ASSERT_EQ(cbor->GetMap().size(), 6u); std::vector keys; keys.emplace_back(10); keys.emplace_back(100); keys.emplace_back(-1); keys.emplace_back(Value::BinaryValue{'x', 'y'}); keys.emplace_back("z"); keys.emplace_back("aa"); for (size_t i = 0; i < keys.size(); ++i) { SCOPED_TRACE(testing::Message() << "testing key at index: " << i); ASSERT_EQ(cbor->GetMap().count(keys[i]), 1u); ASSERT_EQ(cbor->GetMap().find(keys[i])->second.type(), Value::Type::UNSIGNED); EXPECT_EQ(cbor->GetMap().find(keys[i])->second.GetInteger(), static_cast(i)); } auto cbor_data_with_extra_byte = WithExtraneousData(kMapTestCase); cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); size_t num_bytes_consumed; cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor->type(), Value::Type::MAP); ASSERT_EQ(cbor->GetMap().size(), 6u); EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); EXPECT_EQ(num_bytes_consumed, base::size(kMapTestCase)); } TEST(CBORReaderTest, TestReadNestedMap) { static const std::vector 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 cbor = Reader::Read(kNestedMapTestCase); ASSERT_TRUE(cbor.has_value()); const Value cbor_val = std::move(cbor.value()); ASSERT_EQ(cbor_val.type(), Value::Type::MAP); ASSERT_EQ(cbor_val.GetMap().size(), 2u); const Value key_a("a"); ASSERT_EQ(cbor_val.GetMap().count(key_a), 1u); ASSERT_EQ(cbor_val.GetMap().find(key_a)->second.type(), Value::Type::UNSIGNED); EXPECT_EQ(cbor_val.GetMap().find(key_a)->second.GetInteger(), 1u); const Value key_b("b"); ASSERT_EQ(cbor_val.GetMap().count(key_b), 1u); const Value nested_map = cbor_val.GetMap().find(key_b)->second.Clone(); ASSERT_EQ(nested_map.type(), Value::Type::MAP); ASSERT_EQ(nested_map.GetMap().size(), 2u); const Value key_c("c"); ASSERT_EQ(nested_map.GetMap().count(key_c), 1u); ASSERT_EQ(nested_map.GetMap().find(key_c)->second.type(), Value::Type::UNSIGNED); EXPECT_EQ(nested_map.GetMap().find(key_c)->second.GetInteger(), 2u); const Value key_d("d"); ASSERT_EQ(nested_map.GetMap().count(key_d), 1u); ASSERT_EQ(nested_map.GetMap().find(key_d)->second.type(), Value::Type::UNSIGNED); EXPECT_EQ(nested_map.GetMap().find(key_d)->second.GetInteger(), 3u); } TEST(CBORReaderTest, TestIntegerRange) { static const std::vector kMaxPositiveInt = { 0x1b, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static const std::vector kMinNegativeInt = { 0x3b, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; base::Optional max_positive_int = Reader::Read(kMaxPositiveInt); ASSERT_TRUE(max_positive_int.has_value()); EXPECT_EQ(max_positive_int.value().GetInteger(), INT64_MAX); base::Optional min_negative_int = Reader::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 kOutOfRangePositiveInt = { 0x1b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static const std::vector kOutOfRangeNegativeInt = { 0x3b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; Reader::DecoderError error_code; base::Optional positive_int_out_of_range_cbor = Reader::Read(kOutOfRangePositiveInt, &error_code); EXPECT_FALSE(positive_int_out_of_range_cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::OUT_OF_RANGE_INTEGER_VALUE); base::Optional negative_int_out_of_range_cbor = Reader::Read(kOutOfRangeNegativeInt, &error_code); EXPECT_FALSE(negative_int_out_of_range_cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::OUT_OF_RANGE_INTEGER_VALUE); } TEST(CBORReaderTest, TestReadSimpleValue) { static const struct { const Value::SimpleValue value; const std::vector cbor_data; } kSimpleValueTestCases[] = { {Value::SimpleValue::FALSE_VALUE, {0xf4}}, {Value::SimpleValue::TRUE_VALUE, {0xf5}}, {Value::SimpleValue::NULL_VALUE, {0xf6}}, {Value::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 cbor = Reader::Read(test_case.cbor_data); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor.value().type(), Value::Type::SIMPLE_VALUE); EXPECT_EQ(cbor.value().GetSimpleValue(), test_case.value); auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); Reader::DecoderError error_code; cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); size_t num_bytes_consumed; cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); ASSERT_TRUE(cbor.has_value()); ASSERT_EQ(cbor.value().type(), Value::Type::SIMPLE_VALUE); EXPECT_EQ(cbor.value().GetSimpleValue(), test_case.value); EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); } } TEST(CBORReaderTest, TestReadUnsupportedFloatingPointNumbers) { static const std::vector 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)); Reader::DecoderError error_code; base::Optional cbor = Reader::Read(unsupported_floating_point, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::UNSUPPORTED_FLOATING_POINT_VALUE); } } TEST(CBORReaderTest, TestIncompleteCBORDataError) { static const std::vector 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}, {0x18}, // unsigned with pending 1 byte of numeric value. {0x99}, // array with pending 2 byte of numeric value (length). {0xba}, // map with pending 4 byte of numeric value (length). {0x5b}, // byte string with pending 4 byte of numeric value (length). {0x3b}, // negative integer with pending 8 byte of numeric value. {0x99, 0x01}, // array with pending 2 byte of numeric value (length), // with only 1 byte of additional data. {0xba, 0x01, 0x02, 0x03}, // map with pending 4 byte of numeric value // (length), with only 3 bytes of additional // data. {0x3b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, // negative integer with pending 8 byte of // numeric value, with only 7 bytes of // additional data. }; 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++); Reader::DecoderError error_code; base::Optional cbor = Reader::Read(incomplete_data, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::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 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 }; Reader::DecoderError error_code; base::Optional cbor = Reader::Read(kMapWithUintKey, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::INCORRECT_MAP_KEY_TYPE); } TEST(CBORReaderTest, TestUnknownAdditionalInfoError) { static const std::vector 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++); Reader::DecoderError error_code; base::Optional cbor = Reader::Read(incorrect_cbor, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::UNKNOWN_ADDITIONAL_INFO); } } TEST(CBORReaderTest, TestTooMuchNestingError) { static const std::vector 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++); Reader::DecoderError error_code; base::Optional cbor = Reader::Read(zero_depth_data, &error_code, 0); EXPECT_TRUE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); } // Corresponds to a CBOR structure with a nesting depth of 2: // {"a": 1, // "b": [2, 3]} static const std::vector 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 }; Reader::DecoderError error_code; base::Optional cbor_single_layer_max = Reader::Read(kNestedCBORData, &error_code, 1); EXPECT_FALSE(cbor_single_layer_max.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::TOO_MUCH_NESTING); base::Optional cbor_double_layer_max = Reader::Read(kNestedCBORData, &error_code, 2); EXPECT_TRUE(cbor_double_layer_max.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); } TEST(CBORReaderTest, TestOutOfOrderKeyError) { static const std::vector 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" {0xa2, // map with 2 text string keys 0x62, 'a', 'a', // key text string "aa" // (out of order due to longer length) 0x02, 0x61, 'b', // key "b" 0x01, }, {0xa2, // map with 2 byte string keys 0x42, 'x', 'x', // key byte string "xx" // (out of order due to longer length) 0x02, 0x41, 'y', // key byte string "y" 0x01, }, //clang-format on }; int test_element_index = 0; Reader::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 cbor = Reader::Read(unsorted_map, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::OUT_OF_ORDER_KEY); } } TEST(CBORReaderTest, TestDuplicateKeyError) { static const std::vector 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 }; Reader::DecoderError error_code; base::Optional cbor = Reader::Read(kMapWithDuplicateKey, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::OUT_OF_ORDER_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 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; Reader::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 correctly_encoded_cbor = Reader::Read(cbor_byte, &error_code); EXPECT_TRUE(correctly_encoded_cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); } // Incorrect UTF8 encoding referenced by section 3.5.3 of the stress test. std::vector impossible_utf_byte{0x64, 0xfe, 0xfe, 0xff, 0xff}; base::Optional incorrectly_encoded_cbor = Reader::Read(impossible_utf_byte, &error_code); EXPECT_FALSE(incorrectly_encoded_cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::INVALID_UTF8); } TEST(CBORReaderTest, TestExtraneousCBORDataError) { static const std::vector 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++); Reader::DecoderError error_code; base::Optional cbor = Reader::Read(extraneous_cbor_data, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); } } TEST(CBORReaderTest, TestUnsupportedSimpleValue) { static const std::vector 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)); Reader::DecoderError error_code; base::Optional cbor = Reader::Read(unsupported_simple_val, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::UNSUPPORTED_SIMPLE_VALUE); } } TEST(CBORReaderTest, TestSuperLongContentDontCrash) { static const std::vector kTestCases[] = { // CBOR array of 0xffffffff length. {0x9b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, // CBOR map of 0xffffffff pairs. {0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, }; for (const auto& test_case : kTestCases) { Reader::DecoderError error_code; base::Optional cbor = Reader::Read(test_case, &error_code); EXPECT_FALSE(cbor.has_value()); EXPECT_EQ(error_code, Reader::DecoderError::INCOMPLETE_CBOR_DATA); } } TEST(CBORReaderTest, AllowInvalidUTF8) { static const uint8_t kInvalidUTF8[] = { // clang-format off 0xa1, // map of length 1 0x61, 'x', // "x" 0x81, // array of length 1 0xa2, // map of length 2 0x61, 'y', // "y" 0x62, 0xe2, 0x80, // invalid UTF-8 value 0x61, 'z', // "z" 0x61, '.', // "." // clang-format on }; Reader::DecoderError error; Reader::Config config; config.error_code_out = &error; base::Optional cbor = Reader::Read(kInvalidUTF8, config); EXPECT_FALSE(cbor); EXPECT_EQ(Reader::DecoderError::INVALID_UTF8, error); cbor = Reader::Read(kInvalidUTF8, config); EXPECT_FALSE(cbor); EXPECT_EQ(Reader::DecoderError::INVALID_UTF8, error); config.allow_invalid_utf8 = true; cbor = Reader::Read(kInvalidUTF8, config); EXPECT_TRUE(cbor); EXPECT_EQ(Reader::DecoderError::CBOR_NO_ERROR, error); const cbor::Value& invalid_value = cbor->GetMap() .find(Value("x")) ->second.GetArray()[0] .GetMap() .find(Value("y")) ->second; ASSERT_TRUE(invalid_value.is_invalid_utf8()); EXPECT_EQ(std::vector({0xe2, 0x80}), invalid_value.GetInvalidUTF8()); static const uint8_t kInvalidUTF8InMapKey[] = { // clang-format off 0xa1, // map of length 1 0x62, 0xe2, 0x80, // invalid UTF-8 map key 0x61, '.', // "." // clang-format on }; EXPECT_TRUE(config.allow_invalid_utf8); cbor = Reader::Read(kInvalidUTF8InMapKey, config); EXPECT_FALSE(cbor); EXPECT_EQ(Reader::DecoderError::INVALID_UTF8, error); } } // namespace cbor