aws_lc_rs/io/
der.rs

1// Copyright 2015 Brian Smith.
2// SPDX-License-Identifier: ISC
3// Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4// SPDX-License-Identifier: Apache-2.0 OR ISC
5
6//! Building blocks for parsing DER-encoded ASN.1 structures.
7//!
8//! This module contains the foundational parts of an ASN.1 DER parser.
9
10use super::Positive;
11use crate::error;
12
13pub const CONSTRUCTED: u8 = 1 << 5;
14pub const CONTEXT_SPECIFIC: u8 = 2 << 6;
15
16#[non_exhaustive]
17#[derive(Clone, Copy, PartialEq, Eq, Debug)]
18#[repr(u8)]
19pub enum Tag {
20    Boolean = 0x01,
21    Integer = 0x02,
22    BitString = 0x03,
23    OctetString = 0x04,
24    Null = 0x05,
25    OID = 0x06,
26    Sequence = CONSTRUCTED | 0x10, // 0x30
27    UTCTime = 0x17,
28    GeneralizedTime = 0x18,
29
30    ContextSpecificConstructed0 = CONTEXT_SPECIFIC | CONSTRUCTED,
31    ContextSpecificConstructed1 = CONTEXT_SPECIFIC | CONSTRUCTED | 1,
32    ContextSpecificConstructed3 = CONTEXT_SPECIFIC | CONSTRUCTED | 3,
33}
34
35impl From<Tag> for usize {
36    fn from(tag: Tag) -> Self {
37        tag as Self
38    }
39}
40
41impl From<Tag> for u8 {
42    fn from(tag: Tag) -> Self {
43        tag as Self
44    } // XXX: narrowing conversion.
45}
46
47pub fn expect_tag_and_get_value<'a>(
48    input: &mut untrusted::Reader<'a>,
49    tag: Tag,
50) -> Result<untrusted::Input<'a>, error::Unspecified> {
51    let (actual_tag, inner) = read_tag_and_get_value(input)?;
52    if usize::from(tag) != usize::from(actual_tag) {
53        return Err(error::Unspecified);
54    }
55    Ok(inner)
56}
57
58pub fn read_tag_and_get_value<'a>(
59    input: &mut untrusted::Reader<'a>,
60) -> Result<(u8, untrusted::Input<'a>), error::Unspecified> {
61    let tag = input.read_byte()?;
62    if (tag & 0x1F) == 0x1F {
63        return Err(error::Unspecified); // High tag number form is not allowed.
64    }
65
66    // If the high order bit of the first byte is set to zero then the length
67    // is encoded in the seven remaining bits of that byte. Otherwise, those
68    // seven bits represent the number of bytes used to encode the length.
69    let length = match input.read_byte()? {
70        n if (n & 0x80) == 0 => usize::from(n),
71        0x81 => {
72            let second_byte = input.read_byte()?;
73            if second_byte < 128 {
74                return Err(error::Unspecified); // Not the canonical encoding.
75            }
76            usize::from(second_byte)
77        }
78        0x82 => {
79            let second_byte = usize::from(input.read_byte()?);
80            let third_byte = usize::from(input.read_byte()?);
81            let combined = (second_byte << 8) | third_byte;
82            if combined < 256 {
83                return Err(error::Unspecified); // Not the canonical encoding.
84            }
85            combined
86        }
87        _ => {
88            return Err(error::Unspecified); // We don't support longer lengths.
89        }
90    };
91
92    let inner = input.read_bytes(length)?;
93    Ok((tag, inner))
94}
95
96pub fn bit_string_with_no_unused_bits<'a>(
97    input: &mut untrusted::Reader<'a>,
98) -> Result<untrusted::Input<'a>, error::Unspecified> {
99    nested(input, Tag::BitString, error::Unspecified, |value| {
100        let unused_bits_at_end = value.read_byte()?;
101        if unused_bits_at_end != 0 {
102            return Err(error::Unspecified);
103        }
104        Ok(value.read_bytes_to_end())
105    })
106}
107
108// TODO: investigate taking decoder as a reference to reduce generated code
109// size.
110pub fn nested<'a, F, R, E: Copy>(
111    input: &mut untrusted::Reader<'a>,
112    tag: Tag,
113    error: E,
114    decoder: F,
115) -> Result<R, E>
116where
117    F: FnOnce(&mut untrusted::Reader<'a>) -> Result<R, E>,
118{
119    let inner = expect_tag_and_get_value(input, tag).map_err(|_| error)?;
120    inner.read_all(error, decoder)
121}
122
123fn nonnegative_integer<'a>(
124    input: &mut untrusted::Reader<'a>,
125    min_value: u8,
126) -> Result<untrusted::Input<'a>, error::Unspecified> {
127    // Verify that |input|, which has had any leading zero stripped off, is the
128    // encoding of a value of at least |min_value|.
129    fn check_minimum(input: untrusted::Input, min_value: u8) -> Result<(), error::Unspecified> {
130        input.read_all(error::Unspecified, |input| {
131            let first_byte = input.read_byte()?;
132            if input.at_end() && first_byte < min_value {
133                return Err(error::Unspecified);
134            }
135            let _: untrusted::Input = input.read_bytes_to_end();
136            Ok(())
137        })
138    }
139
140    let value = expect_tag_and_get_value(input, Tag::Integer)?;
141
142    value.read_all(error::Unspecified, |input| {
143        // Empty encodings are not allowed.
144        let first_byte = input.read_byte()?;
145
146        if first_byte == 0 {
147            if input.at_end() {
148                // |value| is the legal encoding of zero.
149                if min_value > 0 {
150                    return Err(error::Unspecified);
151                }
152                return Ok(value);
153            }
154
155            let r = input.read_bytes_to_end();
156            r.read_all(error::Unspecified, |input| {
157                let second_byte = input.read_byte()?;
158                if (second_byte & 0x80) == 0 {
159                    // A leading zero is only allowed when the value's high bit
160                    // is set.
161                    return Err(error::Unspecified);
162                }
163                let _: untrusted::Input = input.read_bytes_to_end();
164                Ok(())
165            })?;
166            check_minimum(r, min_value)?;
167            return Ok(r);
168        }
169
170        // Negative values are not allowed.
171        if (first_byte & 0x80) != 0 {
172            return Err(error::Unspecified);
173        }
174
175        let _: untrusted::Input = input.read_bytes_to_end();
176        check_minimum(value, min_value)?;
177        Ok(value)
178    })
179}
180
181/// Parse as integer with a value in the in the range [0, 255], returning its
182/// numeric value. This is typically used for parsing version numbers.
183#[inline]
184pub fn small_nonnegative_integer(input: &mut untrusted::Reader) -> Result<u8, error::Unspecified> {
185    let value = nonnegative_integer(input, 0)?;
186    value.read_all(error::Unspecified, |input| {
187        let r = input.read_byte()?;
188        Ok(r)
189    })
190}
191
192/// Parses a positive DER integer, returning the big-endian-encoded value,
193/// sans any leading zero byte.
194pub fn positive_integer<'a>(
195    input: &mut untrusted::Reader<'a>,
196) -> Result<Positive<'a>, error::Unspecified> {
197    Ok(Positive::new_non_empty_without_leading_zeros(
198        nonnegative_integer(input, 1)?,
199    ))
200}
201
202#[cfg(test)]
203mod tests {
204    use super::*;
205    use untrusted::Input;
206
207    fn with_good_i<F, R>(value: &[u8], f: F)
208    where
209        F: FnOnce(&mut untrusted::Reader) -> Result<R, error::Unspecified>,
210    {
211        let r = Input::from(value).read_all(error::Unspecified, f);
212        assert!(r.is_ok());
213    }
214
215    fn with_bad_i<F, R>(value: &[u8], f: F)
216    where
217        F: FnOnce(&mut untrusted::Reader) -> Result<R, error::Unspecified>,
218    {
219        let r = Input::from(value).read_all(error::Unspecified, f);
220        assert!(r.is_err());
221    }
222
223    static ZERO_INTEGER: &[u8] = &[0x02, 0x01, 0x00];
224
225    static GOOD_POSITIVE_INTEGERS: &[(&[u8], u8)] = &[
226        (&[0x02, 0x01, 0x01], 0x01),
227        (&[0x02, 0x01, 0x02], 0x02),
228        (&[0x02, 0x01, 0x7e], 0x7e),
229        (&[0x02, 0x01, 0x7f], 0x7f),
230        // Values that need to have an 0x00 prefix to disambiguate them from
231        // them from negative values.
232        (&[0x02, 0x02, 0x00, 0x80], 0x80),
233        (&[0x02, 0x02, 0x00, 0x81], 0x81),
234        (&[0x02, 0x02, 0x00, 0xfe], 0xfe),
235        (&[0x02, 0x02, 0x00, 0xff], 0xff),
236    ];
237
238    #[allow(clippy::type_complexity)]
239    static GOOD_BIG_POSITIVE_INTEGERS: &[((&[u8], &[u8]), (&[u8], &[u8]))] = &[
240        ((&[0x02, 0x81, 129u8, 1], &[0; 128]), (&[1], &[0; 128])),
241        ((&[0x02, 0x82, 0x01, 0x00, 1], &[0; 255]), (&[1], &[0; 255])),
242    ];
243
244    static BAD_NONNEGATIVE_INTEGERS: &[&[u8]] = &[
245        &[],           // At end of input
246        &[0x02],       // Tag only
247        &[0x02, 0x00], // Empty value
248        // Length mismatch
249        &[0x02, 0x00, 0x01],
250        &[0x02, 0x01],
251        &[0x02, 0x01, 0x00, 0x01],
252        &[0x02, 0x01, 0x01, 0x00], // Would be valid if last byte is ignored.
253        &[0x02, 0x02, 0x01],
254        // Negative values
255        &[0x02, 0x01, 0x80],
256        &[0x02, 0x01, 0xfe],
257        &[0x02, 0x01, 0xff],
258        // Values that have an unnecessary leading 0x00
259        &[0x02, 0x02, 0x00, 0x00],
260        &[0x02, 0x02, 0x00, 0x01],
261        &[0x02, 0x02, 0x00, 0x02],
262        &[0x02, 0x02, 0x00, 0x7e],
263        &[0x02, 0x02, 0x00, 0x7f],
264    ];
265
266    #[test]
267    fn test_small_nonnegative_integer() {
268        with_good_i(ZERO_INTEGER, |input| {
269            assert_eq!(small_nonnegative_integer(input)?, 0x00);
270            Ok(())
271        });
272        for &(test_in, test_out) in GOOD_POSITIVE_INTEGERS {
273            with_good_i(test_in, |input| {
274                assert_eq!(small_nonnegative_integer(input)?, test_out);
275                Ok(())
276            });
277        }
278        for &test_in in BAD_NONNEGATIVE_INTEGERS {
279            with_bad_i(test_in, |input| {
280                let _: u8 = small_nonnegative_integer(input)?;
281                Ok(())
282            });
283        }
284    }
285
286    #[test]
287    fn test_positive_integer() {
288        with_bad_i(ZERO_INTEGER, |input| {
289            let _: Positive<'_> = positive_integer(input)?;
290            Ok(())
291        });
292        for &(test_in, test_out) in GOOD_POSITIVE_INTEGERS {
293            with_good_i(test_in, |input| {
294                let test_out = [test_out];
295                assert_eq!(
296                    positive_integer(input)?
297                        .big_endian_without_leading_zero_as_input()
298                        .as_slice_less_safe(),
299                    Input::from(&test_out[..]).as_slice_less_safe()
300                );
301                Ok(())
302            });
303        }
304        for &test_in in BAD_NONNEGATIVE_INTEGERS {
305            with_bad_i(test_in, |input| {
306                let _: Positive<'_> = positive_integer(input)?;
307                Ok(())
308            });
309        }
310    }
311
312    #[test]
313    fn test_tag() {
314        let tgt = usize::from(Tag::GeneralizedTime);
315        assert_eq!(0x18usize, tgt);
316
317        let tgt = u8::from(Tag::GeneralizedTime);
318        assert_eq!(0x18u8, tgt);
319
320        let tgt = Tag::GeneralizedTime;
321        assert_eq!(tgt, Tag::GeneralizedTime);
322    }
323
324    #[test]
325    fn test_big() {
326        for &((bytes_in_a, bytes_in_b), (bytes_out_a, bytes_out_b)) in GOOD_BIG_POSITIVE_INTEGERS {
327            let mut bytes_in = Vec::new();
328            bytes_in.extend(bytes_in_a);
329            bytes_in.extend(bytes_in_b);
330            let mut bytes_out: Vec<u8> = Vec::new();
331            bytes_out.extend(bytes_out_a);
332            bytes_out.extend(bytes_out_b);
333
334            with_good_i(&bytes_in, |input| {
335                let positive = positive_integer(input)?;
336                let expected_bytes = positive.big_endian_without_leading_zero();
337                assert_eq!(expected_bytes, &bytes_out);
338                Ok(())
339            });
340        }
341    }
342
343    #[test]
344    fn test_bit_string_with_no_unused_bits() {
345        // Not a BitString
346        let mut reader_bad = untrusted::Reader::new(Input::from(&[0x02, 0x01]));
347        assert!(bit_string_with_no_unused_bits(&mut reader_bad).is_err());
348        // Unused bits at end
349        let mut reader_bad2 = untrusted::Reader::new(Input::from(&[0x03, 0x01, 0x01]));
350        assert!(bit_string_with_no_unused_bits(&mut reader_bad2).is_err());
351
352        let mut reader_good = untrusted::Reader::new(Input::from(&[0x03, 0x01, 0x00]));
353        let input = bit_string_with_no_unused_bits(&mut reader_good).unwrap();
354        let expected_result: &[u8] = &[];
355        assert_eq!(expected_result, input.as_slice_less_safe());
356    }
357}