Coverage Report

Created: 2025-07-11 07:02

/src/spdm-rs/external/webpki/src/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 AUTHORS DISCLAIM ALL WARRANTIES
8
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
10
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15
use crate::{calendar, time, Error};
16
pub use ring::io::{
17
    der::{nested, Tag},
18
    Positive,
19
};
20
21
#[inline(always)]
22
0
pub fn expect_tag_and_get_value<'a>(
23
0
    input: &mut untrusted::Reader<'a>,
24
0
    tag: Tag,
25
0
) -> Result<untrusted::Input<'a>, Error> {
26
0
    ring::io::der::expect_tag_and_get_value(input, tag).map_err(|_| Error::BadDer)
27
0
}
28
29
pub struct Value<'a> {
30
    value: untrusted::Input<'a>,
31
}
32
33
impl<'a> Value<'a> {
34
0
    pub fn value(&self) -> untrusted::Input<'a> {
35
0
        self.value
36
0
    }
37
}
38
39
0
pub fn expect_tag<'a>(input: &mut untrusted::Reader<'a>, tag: Tag) -> Result<Value<'a>, Error> {
40
0
    let (actual_tag, value) = read_tag_and_get_value(input)?;
41
0
    if usize::from(tag) != usize::from(actual_tag) {
42
0
        return Err(Error::BadDer);
43
0
    }
44
0
45
0
    Ok(Value { value })
46
0
}
47
48
#[inline(always)]
49
0
pub fn read_tag_and_get_value<'a>(
50
0
    input: &mut untrusted::Reader<'a>,
51
0
) -> Result<(u8, untrusted::Input<'a>), Error> {
52
0
    ring::io::der::read_tag_and_get_value(input).map_err(|_| Error::BadDer)
53
0
}
54
55
// TODO: investigate taking decoder as a reference to reduce generated code
56
// size.
57
0
pub fn nested_of_mut<'a, E>(
58
0
    input: &mut untrusted::Reader<'a>,
59
0
    outer_tag: Tag,
60
0
    inner_tag: Tag,
61
0
    error: E,
62
0
    mut decoder: impl FnMut(&mut untrusted::Reader<'a>) -> Result<(), E>,
63
0
) -> Result<(), E>
64
0
where
65
0
    E: Copy,
66
0
{
67
0
    nested(input, outer_tag, error, |outer| {
68
        loop {
69
0
            nested(outer, inner_tag, error, |inner| decoder(inner))?;
70
0
            if outer.at_end() {
71
0
                break;
72
0
            }
73
        }
74
0
        Ok(())
75
0
    })
76
0
}
77
78
0
pub fn bit_string_with_no_unused_bits<'a>(
79
0
    input: &mut untrusted::Reader<'a>,
80
0
) -> Result<untrusted::Input<'a>, Error> {
81
0
    nested(input, Tag::BitString, Error::BadDer, |value| {
82
0
        let unused_bits_at_end = value.read_byte().map_err(|_| Error::BadDer)?;
83
0
        if unused_bits_at_end != 0 {
84
0
            return Err(Error::BadDer);
85
0
        }
86
0
        Ok(value.read_bytes_to_end())
87
0
    })
88
0
}
89
90
// Like mozilla::pkix, we accept the nonconformant explicit encoding of
91
// the default value (false) for compatibility with real-world certificates.
92
0
pub fn optional_boolean(input: &mut untrusted::Reader) -> Result<bool, Error> {
93
0
    if !input.peek(Tag::Boolean.into()) {
94
0
        return Ok(false);
95
0
    }
96
0
    nested(input, Tag::Boolean, Error::BadDer, |input| {
97
0
        match input.read_byte() {
98
0
            Ok(0xff) => Ok(true),
99
0
            Ok(0x00) => Ok(false),
100
0
            _ => Err(Error::BadDer),
101
        }
102
0
    })
103
0
}
104
105
0
pub fn positive_integer<'a>(input: &'a mut untrusted::Reader) -> Result<Positive<'a>, Error> {
106
0
    ring::io::der::positive_integer(input).map_err(|_| Error::BadDer)
107
0
}
108
109
0
pub fn small_nonnegative_integer(input: &mut untrusted::Reader) -> Result<u8, Error> {
110
0
    ring::io::der::small_nonnegative_integer(input).map_err(|_| Error::BadDer)
111
0
}
112
113
0
pub fn time_choice(input: &mut untrusted::Reader) -> Result<time::Time, Error> {
114
0
    let is_utc_time = input.peek(Tag::UTCTime.into());
115
0
    let expected_tag = if is_utc_time {
116
0
        Tag::UTCTime
117
    } else {
118
0
        Tag::GeneralizedTime
119
    };
120
121
0
    fn read_digit(inner: &mut untrusted::Reader) -> Result<u64, Error> {
122
        const DIGIT: core::ops::RangeInclusive<u8> = b'0'..=b'9';
123
0
        let b = inner.read_byte().map_err(|_| Error::BadDerTime)?;
124
0
        if DIGIT.contains(&b) {
125
0
            return Ok(u64::from(b - DIGIT.start()));
126
0
        }
127
0
        Err(Error::BadDerTime)
128
0
    }
129
130
0
    fn read_two_digits(inner: &mut untrusted::Reader, min: u64, max: u64) -> Result<u64, Error> {
131
0
        let hi = read_digit(inner)?;
132
0
        let lo = read_digit(inner)?;
133
0
        let value = (hi * 10) + lo;
134
0
        if value < min || value > max {
135
0
            return Err(Error::BadDerTime);
136
0
        }
137
0
        Ok(value)
138
0
    }
139
140
0
    nested(input, expected_tag, Error::BadDer, |value| {
141
0
        let (year_hi, year_lo) = if is_utc_time {
142
0
            let lo = read_two_digits(value, 0, 99)?;
143
0
            let hi = if lo >= 50 { 19 } else { 20 };
144
0
            (hi, lo)
145
        } else {
146
0
            let hi = read_two_digits(value, 0, 99)?;
147
0
            let lo = read_two_digits(value, 0, 99)?;
148
0
            (hi, lo)
149
        };
150
151
0
        let year = (year_hi * 100) + year_lo;
152
0
        let month = read_two_digits(value, 1, 12)?;
153
0
        let days_in_month = calendar::days_in_month(year, month);
154
0
        let day_of_month = read_two_digits(value, 1, days_in_month)?;
155
0
        let hours = read_two_digits(value, 0, 23)?;
156
0
        let minutes = read_two_digits(value, 0, 59)?;
157
0
        let seconds = read_two_digits(value, 0, 59)?;
158
159
0
        let time_zone = value.read_byte().map_err(|_| Error::BadDerTime)?;
160
0
        if time_zone != b'Z' {
161
0
            return Err(Error::BadDerTime);
162
0
        }
163
0
164
0
        calendar::time_from_ymdhms_utc(year, month, day_of_month, hours, minutes, seconds)
165
0
    })
166
0
}
167
168
macro_rules! oid {
169
    ( $first:expr, $second:expr, $( $tail:expr ),* ) =>
170
    (
171
        [(40 * $first) + $second, $( $tail ),*]
172
    )
173
}