Coverage Report

Created: 2025-08-25 06:27

/src/spdm-rs/external/ring/src/io/der.rs
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2015 Brian Smith.
2
//
3
// Permission to use, copy, modify, and/or distribute this software for any
4
// purpose with or without fee is hereby granted, provided that the above
5
// copyright notice and this permission notice appear in all copies.
6
//
7
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15
//! Building blocks for parsing DER-encoded ASN.1 structures.
16
//!
17
//! This module contains the foundational parts of an ASN.1 DER parser.
18
19
use super::Positive;
20
use crate::error;
21
22
pub const CONSTRUCTED: u8 = 1 << 5;
23
pub const CONTEXT_SPECIFIC: u8 = 2 << 6;
24
25
#[derive(Clone, Copy, PartialEq)]
26
#[repr(u8)]
27
pub enum Tag {
28
    Boolean = 0x01,
29
    Integer = 0x02,
30
    BitString = 0x03,
31
    OctetString = 0x04,
32
    Null = 0x05,
33
    OID = 0x06,
34
    Sequence = CONSTRUCTED | 0x10, // 0x30
35
    UTCTime = 0x17,
36
    GeneralizedTime = 0x18,
37
38
    ContextSpecific1 = CONTEXT_SPECIFIC | 1,
39
40
    ContextSpecificConstructed0 = CONTEXT_SPECIFIC | CONSTRUCTED | 0,
41
    ContextSpecificConstructed1 = CONTEXT_SPECIFIC | CONSTRUCTED | 1,
42
    ContextSpecificConstructed3 = CONTEXT_SPECIFIC | CONSTRUCTED | 3,
43
}
44
45
impl From<Tag> for usize {
46
0
    fn from(tag: Tag) -> Self {
47
0
        Self::from(Tag::into(tag))
48
0
    }
49
}
50
51
impl From<Tag> for u8 {
52
0
    fn from(tag: Tag) -> Self {
53
0
        Tag::into(tag)
54
0
    }
55
}
56
57
// `impl From<Tag> for u8` but as a `const fn`.
58
impl Tag {
59
0
    pub const fn into(self) -> u8 {
60
0
        self as u8
61
0
    }
62
}
63
64
0
pub fn expect_tag_and_get_value<'a>(
65
0
    input: &mut untrusted::Reader<'a>,
66
0
    tag: Tag,
67
0
) -> Result<untrusted::Input<'a>, error::Unspecified> {
68
0
    let (actual_tag, inner) = read_tag_and_get_value(input)?;
69
0
    if usize::from(tag) != usize::from(actual_tag) {
70
0
        return Err(error::Unspecified);
71
0
    }
72
0
    Ok(inner)
73
0
}
74
75
0
pub fn read_tag_and_get_value<'a>(
76
0
    input: &mut untrusted::Reader<'a>,
77
0
) -> Result<(u8, untrusted::Input<'a>), error::Unspecified> {
78
0
    let tag = input.read_byte()?;
79
0
    if (tag & 0x1F) == 0x1F {
80
0
        return Err(error::Unspecified); // High tag number form is not allowed.
81
0
    }
82
83
    // If the high order bit of the first byte is set to zero then the length
84
    // is encoded in the seven remaining bits of that byte. Otherwise, those
85
    // seven bits represent the number of bytes used to encode the length.
86
0
    let length = match input.read_byte()? {
87
0
        n if (n & 0x80) == 0 => usize::from(n),
88
        0x81 => {
89
0
            let second_byte = input.read_byte()?;
90
0
            if second_byte < 128 {
91
0
                return Err(error::Unspecified); // Not the canonical encoding.
92
0
            }
93
0
            usize::from(second_byte)
94
        }
95
        0x82 => {
96
0
            let second_byte = usize::from(input.read_byte()?);
97
0
            let third_byte = usize::from(input.read_byte()?);
98
0
            let combined = (second_byte << 8) | third_byte;
99
0
            if combined < 256 {
100
0
                return Err(error::Unspecified); // Not the canonical encoding.
101
0
            }
102
0
            combined
103
        }
104
        _ => {
105
0
            return Err(error::Unspecified); // We don't support longer lengths.
106
        }
107
    };
108
109
0
    let inner = input.read_bytes(length)?;
110
0
    Ok((tag, inner))
111
0
}
112
113
#[inline]
114
0
pub fn bit_string_with_no_unused_bits<'a>(
115
0
    input: &mut untrusted::Reader<'a>,
