1use super::Positive;
20use crate::error;
21
22pub const CONSTRUCTED: u8 = 1 << 5;
23pub const CONTEXT_SPECIFIC: u8 = 2 << 6;
24
25#[derive(Clone, Copy, PartialEq)]
26#[repr(u8)]
27pub enum Tag {
28 Boolean = 0x01,
29 Integer = 0x02,
30 BitString = 0x03,
31 OctetString = 0x04,
32 Null = 0x05,
33 OID = 0x06,
34 Sequence = CONSTRUCTED | 0x10, 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
45impl From<Tag> for usize {
46 fn from(tag: Tag) -> Self {
47 Self::from(Tag::into(tag))
48 }
49}
50
51impl From<Tag> for u8 {
52 fn from(tag: Tag) -> Self {
53 Tag::into(tag)
54 }
55}
56
57impl Tag {
59 pub const fn into(self) -> u8 {
60 self as u8
61 }
62}
63
64pub fn expect_tag_and_get_value<'a>(
65 input: &mut untrusted::Reader<'a>,
66 tag: Tag,
67) -> Result<untrusted::Input<'a>, error::Unspecified> {
68 let (actual_tag, inner) = read_tag_and_get_value(input)?;
69 if usize::from(tag) != usize::from(actual_tag) {
70 return Err(error::Unspecified);
71 }
72 Ok(inner)
73}
74
75pub fn read_tag_and_get_value<'a>(
76 input: &mut untrusted::Reader<'a>,
77) -> Result<(u8, untrusted::Input<'a>), error::Unspecified> {
78 let tag = input.read_byte()?;
79 if (tag & 0x1F) == 0x1F {
80 return Err(error::Unspecified); }
82
83 let length = match input.read_byte()? {
87 n if (n & 0x80) == 0 => usize::from(n),
88 0x81 => {
89 let second_byte = input.read_byte()?;
90 if second_byte < 128 {
91 return Err(error::Unspecified); }
93 usize::from(second_byte)
94 }
95 0x82 => {
96 let second_byte = usize::from(input.read_byte()?);
97 let third_byte = usize::from(input.read_byte()?);
98 let combined = (second_byte << 8) | third_byte;
99 if combined < 256 {
100 return Err(error::Unspecified); }
102 combined
103 }
104 _ => {
105 return Err(error::Unspecified); }
107 };
108
109 let inner = input.read_bytes(length)?;
110 Ok((tag, inner))
111}
112
113#[inline]
114pub fn bit_string_with_no_unused_bits<'a>(
115 input: &mut untrusted::Reader<'a>,
116) -> Result<untrusted::Input<'a>, error::Unspecified> {
117 bit_string_tagged_with_no_unused_bits(Tag::BitString, input)
118}
119
120pub(crate) fn bit_string_tagged_with_no_unused_bits<'a>(
121 tag: Tag,
122 input: &mut untrusted::Reader<'a>,
123) -> Result<untrusted::Input<'a>, error::Unspecified> {
124 nested(input, tag, error::Unspecified, |value| {
125 let unused_bits_at_end = value.read_byte().map_err(|_| error::Unspecified)?;
126 if unused_bits_at_end != 0 {
127 return Err(error::Unspecified);
128 }
129 Ok(value.read_bytes_to_end())
130 })
131}
132
133pub fn nested<'a, F, R, E: Copy>(
136 input: &mut untrusted::Reader<'a>,
137 tag: Tag,
138 error: E,
139 decoder: F,
140) -> Result<R, E>
141where
142 F: FnOnce(&mut untrusted::Reader<'a>) -> Result<R, E>,
143{
144 let inner = expect_tag_and_get_value(input, tag).map_err(|_| error)?;
145 inner.read_all(error, decoder)
146}
147
148pub(crate) fn nonnegative_integer<'a>(
149 input: &mut untrusted::Reader<'a>,
150) -> Result<untrusted::Input<'a>, error::Unspecified> {
151 let value = expect_tag_and_get_value(input, Tag::Integer)?;
152 match value
153 .as_slice_less_safe()
154 .split_first()
155 .ok_or(error::Unspecified)?
156 {
157 (0, rest) => {
159 match rest.first() {
160 None => Ok(value),
162 Some(&second) if second & 0x80 == 0x80 => Ok(untrusted::Input::from(rest)),
164 _ => Err(error::Unspecified),
166 }
167 }
168 (first, _) if first & 0x80 == 0 => Ok(value),
170 (_, _) => Err(error::Unspecified),
172 }
173}
174
175#[inline]
178pub fn small_nonnegative_integer(input: &mut untrusted::Reader) -> Result<u8, error::Unspecified> {
179 let value = nonnegative_integer(input)?;
180 match *value.as_slice_less_safe() {
181 [b] => Ok(b),
182 _ => Err(error::Unspecified),
183 }
184}
185
186pub fn positive_integer<'a>(
189 input: &mut untrusted::Reader<'a>,
190) -> Result<Positive<'a>, error::Unspecified> {
191 let value = nonnegative_integer(input)?;
192 Positive::from_be_bytes(value)
193}
194
195#[cfg(test)]
196mod 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 (&[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 (&[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 &[], &[0x02], &[0x02, 0x00], &[0x02, 0x00, 0x01],
241 &[0x02, 0x01],
242 &[0x02, 0x01, 0x00, 0x01],
244 &[0x02, 0x01, 0x01, 0x00], &[0x02, 0x02, 0x01],
246 &[0x02, 0x01, 0x80],
248 &[0x02, 0x01, 0x81],
249 &[0x02, 0x01, 0xfe],
250 &[0x02, 0x01, 0xff],
251 &[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}