summaryrefslogtreecommitdiffstats
path: root/third_party/rust/moz_cbor/src/decoder.rs
blob: f93bb13f1cfb4dd51d1076b85d8666a2ae13f8de (plain)
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
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?
}