der_parser/der/
tagged.rs

1use crate::ber::MAX_RECURSION;
2use crate::der::*;
3use crate::error::*;
4use nom::error::ParseError;
5use nom::{Err, IResult};
6
7/// Read a TAGGED EXPLICIT value (combinator)
8///
9/// The built object will use the outer header (and tag), and contains a `Tagged` object
10/// with class, value and content.
11///
12/// For a generic version (different output and error types), see
13/// [parse_der_tagged_explicit_g](fn.parse_der_tagged_explicit_g.html).
14///
15/// The following parses `[2] EXPLICIT INTEGER`:
16///
17/// ```rust
18/// # use der_parser::der::*;
19/// # use der_parser::error::BerResult;
20/// use nom::combinator::map_res;
21/// #
22/// fn parse_int_explicit(i:&[u8]) -> BerResult<u32> {
23///    map_res(
24///        parse_der_tagged_explicit(2, parse_der_integer),
25///        |x: DerObject| x.as_tagged()?.2.as_u32()
26///    )(i)
27/// }
28///
29/// # let bytes = &[0xa2, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01];
30/// let res = parse_int_explicit(bytes);
31/// # match res {
32/// #     Ok((rem,val)) => {
33/// #         assert!(rem.is_empty());
34/// #         assert_eq!(val, 0x10001);
35/// #     },
36/// #     _ => assert!(false)
37/// # }
38/// ```
39pub fn parse_der_tagged_explicit<'a, T, F>(tag: T, f: F) -> impl FnMut(&'a [u8]) -> BerResult
40where
41    F: Fn(&'a [u8]) -> BerResult<DerObject>,
42    T: Into<Tag>,
43{
44    let tag = tag.into();
45    parse_der_tagged_explicit_g(tag, move |content, hdr| {
46        let (rem, obj) = f(content)?;
47        let class = hdr.class();
48        let obj2 = DerObject::from_header_and_content(
49            hdr,
50            DerObjectContent::Tagged(class, tag, Box::new(obj)),
51        );
52        Ok((rem, obj2))
53    })
54}
55
56/// Read a TAGGED EXPLICIT value (generic version)
57///
58/// The following parses `[2] EXPLICIT INTEGER`:
59///
60/// ```rust
61/// # use der_parser::der::*;
62/// # use der_parser::error::BerResult;
63/// #
64/// fn parse_int_explicit(i:&[u8]) -> BerResult<u32> {
65///     parse_der_tagged_explicit_g(2, move |content, hdr| {
66///         let (rem, obj) = parse_der_integer(content)?;
67///         let value = obj.as_u32()?;
68///         Ok((rem, value))
69///    })(i)
70/// }
71///
72/// # let bytes = &[0xa2, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01];
73/// let res = parse_int_explicit(bytes);
74/// # match res {
75/// #     Ok((rem,val)) => {
76/// #         assert!(rem.is_empty());
77/// #         assert_eq!(val, 0x10001);
78/// #     },
79/// #     _ => assert!(false)
80/// # }
81/// ```
82pub fn parse_der_tagged_explicit_g<'a, T, Output, F, E>(
83    tag: T,
84    f: F,
85) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], Output, E>
86where
87    F: Fn(&'a [u8], Header<'a>) -> IResult<&'a [u8], Output, E>,
88    E: ParseError<&'a [u8]> + From<BerError>,
89    T: Into<Tag>,
90{
91    let tag = tag.into();
92    parse_der_container(move |i, hdr| {
93        if hdr.class() == Class::Universal {
94            return Err(Err::Error(
95                BerError::unexpected_class(None, hdr.class()).into(),
96            ));
97        }
98        hdr.assert_tag(tag).map_err(|e| Err::Error(e.into()))?;
99        // X.690 8.14.2: if implicit tagging was not used, the encoding shall be constructed
100        if !hdr.is_constructed() {
101            return Err(Err::Error(BerError::ConstructExpected.into()));
102        }
103        f(i, hdr)
104        // trailing bytes are ignored
105    })
106}
107
108/// Read a TAGGED IMPLICIT value (combinator)
109///
110/// Parse a TAGGED IMPLICIT value, given the expected tag, and the content parsing function.
111///
112/// The built object will use the original header (and tag), so the content may not match the tag
113/// value.
114///
115/// For a generic version (different output and error types), see
116/// [parse_der_tagged_implicit_g](fn.parse_der_tagged_implicit_g.html).
117///
118/// # Examples
119///
120/// The following parses `[2] IMPLICIT INTEGER` into a `DerObject`:
121///
122/// ```rust
123/// # use der_parser::der::*;
124/// # use der_parser::error::BerResult;
125/// #
126/// fn parse_int_implicit(i:&[u8]) -> BerResult<DerObject> {
127///     parse_der_tagged_implicit(
128///         2,
129///         parse_der_content(Tag::Integer),
130///     )(i)
131/// }
132///
133/// # let bytes = &[0x82, 0x03, 0x01, 0x00, 0x01];
134/// let res = parse_int_implicit(bytes);
135/// # match res {
136/// #     Ok((rem, content)) => {
137/// #         assert!(rem.is_empty());
138/// #         assert_eq!(content.as_u32(), Ok(0x10001));
139/// #     },
140/// #     _ => assert!(false)
141/// # }
142/// ```
143///
144/// The following parses `[2] IMPLICIT INTEGER` into an `u32`, raising an error if the integer is
145/// too large:
146///
147/// ```rust
148/// # use der_parser::der::*;
149/// # use der_parser::error::BerResult;
150/// use nom::combinator::map_res;
151/// #
152/// fn parse_int_implicit(i:&[u8]) -> BerResult<u32> {
153///     map_res(
154///         parse_der_tagged_implicit(
155///             2,
156///             parse_der_content(Tag::Integer),
157///         ),
158///         |x: DerObject| x.as_u32()
159///     )(i)
160/// }
161///
162/// # let bytes = &[0x82, 0x03, 0x01, 0x00, 0x01];
163/// let res = parse_int_implicit(bytes);
164/// # match res {
165/// #     Ok((rem, val)) => {
166/// #         assert!(rem.is_empty());
167/// #         assert_eq!(val, 0x10001);
168/// #     },
169/// #     _ => assert!(false)
170/// # }
171/// ```
172pub fn parse_der_tagged_implicit<'a, T, F>(tag: T, f: F) -> impl FnMut(&'a [u8]) -> BerResult
173where
174    F: Fn(&'a [u8], &'_ Header, usize) -> BerResult<'a, DerObjectContent<'a>>,
175    T: Into<Tag>,
176{
177    let tag = tag.into();
178    parse_der_tagged_implicit_g(tag, move |i, hdr, depth| {
179        let (rem, content) = f(i, &hdr, depth)?;
180        // trailing bytes are ignored
181        let obj = DerObject::from_header_and_content(hdr, content);
182        Ok((rem, obj))
183    })
184}
185
186/// Read a TAGGED IMPLICIT value (generic version)
187///
188/// Parse a TAGGED IMPLICIT value, given the expected tag, and the content parsing function.
189///
190/// # Examples
191///
192/// The following parses `[1] IMPLICIT OCTETSTRING`, returning a `DerObject`:
193///
194/// ```rust
195/// # use der_parser::der::*;
196/// # use der_parser::error::BerResult;
197/// #
198/// fn parse_implicit_0_octetstring(i:&[u8]) -> BerResult<DerObjectContent> {
199///     parse_der_tagged_implicit_g(
200///         2,
201///         parse_der_content2(Tag::OctetString)
202///     )(i)
203/// }
204///
205/// # let bytes = &[0x02, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f];
206/// let res = parse_implicit_0_octetstring(bytes);
207/// # match res {
208/// #     Ok((rem, val)) => {
209/// #         assert!(rem.is_empty());
210/// #         let s = val.as_slice().unwrap();
211/// #         assert_eq!(s, b"hello");
212/// #     },
213/// #     _ => assert!(false)
214/// # }
215/// ```
216///
217/// The following parses `[2] IMPLICIT INTEGER` into an `u32`, raising an error if the integer is
218/// too large:
219///
220/// ```rust
221/// # use der_parser::der::*;
222/// # use der_parser::error::BerResult;
223/// #
224/// fn parse_int_implicit(i:&[u8]) -> BerResult<u32> {
225///     parse_der_tagged_implicit_g(
226///         2,
227///         |content, hdr, depth| {
228///             let (rem, obj_content) = parse_der_content(Tag::Integer)(content, &hdr, depth)?;
229///             let value = obj_content.as_u32()?;
230///             Ok((rem, value))
231///         }
232///     )(i)
233/// }
234///
235/// # let bytes = &[0x82, 0x03, 0x01, 0x00, 0x01];
236/// let res = parse_int_implicit(bytes);
237/// # match res {
238/// #     Ok((rem, val)) => {
239/// #         assert!(rem.is_empty());
240/// #         assert_eq!(val, 0x10001);
241/// #     },
242/// #     _ => assert!(false)
243/// # }
244/// ```
245pub fn parse_der_tagged_implicit_g<'a, T, Output, F, E>(
246    tag: T,
247    f: F,
248) -> impl FnMut(&'a [u8]) -> IResult<&[u8], Output, E>
249where
250    F: Fn(&'a [u8], Header<'a>, usize) -> IResult<&'a [u8], Output, E>,
251    E: ParseError<&'a [u8]> + From<BerError>,
252    T: Into<Tag>,
253{
254    let tag = tag.into();
255    parse_der_container(move |i, hdr| {
256        hdr.assert_tag(tag).map_err(|e| Err::Error(e.into()))?;
257        // XXX MAX_RECURSION should not be used, it resets the depth counter
258        f(i, hdr, MAX_RECURSION)
259        // trailing bytes are ignored
260    })
261}