Coverage Report

Created: 2026-05-16 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/aws-lc-rs-1.16.2/src/io/der.rs
Line
Count
Source
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
10
use super::Positive;
11
use crate::error;
12
13
pub const CONSTRUCTED: u8 = 1 << 5;
14
pub const CONTEXT_SPECIFIC: u8 = 2 << 6;
15
16
#[non_exhaustive]
17
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
18
#[repr(u8)]
19
pub 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
35
impl From<Tag> for usize {
36
0
    fn from(tag: Tag) -> Self {
37
0
        tag as Self
38
0
    }
39
}
40
41
impl From<Tag> for u8 {
42
0
    fn from(tag: Tag) -> Self {
43
0
        tag as Self
44
0
    } // XXX: narrowing conversion.
45
}
46
47
0
pub fn expect_tag_and_get_value<'a>(
48
0
    input: &mut untrusted::Reader<'a>,
49
0
    tag: Tag,
50
0
) -> Result<untrusted::Input<'a>, error::Unspecified> {
51
0
    let (actual_tag, inner) = read_tag_and_get_value(input)?;
52
0
    if usize::from(tag) != usize::from(actual_tag) {
53
0
        return Err(error::Unspecified);
54
0
    }
55
0
    Ok(inner)
56
0
}
57
58
0
pub fn read_tag_and_get_value<'a>(
59
0
    input: &mut untrusted::Reader<'a>,
60
0
) -> Result<(u8, untrusted::Input<'a>), error::Unspecified> {
61
0
    let tag = input.read_byte()?;
62
0
    if (tag & 0x1F) == 0x1F {
63
0
        return Err(error::Unspecified); // High tag number form is not allowed.
64
0
    }
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
0
    let length = match input.read_byte()? {
70
0
        n if (n & 0x80) == 0 => usize::from(n),
71
        0x81 => {
72
0
            let second_byte = input.read_byte()?;
73
0
            if second_byte < 128 {
74
0
                return Err(error::Unspecified); // Not the canonical encoding.
75
0
            }
76
0
            usize::from(second_byte)
77
        }
78
        0x82 => {
79
0
            let second_byte = usize::from(input.read_byte()?);
80
0
            let third_byte = usize::from(input.read_byte()?);
81
0
            let combined = (second_byte << 8) | third_byte;
82
0
            if combined < 256 {
83
0
                return Err(error::Unspecified); // Not the canonical encoding.
84
0
            }
85
0
            combined
86
        }
87
        _ => {
88
0
            return Err(error::Unspecified); // We don't support longer lengths.
89
        }
90
    };
91
92
0
    let inner = input.read_bytes(length)?;
93
0
    Ok((tag, inner))
94
0
}
95
96
0
pub fn bit_string_with_no_unused_bits<'a>(
97
0
    input: &mut untrusted::Reader<'a>,
98
0
) -> Result<untrusted::Input<'a>, error::Unspecified> {
99
0
    nested(input, Tag::BitString, error::Unspecified, |value| {
100
0
        let unused_bits_at_end = value.read_byte()?;
101
0
        if unused_bits_at_end != 0 {
102
0
            return Err(error::Unspecified);
103
0
        }
104
0
        Ok(value.read_bytes_to_end())
105
0
    })
106
0
}
107
108
// TODO: investigate taking decoder as a reference to reduce generated code
109
// size.
110
0
pub fn nested<'a, F, R, E: Copy>(
111
0
    input: &mut untrusted::Reader<'a>,
112
0
    tag: Tag,
113
0
    error: E,
114
0
    decoder: F,
115
0
) -> Result<R, E>
116
0
where
117
0
    F: FnOnce(&mut untrusted::Reader<'a>) -> Result<R, E>,
118
{
119
0
    let inner = expect_tag_and_get_value(input, tag).map_err(|_| error)?;
120
0
    inner.read_all(error, decoder)
121
0
}
122
123
0
fn nonnegative_integer<'a>(
124
0
    input: &mut untrusted::Reader<'a>,
125
0
    min_value: u8,
126
0
) -> 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
0
    fn check_minimum(input: untrusted::Input, min_value: u8) -> Result<(), error::Unspecified> {
130
0
        input.read_all(error::Unspecified, |input| {
131
0
            let first_byte = input.read_byte()?;
132
0
            if input.at_end() && first_byte < min_value {
133
0
                return Err(error::Unspecified);
134
0
            }
135
0
            let _: untrusted::Input = input.read_bytes_to_end();
136
0
            Ok(())
137
0
        })
138
0
    }
139
140
0
    let value = expect_tag_and_get_value(input, Tag::Integer)?;
141
142
0
    value.read_all(error::Unspecified, |input| {
143
        // Empty encodings are not allowed.
144
0
        let first_byte = input.read_byte()?;
145
146
0
        if first_byte == 0 {
147
0
            if input.at_end() {
148
                // |value| is the legal encoding of zero.
149
0
                if min_value > 0 {
150
0
                    return Err(error::Unspecified);
151
0
                }
152
0
                return Ok(value);
153
0
            }
154
155
0
            let r = input.read_bytes_to_end();
156
0
            r.read_all(error::Unspecified, |input| {
157
0
                let second_byte = input.read_byte()?;
158
0
                if (second_byte & 0x80) == 0 {
159
                    // A leading zero is only allowed when the value's high bit
160
                    // is set.
161
0
                    return Err(error::Unspecified);
162
0
                }
163
0
                let _: untrusted::Input = input.read_bytes_to_end();
164
0
                Ok(())
165
0
            })?;
166
0
            check_minimum(r, min_value)?;
167
0
            return Ok(r);
168
0
        }
169
170
        // Negative values are not allowed.
171
0
        if (first_byte & 0x80) != 0 {
172
0
            return Err(error::Unspecified);
173
0
        }
174
175
0
        let _: untrusted::Input = input.read_bytes_to_end();
176
0
        check_minimum(value, min_value)?;
177
0
        Ok(value)
178
0
    })
179
0
}
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]
184
0
pub fn small_nonnegative_integer(input: &mut untrusted::Reader) -> Result<u8, error::Unspecified> {
185
0
    let value = nonnegative_integer(input, 0)?;
186
0
    value.read_all(error::Unspecified, |input| {
187
0
        let r = input.read_byte()?;
188
0
        Ok(r)
189
0
    })
190
0
}
191
192
/// Parses a positive DER integer, returning the big-endian-encoded value,
193
/// sans any leading zero byte.
194
0
pub fn positive_integer<'a>(
195
0
    input: &mut untrusted::Reader<'a>,
196
0
) -> Result<Positive<'a>, error::Unspecified> {
197
0
    Ok(Positive::new_non_empty_without_leading_zeros(
198
0
        nonnegative_integer(input, 1)?,
199
    ))
200
0
}
201
202
#[cfg(test)]
203
mod 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
}