der_parser/ber/
tagged.rs

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