diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/rust/moz_cbor/src | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/moz_cbor/src')
-rw-r--r-- | third_party/rust/moz_cbor/src/decoder.rs | 165 | ||||
-rw-r--r-- | third_party/rust/moz_cbor/src/lib.rs | 51 | ||||
-rw-r--r-- | third_party/rust/moz_cbor/src/serializer.rs | 124 | ||||
-rw-r--r-- | third_party/rust/moz_cbor/src/test_decoder.rs | 445 | ||||
-rw-r--r-- | third_party/rust/moz_cbor/src/test_serializer.rs | 324 |
5 files changed, 1109 insertions, 0 deletions
diff --git a/third_party/rust/moz_cbor/src/decoder.rs b/third_party/rust/moz_cbor/src/decoder.rs new file mode 100644 index 0000000000..f93bb13f1c --- /dev/null +++ b/third_party/rust/moz_cbor/src/decoder.rs @@ -0,0 +1,165 @@ +use std::collections::BTreeMap; +use std::io::{Cursor, Read, Seek, SeekFrom}; +use {CborError, CborType}; + +// We limit the length of any cbor byte array to 128MiB. This is a somewhat +// arbitrary limit that should work on all platforms and is large enough for +// any benign data. +pub const MAX_ARRAY_SIZE: usize = 134_217_728; + +// Prevent stack exhaustion by limiting the nested depth of CBOR data. +const MAX_NESTED_DEPTH: usize = 256; + +/// Struct holding a cursor and additional information for decoding. +#[derive(Debug)] +struct DecoderCursor<'a> { + cursor: Cursor<&'a [u8]>, + depth: usize, +} + +/// Apply this mask (with &) to get the value part of the initial byte of a CBOR item. +const INITIAL_VALUE_MASK: u64 = 0b0001_1111; + +impl<'a> DecoderCursor<'a> { + /// Read and return the given number of bytes from the cursor. Advances the cursor. + fn read_bytes(&mut self, len: usize) -> Result<Vec<u8>, CborError> { + if len > MAX_ARRAY_SIZE { + return Err(CborError::InputTooLarge); + } + let mut buf: Vec<u8> = vec![0; len]; + if self.cursor.read_exact(&mut buf).is_err() { + Err(CborError::TruncatedInput) + } else { + Ok(buf) + } + } + + /// Convert num bytes to a u64 + fn read_uint_from_bytes(&mut self, num: usize) -> Result<u64, CborError> { + let x = self.read_bytes(num)?; + let mut result: u64 = 0; + for i in (0..num).rev() { + result += u64::from(x[num - 1 - i]) << (i * 8); + } + Ok(result) + } + + /// Read an integer and return it as u64. + fn read_int(&mut self) -> Result<u64, CborError> { + let first_value = self.read_uint_from_bytes(1)? & INITIAL_VALUE_MASK; + match first_value { + 0..=23 => Ok(first_value), + 24 => self.read_uint_from_bytes(1), + 25 => self.read_uint_from_bytes(2), + 26 => self.read_uint_from_bytes(4), + 27 => self.read_uint_from_bytes(8), + _ => Err(CborError::MalformedInput), + } + } + + fn read_negative_int(&mut self) -> Result<CborType, CborError> { + let uint = self.read_int()?; + if uint > i64::max_value() as u64 { + return Err(CborError::InputValueOutOfRange); + } + let result: i64 = -1 - uint as i64; + Ok(CborType::SignedInteger(result)) + } + + /// Read an array of data items and return it. + fn read_array(&mut self) -> Result<CborType, CborError> { + // Create a new array. + let mut array: Vec<CborType> = Vec::new(); + // Read the length of the array. + let num_items = self.read_int()?; + // Decode each of the num_items data items. + for _ in 0..num_items { + let new_item = self.decode_item()?; + array.push(new_item); + } + Ok(CborType::Array(array)) + } + + /// Read a byte string and return it. + fn read_byte_string(&mut self) -> Result<CborType, CborError> { + let length = self.read_int()?; + if length > MAX_ARRAY_SIZE as u64 { + return Err(CborError::InputTooLarge); + } + let byte_string = self.read_bytes(length as usize)?; + Ok(CborType::Bytes(byte_string)) + } + + /// Read a map. + fn read_map(&mut self) -> Result<CborType, CborError> { + let num_items = self.read_int()?; + // Create a new array. + let mut map: BTreeMap<CborType, CborType> = BTreeMap::new(); + // Decode each of the num_items (key, data item) pairs. + for _ in 0..num_items { + let key_val = self.decode_item()?; + let item_value = self.decode_item()?; + if map.insert(key_val, item_value).is_some() { + return Err(CborError::DuplicateMapKey); + } + } + Ok(CborType::Map(map)) + } + + fn read_null(&mut self) -> Result<CborType, CborError> { + let value = self.read_uint_from_bytes(1)? & INITIAL_VALUE_MASK; + if value != 22 { + return Err(CborError::UnsupportedType); + } + Ok(CborType::Null) + } + + /// Peeks at the next byte in the cursor, but does not change the position. + fn peek_byte(&mut self) -> Result<u8, CborError> { + let x = self.read_bytes(1)?; + if self.cursor.seek(SeekFrom::Current(-1)).is_err() { + return Err(CborError::LibraryError); + }; + Ok(x[0]) + } + + /// Decodes the next CBOR item. + pub fn decode_item(&mut self) -> Result<CborType, CborError> { + if self.depth > MAX_NESTED_DEPTH { + return Err(CborError::MalformedInput); + } + self.depth += 1; + let major_type = self.peek_byte()? >> 5; + let result = match major_type { + 0 => { + let value = self.read_int()?; + Ok(CborType::Integer(value)) + } + 1 => self.read_negative_int(), + 2 => self.read_byte_string(), + 4 => self.read_array(), + 5 => self.read_map(), + 6 => { + let tag = self.read_int()?; + let item = self.decode_item()?; + Ok(CborType::Tag(tag, Box::new(item))) + } + 7 => self.read_null(), + _ => Err(CborError::UnsupportedType), + }; + self.depth -= 1; + result + } +} + +/// Read the CBOR structure in bytes and return it as a `CborType`. To prevent stack exhaustion, the +/// maximum nested depth of CBOR objects (for example, an array of an array of an array...) is 256. +/// If the input data describes a CBOR structure that exceeds this limit, an error will be returned. +pub fn decode(bytes: &[u8]) -> Result<CborType, CborError> { + let mut decoder_cursor = DecoderCursor { + cursor: Cursor::new(bytes), + depth: 0, + }; + decoder_cursor.decode_item() + // TODO: check cursor at end? +} diff --git a/third_party/rust/moz_cbor/src/lib.rs b/third_party/rust/moz_cbor/src/lib.rs new file mode 100644 index 0000000000..de9f992df0 --- /dev/null +++ b/third_party/rust/moz_cbor/src/lib.rs @@ -0,0 +1,51 @@ +pub mod decoder; +pub mod serializer; +#[cfg(test)] +mod test_decoder; +#[cfg(test)] +mod test_serializer; + +use std::cmp::Ordering; +use std::collections::BTreeMap; + +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq)] +pub enum CborType { + Integer(u64), + SignedInteger(i64), + Tag(u64, Box<CborType>), + Bytes(Vec<u8>), + String(String), + Array(Vec<CborType>), + Map(BTreeMap<CborType, CborType>), + Null, +} + +#[derive(Debug, PartialEq)] +pub enum CborError { + DuplicateMapKey, + InputTooLarge, + InputValueOutOfRange, + LibraryError, + MalformedInput, + TruncatedInput, + UnsupportedType, +} + +impl Ord for CborType { + /// Sorting for maps: RFC 7049 Section 3.9 + /// + /// The keys in every map must be sorted lowest value to highest. + /// * 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. + fn cmp(&self, other: &Self) -> Ordering { + let self_bytes = self.serialize(); + let other_bytes = other.serialize(); + if self_bytes.len() == other_bytes.len() { + return self_bytes.cmp(&other_bytes); + } + self_bytes.len().cmp(&other_bytes.len()) + } +} diff --git a/third_party/rust/moz_cbor/src/serializer.rs b/third_party/rust/moz_cbor/src/serializer.rs new file mode 100644 index 0000000000..b796aaedc7 --- /dev/null +++ b/third_party/rust/moz_cbor/src/serializer.rs @@ -0,0 +1,124 @@ +use std::collections::BTreeMap; +use CborType; + +/// Given a vector of bytes to append to, a tag to use, and an unsigned value to encode, uses the +/// CBOR unsigned integer encoding to represent the given value. +fn common_encode_unsigned(output: &mut Vec<u8>, tag: u8, value: u64) { + assert!(tag < 8); + let shifted_tag = tag << 5; + match value { + 0..=23 => { + output.push(shifted_tag | (value as u8)); + } + 24..=255 => { + output.push(shifted_tag | 24); + output.push(value as u8); + } + 256..=65_535 => { + output.push(shifted_tag | 25); + output.push((value >> 8) as u8); + output.push((value & 255) as u8); + } + 65_536..=4_294_967_295 => { + output.push(shifted_tag | 26); + output.push((value >> 24) as u8); + output.push(((value >> 16) & 255) as u8); + output.push(((value >> 8) & 255) as u8); + output.push((value & 255) as u8); + } + _ => { + output.push(shifted_tag | 27); + output.push((value >> 56) as u8); + output.push(((value >> 48) & 255) as u8); + output.push(((value >> 40) & 255) as u8); + output.push(((value >> 32) & 255) as u8); + output.push(((value >> 24) & 255) as u8); + output.push(((value >> 16) & 255) as u8); + output.push(((value >> 8) & 255) as u8); + output.push((value & 255) as u8); + } + }; +} + +/// The major type is 0. For values 0 through 23, the 5 bits of additional information is just the +/// value of the unsigned number. For values representable in one byte, the additional information +/// has the value 24. If two bytes are necessary, the value is 25. If four bytes are necessary, the +/// value is 26. If 8 bytes are necessary, the value is 27. The following bytes are the value of the +/// unsigned number in as many bytes were indicated in network byte order (big endian). +fn encode_unsigned(output: &mut Vec<u8>, unsigned: u64) { + common_encode_unsigned(output, 0, unsigned); +} + +/// The major type is 1. The encoding is the same as for positive (i.e. unsigned) integers, except +/// the value encoded is -1 minus the value of the negative number. +fn encode_negative(output: &mut Vec<u8>, negative: i64) { + assert!(negative < 0); + let value_to_encode: u64 = (-1 - negative) as u64; + common_encode_unsigned(output, 1, value_to_encode); +} + +/// The major type is 2. The length of the data is encoded as with positive integers, followed by +/// the actual data. +fn encode_bytes(output: &mut Vec<u8>, bstr: &[u8]) { + common_encode_unsigned(output, 2, bstr.len() as u64); + output.extend_from_slice(bstr); +} + +/// The major type is 3. The length is as with bstr. The UTF-8-encoded bytes of the string follow. +fn encode_string(output: &mut Vec<u8>, tstr: &str) { + let utf8_bytes = tstr.as_bytes(); + common_encode_unsigned(output, 3, utf8_bytes.len() as u64); + output.extend_from_slice(utf8_bytes); +} + +/// The major type is 4. The number of items is encoded as with positive integers. Then follows the +/// encodings of the items themselves. +fn encode_array(output: &mut Vec<u8>, array: &[CborType]) { + common_encode_unsigned(output, 4, array.len() as u64); + for element in array { + output.append(&mut element.serialize()); + } +} + +/// The major type is 5. The number of pairs is encoded as with positive integers. Then follows the +/// encodings of each key, value pair. In Canonical CBOR, the keys must be sorted lowest value to +/// highest. +fn encode_map(output: &mut Vec<u8>, map: &BTreeMap<CborType, CborType>) { + common_encode_unsigned(output, 5, map.len() as u64); + for (key, value) in map { + output.append(&mut key.serialize()); + output.append(&mut value.serialize()); + } +} + +fn encode_tag(output: &mut Vec<u8>, tag: &u64, val: &CborType) { + common_encode_unsigned(output, 6, *tag); + output.append(&mut val.serialize()); +} + +/// The major type is 7. The only supported value for this type is 22, which is Null. +/// This makes the encoded value 246, or 0xf6. +fn encode_null(output: &mut Vec<u8>) { + output.push(0xf6); +} + +impl CborType { + /// Serialize a Cbor object. NB: if the object to be serialized consists of too many nested + /// Cbor objects (for example, Array(Array(Array(...(Array(0))))), it is possible that calling + /// serialize will exhaust the stack. It is considered the caller's responsibility to prevent + /// this. + pub fn serialize(&self) -> Vec<u8> { + let mut bytes: Vec<u8> = Vec::new(); + match *self { + CborType::Integer(ref unsigned) => encode_unsigned(&mut bytes, *unsigned), + CborType::SignedInteger(ref negative) => encode_negative(&mut bytes, *negative), + CborType::Bytes(ref bstr) => encode_bytes(&mut bytes, bstr), + CborType::String(ref tstr) => encode_string(&mut bytes, tstr), + CborType::Array(ref arr) => encode_array(&mut bytes, arr), + CborType::Map(ref map) => encode_map(&mut bytes, map), + CborType::Tag(ref t, ref val) => encode_tag(&mut bytes, t, val), + CborType::Null => encode_null(&mut bytes), + }; + bytes + } +} diff --git a/third_party/rust/moz_cbor/src/test_decoder.rs b/third_party/rust/moz_cbor/src/test_decoder.rs new file mode 100644 index 0000000000..68db8724d9 --- /dev/null +++ b/third_party/rust/moz_cbor/src/test_decoder.rs @@ -0,0 +1,445 @@ +use decoder::{decode, MAX_ARRAY_SIZE}; +use std::collections::BTreeMap; +use {CborError, CborType}; + +// First test all the basic types +fn test_decoder(bytes: Vec<u8>, expected: CborType) { + let result = decode(&bytes); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), expected); +} + +fn test_decoder_error(bytes: Vec<u8>, expected_error: CborError) { + let result = decode(&bytes); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), expected_error); +} + +fn test_integer(bytes: Vec<u8>, expected: u64) { + let decoded = decode(&bytes).unwrap(); + match decoded { + CborType::Integer(val) => assert_eq!(val, expected), + _ => assert_eq!(1, 0), + } +} + +fn test_integer_all(bytes: Vec<u8>, expected_value: u64) { + let expected = CborType::Integer(expected_value); + test_decoder(bytes.clone(), expected); + test_integer(bytes, expected_value); +} + +#[test] +fn test_integer_objects() { + let bytes: Vec<u8> = vec![0x00]; + test_integer_all(bytes, 0); + + let bytes = vec![0x01]; + test_integer_all(bytes, 1); + + let bytes = vec![0x0A]; + test_integer_all(bytes, 10); + + let bytes = vec![0x17]; + test_integer_all(bytes, 23); + + let bytes = vec![0x18, 0x18]; + test_integer_all(bytes, 24); + + let bytes = vec![0x18, 0x19]; + test_integer_all(bytes, 25); + + let bytes = vec![0x18, 0x64]; + test_integer_all(bytes, 100); + + let bytes = vec![0x19, 0x03, 0xe8]; + test_integer_all(bytes, 1000); + + let bytes = vec![0x1a, 0x00, 0x0f, 0x42, 0x40]; + test_integer_all(bytes, 1000000); + + let bytes = vec![0x1b, 0x00, 0x00, 0x00, 0xe8, 0xd4, 0xa5, 0x10, 0x00]; + test_integer_all(bytes, 1000000000000); + + let bytes = vec![0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; + test_integer_all(bytes, 18446744073709551615); +} + +#[cfg(test)] +fn test_tag(bytes: Vec<u8>, expected_tag: u64, expected_value: CborType) { + let decoded = decode(&bytes).unwrap(); + match decoded { + CborType::Tag(tag, value) => { + assert_eq!(expected_tag, tag); + assert_eq!(expected_value, *value); + } + _ => assert_eq!(1, 0), + } +} + +#[test] +fn test_tagged_objects() { + let bytes: Vec<u8> = vec![0xD2, 0x02]; + let expected_tag_value = 0x12; + let expected_value = CborType::Integer(2); + let expected = CborType::Tag(expected_tag_value, Box::new(expected_value.clone())); + test_decoder(bytes.clone(), expected); + test_tag(bytes, expected_tag_value, expected_value); +} + +#[test] +#[cfg_attr(rustfmt, rustfmt_skip)] +fn test_arrays() { + // [] + let bytes: Vec<u8> = vec![0x80]; + let expected = CborType::Array(vec![]); + test_decoder(bytes, expected); + + // [1, 2, 3] + let bytes: Vec<u8> = vec![0x83, 0x01, 0x02, 0x03]; + let tmp = vec![ + CborType::Integer(1), + CborType::Integer(2), + CborType::Integer(3), + ]; + let expected = CborType::Array(tmp); + test_decoder(bytes, expected); + + // [1, [2, 3], [4, 5]] + let bytes: Vec<u8> = vec![0x83, 0x01, 0x82, 0x02, 0x03, 0x82, 0x04, 0x05]; + let tmp1 = vec![CborType::Integer(2), CborType::Integer(3)]; + let tmp2 = vec![CborType::Integer(4), CborType::Integer(5)]; + let tmp = vec![ + CborType::Integer(1), + CborType::Array(tmp1), + CborType::Array(tmp2), + ]; + let expected = CborType::Array(tmp); + test_decoder(bytes, expected); + + // [1, [[[[1]]]], [1]] + let bytes: Vec<u8> = vec![0x83, 0x01, 0x81, 0x81, 0x81, 0x81, 0x01, 0x81, 0x02]; + let tmp = vec![ + CborType::Integer(1), + CborType::Array(vec![ + CborType::Array(vec![ + CborType::Array(vec![ + CborType::Array(vec![ + CborType::Integer(1)])])])]), + CborType::Array(vec![CborType::Integer(2)]), + ]; + let expected = CborType::Array(tmp); + test_decoder(bytes, expected); + + let bytes: Vec<u8> = vec![0x98, 0x1A, 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, 0x82, 0x81, 0x81, + 0x81, 0x05, 0x81, 0x1A, 0x49, 0x96, 0x02, 0xD2]; + // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + // 21, 22, 23, 24, 25, [[[[5]]], [1234567890]]] + let tmp = vec![ + CborType::Integer(1), + CborType::Integer(2), + CborType::Integer(3), + CborType::Integer(4), + CborType::Integer(5), + CborType::Integer(6), + CborType::Integer(7), + CborType::Integer(8), + CborType::Integer(9), + CborType::Integer(10), + CborType::Integer(11), + CborType::Integer(12), + CborType::Integer(13), + CborType::Integer(14), + CborType::Integer(15), + CborType::Integer(16), + CborType::Integer(17), + CborType::Integer(18), + CborType::Integer(19), + CborType::Integer(20), + CborType::Integer(21), + CborType::Integer(22), + CborType::Integer(23), + CborType::Integer(24), + CborType::Integer(25), + CborType::Array(vec![ + CborType::Array(vec![ + CborType::Array(vec![ + CborType::Array(vec![ + CborType::Integer(5)])])]), + CborType::Array(vec![CborType::Integer(1234567890)])]) + ]; + let expected = CborType::Array(tmp); + test_decoder(bytes, expected); +} + +#[test] +fn test_signed_integer() { + let bytes: Vec<u8> = vec![0x20]; + let expected = CborType::SignedInteger(-1); + test_decoder(bytes, expected); + + let bytes = vec![0x29]; + let expected = CborType::SignedInteger(-10); + test_decoder(bytes, expected); + + let bytes = vec![0x38, 0x63]; + let expected = CborType::SignedInteger(-100); + test_decoder(bytes, expected); + + let bytes = vec![0x39, 0x03, 0xe7]; + let expected = CborType::SignedInteger(-1000); + test_decoder(bytes, expected); + + let bytes = vec![0x39, 0x27, 0x0F]; + let expected = CborType::SignedInteger(-10000); + test_decoder(bytes, expected); + + let bytes = vec![0x3A, 0x00, 0x01, 0x86, 0x9F]; + let expected = CborType::SignedInteger(-100000); + test_decoder(bytes, expected); + + let bytes = vec![0x3B, 0x00, 0x00, 0x00, 0xE8, 0xD4, 0xA5, 0x0F, 0xFF]; + let expected = CborType::SignedInteger(-1000000000000); + test_decoder(bytes, expected); +} + +#[test] +fn test_byte_strings() { + let bytes: Vec<u8> = vec![0x40]; + let expected = CborType::Bytes(vec![]); + test_decoder(bytes, expected); + + // 01020304 + let bytes: Vec<u8> = vec![0x44, 0x01, 0x02, 0x03, 0x04]; + let expected = CborType::Bytes(vec![0x01, 0x02, 0x03, 0x04]); + test_decoder(bytes, expected); + + // 0102030405060708090A0B0C0D0E0F10203040506070 + let bytes: Vec<u8> = vec![ + 0x56, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, + ]; + let expected = CborType::Bytes(vec![ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, + ]); + test_decoder(bytes, expected); + + let bytes: Vec<u8> = vec![ + 0x59, 0x01, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, + ]; + let expected = CborType::Bytes(vec![ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + ]); + test_decoder(bytes, expected); +} + +#[test] +fn test_maps() { + // {} + let bytes: Vec<u8> = vec![0xa0]; + let expected: BTreeMap<CborType, CborType> = BTreeMap::new(); + test_decoder(bytes, CborType::Map(expected)); + + // {1: 2, 3: 4} + let bytes: Vec<u8> = vec![0xa2, 0x01, 0x02, 0x03, 0x04]; + let mut expected: BTreeMap<CborType, CborType> = BTreeMap::new(); + expected.insert(CborType::Integer(1), CborType::Integer(2)); + expected.insert(CborType::Integer(3), CborType::Integer(4)); + test_decoder(bytes, CborType::Map(expected)); + + // TODO: strings aren't properly supported as keys yet. + // {"a": 1, "b": [2, 3]} + // let bytes: Vec<u8> = vec![0xa2, 0x61, 0x61, 0x01, 0x61, 0x62, 0x82, 0x02, 0x03]; + // let expected = + // CborType::Map(vec![ + // CborMap{key: CborType::Integer(1), value: CborType::Integer(2)}, + // CborMap{key: CborType::Integer(3), value: CborType::Integer(4)}]); + // test_decoder(bytes, expected); + + // let bytes: Vec<u8> = vec![0x82, 0x61, 0x61, 0xa1, 0x61, 0x62, 0x61, 0x63]; + // test_decoder(bytes, "[a, {b: c}]"); + + // let bytes: Vec<u8> = vec![0xa5, 0x61, 0x61, 0x61, 0x41, 0x61, 0x62, 0x61, + // 0x42, 0x61, 0x63, 0x61, 0x43, 0x61, 0x64, 0x61, + // 0x44, 0x61, 0x65, 0x61, 0x45]; + // test_decoder(bytes, "{a: A, b: B, c: C, d: D, e: E}"); +} + +#[test] +fn test_map_duplicate_keys() { + let bytes: Vec<u8> = vec![0xa4, 0x01, 0x02, 0x02, 0x03, 0x01, 0x03, 0x04, 0x04]; + test_decoder_error(bytes, CborError::DuplicateMapKey); +} + +#[test] +fn test_tag_with_no_value() { + let bytes: Vec<u8> = vec![0xc0]; + test_decoder_error(bytes, CborError::TruncatedInput); +} + +#[test] +fn test_truncated_int() { + let bytes: Vec<u8> = vec![0x19, 0x03]; + test_decoder_error(bytes, CborError::TruncatedInput); +} + +#[test] +fn test_truncated_array() { + let bytes: Vec<u8> = vec![0x83, 0x01, 0x02]; + test_decoder_error(bytes, CborError::TruncatedInput); +} + +#[test] +fn test_truncated_map() { + let bytes: Vec<u8> = vec![0xa2, 0x01, 0x02, 0x00]; + test_decoder_error(bytes, CborError::TruncatedInput); +} + +#[test] +fn test_malformed_integer() { + let bytes: Vec<u8> = vec![0x1c]; + test_decoder_error(bytes, CborError::MalformedInput); +} + +#[test] +fn test_signed_integer_too_large() { + let bytes = vec![0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; + test_decoder_error(bytes, CborError::InputValueOutOfRange); +} + +#[test] +fn test_null() { + let bytes = vec![0xf6]; + test_decoder(bytes, CborType::Null); +} + +#[test] +fn test_null_in_array() { + let bytes = vec![0x82, 0xf6, 0xf6]; + test_decoder(bytes, CborType::Array(vec![CborType::Null, CborType::Null])); +} + +#[test] +fn test_major_type_7() { + for i in 0..0x20 { + if i != 22 { + let bytes = vec![0xe0 | i]; + test_decoder_error(bytes, CborError::UnsupportedType); + } + } +} + +#[test] +fn test_large_input() { + let array = vec![0xFF; MAX_ARRAY_SIZE]; + let expected = CborType::Bytes(array.clone()); + let mut bytes = vec![0x5A, 0x08, 0x00, 0x00, 0x00]; + bytes.extend_from_slice(&array); + test_decoder(bytes, expected); +} + +#[test] +fn test_too_large_input() { + let array = vec![0xFF; MAX_ARRAY_SIZE + 1]; + let mut bytes = vec![0x5A, 0x08, 0x00, 0x00, 0x01]; + bytes.extend_from_slice(&array); + test_decoder_error(bytes, CborError::InputTooLarge); +} + +// We currently don't support CBOR strings (issue #39). +#[test] +fn test_invalid_input() { + let bytes = vec![0x60]; + test_decoder_error(bytes, CborError::UnsupportedType); +} + +#[test] +fn test_avoid_stack_exhaustion_with_arrays() { + let mut bytes: Vec<u8> = Vec::new(); + // Create a payload representing Array(Array(Array(Array(...(Array(0)))))) + // If the implementation is not careful, this will exhaust the stack. + for _ in 1..10000 { + bytes.push(0b1000_0001); + } + bytes.push(0); + test_decoder_error(bytes, CborError::MalformedInput); +} + +#[test] +fn test_avoid_stack_exhaustion_with_maps_1() { + let mut bytes: Vec<u8> = Vec::new(); + // Create a payload representing Map(0: Map(0: Map(0: Map(...Map())))) + // If the implementation is not careful, this will exhaust the stack. + for _ in 1..10000 { + bytes.push(0b1010_0001); + bytes.push(0); + } + bytes.push(0b1010_0000); + test_decoder_error(bytes, CborError::MalformedInput); +} + +#[test] +fn test_avoid_stack_exhaustion_with_maps_2() { + let mut bytes: Vec<u8> = Vec::new(); + // Create a payload representing Map(Map(Map(...(Map(): 0): 0): 0): 0) + // If the implementation is not careful, this will exhaust the stack. + for _ in 1..10000 { + bytes.push(0b1010_0001); + } + bytes.push(0b1010_0000); + for _ in 1..9999 { + bytes.push(0); + } + test_decoder_error(bytes, CborError::MalformedInput); +} + +#[test] +fn test_avoid_stack_exhaustion_with_tags() { + let mut bytes: Vec<u8> = Vec::new(); + // Create a payload representing Tag(6: Tag(6: Tag(6: Tag(...Tag(0))))) + // If the implementation is not careful, this will exhaust the stack. + for _ in 1..10000 { + bytes.push(0b1100_0110); + } + bytes.push(0); + test_decoder_error(bytes, CborError::MalformedInput); +} diff --git a/third_party/rust/moz_cbor/src/test_serializer.rs b/third_party/rust/moz_cbor/src/test_serializer.rs new file mode 100644 index 0000000000..09800f5a50 --- /dev/null +++ b/third_party/rust/moz_cbor/src/test_serializer.rs @@ -0,0 +1,324 @@ +use std::collections::BTreeMap; +use CborType; + +#[test] +fn test_nint() { + struct Testcase { + value: i64, + expected: Vec<u8>, + } + let testcases: Vec<Testcase> = vec![ + Testcase { + value: -1, + expected: vec![0x20], + }, + Testcase { + value: -10, + expected: vec![0x29], + }, + Testcase { + value: -100, + expected: vec![0x38, 0x63], + }, + Testcase { + value: -1000, + expected: vec![0x39, 0x03, 0xe7], + }, + Testcase { + value: -1000000, + expected: vec![0x3a, 0x00, 0x0f, 0x42, 0x3f], + }, + Testcase { + value: -4611686018427387903, + expected: vec![0x3b, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe], + }, + ]; + for testcase in testcases { + let cbor = CborType::SignedInteger(testcase.value); + assert_eq!(testcase.expected, cbor.serialize()); + } +} + +#[test] +fn test_bstr() { + struct Testcase { + value: Vec<u8>, + expected: Vec<u8>, + } + let testcases: Vec<Testcase> = vec![ + Testcase { + value: vec![], + expected: vec![0x40], + }, + Testcase { + value: vec![0x01, 0x02, 0x03, 0x04], + expected: vec![0x44, 0x01, 0x02, 0x03, 0x04], + }, + Testcase { + value: vec![ + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + ], + expected: vec![ + 0x58, 0x19, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + ], + }, + ]; + for testcase in testcases { + let cbor = CborType::Bytes(testcase.value); + assert_eq!(testcase.expected, cbor.serialize()); + } +} + +#[test] +fn test_tstr() { + struct Testcase { + value: String, + expected: Vec<u8>, + } + let testcases: Vec<Testcase> = vec![ + Testcase { + value: String::new(), + expected: vec![0x60], + }, + Testcase { + value: String::from("a"), + expected: vec![0x61, 0x61], + }, + Testcase { + value: String::from("IETF"), + expected: vec![0x64, 0x49, 0x45, 0x54, 0x46], + }, + Testcase { + value: String::from("\"\\"), + expected: vec![0x62, 0x22, 0x5c], + }, + Testcase { + value: String::from("水"), + expected: vec![0x63, 0xe6, 0xb0, 0xb4], + }, + ]; + for testcase in testcases { + let cbor = CborType::String(testcase.value); + assert_eq!(testcase.expected, cbor.serialize()); + } +} + +#[test] +fn test_arr() { + struct Testcase { + value: Vec<CborType>, + expected: Vec<u8>, + } + let nested_arr_1 = vec![CborType::Integer(2), CborType::Integer(3)]; + let nested_arr_2 = vec![CborType::Integer(4), CborType::Integer(5)]; + let testcases: Vec<Testcase> = vec![ + Testcase { + value: vec![], + expected: vec![0x80], + }, + Testcase { + value: vec![ + CborType::Integer(1), + CborType::Integer(2), + CborType::Integer(3), + ], + expected: vec![0x83, 0x01, 0x02, 0x03], + }, + Testcase { + value: vec![ + CborType::Integer(1), + CborType::Array(nested_arr_1), + CborType::Array(nested_arr_2), + ], + expected: vec![0x83, 0x01, 0x82, 0x02, 0x03, 0x82, 0x04, 0x05], + }, + Testcase { + value: vec![ + CborType::Integer(1), + CborType::Integer(2), + CborType::Integer(3), + CborType::Integer(4), + CborType::Integer(5), + CborType::Integer(6), + CborType::Integer(7), + CborType::Integer(8), + CborType::Integer(9), + CborType::Integer(10), + CborType::Integer(11), + CborType::Integer(12), + CborType::Integer(13), + CborType::Integer(14), + CborType::Integer(15), + CborType::Integer(16), + CborType::Integer(17), + CborType::Integer(18), + CborType::Integer(19), + CborType::Integer(20), + CborType::Integer(21), + CborType::Integer(22), + CborType::Integer(23), + CborType::Integer(24), + CborType::Integer(25), + ], + expected: 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, + ], + }, + ]; + for testcase in testcases { + let cbor = CborType::Array(testcase.value); + assert_eq!(testcase.expected, cbor.serialize()); + } +} + +#[test] +fn test_map() { + let empty_map: BTreeMap<CborType, CborType> = BTreeMap::new(); + assert_eq!(vec![0xa0], CborType::Map(empty_map).serialize()); + + let mut positive_map: BTreeMap<CborType, CborType> = BTreeMap::new(); + positive_map.insert(CborType::Integer(20), CborType::Integer(10)); + positive_map.insert(CborType::Integer(10), CborType::Integer(20)); + positive_map.insert(CborType::Integer(15), CborType::Integer(15)); + assert_eq!( + vec![0xa3, 0x0a, 0x14, 0x0f, 0x0f, 0x14, 0x0a], + CborType::Map(positive_map).serialize() + ); + + let mut negative_map: BTreeMap<CborType, CborType> = BTreeMap::new(); + negative_map.insert(CborType::SignedInteger(-4), CborType::Integer(10)); + negative_map.insert(CborType::SignedInteger(-1), CborType::Integer(20)); + negative_map.insert(CborType::SignedInteger(-5), CborType::Integer(15)); + negative_map.insert(CborType::SignedInteger(-6), CborType::Integer(10)); + assert_eq!( + vec![0xa4, 0x20, 0x14, 0x23, 0x0a, 0x24, 0x0f, 0x25, 0x0a], + CborType::Map(negative_map).serialize() + ); + + let mut mixed_map: BTreeMap<CborType, CborType> = BTreeMap::new(); + mixed_map.insert(CborType::Integer(0), CborType::Integer(10)); + mixed_map.insert(CborType::SignedInteger(-10), CborType::Integer(20)); + mixed_map.insert(CborType::Integer(15), CborType::Integer(15)); + assert_eq!( + vec![0xa3, 0x00, 0x0a, 0x0f, 0x0f, 0x29, 0x14], + CborType::Map(mixed_map).serialize() + ); + + let mut very_mixed_map: BTreeMap<CborType, CborType> = BTreeMap::new(); + very_mixed_map.insert(CborType::Integer(0), CborType::Integer(10)); + very_mixed_map.insert( + CborType::SignedInteger(-10000), + CborType::String("low".to_string()), + ); + very_mixed_map.insert(CborType::SignedInteger(-10), CborType::Integer(20)); + very_mixed_map.insert( + CborType::Integer(10001), + CborType::String("high".to_string()), + ); + very_mixed_map.insert( + CborType::Integer(10000), + CborType::String("high".to_string()), + ); + very_mixed_map.insert(CborType::Integer(15), CborType::Integer(15)); + let expected = vec![ + 0xa6, 0x00, 0x0a, 0x0f, 0x0f, 0x29, 0x14, 0x19, 0x27, 0x10, 0x64, 0x68, 0x69, 0x67, 0x68, + 0x19, 0x27, 0x11, 0x64, 0x68, 0x69, 0x67, 0x68, 0x39, 0x27, 0x0F, 0x63, 0x6C, 0x6F, 0x77, + ]; + assert_eq!(expected, CborType::Map(very_mixed_map).serialize()); +} + +#[test] +#[ignore] +// XXX: The string isn't put into the map at the moment, so we can't actually +// test this. +fn test_invalid_map() { + let mut invalid_map: BTreeMap<CborType, CborType> = BTreeMap::new(); + invalid_map.insert(CborType::SignedInteger(-10), CborType::Integer(20)); + invalid_map.insert(CborType::String("0".to_string()), CborType::Integer(10)); + invalid_map.insert(CborType::Integer(15), CborType::Integer(15)); + let expected: Vec<u8> = vec![]; + assert_eq!(expected, CborType::Map(invalid_map).serialize()); +} + +#[test] +fn test_integer() { + struct Testcase { + value: u64, + expected: Vec<u8>, + } + let testcases: Vec<Testcase> = vec![ + Testcase { + value: 0, + expected: vec![0], + }, + Testcase { + value: 1, + expected: vec![1], + }, + Testcase { + value: 10, + expected: vec![0x0a], + }, + Testcase { + value: 23, + expected: vec![0x17], + }, + Testcase { + value: 24, + expected: vec![0x18, 0x18], + }, + Testcase { + value: 25, + expected: vec![0x18, 0x19], + }, + Testcase { + value: 100, + expected: vec![0x18, 0x64], + }, + Testcase { + value: 1000, + expected: vec![0x19, 0x03, 0xe8], + }, + Testcase { + value: 1000000, + expected: vec![0x1a, 0x00, 0x0f, 0x42, 0x40], + }, + Testcase { + value: 1000000000000, + expected: vec![0x1b, 0x00, 0x00, 0x00, 0xe8, 0xd4, 0xa5, 0x10, 0x00], + }, + Testcase { + value: 18446744073709551615, + expected: vec![0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], + }, + ]; + for testcase in testcases { + let cbor = CborType::Integer(testcase.value); + assert_eq!(testcase.expected, cbor.serialize()); + } +} + +#[test] +fn test_tagged_item() { + let cbor = CborType::Tag(0x12, Box::new(CborType::Integer(2).clone())); + assert_eq!(vec![0xD2, 0x02], cbor.serialize()); + + let cbor = CborType::Tag(0x62, Box::new(CborType::Array(vec![]).clone())); + assert_eq!(vec![0xD8, 0x62, 0x80], cbor.serialize()); +} + +#[test] +fn test_null() { + let cbor = CborType::Null; + assert_eq!(vec![0xf6], cbor.serialize()); +} + +#[test] +fn test_null_in_array() { + let cbor = CborType::Array(vec![CborType::Null, CborType::Null]); + assert_eq!(vec![0x82, 0xf6, 0xf6], cbor.serialize()); +} |