116
0
) -> Result<untrusted::Input<'a>, error::Unspecified> {
117
0
    bit_string_tagged_with_no_unused_bits(Tag::BitString, input)
118
0
}
119
120
0
pub(crate) fn bit_string_tagged_with_no_unused_bits<'a>(
121
0
    tag: Tag,
122
0
    input: &mut untrusted::Reader<'a>,
123
0
) -> Result<untrusted::Input<'a>, error::Unspecified> {
124
0
    nested(input, tag, error::Unspecified, |value| {
125
0
        let unused_bits_at_end = value.read_byte().map_err(|_| error::Unspecified)?;
126
0
        if unused_bits_at_end != 0 {
127
0
            return Err(error::Unspecified);
128
0
        }
129
0
        Ok(value.read_bytes_to_end())
130
0
    })
131
0
}
132
133
// TODO: investigate taking decoder as a reference to reduce generated code
134
// size.
135
0
pub fn nested<'a, F, R, E: Copy>(
136
0
    input: &mut untrusted::Reader<'a>,
137
0
    tag: Tag,
138
0
    error: E,
139
0
    decoder: F,
140
0
) -> Result<R, E>
141
0
where
142
0
    F: FnOnce(&mut untrusted::Reader<'a>) -> Result<R, E>,
143
0
{
144
0
    let inner = expect_tag_and_get_value(input, tag).map_err(|_| error)?;
Unexecuted instantiation: ring::io::der::nested::<ring::rsa::parse_public_key::{closure#0}::{closure#0}, (ring::io::positive::Positive, ring::io::positive::Positive), ring::error::unspecified::Unspecified>::{closure#0}
Unexecuted instantiation: ring::io::der::nested::<ring::pkcs8::unwrap_key_::{closure#0}::{closure#0}, (untrusted::input::Input, core::option::Option<untrusted::input::Input>), ring::error::key_rejected::KeyRejected>::{closure#0}
Unexecuted instantiation: ring::io::der::nested::<ring::ec::suite_b::key_pair_from_pkcs8::{closure#0}::{closure#0}, (untrusted::input::Input, untrusted::input::Input), ring::error::key_rejected::KeyRejected>::{closure#0}
Unexecuted instantiation: ring::io::der::nested::<ring::io::der::bit_string_tagged_with_no_unused_bits::{closure#0}, untrusted::input::Input, ring::error::unspecified::Unspecified>::{closure#0}
Unexecuted instantiation: ring::io::der::nested::<ring::ec::suite_b::ecdsa::verification::split_rs_asn1::{closure#0}, (untrusted::input::Input, untrusted::input::Input), ring::error::unspecified::Unspecified>::{closure#0}
Unexecuted instantiation: ring::io::der::nested::<ring::io::der::bit_string_with_no_unused_bits, untrusted::input::Input, ring::error::unspecified::Unspecified>::{closure#0}
Unexecuted instantiation: ring::io::der::nested::<<ring::rsa::keypair::KeyPair>::from_der_reader, ring::rsa::keypair::KeyPair, ring::error::key_rejected::KeyRejected>::{closure#0}
145
0
    inner.read_all(error, decoder)
146
0
}
Unexecuted instantiation: ring::io::der::nested::<ring::rsa::parse_public_key::{closure#0}::{closure#0}, (ring::io::positive::Positive, ring::io::positive::Positive), ring::error::unspecified::Unspecified>
Unexecuted instantiation: ring::io::der::nested::<ring::pkcs8::unwrap_key_::{closure#0}::{closure#0}, (untrusted::input::Input, core::option::Option<untrusted::input::Input>), ring::error::key_rejected::KeyRejected>
Unexecuted instantiation: ring::io::der::nested::<ring::ec::suite_b::key_pair_from_pkcs8::{closure#0}::{closure#0}, (untrusted::input::Input, untrusted::input::Input), ring::error::key_rejected::KeyRejected>
Unexecuted instantiation: ring::io::der::nested::<ring::io::der::bit_string_tagged_with_no_unused_bits::{closure#0}, untrusted::input::Input, ring::error::unspecified::Unspecified>
Unexecuted instantiation: ring::io::der::nested::<ring::ec::suite_b::ecdsa::verification::split_rs_asn1::{closure#0}, (untrusted::input::Input, untrusted::input::Input), ring::error::unspecified::Unspecified>
Unexecuted instantiation: ring::io::der::nested::<ring::io::der::bit_string_with_no_unused_bits, untrusted::input::Input, ring::error::unspecified::Unspecified>
Unexecuted instantiation: ring::io::der::nested::<<ring::rsa::keypair::KeyPair>::from_der_reader, ring::rsa::keypair::KeyPair, ring::error::key_rejected::KeyRejected>
147
148
0
pub(crate) fn nonnegative_integer<'a>(
149
0
    input: &mut untrusted::Reader<'a>,
150
0
) -> Result<untrusted::Input<'a>, error::Unspecified> {
151
0
    let value = expect_tag_and_get_value(input, Tag::Integer)?;
152
0
    match value
153
0
        .as_slice_less_safe()
154
0
        .split_first()
155
0
        .ok_or(error::Unspecified)?
156
    {
157
        // Zero or leading zero.
158
0
        (0, rest) => {
159
0
            match rest.first() {
160
                // Zero.
161
0
                None => Ok(value),
162
                // Necessary leading zero.
163
0
                Some(&second) if second & 0x80 == 0x80 => Ok(untrusted::Input::from(rest)),
164
                // Unnecessary leading zero.
165
0
                _ => Err(error::Unspecified),
166
            }
167
        }
168
        // Positive value with no leading zero.
169
0
        (first, _) if first & 0x80 == 0 => Ok(value),
170
        // Negative value.
171
0
        (_, _) => Err(error::Unspecified),
172
    }
173
0
}
174
175
/// Parse as integer with a value in the in the range [0, 255], returning its
176
/// numeric value. This is typically used for parsing version numbers.
177
#[inline]
178
0
pub fn small_nonnegative_integer(input: &mut untrusted::Reader) -> Result<u8, error::Unspecified> {
179
0
    let value = nonnegative_integer(input)?;
180
0
    match *value.as_slice_less_safe() {
181
0
        [b] => Ok(b),
182
0
        _ => Err(error::Unspecified),
183
    }
184
0
}
185
186
/// Parses a positive DER integer, returning the big-endian-encoded value,
187
/// sans any leading zero byte.
188
0
pub fn positive_integer<'a>(
189
0
    input: &mut untrusted::Reader<'a>,
190
0
) -> Result<Positive<'a>, error::Unspecified> {
191
0
    let value = nonnegative_integer(input)?;
192
0
    Positive::from_be_bytes(value)
193
0
}
194
195
#[cfg(test)]
196
mod tests {
197
    use super::*;
198
    use crate::error;
199
200
    fn with_i<'a, F, R>(value: &'a [u8], f: F) -> Result<R, error::Unspecified>
201
    where
202
        F: FnOnce(&mut untrusted::Reader<'a>) -> Result<R, error::Unspecified>,
203
    {
204
        untrusted::Input::from(value).read_all(error::Unspecified, f)
205
    }
206
207
    static ZERO_INTEGER: &[u8] = &[0x02, 0x01, 0x00];
208
209
    static GOOD_POSITIVE_INTEGERS_SMALL: &[(&[u8], u8)] = &[
210
        (&[0x02, 0x01, 0x01], 0x01),
211
        (&[0x02, 0x01, 0x02], 0x02),
212
        (&[0x02, 0x01, 0x7e], 0x7e),
213
        (&[0x02, 0x01, 0x7f], 0x7f),
214
        // Values that need to have an 0x00 prefix to disambiguate them from
215
        // them from negative values.
216
        (&[0x02, 0x02, 0x00, 0x80], 0x80),
217
        (&[0x02, 0x02, 0x00, 0x81], 0x81),
218
        (&[0x02, 0x02, 0x00, 0xfe], 0xfe),
219
        (&[0x02, 0x02, 0x00, 0xff], 0xff),
220
    ];
221
222
    static GOOD_POSITIVE_INTEGERS_LARGE: &[(&[u8], &[u8])] = &[
223
        (&[0x02, 0x02, 0x01, 0x00], &[0x01, 0x00]),
224
        (&[0x02, 0x02, 0x02, 0x01], &[0x02, 0x01]),
225
        (&[0x02, 0x02, 0x7e, 0xfe], &[0x7e, 0xfe]),
226
        (&[0x02, 0x02, 0x7f, 0xff], &[0x7f, 0xff]),
227
        // Values that need to have an 0x00 prefix to disambiguate them from
228
        // them from negative values.
229
        (&[0x02, 0x03, 0x00, 0x80, 0x00], &[0x80, 0x00]),
230
        (&[0x02, 0x03, 0x00, 0x81, 0x01], &[0x81, 0x01]),
231
        (&[0x02, 0x03, 0x00, 0xfe, 0xfe], &[0xfe, 0xfe]),
232
        (&[0x02, 0x03, 0x00, 0xff, 0xff], &[0xff, 0xff]),
233
    ];
234
235
    static BAD_NONNEGATIVE_INTEGERS: &[&[u8]] = &[
236
        &[],           // At end of input
237
        &[0x02],       // Tag only
238
        &[0x02, 0x00], // Empty value
239
        // Length mismatch
240
        &[0x02, 0x00, 0x01],
241
        &[0x02, 0x01],
242
        // Would be valid if leading zero is ignored when comparing length.
243
        &[0x02, 0x01, 0x00, 0x01],
244
        &[0x02, 0x01, 0x01, 0x00], // Would be valid if last byte is ignored.
245
        &[0x02, 0x02, 0x01],
246
        // Values that are missing a necessary leading 0x00
247
        &[0x02, 0x01, 0x80],
248
        &[0x02, 0x01, 0x81],
249
        &[0x02, 0x01, 0xfe],
250
        &[0x02, 0x01, 0xff],
251
        // Values that have an unnecessary leading 0x00
252
        &[0x02, 0x02, 0x00, 0x00],
253
        &[0x02, 0x02, 0x00, 0x01],
254
        &[0x02, 0x02, 0x00, 0x02],
255
        &[0x02, 0x02, 0x00, 0x7e],
256
        &[0x02, 0x02, 0x00, 0x7f],
257
    ];
258
259
    #[test]
260
    fn test_small_nonnegative_integer() {
261
        let zero = (ZERO_INTEGER, 0x00);
262
        for &(test_in, test_out) in
263
            core::iter::once(&zero).chain(GOOD_POSITIVE_INTEGERS_SMALL.iter())
264
        {
265
            let result = with_i(test_in, |input| {
266
                assert_eq!(small_nonnegative_integer(input)?, test_out);
267
                Ok(())
268
            });
269
            assert_eq!(result, Ok(()));
270
        }
271
        for &test_in in BAD_NONNEGATIVE_INTEGERS
272
            .iter()
273
            .chain(GOOD_POSITIVE_INTEGERS_LARGE.iter().map(|(input, _)| input))
274
        {
275
            let result = with_i(test_in, small_nonnegative_integer);
276
            assert_eq!(result, Err(error::Unspecified));
277
        }
278
    }
279
280
    #[test]
281
    fn test_positive_integer() {
282
        for (test_in, test_out) in GOOD_POSITIVE_INTEGERS_SMALL
283
            .iter()
284
            .map(|(test_in, test_out)| (*test_in, core::slice::from_ref(test_out)))
285
            .chain(GOOD_POSITIVE_INTEGERS_LARGE.iter().copied())
286
        {
287
            let result = with_i(test_in, |input| {
288
                assert_eq!(
289
                    positive_integer(input)?.big_endian_without_leading_zero(),
290
                    test_out
291
                );
292
                Ok(())
293
            });
294
            assert_eq!(result, Ok(()))
295
        }
296
        for &test_in in core::iter::once(&ZERO_INTEGER).chain(BAD_NONNEGATIVE_INTEGERS.iter()) {
297
            let result = with_i(test_in, positive_integer);
298
            assert!(matches!(result, Err(error::Unspecified)));
299
        }
300
    }
301
}