encoding_asn1/
unmarshal.rs

1use crate::common;
2pub use encoding_asn1_derive::Unmarshal;
3use thiserror::Error;
4
5#[derive(Error, Debug)]
6pub enum Error {
7    #[error("structural error")]
8    StructuralError(String),
9
10    #[error("Syntax error")]
11    SyntaxError(String),
12}
13
14// parseBase128Int parses a base-128 encoded int from the given offset in the
15// given byte slice. It returns the value and the new offset.
16fn parse_base128_int(bytes: &[u8], init_offset: usize) -> Result<(i32, usize), Error> {
17    let mut offset = init_offset;
18    let mut ret64: i64 = 0;
19    //for shifted := 0; offset < len(bytes); shifted++ {
20    let mut shifted = 0;
21    while offset < bytes.len() {
22        // 5 * 7 bits per byte == 35 bits of data
23        // Thus the representation is either non-minimal or too large for an int32
24        if shifted == 5 {
25            return Err(Error::StructuralError(
26                "base 128 integer too large".to_string(),
27            ));
28        }
29        ret64 <<= 7;
30        let b = bytes[offset];
31        // integers should be minimally encoded, so the leading octet should
32        // never be 0x80
33        if shifted == 0 && b == 0x80 {
34            return Err(Error::SyntaxError(
35                "integer is not minimally encoded".to_string(),
36            ));
37        }
38        ret64 |= (b & 0x7f) as i64;
39        offset += 1;
40        if b & 0x80 == 0 {
41            let ret = ret64 as i32;
42            // Ensure that the returned value fits in an int on all platforms
43            if ret64 > i32::MAX.into() {
44                return Err(Error::SyntaxError("base 128 integer too large".to_string()));
45            }
46            return Ok((ret, offset));
47        }
48
49        shifted += 1;
50    }
51    return Err(Error::SyntaxError("truncated base 128 integer".to_string()));
52}
53
54// parseTagAndLength parses an ASN.1 tag and length pair from the given offset
55// into a byte slice. It returns the parsed data and the new offset. SET and
56// SET OF (tag 17) are mapped to SEQUENCE and SEQUENCE OF (tag 16) since we
57// don't distinguish between ordered and unordered objects in this code.
58pub fn parse_tag_and_length(bytes: &[u8]) -> Result<(common::TagAndLength, &[u8]), Error> {
59    let mut ret = common::TagAndLength::default();
60    let mut offset = 0;
61
62    let mut b = bytes[offset];
63    offset += 1;
64    ret.class = (b >> 6) as i32;
65    ret.is_compound = (b & 0x20) == 0x20;
66    ret.tag = (b & 0x1f) as i32;
67
68    // If the bottom five bits are set, then the tag number is actually base 128
69    // encoded afterwards
70    if ret.tag == 0x1f {
71        let tmp = parse_base128_int(bytes, offset)?;
72        ret.tag = tmp.0;
73        offset = tmp.1;
74        // Tags should be encoded in minimal form.
75        if ret.tag < 0x1f {
76            return Err(Error::SyntaxError("non-minimal tag".to_string()));
77        }
78    }
79
80    b = bytes[offset];
81    offset += 1;
82    if b & 0x80 == 0 {
83        // The length is encoded in the bottom 7 bits.
84        ret.length = (b & 0x7f) as usize;
85    } else {
86        // Bottom 7 bits give the number of length bytes to follow.
87        let num_bytes = (b & 0x7f) as i32;
88        if num_bytes == 0 {
89            //err = SyntaxError{"indefinite length found (not DER)"}
90            //return
91        }
92        ret.length = 0;
93        //for i := 0; i < numBytes; i++ {
94        for _i in 0..num_bytes {
95            //if offset >= len(bytes) {
96            //    err = SyntaxError{"truncated tag or length"}
97            //    return
98            //}
99            b = bytes[offset];
100            offset += 1;
101            //if ret.length >= 1<<23 {
102            // We can't shift ret.length up without
103            // overflowing.
104            //    err = StructuralError{"length too large"}
105            //    return
106            //}
107            ret.length <<= 8;
108            ret.length |= b as usize;
109            //if ret.length == 0 {
110            // DER requires that lengths be minimal.
111            //    err = StructuralError{"superfluous leading zeros in length"}
112            //    return
113            //}
114        }
115        // Short lengths must be encoded in short form.
116        if ret.length < 0x80 {
117            //err = StructuralError{"non-minimal length"}
118            //return
119        }
120    }
121
122    Ok((ret, &bytes[offset..]))
123}
124
125pub trait Unmarshaler<T> {
126    fn unmarshal(bytes: &[u8]) -> Result<(T, &[u8]), Error> {
127        Self::unmarshal_with_params(bytes, &common::FieldParameters::default())
128    }
129    fn unmarshal_with_params<'a>(
130        bytes: &'a [u8],
131        params: &common::FieldParameters,
132    ) -> Result<(T, &'a [u8]), Error>;
133}
134
135pub fn unmarshal<T: Unmarshaler<T>>(bytes: &[u8]) -> Result<(T, &[u8]), Error> {
136    T::unmarshal(bytes)
137}
138
139pub fn unmarshal_with_params<'a, T: Unmarshaler<T>>(
140    bytes: &'a [u8],
141    params: &common::FieldParameters,
142) -> Result<(T, &'a [u8]), Error> {
143    T::unmarshal_with_params(bytes, params)
144}
145
146pub fn parse_int32(bytes: &[u8]) -> i32 {
147    let mut ret = 0;
148    for bytes_read in 0..bytes.len() {
149        ret <<= 8;
150        ret |= bytes[bytes_read] as i32;
151    }
152
153    // Shift up and down in order to sign extend the result.
154    ret <<= 32 - (bytes.len() as u8) * 8;
155    ret >>= 32 - (bytes.len() as u8) * 8;
156    ret
157}
158
159impl Unmarshaler<i32> for i32 {
160    fn unmarshal_with_params<'a>(
161        bytes: &'a [u8],
162        _params: &common::FieldParameters,
163    ) -> Result<(i32, &'a [u8]), Error> {
164        println!("bytes: {:02X?}", bytes);
165
166        let (tag_and_length, bytes) = parse_tag_and_length(bytes)?;
167        println!("tag_and_length: {:?}", tag_and_length);
168        println!("bytes: {:02X?}", bytes);
169        let ret = parse_int32(&bytes[..tag_and_length.length as usize]);
170        Ok((ret, &bytes[(tag_and_length.length as usize)..]))
171    }
172}
173
174#[cfg(test)]
175mod tests {
176    use super::*;
177
178    #[derive(Debug, Unmarshal)]
179    struct IntStruct {
180        a: i32,
181    }
182
183    #[test]
184    fn it_works() {
185        assert_eq!(parse_int32(&vec![0x00]), 0);
186        assert_eq!(parse_int32(&vec![0x7f]), 127);
187        assert_eq!(parse_int32(&vec![0x00, 0x80]), 128);
188        assert_eq!(parse_int32(&vec![0x01, 0x00]), 256);
189        assert_eq!(parse_int32(&vec![0x80]), -128);
190        assert_eq!(parse_int32(&vec![0xff, 0x7f]), -129);
191        assert_eq!(parse_int32(&vec![0xff]), -1);
192        assert_eq!(parse_int32(&vec![0x80, 0x00, 0x00, 0x00]), -2147483648);
193
194        struct TagAndLengthTest {
195            bytes: Vec<u8>,
196            out: common::TagAndLength,
197        }
198
199        let tag_and_length_data = vec![
200            TagAndLengthTest {
201                bytes: vec![0x80, 0x01],
202                out: common::TagAndLength {
203                    class: 2,
204                    length: 1,
205                    ..common::TagAndLength::default()
206                },
207            },
208            TagAndLengthTest {
209                bytes: vec![0xa0, 0x01],
210                out: common::TagAndLength {
211                    class: 2,
212                    length: 1,
213                    is_compound: true,
214                    ..common::TagAndLength::default()
215                },
216            },
217            TagAndLengthTest {
218                bytes: vec![0x02, 0x00],
219                out: common::TagAndLength {
220                    class: 0,
221                    tag: 2,
222                    length: 0,
223                    is_compound: false,
224                },
225            },
226            TagAndLengthTest {
227                bytes: vec![0xfe, 0x00],
228                out: common::TagAndLength {
229                    class: 3,
230                    tag: 30,
231                    length: 0,
232                    is_compound: true,
233                },
234            },
235            TagAndLengthTest {
236                bytes: vec![0x1f, 0x1f, 0x00],
237                out: common::TagAndLength {
238                    class: 0,
239                    tag: 31,
240                    length: 0,
241                    is_compound: false,
242                },
243            },
244            TagAndLengthTest {
245                bytes: vec![0x1f, 0x81, 0x00, 0x00],
246                out: common::TagAndLength {
247                    class: 0,
248                    tag: 128,
249                    length: 0,
250                    is_compound: false,
251                },
252            },
253            TagAndLengthTest {
254                bytes: vec![0x1f, 0x81, 0x80, 0x01, 0x00],
255                out: common::TagAndLength {
256                    class: 0,
257                    tag: 0x4001,
258                    length: 0,
259                    is_compound: false,
260                },
261            },
262            TagAndLengthTest {
263                bytes: vec![0x00, 0x81, 0x80],
264                out: common::TagAndLength {
265                    class: 0,
266                    tag: 0,
267                    length: 128,
268                    is_compound: false,
269                },
270            },
271            TagAndLengthTest {
272                bytes: vec![0x00, 0x82, 0x01, 0x00],
273                out: common::TagAndLength {
274                    class: 0,
275                    tag: 0,
276                    length: 256,
277                    is_compound: false,
278                },
279            },
280            TagAndLengthTest {
281                bytes: vec![0xa0, 0x84, 0x7f, 0xff, 0xff, 0xff],
282                out: common::TagAndLength {
283                    class: 2,
284                    tag: 0,
285                    length: 0x7fffffff,
286                    is_compound: true,
287                },
288            },
289            TagAndLengthTest {
290                bytes: vec![0x1f, 0x87, 0xFF, 0xFF, 0xFF, 0x7F, 0x00],
291                out: common::TagAndLength {
292                    class: 0,
293                    tag: i32::MAX,
294                    length: 0,
295                    is_compound: false,
296                },
297            },
298        ];
299
300        for test in &tag_and_length_data {
301            let (tl, _) = parse_tag_and_length(&test.bytes).unwrap();
302            assert_eq!(tl, test.out);
303        }
304
305        let bytes = vec![0x02, 0x01, 0x42];
306        let i = i32::unmarshal(&bytes).unwrap();
307        assert_eq!(i.0, 0x42);
308
309        let bytes = vec![0x30, 0x03, 0x02, 0x01, 0x40];
310        let is = IntStruct::unmarshal(&bytes);
311        println!("is: {:?}", is);
312    }
313}