1use super::{BerObject, BerObjectContent, BitStringObject};
2use crate::ber::{ber_get_object_content, MAX_OBJECT_SIZE};
3use crate::error::{BerError, BerResult};
4use alloc::vec::Vec;
5use asn1_rs::*;
6use nom::Err;
7use rusticata_macros::custom_check;
8
9pub fn parse_ber_any_with_tag_r(i: &[u8], tag: Tag, max_depth: usize) -> BerResult {
13 custom_check!(i, max_depth == 0, BerError::BerMaxDepth)?;
14 let (rem, any) = Any::from_ber(i)?;
15 any.header.assert_tag(tag)?;
16 let obj = try_berobject_from_any(any, max_depth)?;
17 Ok((rem, obj))
18}
19
20pub fn parse_ber_any_r(i: &[u8], max_depth: usize) -> BerResult {
24 custom_check!(i, max_depth == 0, BerError::BerMaxDepth)?;
25 let (rem, any) = Any::from_ber(i)?;
26 let obj = try_berobject_from_any(any, max_depth)?;
27 Ok((rem, obj))
28}
29
30pub fn parse_ber_any(i: &[u8]) -> BerResult<Any> {
32 Any::from_ber(i)
33}
34
35macro_rules! from_obj {
36 ($header:ident, $content:expr) => {
37 BerObject::from_header_and_content($header, $content)
38 };
39 (STRING $ty:ident, $any:ident, $header:ident) => {
40 from_obj!(STRING $ty, $ty, $any, $header)
41 };
42 (STRING $ty:ident, $variant:ident, $any:ident, $header:ident) => {{
44 custom_check!($any.data, $header.constructed(), BerError::Unsupported)?; <$ty>::test_valid_charset($any.data)?;
46 let s = core::str::from_utf8($any.data)?;
47 Ok(BerObject::from_header_and_content(
48 $header,
49 BerObjectContent::$variant(s),
50 ))
51 }};
52}
53
54pub(crate) fn try_read_berobjectcontent_as(
58 i: &[u8],
59 tag: Tag,
60 length: Length,
61 constructed: bool,
62 max_depth: usize,
63) -> BerResult<BerObjectContent> {
64 if let Length::Definite(l) = length {
65 custom_check!(i, l > MAX_OBJECT_SIZE, BerError::InvalidLength)?;
66 if i.len() < l {
67 return Err(Err::Incomplete(Needed::new(l)));
68 }
69 }
70 let header = Header::new(Class::Universal, constructed, tag, length);
71 let (rem, i) = ber_get_object_content(i, &header, max_depth)?;
72 let any = Any::new(header, i);
73 let object = try_berobject_from_any(any, max_depth)?;
74 Ok((rem, object.content))
75}
76
77fn try_berobject_from_any(any: Any, max_depth: usize) -> Result<BerObject> {
79 custom_check!(any.data, max_depth == 0, BerError::BerMaxDepth)?;
80 let obj_from = BerObject::from_header_and_content;
81 let header = any.header.clone();
82 if any.class() != Class::Universal {
83 return Ok(obj_from(header, BerObjectContent::Unknown(any)));
84 }
85 match any.tag() {
86 Tag::BitString => {
87 if any.data.is_empty() {
88 return Err(BerError::BerValueError);
89 }
90 custom_check!(any.data, header.constructed(), BerError::Unsupported)?; let ignored_bits = any.data[0];
92 let data = &any.data[1..];
93 Ok(obj_from(
94 header,
95 BerObjectContent::BitString(ignored_bits, BitStringObject { data }),
96 ))
97 }
98 Tag::BmpString => from_obj!(STRING BmpString, any, header),
99 Tag::Boolean => {
100 let b = any.bool()?;
101 Ok(obj_from(header, BerObjectContent::Boolean(b)))
102 }
103 Tag::EndOfContent => Ok(obj_from(header, BerObjectContent::EndOfContent)),
104 Tag::Enumerated => {
105 let obj = any.enumerated()?;
106 Ok(obj_from(header, BerObjectContent::Enum(obj.0 as u64)))
107 }
108 Tag::GeneralizedTime => {
109 let time = any.generalizedtime()?;
110 Ok(obj_from(header, BerObjectContent::GeneralizedTime(time.0)))
111 }
112 Tag::GeneralString => from_obj!(STRING GeneralString, any, header),
113 Tag::GraphicString => from_obj!(STRING GraphicString, any, header),
114 Tag::Ia5String => from_obj!(STRING Ia5String, IA5String, any, header),
115 Tag::Integer => {
116 let obj = obj_from(header, BerObjectContent::Integer(any.data));
117 Ok(obj)
118 }
119 Tag::Null => Ok(obj_from(header, BerObjectContent::Null)),
120 Tag::NumericString => from_obj!(STRING NumericString, any, header),
121 Tag::ObjectDescriptor => from_obj!(STRING ObjectDescriptor, any, header),
122 Tag::OctetString => Ok(obj_from(header, BerObjectContent::OctetString(any.data))),
123 Tag::Oid => {
124 let oid = any.oid()?;
125 Ok(obj_from(header, BerObjectContent::OID(oid)))
126 }
127 Tag::PrintableString => from_obj!(STRING PrintableString, any, header),
128 Tag::RelativeOid => {
129 let oid = any.relative_oid()?;
130 Ok(obj_from(header, BerObjectContent::RelativeOID(oid)))
131 }
132 Tag::Sequence => {
133 header.assert_constructed()?;
134 let objects: Result<Vec<_>> = SequenceIterator::<Any, BerParser>::new(any.data)
135 .map(|item| {
136 let item = item?;
137 try_berobject_from_any(item, max_depth - 1)
138 })
139 .collect();
140 let objects = objects?;
141 Ok(obj_from(header, BerObjectContent::Sequence(objects)))
142 }
143 Tag::Set => {
144 header.assert_constructed()?;
145 let objects: Result<Vec<_>> = SetIterator::<Any, BerParser>::new(any.data)
146 .map(|item| {
147 let item = item?;
148 try_berobject_from_any(item, max_depth - 1)
149 })
150 .collect();
151 let objects = objects?;
152 Ok(obj_from(header, BerObjectContent::Set(objects)))
153 }
154 Tag::TeletexString => from_obj!(STRING TeletexString, T61String, any, header),
155 Tag::UtcTime => {
156 let time = any.utctime()?;
157 Ok(obj_from(header, BerObjectContent::UTCTime(time.0)))
158 }
159 Tag::UniversalString => {
160 custom_check!(any.data, header.constructed(), BerError::Unsupported)?; Ok(obj_from(
165 header,
166 BerObjectContent::UniversalString(any.data),
167 ))
168 }
169 Tag::Utf8String => from_obj!(STRING Utf8String, UTF8String, any, header),
170 Tag::VideotexString => from_obj!(STRING VideotexString, any, header),
171 Tag::VisibleString => from_obj!(STRING VisibleString, any, header),
172 _ => {
173 Ok(obj_from(header, BerObjectContent::Unknown(any)))
177 }
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use crate::ber::{BerObject, BerObjectContent, MAX_RECURSION};
184 use crate::error::BerError;
185 use hex_literal::hex;
186 use test_case::test_case;
187
188 use super::parse_ber_any_r;
189
190 #[test_case(&hex!("01 01 00") => matches Ok(BerObject{header:_, content:BerObjectContent::Boolean(false)}) ; "val false")]
191 #[test_case(&hex!("01 01 ff") => matches Ok(BerObject{header:_, content:BerObjectContent::Boolean(true)}) ; "val true")]
192 #[test_case(&hex!("01 01 7f") => matches Ok(BerObject{header:_, content:BerObjectContent::Boolean(true)}) ; "true not ff")]
193 #[test_case(&hex!("02 02 00 ff") => matches Ok(BerObject{header:_, content:BerObjectContent::Integer(_)}) ; "u32-255")]
194 #[test_case(&hex!("02 02 01 23") => matches Ok(BerObject{header:_, content:BerObjectContent::Integer(_)}) ; "u32-0x123")]
195 #[test_case(&hex!("02 04 ff ff ff ff") => matches Ok(BerObject{header:_, content:BerObjectContent::Integer(_)}) ; "u32-long-neg")]
196 #[test_case(&hex!("0c 04 31 32 33 34") => matches Ok(BerObject{header:_, content:BerObjectContent::UTF8String("1234")}) ; "utf8: numeric")]
197 #[test_case(&hex!("0d 04 c2 7b 03 02") => matches Ok(BerObject{header:_, content:BerObjectContent::RelativeOID(_)}) ; "relative OID")]
198 #[test_case(&hex!("12 04 31 32 33 34") => matches Ok(BerObject{header:_, content:BerObjectContent::NumericString("1234")}) ; "numeric string")]
199 #[test_case(&hex!("12 04 01 02 03 04") => matches Err(BerError::StringInvalidCharset) ; "numeric string err")]
200 #[test_case(&hex!("13 04 31 32 33 34") => matches Ok(BerObject{header:_, content:BerObjectContent::PrintableString("1234")}) ; "printable string")]
201 #[test_case(&hex!("13 04 01 02 03 04") => matches Err(BerError::StringInvalidCharset) ; "printable string err")]
202 #[test_case(&hex!("16 04 31 32 33 34") => matches Ok(BerObject{header:_, content:BerObjectContent::IA5String("1234")}) ; "ia5: numeric")]
203 #[test_case(&hex!("1a 04 31 32 33 34") => matches Ok(BerObject{header:_, content:BerObjectContent::VisibleString("1234")}) ; "visible: numeric")]
204 #[test_case(&hex!("1e 08 00 55 00 73 00 65 00 72") => matches Ok(BerObject{header:_, content:BerObjectContent::BmpString("\x00U\x00s\x00e\x00r")}) ; "bmp")]
205 #[test_case(&hex!("30 80 04 03 56 78 90 00 00") => matches Ok(BerObject{header:_, content:BerObjectContent::Sequence(_)}) ; "indefinite length")]
206 #[test_case(&hex!("c0 03 01 00 01") => matches Ok(BerObject{header:_, content:BerObjectContent::Unknown(_)}) ; "private")]
207 fn ber_from_any(i: &[u8]) -> Result<BerObject, BerError> {
208 let (rem, res) = parse_ber_any_r(i, MAX_RECURSION)?;
209 assert!(rem.is_empty());
210 Ok(res)
212 }
213}