/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 | | } |