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