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