moz_cbor/
decoder.rs

1use std::collections::BTreeMap;
2use std::io::{Cursor, Read, Seek, SeekFrom};
3use {CborError, CborType};
4
5// We limit the length of any cbor byte array to 128MiB. This is a somewhat
6// arbitrary limit that should work on all platforms and is large enough for
7// any benign data.
8pub const MAX_ARRAY_SIZE: usize = 134_217_728;
9
10// Prevent stack exhaustion by limiting the nested depth of CBOR data.
11const MAX_NESTED_DEPTH: usize = 256;
12
13/// Struct holding a cursor and additional information for decoding.
14#[derive(Debug)]
15struct DecoderCursor<'a> {
16    cursor: Cursor<&'a [u8]>,
17    depth: usize,
18}
19
20/// Apply this mask (with &) to get the value part of the initial byte of a CBOR item.
21const INITIAL_VALUE_MASK: u64 = 0b0001_1111;
22
23impl<'a> DecoderCursor<'a> {
24    /// Read and return the given number of bytes from the cursor. Advances the cursor.
25    fn read_bytes(&mut self, len: usize) -> Result<Vec<u8>, CborError> {
26        if len > MAX_ARRAY_SIZE {
27            return Err(CborError::InputTooLarge);
28        }
29        let mut buf: Vec<u8> = vec![0; len];
30        if self.cursor.read_exact(&mut buf).is_err() {
31            Err(CborError::TruncatedInput)
32        } else {
33            Ok(buf)
34        }
35    }
36
37    /// Convert num bytes to a u64
38    fn read_uint_from_bytes(&mut self, num: usize) -> Result<u64, CborError> {
39        let x = self.read_bytes(num)?;
40        let mut result: u64 = 0;
41        for i in (0..num).rev() {
42            result += u64::from(x[num - 1 - i]) << (i * 8);
43        }
44        Ok(result)
45    }
46
47    /// Read an integer and return it as u64.
48    fn read_int(&mut self) -> Result<u64, CborError> {
49        let first_value = self.read_uint_from_bytes(1)? & INITIAL_VALUE_MASK;
50        match first_value {
51            0..=23 => Ok(first_value),
52            24 => self.read_uint_from_bytes(1),
53            25 => self.read_uint_from_bytes(2),
54            26 => self.read_uint_from_bytes(4),
55            27 => self.read_uint_from_bytes(8),
56            _ => Err(CborError::MalformedInput),
57        }
58    }
59
60    fn read_negative_int(&mut self) -> Result<CborType, CborError> {
61        let uint = self.read_int()?;
62        if uint > i64::max_value() as u64 {
63            return Err(CborError::InputValueOutOfRange);
64        }
65        let result: i64 = -1 - uint as i64;
66        Ok(CborType::SignedInteger(result))
67    }
68
69    /// Read an array of data items and return it.
70    fn read_array(&mut self) -> Result<CborType, CborError> {
71        // Create a new array.
72        let mut array: Vec<CborType> = Vec::new();
73        // Read the length of the array.
74        let num_items = self.read_int()?;
75        // Decode each of the num_items data items.
76        for _ in 0..num_items {
77            let new_item = self.decode_item()?;
78            array.push(new_item);
79        }
80        Ok(CborType::Array(array))
81    }
82
83    /// Read a byte string and return it.
84    fn read_byte_string(&mut self) -> Result<CborType, CborError> {
85        let length = self.read_int()?;
86        if length > MAX_ARRAY_SIZE as u64 {
87            return Err(CborError::InputTooLarge);
88        }
89        let byte_string = self.read_bytes(length as usize)?;
90        Ok(CborType::Bytes(byte_string))
91    }
92
93    /// Read a map.
94    fn read_map(&mut self) -> Result<CborType, CborError> {
95        let num_items = self.read_int()?;
96        // Create a new array.
97        let mut map: BTreeMap<CborType, CborType> = BTreeMap::new();
98        // Decode each of the num_items (key, data item) pairs.
99        for _ in 0..num_items {
100            let key_val = self.decode_item()?;
101            let item_value = self.decode_item()?;
102            if map.insert(key_val, item_value).is_some() {
103                return Err(CborError::DuplicateMapKey);
104            }
105        }
106        Ok(CborType::Map(map))
107    }
108
109    fn read_null(&mut self) -> Result<CborType, CborError> {
110        let value = self.read_uint_from_bytes(1)? & INITIAL_VALUE_MASK;
111        if value != 22 {
112            return Err(CborError::UnsupportedType);
113        }
114        Ok(CborType::Null)
115    }
116
117    /// Peeks at the next byte in the cursor, but does not change the position.
118    fn peek_byte(&mut self) -> Result<u8, CborError> {
119        let x = self.read_bytes(1)?;
120        if self.cursor.seek(SeekFrom::Current(-1)).is_err() {
121            return Err(CborError::LibraryError);
122        };
123        Ok(x[0])
124    }
125
126    /// Decodes the next CBOR item.
127    pub fn decode_item(&mut self) -> Result<CborType, CborError> {
128        if self.depth > MAX_NESTED_DEPTH {
129            return Err(CborError::MalformedInput);
130        }
131        self.depth += 1;
132        let major_type = self.peek_byte()? >> 5;
133        let result = match major_type {
134            0 => {
135                let value = self.read_int()?;
136                Ok(CborType::Integer(value))
137            }
138            1 => self.read_negative_int(),
139            2 => self.read_byte_string(),
140            4 => self.read_array(),
141            5 => self.read_map(),
142            6 => {
143                let tag = self.read_int()?;
144                let item = self.decode_item()?;
145                Ok(CborType::Tag(tag, Box::new(item)))
146            }
147            7 => self.read_null(),
148            _ => Err(CborError::UnsupportedType),
149        };
150        self.depth -= 1;
151        result
152    }
153}
154
155/// Read the CBOR structure in bytes and return it as a `CborType`. To prevent stack exhaustion, the
156/// maximum nested depth of CBOR objects (for example, an array of an array of an array...) is 256.
157/// If the input data describes a CBOR structure that exceeds this limit, an error will be returned.
158pub fn decode(bytes: &[u8]) -> Result<CborType, CborError> {
159    let mut decoder_cursor = DecoderCursor {
160        cursor: Cursor::new(bytes),
161        depth: 0,
162    };
163    decoder_cursor.decode_item()
164    // TODO: check cursor at end?
165}