Change the read()/write() methods to use a nesting limit of 127
internally, to avoid the possibility of heavily nested inputs exhausting
the stack.
Library users that still want to skip nesting checks can still get at
this functionality by using `{read,write}_nested(..., None)`.
833 lines
28 KiB
Rust
833 lines
28 KiB
Rust
// Copyright 2019 Google LLC
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//! Functionality for deserializing CBOR data into values.
|
|
|
|
use super::values::{Constants, SimpleValue, Value};
|
|
use crate::{
|
|
cbor_array_vec, cbor_bytes_lit, cbor_map_collection, cbor_tagged, cbor_text, cbor_unsigned,
|
|
};
|
|
use alloc::str;
|
|
use alloc::vec::Vec;
|
|
|
|
/// Possible errors from a deserialization operation.
|
|
#[derive(Debug, PartialEq)]
|
|
pub enum DecoderError {
|
|
UnsupportedMajorType,
|
|
UnknownAdditionalInfo,
|
|
IncompleteCborData,
|
|
TooMuchNesting,
|
|
InvalidUtf8,
|
|
ExtraneousData,
|
|
OutOfOrderKey,
|
|
NonMinimalCborEncoding,
|
|
UnsupportedSimpleValue,
|
|
UnsupportedFloatingPointValue,
|
|
OutOfRangeIntegerValue,
|
|
}
|
|
|
|
/// Deserialize CBOR binary data to produce a single [`Value`], expecting that there is no additional data.
|
|
/// Maximum level of nesting supported is 127; more deeply nested structures will fail with
|
|
/// [`DecoderError::TooMuchNesting`].
|
|
pub fn read(encoded_cbor: &[u8]) -> Result<Value, DecoderError> {
|
|
read_nested(encoded_cbor, Some(i8::MAX))
|
|
}
|
|
|
|
/// Deserialize CBOR binary data to produce a single [`Value`], expecting that there is no additional data. If
|
|
/// `max_nest` is `Some(max)`, then nested structures are only supported up to the given limit (returning
|
|
/// [`DecoderError::TooMuchNesting`] if the limit is hit).
|
|
pub fn read_nested(encoded_cbor: &[u8], max_nest: Option<i8>) -> Result<Value, DecoderError> {
|
|
let mut reader = Reader::new(encoded_cbor);
|
|
let value = reader.decode_complete_data_item(max_nest)?;
|
|
if !reader.remaining_cbor.is_empty() {
|
|
return Err(DecoderError::ExtraneousData);
|
|
}
|
|
Ok(value)
|
|
}
|
|
|
|
struct Reader<'a> {
|
|
remaining_cbor: &'a [u8],
|
|
}
|
|
|
|
impl<'a> Reader<'a> {
|
|
pub fn new(cbor: &'a [u8]) -> Reader<'a> {
|
|
Reader {
|
|
remaining_cbor: cbor,
|
|
}
|
|
}
|
|
|
|
pub fn decode_complete_data_item(
|
|
&mut self,
|
|
remaining_depth: Option<i8>,
|
|
) -> Result<Value, DecoderError> {
|
|
if remaining_depth.map_or(false, |d| d < 0) {
|
|
return Err(DecoderError::TooMuchNesting);
|
|
}
|
|
|
|
match self.read_bytes(1) {
|
|
Some([first_byte]) => {
|
|
// Unsigned byte means logical shift, so only zeros get shifted in.
|
|
let major_type_value = first_byte >> Constants::MAJOR_TYPE_BIT_SHIFT;
|
|
let additional_info = first_byte & Constants::ADDITIONAL_INFORMATION_MASK;
|
|
let size_value = self.read_variadic_length_integer(additional_info)?;
|
|
match major_type_value {
|
|
0 => self.decode_value_to_unsigned(size_value),
|
|
1 => self.decode_value_to_negative(size_value),
|
|
2 => self.read_byte_string_content(size_value),
|
|
3 => self.read_text_string_content(size_value),
|
|
4 => self.read_array_content(size_value, remaining_depth),
|
|
5 => self.read_map_content(size_value, remaining_depth),
|
|
6 => self.read_tagged_content(size_value, remaining_depth),
|
|
7 => self.decode_to_simple_value(size_value, additional_info),
|
|
_ => Err(DecoderError::UnsupportedMajorType),
|
|
}
|
|
}
|
|
_ => Err(DecoderError::IncompleteCborData),
|
|
}
|
|
}
|
|
|
|
fn read_bytes(&mut self, num_bytes: usize) -> Option<&[u8]> {
|
|
if num_bytes > self.remaining_cbor.len() {
|
|
None
|
|
} else {
|
|
let (left, right) = self.remaining_cbor.split_at(num_bytes);
|
|
self.remaining_cbor = right;
|
|
Some(left)
|
|
}
|
|
}
|
|
|
|
fn read_variadic_length_integer(&mut self, additional_info: u8) -> Result<u64, DecoderError> {
|
|
let additional_bytes_num = match additional_info {
|
|
0..=Constants::ADDITIONAL_INFORMATION_MAX_INT => return Ok(additional_info as u64),
|
|
Constants::ADDITIONAL_INFORMATION_1_BYTE => 1,
|
|
Constants::ADDITIONAL_INFORMATION_2_BYTES => 2,
|
|
Constants::ADDITIONAL_INFORMATION_4_BYTES => 4,
|
|
Constants::ADDITIONAL_INFORMATION_8_BYTES => 8,
|
|
_ => return Err(DecoderError::UnknownAdditionalInfo),
|
|
};
|
|
match self.read_bytes(additional_bytes_num) {
|
|
Some(bytes) => {
|
|
let mut size_value = 0u64;
|
|
for byte in bytes {
|
|
size_value <<= 8;
|
|
size_value += *byte as u64;
|
|
}
|
|
if (additional_bytes_num == 1 && size_value < 24)
|
|
|| size_value < (1u64 << (8 * (additional_bytes_num >> 1)))
|
|
{
|
|
Err(DecoderError::NonMinimalCborEncoding)
|
|
} else {
|
|
Ok(size_value)
|
|
}
|
|
}
|
|
None => Err(DecoderError::IncompleteCborData),
|
|
}
|
|
}
|
|
|
|
fn decode_value_to_unsigned(&self, size_value: u64) -> Result<Value, DecoderError> {
|
|
Ok(cbor_unsigned!(size_value))
|
|
}
|
|
|
|
fn decode_value_to_negative(&self, size_value: u64) -> Result<Value, DecoderError> {
|
|
let signed_size = size_value as i64;
|
|
if signed_size < 0 {
|
|
Err(DecoderError::OutOfRangeIntegerValue)
|
|
} else {
|
|
Ok(Value::Negative(-(size_value as i64) - 1))
|
|
}
|
|
}
|
|
|
|
fn read_byte_string_content(&mut self, size_value: u64) -> Result<Value, DecoderError> {
|
|
match self.read_bytes(size_value as usize) {
|
|
Some(bytes) => Ok(cbor_bytes_lit!(bytes)),
|
|
None => Err(DecoderError::IncompleteCborData),
|
|
}
|
|
}
|
|
|
|
fn read_text_string_content(&mut self, size_value: u64) -> Result<Value, DecoderError> {
|
|
match self.read_bytes(size_value as usize) {
|
|
Some(bytes) => match str::from_utf8(bytes) {
|
|
Ok(s) => Ok(cbor_text!(s)),
|
|
Err(_) => Err(DecoderError::InvalidUtf8),
|
|
},
|
|
None => Err(DecoderError::IncompleteCborData),
|
|
}
|
|
}
|
|
|
|
fn read_array_content(
|
|
&mut self,
|
|
size_value: u64,
|
|
remaining_depth: Option<i8>,
|
|
) -> Result<Value, DecoderError> {
|
|
// Don't set the capacity already, it is an unsanitized input.
|
|
let mut value_array = Vec::new();
|
|
for _ in 0..size_value {
|
|
value_array.push(self.decode_complete_data_item(remaining_depth.map(|d| d - 1))?);
|
|
}
|
|
Ok(cbor_array_vec!(value_array))
|
|
}
|
|
|
|
fn read_map_content(
|
|
&mut self,
|
|
size_value: u64,
|
|
remaining_depth: Option<i8>,
|
|
) -> Result<Value, DecoderError> {
|
|
let mut value_map = Vec::<(Value, Value)>::new();
|
|
for _ in 0..size_value {
|
|
let key = self.decode_complete_data_item(remaining_depth.map(|d| d - 1))?;
|
|
if let Some(last_item) = value_map.last() {
|
|
if last_item.0 >= key {
|
|
return Err(DecoderError::OutOfOrderKey);
|
|
}
|
|
}
|
|
value_map.push((
|
|
key,
|
|
self.decode_complete_data_item(remaining_depth.map(|d| d - 1))?,
|
|
));
|
|
}
|
|
Ok(cbor_map_collection!(value_map))
|
|
}
|
|
|
|
fn read_tagged_content(
|
|
&mut self,
|
|
tag_value: u64,
|
|
remaining_depth: Option<i8>,
|
|
) -> Result<Value, DecoderError> {
|
|
let inner_value = self.decode_complete_data_item(remaining_depth.map(|d| d - 1))?;
|
|
Ok(cbor_tagged!(tag_value, inner_value))
|
|
}
|
|
|
|
fn decode_to_simple_value(
|
|
&self,
|
|
size_value: u64,
|
|
additional_info: u8,
|
|
) -> Result<Value, DecoderError> {
|
|
if additional_info > Constants::ADDITIONAL_INFORMATION_MAX_INT
|
|
&& additional_info != Constants::ADDITIONAL_INFORMATION_1_BYTE
|
|
{
|
|
// TODO(kaczmarczyck) the chromium C++ reference allows equality to 24 here, why?
|
|
// Also, why not just disallow ANY additional_info != size_value?
|
|
return Err(DecoderError::UnsupportedFloatingPointValue);
|
|
}
|
|
match SimpleValue::from_integer(size_value) {
|
|
Some(simple_value) => Ok(Value::Simple(simple_value)),
|
|
None => Err(DecoderError::UnsupportedSimpleValue),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
use crate::{
|
|
cbor_array, cbor_bytes, cbor_false, cbor_int, cbor_map, cbor_null, cbor_true,
|
|
cbor_undefined,
|
|
};
|
|
use alloc::vec;
|
|
|
|
#[test]
|
|
fn test_read_unsigned() {
|
|
let cases = vec![
|
|
(0, vec![0x00]),
|
|
(1, vec![0x01]),
|
|
(10, vec![0x0A]),
|
|
(23, vec![0x17]),
|
|
(24, vec![0x18, 0x18]),
|
|
(255, vec![0x18, 0xFF]),
|
|
(256, vec![0x19, 0x01, 0x00]),
|
|
(65535, vec![0x19, 0xFF, 0xFF]),
|
|
(65536, vec![0x1A, 0x00, 0x01, 0x00, 0x00]),
|
|
(0xFFFFFFFF, vec![0x1A, 0xFF, 0xFF, 0xFF, 0xFF]),
|
|
(
|
|
0x100000000,
|
|
vec![0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00],
|
|
),
|
|
(
|
|
core::i64::MAX,
|
|
vec![0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
|
|
),
|
|
];
|
|
for (unsigned, mut cbor) in cases {
|
|
assert_eq!(read(&cbor), Ok(cbor_int!(unsigned)));
|
|
cbor.push(0x01);
|
|
assert_eq!(read(&cbor), Err(DecoderError::ExtraneousData));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_unsigned_non_minimum_byte_length() {
|
|
let encodings = vec![
|
|
// Uint 23 encoded with 1 byte.
|
|
vec![0x18, 0x17],
|
|
// Uint 255 encoded with 2 bytes.
|
|
vec![0x19, 0x00, 0xff],
|
|
// Uint 65535 encoded with 4 bytes.
|
|
vec![0x1a, 0x00, 0x00, 0xff, 0xff],
|
|
// Uint 4294967295 encoded with 8 bytes.
|
|
vec![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.
|
|
vec![
|
|
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"
|
|
],
|
|
vec![
|
|
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"
|
|
],
|
|
vec![
|
|
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"
|
|
],
|
|
];
|
|
for encoding in encodings {
|
|
assert_eq!(read(&encoding), Err(DecoderError::NonMinimalCborEncoding));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_negative() {
|
|
let cases = vec![
|
|
(-1, vec![0x20]),
|
|
(-24, vec![0x37]),
|
|
(-25, vec![0x38, 0x18]),
|
|
(-256, vec![0x38, 0xFF]),
|
|
(-1000, vec![0x39, 0x03, 0xE7]),
|
|
(-1000000, vec![0x3A, 0x00, 0x0F, 0x42, 0x3F]),
|
|
(-4294967296, vec![0x3A, 0xFF, 0xFF, 0xFF, 0xFF]),
|
|
(
|
|
core::i64::MIN,
|
|
vec![0x3B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
|
|
),
|
|
];
|
|
for (negative, mut cbor) in cases {
|
|
assert_eq!(read(&cbor), Ok(cbor_int!(negative)));
|
|
cbor.push(0x01);
|
|
assert_eq!(read(&cbor), Err(DecoderError::ExtraneousData));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_byte_string() {
|
|
let cases = vec![
|
|
(Vec::new(), vec![0x40]),
|
|
(
|
|
vec![0x01, 0x02, 0x03, 0x04],
|
|
vec![0x44, 0x01, 0x02, 0x03, 0x04],
|
|
),
|
|
];
|
|
for (byte_string, mut cbor) in cases {
|
|
assert_eq!(read(&cbor), Ok(cbor_bytes!(byte_string)));
|
|
cbor.push(0x01);
|
|
assert_eq!(read(&cbor), Err(DecoderError::ExtraneousData));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_text_string() {
|
|
let unicode_3byte = vec![0xE6, 0xB0, 0xB4];
|
|
let cases = vec![
|
|
("", vec![0x60]),
|
|
("a", vec![0x61, 0x61]),
|
|
("IETF", vec![0x64, 0x49, 0x45, 0x54, 0x46]),
|
|
("\"\\", vec![0x62, 0x22, 0x5C]),
|
|
("ü", vec![0x62, 0xC3, 0xBC]),
|
|
(
|
|
core::str::from_utf8(&unicode_3byte).unwrap(),
|
|
vec![0x63, 0xE6, 0xB0, 0xB4],
|
|
),
|
|
("𐅑", vec![0x64, 0xF0, 0x90, 0x85, 0x91]),
|
|
];
|
|
for (text_string, mut cbor) in cases {
|
|
assert_eq!(read(&cbor), Ok(cbor_text!(text_string)));
|
|
cbor.push(0x01);
|
|
assert_eq!(read(&cbor), Err(DecoderError::ExtraneousData));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_text_string_with_nul() {
|
|
let cases = vec![
|
|
(
|
|
"string_without_nul",
|
|
vec![
|
|
0x72, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x5F, 0x77, 0x69, 0x74, 0x68, 0x6F,
|
|
0x75, 0x74, 0x5F, 0x6E, 0x75, 0x6C,
|
|
],
|
|
),
|
|
(
|
|
"nul_terminated_string\0",
|
|
vec![
|
|
0x76, 0x6E, 0x75, 0x6C, 0x5F, 0x74, 0x65, 0x72, 0x6D, 0x69, 0x6E, 0x61, 0x74,
|
|
0x65, 0x64, 0x5F, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x00,
|
|
],
|
|
),
|
|
(
|
|
"embedded\0nul",
|
|
vec![
|
|
0x6C, 0x65, 0x6D, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x00, 0x6E, 0x75, 0x6C,
|
|
],
|
|
),
|
|
(
|
|
"trailing_nuls\0\0",
|
|
vec![
|
|
0x6F, 0x74, 0x72, 0x61, 0x69, 0x6C, 0x69, 0x6E, 0x67, 0x5F, 0x6E, 0x75, 0x6C,
|
|
0x73, 0x00, 0x00,
|
|
],
|
|
),
|
|
];
|
|
for (text_string, mut cbor) in cases {
|
|
assert_eq!(read(&cbor), Ok(cbor_text!(text_string)));
|
|
cbor.push(0x01);
|
|
assert_eq!(read(&cbor), Err(DecoderError::ExtraneousData));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_text_string_with_invalid_byte_sequence_after_nul() {
|
|
assert_eq!(
|
|
read(&vec![0x63, 0x00, 0x00, 0xA6]),
|
|
Err(DecoderError::InvalidUtf8)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_array() {
|
|
let value_vec: Vec<_> = (1..26).collect();
|
|
let mut test_cbor = vec![
|
|
0x98, 0x19, 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,
|
|
];
|
|
assert_eq!(read(&test_cbor.clone()), Ok(cbor_array_vec!(value_vec)));
|
|
test_cbor.push(0x01);
|
|
assert_eq!(read(&test_cbor), Err(DecoderError::ExtraneousData));
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_map() {
|
|
let value_map = cbor_map! {
|
|
24 => "abc",
|
|
"" => ".",
|
|
"b" => "B",
|
|
"aa" => "AA",
|
|
};
|
|
let mut test_cbor = vec![
|
|
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"
|
|
];
|
|
assert_eq!(read(&test_cbor), Ok(value_map));
|
|
test_cbor.push(0x01);
|
|
assert_eq!(read(&test_cbor), Err(DecoderError::ExtraneousData));
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_map_with_unsigned_keys() {
|
|
let value_map = cbor_map! {
|
|
1 => "a",
|
|
9 => "b",
|
|
999 => "c",
|
|
1111 => "d",
|
|
};
|
|
let mut test_cbor = vec![
|
|
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"
|
|
];
|
|
assert_eq!(read(&test_cbor), Ok(value_map));
|
|
test_cbor.push(0x01);
|
|
assert_eq!(read(&test_cbor), Err(DecoderError::ExtraneousData));
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_map_with_negative_keys() {
|
|
let value_map = cbor_map! {
|
|
-1 => 1,
|
|
-2 => 2,
|
|
-100 => 3,
|
|
};
|
|
let mut test_cbor = vec![
|
|
0xA3, // map with 3 key value pairs
|
|
0x20, // key : -1
|
|
0x01, // value : 1
|
|
0x21, // key : -2
|
|
0x02, // value : 2
|
|
0x38, 0x63, // key : -100
|
|
0x03, // value : 3
|
|
];
|
|
assert_eq!(read(&test_cbor), Ok(value_map));
|
|
test_cbor.push(0x01);
|
|
assert_eq!(read(&test_cbor), Err(DecoderError::ExtraneousData));
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_map_with_array() {
|
|
let value_map = cbor_map! {
|
|
"a" => 1,
|
|
"b" => cbor_array![2, 3],
|
|
};
|
|
let mut test_cbor = vec![
|
|
0xa2, // map of 2 pairs
|
|
0x61, 0x61, // "a"
|
|
0x01, 0x61, 0x62, // "b"
|
|
0x82, // array with 2 elements
|
|
0x02, 0x03,
|
|
];
|
|
assert_eq!(read(&test_cbor), Ok(value_map));
|
|
test_cbor.push(0x01);
|
|
assert_eq!(read(&test_cbor), Err(DecoderError::ExtraneousData));
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_map_with_text_string_keys() {
|
|
let value_map = cbor_map! {
|
|
"k" => "v",
|
|
"foo" => "bar",
|
|
};
|
|
let mut test_cbor = vec![
|
|
0xa2, // map of 2 pairs
|
|
0x61, b'k', // text string "k"
|
|
0x61, b'v', 0x63, b'f', b'o', b'o', // text string "foo"
|
|
0x63, b'b', b'a', b'r',
|
|
];
|
|
assert_eq!(read(&test_cbor), Ok(value_map));
|
|
test_cbor.push(0x01);
|
|
assert_eq!(read(&test_cbor), Err(DecoderError::ExtraneousData));
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_map_with_byte_string_keys() {
|
|
let value_map = cbor_map! {
|
|
b"k" => b"v",
|
|
b"foo" => b"bar",
|
|
};
|
|
let mut test_cbor = vec![
|
|
0xa2, // map of 2 pairs
|
|
0x41, b'k', // text string "k"
|
|
0x41, b'v', 0x43, b'f', b'o', b'o', // text string "foo"
|
|
0x43, b'b', b'a', b'r',
|
|
];
|
|
assert_eq!(read(&test_cbor), Ok(value_map));
|
|
test_cbor.push(0x01);
|
|
assert_eq!(read(&test_cbor), Err(DecoderError::ExtraneousData));
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_nested_map() {
|
|
let value_map = cbor_map! {
|
|
"a" => 1,
|
|
"b" => cbor_map! {
|
|
"c" => 2,
|
|
"d" => 3,
|
|
},
|
|
};
|
|
let mut test_cbor = vec![
|
|
0xa2, // map of 2 pairs
|
|
0x61, 0x61, 0x01, // "a"
|
|
0x61, 0x62, // "b"
|
|
0xa2, // map of 2 pairs
|
|
0x61, 0x63, 0x02, // "c"
|
|
0x61, 0x64, 0x03, // "d"
|
|
];
|
|
assert_eq!(read(&test_cbor), Ok(value_map));
|
|
test_cbor.push(0x01);
|
|
assert_eq!(read(&test_cbor), Err(DecoderError::ExtraneousData));
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_tagged() {
|
|
let cases = vec![
|
|
(cbor_tagged!(6, cbor_int!(0x42)), vec![0xc6, 0x18, 0x42]),
|
|
(cbor_tagged!(1, cbor_true!()), vec![0xc1, 0xf5]),
|
|
(
|
|
cbor_tagged!(
|
|
1000,
|
|
cbor_map! {
|
|
"a" => 1,
|
|
"b" => cbor_array![2, 3],
|
|
}
|
|
),
|
|
vec![
|
|
0xd9, 0x03, 0xe8, 0xa2, // map of 2 pairs
|
|
0x61, 0x61, // "a"
|
|
0x01, 0x61, 0x62, // "b"
|
|
0x82, // array with 2 elements
|
|
0x02, 0x03,
|
|
],
|
|
),
|
|
];
|
|
for (value, mut cbor) in cases {
|
|
assert_eq!(read(&cbor), Ok(value));
|
|
cbor.push(0x01);
|
|
assert_eq!(read(&cbor), Err(DecoderError::ExtraneousData));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_integer_out_of_range() {
|
|
let cases = vec![
|
|
// The positive case is impossible since we support u64.
|
|
// vec![0x1B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
|
vec![0x3B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
|
];
|
|
for cbor in cases {
|
|
assert_eq!(read(&cbor), Err(DecoderError::OutOfRangeIntegerValue));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_simple_value() {
|
|
let cases = vec![
|
|
(cbor_false!(), vec![0xF4]),
|
|
(cbor_true!(), vec![0xF5]),
|
|
(cbor_null!(), vec![0xF6]),
|
|
(cbor_undefined!(), vec![0xF7]),
|
|
];
|
|
for (simple, mut cbor) in cases {
|
|
assert_eq!(read(&cbor.clone()), Ok(simple));
|
|
cbor.push(0x01);
|
|
assert_eq!(read(&cbor), Err(DecoderError::ExtraneousData));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_unsupported_floating_point_numbers() {
|
|
let cases = vec![
|
|
vec![0xF9, 0x10, 0x00],
|
|
vec![0xFA, 0x10, 0x00, 0x00, 0x00],
|
|
vec![0xFB, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
|
];
|
|
for cbor in cases {
|
|
assert_eq!(
|
|
read(&cbor),
|
|
Err(DecoderError::UnsupportedFloatingPointValue)
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_incomplete_cbor_data_error() {
|
|
let cases = vec![
|
|
vec![0x19, 0x03],
|
|
vec![0x44, 0x01, 0x02, 0x03],
|
|
vec![0x65, 0x49, 0x45, 0x54, 0x46],
|
|
vec![0x82, 0x02],
|
|
vec![0xA2, 0x61, 0x61, 0x01],
|
|
vec![0x18],
|
|
vec![0x99],
|
|
vec![0xBA],
|
|
vec![0x5B],
|
|
vec![0x3B],
|
|
vec![0x99, 0x01],
|
|
vec![0xBA, 0x01, 0x02, 0x03],
|
|
vec![0x3B, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07],
|
|
];
|
|
for cbor in cases {
|
|
assert_eq!(read(&cbor), Err(DecoderError::IncompleteCborData));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_unknown_additional_info_error() {
|
|
let cases = vec![
|
|
vec![0x7C, 0x49, 0x45, 0x54, 0x46],
|
|
vec![0x7D, 0x22, 0x5C],
|
|
vec![0x7E, 0xC3, 0xBC],
|
|
vec![0x7F, 0xE6, 0xB0, 0xB4],
|
|
vec![0xFC],
|
|
vec![0xFD],
|
|
vec![0xFE],
|
|
vec![0xFF],
|
|
];
|
|
for cbor in cases {
|
|
assert_eq!(read(&cbor), Err(DecoderError::UnknownAdditionalInfo));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_too_much_nesting_error() {
|
|
let cases = vec![
|
|
vec![0x18, 0x64],
|
|
vec![0x44, 0x01, 0x02, 0x03, 0x04],
|
|
vec![0x64, 0x49, 0x45, 0x54, 0x46],
|
|
vec![0x80],
|
|
vec![0xA0],
|
|
];
|
|
for cbor in cases {
|
|
let mut reader = Reader::new(&cbor);
|
|
assert!(reader.decode_complete_data_item(Some(0)).is_ok());
|
|
}
|
|
let map_cbor = vec![
|
|
0xa2, // map of 2 pairs
|
|
0x61, 0x61, // "a"
|
|
0x01, 0x61, 0x62, // "b"
|
|
0x82, // array with 2 elements
|
|
0x02, 0x03,
|
|
];
|
|
let mut reader = Reader::new(&map_cbor);
|
|
assert_eq!(
|
|
reader.decode_complete_data_item(Some(1)),
|
|
Err(DecoderError::TooMuchNesting)
|
|
);
|
|
reader = Reader::new(&map_cbor);
|
|
assert!(reader.decode_complete_data_item(Some(2)).is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_out_of_order_key_error() {
|
|
let cases = vec![
|
|
vec![
|
|
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"
|
|
],
|
|
vec![
|
|
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
|
|
],
|
|
vec![
|
|
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"
|
|
],
|
|
vec![
|
|
0xa2, // map with 2 text string keys
|
|
0x62, b'a', b'a', // key text string "aa"
|
|
// (out of order due to longer length)
|
|
0x02, 0x61, b'b', // key "b"
|
|
0x01,
|
|
],
|
|
vec![
|
|
0xa2, // map with 2 byte string keys
|
|
0x42, b'x', b'x', // key byte string "xx"
|
|
// (out of order due to longer length)
|
|
0x02, 0x41, b'y', // key byte string "y"
|
|
0x01,
|
|
],
|
|
];
|
|
for cbor in cases {
|
|
assert_eq!(read(&cbor), Err(DecoderError::OutOfOrderKey));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_duplicate_key_error() {
|
|
let map_with_duplicate_key = vec![
|
|
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"
|
|
];
|
|
assert_eq!(
|
|
read(&map_with_duplicate_key),
|
|
Err(DecoderError::OutOfOrderKey)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_incorrect_string_encoding_error() {
|
|
let cases = vec![
|
|
vec![0x63, 0xED, 0x9F, 0xBF],
|
|
vec![0x63, 0xEE, 0x80, 0x80],
|
|
vec![0x63, 0xEF, 0xBF, 0xBD],
|
|
];
|
|
for cbor in cases {
|
|
assert!(read(&cbor).is_ok());
|
|
}
|
|
let impossible_utf_byte = vec![0x64, 0xFE, 0xFE, 0xFF, 0xFF];
|
|
assert_eq!(read(&impossible_utf_byte), Err(DecoderError::InvalidUtf8));
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_extraneous_cbor_data_error() {
|
|
let cases = vec![
|
|
vec![0x19, 0x03, 0x05, 0x00],
|
|
vec![0x44, 0x01, 0x02, 0x03, 0x04, 0x00],
|
|
vec![0x64, 0x49, 0x45, 0x54, 0x46, 0x00],
|
|
vec![0x82, 0x01, 0x02, 0x00],
|
|
vec![0xa1, 0x61, 0x63, 0x02, 0x61, 0x64, 0x03],
|
|
];
|
|
for cbor in cases {
|
|
assert_eq!(read(&cbor), Err(DecoderError::ExtraneousData));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_unsupported_simple_type() {
|
|
let cases = vec![
|
|
vec![0xE0],
|
|
vec![0xF3],
|
|
vec![0xF8, 0x18],
|
|
vec![0xF8, 0x1C],
|
|
vec![0xF8, 0x1D],
|
|
vec![0xF8, 0x1E],
|
|
vec![0xF8, 0x1F],
|
|
vec![0xF8, 0x20],
|
|
vec![0xF8, 0xFF],
|
|
];
|
|
for cbor in cases {
|
|
assert_eq!(read(&cbor), Err(DecoderError::UnsupportedSimpleValue));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_super_long_content_dont_crash() {
|
|
let cases = vec![
|
|
vec![0x9B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
|
|
vec![0xBB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
|
|
];
|
|
for cbor in cases {
|
|
assert_eq!(read(&cbor), Err(DecoderError::IncompleteCborData));
|
|
}
|
|
}
|
|
}
|