der_parser/ber/tagged.rs
1use crate::ber::*;
2use crate::error::*;
3use asn1_rs::Tag;
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_ber_tagged_explicit_g](fn.parse_ber_tagged_explicit_g.html).
14///
15/// The following parses `[2] EXPLICIT INTEGER`:
16///
17/// ```rust
18/// # use der_parser::ber::*;
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_ber_tagged_explicit(2, parse_ber_integer),
25/// |x: BerObject| 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_ber_tagged_explicit<'a, T, F>(tag: T, f: F) -> impl FnMut(&'a [u8]) -> BerResult
40where
41 F: Fn(&'a [u8]) -> BerResult<BerObject>,
42 T: Into<Tag>,
43{
44 let tag = tag.into();
45 parse_ber_tagged_explicit_g(tag, move |content, hdr| {
46 let (rem, obj) = f(content)?;
47 let class = hdr.class();
48 let obj2 = BerObject::from_header_and_content(
49 hdr,
50 BerObjectContent::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::ber::*;
62/// # use der_parser::error::BerResult;
63/// #
64/// fn parse_int_explicit(i:&[u8]) -> BerResult<u32> {
65/// parse_ber_tagged_explicit_g(2, move |content, hdr| {
66/// let (rem, obj) = parse_ber_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_ber_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_ber_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 hdr.assert_constructed().map_err(|e| Err::Error(e.into()))?;
101
102 f(i, hdr)
103 // trailing bytes are ignored
104 })
105}
106
107/// Read a TAGGED IMPLICIT value (combinator)
108///
109/// Parse a TAGGED IMPLICIT value, given the expected tag, and the content parsing function.
110///
111/// The built object will use the original header (and tag), so the content may not match the tag
112/// value.
113///
114/// For a generic version (different output and error types), see
115/// [parse_ber_tagged_implicit_g](fn.parse_ber_tagged_implicit_g.html).
116///
117/// # Examples
118///
119/// The following parses `[2] IMPLICIT INTEGER` into a `BerObject`:
120///
121/// ```rust
122/// # use der_parser::ber::*;
123/// # use der_parser::error::BerResult;
124/// #
125/// fn parse_int_implicit(i:&[u8]) -> BerResult<BerObject> {
126/// parse_ber_tagged_implicit(
127/// 2,
128/// parse_ber_content(Tag::Integer),
129/// )(i)
130/// }
131///
132/// # let bytes = &[0x82, 0x03, 0x01, 0x00, 0x01];
133/// let res = parse_int_implicit(bytes);
134/// # match res {
135/// # Ok((rem, content)) => {
136/// # assert!(rem.is_empty());
137/// # assert_eq!(content.as_u32(), Ok(0x10001));
138/// # },
139/// # _ => assert!(false)
140/// # }
141/// ```
142///
143/// The following parses `[2] IMPLICIT INTEGER` into an `u32`, raising an error if the integer is
144/// too large:
145///
146/// ```rust
147/// # use der_parser::ber::*;
148/// # use der_parser::error::BerResult;
149/// use nom::combinator::map_res;
150/// #
151/// fn parse_int_implicit(i:&[u8]) -> BerResult<u32> {
152/// map_res(
153/// parse_ber_tagged_implicit(
154/// 2,
155/// parse_ber_content(Tag::Integer),
156/// ),
157/// |x: BerObject| x.as_u32()
158/// )(i)
159/// }
160///
161/// # let bytes = &[0x82, 0x03, 0x01, 0x00, 0x01];
162/// let res = parse_int_implicit(bytes);
163/// # match res {
164/// # Ok((rem, val)) => {
165/// # assert!(rem.is_empty());
166/// # assert_eq!(val, 0x10001);
167/// # },
168/// # _ => assert!(false)
169/// # }
170/// ```
171pub fn parse_ber_tagged_implicit<'a, T, F>(tag: T, f: F) -> impl FnMut(&'a [u8]) -> BerResult
172where
173 F: Fn(&'a [u8], &'_ Header, usize) -> BerResult<'a, BerObjectContent<'a>>,
174 T: Into<Tag>,
175{
176 let tag = tag.into();
177 parse_ber_tagged_implicit_g(tag, move |i, hdr, depth| {
178 let (rem, content) = f(i, &hdr, depth)?;
179 // trailing bytes are ignored
180 let obj = BerObject::from_header_and_content(hdr, content);
181 Ok((rem, obj))
182 })
183}
184
185/// Read a TAGGED IMPLICIT value (generic version)
186///
187/// Parse a TAGGED IMPLICIT value, given the expected tag, and the content parsing function.
188///
189/// # Examples
190///
191/// The following parses `[1] IMPLICIT OCTETSTRING`, returning a `BerObject`:
192///
193/// ```rust
194/// # use der_parser::ber::*;
195/// # use der_parser::error::BerResult;
196/// #
197/// fn parse_implicit_0_octetstring(i:&[u8]) -> BerResult<BerObjectContent> {
198/// parse_ber_tagged_implicit_g(
199/// 2,
200/// parse_ber_content2(Tag::OctetString)
201/// )(i)
202/// }
203///
204/// # let bytes = &[0x02, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f];
205/// let res = parse_implicit_0_octetstring(bytes);
206/// # match res {
207/// # Ok((rem, val)) => {
208/// # assert!(rem.is_empty());
209/// # let s = val.as_slice().unwrap();
210/// # assert_eq!(s, b"hello");
211/// # },
212/// # _ => assert!(false)
213/// # }
214/// ```
215///
216/// The following parses `[2] IMPLICIT INTEGER` into an `u32`, raising an error if the integer is
217/// too large:
218///
219/// ```rust
220/// # use der_parser::ber::*;
221/// # use der_parser::error::BerResult;
222/// #
223/// fn parse_int_implicit(i:&[u8]) -> BerResult<u32> {
224/// parse_ber_tagged_implicit_g(
225/// 2,
226/// |content, hdr, depth| {
227/// let (rem, obj_content) = parse_ber_content(Tag::Integer)(content, &hdr, depth)?;
228/// let value = obj_content.as_u32()?;
229/// Ok((rem, value))
230/// }
231/// )(i)
232/// }
233///
234/// # let bytes = &[0x82, 0x03, 0x01, 0x00, 0x01];
235/// let res = parse_int_implicit(bytes);
236/// # match res {
237/// # Ok((rem, val)) => {
238/// # assert!(rem.is_empty());
239/// # assert_eq!(val, 0x10001);
240/// # },
241/// # _ => assert!(false)
242/// # }
243/// ```
244pub fn parse_ber_tagged_implicit_g<'a, T, Output, F, E>(
245 tag: T,
246 f: F,
247) -> impl FnMut(&'a [u8]) -> IResult<&[u8], Output, E>
248where
249 F: Fn(&'a [u8], Header<'a>, usize) -> IResult<&'a [u8], Output, E>,
250 E: ParseError<&'a [u8]> + From<BerError>,
251 T: Into<Tag>,
252{
253 let tag = tag.into();
254 parse_ber_container(move |i, hdr| {
255 hdr.assert_tag(tag).map_err(|e| Err::Error(e.into()))?;
256 // XXX MAX_RECURSION should not be used, it resets the depth counter
257 f(i, hdr, MAX_RECURSION)
258 // trailing bytes are ignored
259 })
260}