asn1_rs/asn1_types/
any.rs

1use crate::ber::*;
2use crate::*;
3use alloc::borrow::Cow;
4#[cfg(not(feature = "std"))]
5use alloc::string::String;
6use core::convert::{TryFrom, TryInto};
7
8use self::debug::trace;
9
10/// The `Any` object is not strictly an ASN.1 type, but holds a generic description of any object
11/// that could be encoded.
12///
13/// It contains a header, and either a reference to or owned data for the object content.
14///
15/// Note: this type is only provided in **borrowed** version (*i.e.* it cannot own the inner data).
16#[derive(Clone, Debug, PartialEq, Eq)]
17pub struct Any<'a> {
18    /// The object header
19    pub header: Header<'a>,
20    /// The object contents
21    pub data: &'a [u8],
22}
23
24impl<'a> Any<'a> {
25    /// Create a new `Any` from BER/DER header and content
26    #[inline]
27    pub const fn new(header: Header<'a>, data: &'a [u8]) -> Self {
28        Any { header, data }
29    }
30
31    /// Create a new `Any` from a tag, and BER/DER content
32    #[inline]
33    pub const fn from_tag_and_data(tag: Tag, data: &'a [u8]) -> Self {
34        let constructed = matches!(tag, Tag::Sequence | Tag::Set);
35        Any {
36            header: Header {
37                tag,
38                constructed,
39                class: Class::Universal,
40                length: Length::Definite(data.len()),
41                raw_tag: None,
42            },
43            data,
44        }
45    }
46
47    /// Return the `Class` of this object
48    #[inline]
49    pub const fn class(&self) -> Class {
50        self.header.class
51    }
52
53    /// Update the class of the current object
54    #[inline]
55    pub fn with_class(self, class: Class) -> Self {
56        Any {
57            header: self.header.with_class(class),
58            ..self
59        }
60    }
61
62    /// Return the `Tag` of this object
63    #[inline]
64    pub const fn tag(&self) -> Tag {
65        self.header.tag
66    }
67
68    /// Update the tag of the current object
69    #[inline]
70    pub fn with_tag(self, tag: Tag) -> Self {
71        Any {
72            header: self.header.with_tag(tag),
73            data: self.data,
74        }
75    }
76
77    /// Get the bytes representation of the *content*
78    #[inline]
79    pub fn as_bytes(&self) -> &'a [u8] {
80        self.data
81    }
82
83    #[inline]
84    pub fn parse_ber<T>(&self) -> ParseResult<'a, T>
85    where
86        T: FromBer<'a>,
87    {
88        T::from_ber(self.data)
89    }
90
91    /// Parse a BER value and apply the provided parsing function to content
92    ///
93    /// After parsing, the sequence object and header are discarded.
94    pub fn from_ber_and_then<F, T, E>(
95        class: Class,
96        tag: u32,
97        bytes: &'a [u8],
98        op: F,
99    ) -> ParseResult<'a, T, E>
100    where
101        F: FnOnce(&'a [u8]) -> ParseResult<T, E>,
102        E: From<Error>,
103    {
104        let (rem, any) = Any::from_ber(bytes).map_err(Err::convert)?;
105        any.tag()
106            .assert_eq(Tag(tag))
107            .map_err(|e| Err::Error(e.into()))?;
108        any.class()
109            .assert_eq(class)
110            .map_err(|e| Err::Error(e.into()))?;
111        let (_, res) = op(any.data)?;
112        Ok((rem, res))
113    }
114
115    /// Parse a DER value and apply the provided parsing function to content
116    ///
117    /// After parsing, the sequence object and header are discarded.
118    pub fn from_der_and_then<F, T, E>(
119        class: Class,
120        tag: u32,
121        bytes: &'a [u8],
122        op: F,
123    ) -> ParseResult<'a, T, E>
124    where
125        F: FnOnce(&'a [u8]) -> ParseResult<T, E>,
126        E: From<Error>,
127    {
128        let (rem, any) = Any::from_der(bytes).map_err(Err::convert)?;
129        any.tag()
130            .assert_eq(Tag(tag))
131            .map_err(|e| Err::Error(e.into()))?;
132        any.class()
133            .assert_eq(class)
134            .map_err(|e| Err::Error(e.into()))?;
135        let (_, res) = op(any.data)?;
136        Ok((rem, res))
137    }
138
139    #[inline]
140    pub fn parse_der<T>(&self) -> ParseResult<'a, T>
141    where
142        T: FromDer<'a>,
143    {
144        T::from_der(self.data)
145    }
146
147    /// Get the content following a BER header
148    #[inline]
149    pub fn parse_ber_content<'i>(i: &'i [u8], header: &'_ Header) -> ParseResult<'i, &'i [u8]> {
150        header.parse_ber_content(i)
151    }
152
153    /// Get the content following a DER header
154    #[inline]
155    pub fn parse_der_content<'i>(i: &'i [u8], header: &'_ Header) -> ParseResult<'i, &'i [u8]> {
156        header.assert_definite()?;
157        DerParser::get_object_content(i, header, 8)
158    }
159}
160
161macro_rules! impl_any_into {
162    (IMPL $sname:expr, $fn_name:ident => $ty:ty, $asn1:expr) => {
163        #[doc = "Attempt to convert object to `"]
164        #[doc = $sname]
165        #[doc = "` (ASN.1 type: `"]
166        #[doc = $asn1]
167        #[doc = "`)."]
168        pub fn $fn_name(self) -> Result<$ty> {
169            self.try_into()
170        }
171    };
172    ($fn_name:ident => $ty:ty, $asn1:expr) => {
173        impl_any_into! {
174            IMPL stringify!($ty), $fn_name => $ty, $asn1
175        }
176    };
177}
178
179macro_rules! impl_any_as {
180    (IMPL $sname:expr, $fn_name:ident => $ty:ty, $asn1:expr) => {
181        #[doc = "Attempt to create ASN.1 type `"]
182        #[doc = $asn1]
183        #[doc = "` from this object."]
184        #[inline]
185        pub fn $fn_name(&self) -> Result<$ty> {
186            TryFrom::try_from(self)
187        }
188    };
189    ($fn_name:ident => $ty:ty, $asn1:expr) => {
190        impl_any_as! {
191            IMPL stringify!($ty), $fn_name => $ty, $asn1
192        }
193    };
194}
195
196impl<'a> Any<'a> {
197    impl_any_into!(bitstring => BitString<'a>, "BIT STRING");
198    impl_any_into!(bmpstring => BmpString<'a>, "BMPString");
199    impl_any_into!(bool => bool, "BOOLEAN");
200    impl_any_into!(boolean => Boolean, "BOOLEAN");
201    impl_any_into!(embedded_pdv => EmbeddedPdv<'a>, "EMBEDDED PDV");
202    impl_any_into!(enumerated => Enumerated, "ENUMERATED");
203    impl_any_into!(generalizedtime => GeneralizedTime, "GeneralizedTime");
204    impl_any_into!(generalstring => GeneralString<'a>, "GeneralString");
205    impl_any_into!(graphicstring => GraphicString<'a>, "GraphicString");
206    impl_any_into!(i8 => i8, "INTEGER");
207    impl_any_into!(i16 => i16, "INTEGER");
208    impl_any_into!(i32 => i32, "INTEGER");
209    impl_any_into!(i64 => i64, "INTEGER");
210    impl_any_into!(i128 => i128, "INTEGER");
211    impl_any_into!(ia5string => Ia5String<'a>, "IA5String");
212    impl_any_into!(integer => Integer<'a>, "INTEGER");
213    impl_any_into!(null => Null, "NULL");
214    impl_any_into!(numericstring => NumericString<'a>, "NumericString");
215    impl_any_into!(objectdescriptor => ObjectDescriptor<'a>, "ObjectDescriptor");
216    impl_any_into!(octetstring => OctetString<'a>, "OCTET STRING");
217    impl_any_into!(oid => Oid<'a>, "OBJECT IDENTIFIER");
218    impl_any_into!(real => Real, "REAL");
219    /// Attempt to convert object to `Oid` (ASN.1 type: `RELATIVE-OID`).
220    pub fn relative_oid(self) -> Result<Oid<'a>> {
221        self.header.assert_tag(Tag::RelativeOid)?;
222        let asn1 = Cow::Borrowed(self.data);
223        Ok(Oid::new_relative(asn1))
224    }
225    impl_any_into!(printablestring => PrintableString<'a>, "PrintableString");
226    // XXX REAL
227    impl_any_into!(sequence => Sequence<'a>, "SEQUENCE");
228    impl_any_into!(set => Set<'a>, "SET");
229    impl_any_into!(str => &'a str, "UTF8String");
230    impl_any_into!(string => String, "UTF8String");
231    impl_any_into!(teletexstring => TeletexString<'a>, "TeletexString");
232    impl_any_into!(u8 => u8, "INTEGER");
233    impl_any_into!(u16 => u16, "INTEGER");
234    impl_any_into!(u32 => u32, "INTEGER");
235    impl_any_into!(u64 => u64, "INTEGER");
236    impl_any_into!(u128 => u128, "INTEGER");
237    impl_any_into!(universalstring => UniversalString<'a>, "UniversalString");
238    impl_any_into!(utctime => UtcTime, "UTCTime");
239    impl_any_into!(utf8string => Utf8String<'a>, "UTF8String");
240    impl_any_into!(videotexstring => VideotexString<'a>, "VideotexString");
241    impl_any_into!(visiblestring => VisibleString<'a>, "VisibleString");
242
243    impl_any_as!(as_bitstring => BitString, "BITSTRING");
244    impl_any_as!(as_bmpstring => BmpString, "BMPString");
245    impl_any_as!(as_bool => bool, "BOOLEAN");
246    impl_any_as!(as_boolean => Boolean, "BOOLEAN");
247    impl_any_as!(as_embedded_pdv => EmbeddedPdv, "EMBEDDED PDV");
248    impl_any_as!(as_endofcontent => EndOfContent, "END OF CONTENT (not a real ASN.1 type)");
249    impl_any_as!(as_enumerated => Enumerated, "ENUMERATED");
250    impl_any_as!(as_generalizedtime => GeneralizedTime, "GeneralizedTime");
251    impl_any_as!(as_generalstring => GeneralString, "GeneralString");
252    impl_any_as!(as_graphicstring => GraphicString, "GraphicString");
253    impl_any_as!(as_i8 => i8, "INTEGER");
254    impl_any_as!(as_i16 => i16, "INTEGER");
255    impl_any_as!(as_i32 => i32, "INTEGER");
256    impl_any_as!(as_i64 => i64, "INTEGER");
257    impl_any_as!(as_i128 => i128, "INTEGER");
258    impl_any_as!(as_ia5string => Ia5String, "IA5String");
259    impl_any_as!(as_integer => Integer, "INTEGER");
260    impl_any_as!(as_null => Null, "NULL");
261    impl_any_as!(as_numericstring => NumericString, "NumericString");
262    impl_any_as!(as_objectdescriptor => ObjectDescriptor, "OBJECT IDENTIFIER");
263    impl_any_as!(as_octetstring => OctetString, "OCTET STRING");
264    impl_any_as!(as_oid => Oid, "OBJECT IDENTIFIER");
265    impl_any_as!(as_real => Real, "REAL");
266    /// Attempt to create ASN.1 type `RELATIVE-OID` from this object.
267    pub fn as_relative_oid(&self) -> Result<Oid<'a>> {
268        self.header.assert_tag(Tag::RelativeOid)?;
269        let asn1 = Cow::Borrowed(self.data);
270        Ok(Oid::new_relative(asn1))
271    }
272    impl_any_as!(as_printablestring => PrintableString, "PrintableString");
273    impl_any_as!(as_sequence => Sequence, "SEQUENCE");
274    impl_any_as!(as_set => Set, "SET");
275    impl_any_as!(as_str => &str, "UTF8String");
276    impl_any_as!(as_string => String, "UTF8String");
277    impl_any_as!(as_teletexstring => TeletexString, "TeletexString");
278    impl_any_as!(as_u8 => u8, "INTEGER");
279    impl_any_as!(as_u16 => u16, "INTEGER");
280    impl_any_as!(as_u32 => u32, "INTEGER");
281    impl_any_as!(as_u64 => u64, "INTEGER");
282    impl_any_as!(as_u128 => u128, "INTEGER");
283    impl_any_as!(as_universalstring => UniversalString, "UniversalString");
284    impl_any_as!(as_utctime => UtcTime, "UTCTime");
285    impl_any_as!(as_utf8string => Utf8String, "UTF8String");
286    impl_any_as!(as_videotexstring => VideotexString, "VideotexString");
287    impl_any_as!(as_visiblestring => VisibleString, "VisibleString");
288
289    /// Attempt to create an `Option<T>` from this object.
290    pub fn as_optional<'b, T>(&'b self) -> Result<Option<T>>
291    where
292        T: TryFrom<&'b Any<'a>, Error = Error>,
293        'a: 'b,
294    {
295        match TryFrom::try_from(self) {
296            Ok(t) => Ok(Some(t)),
297            Err(Error::UnexpectedTag { .. }) => Ok(None),
298            Err(e) => Err(e),
299        }
300    }
301
302    /// Attempt to create a tagged value (EXPLICIT) from this object.
303    pub fn as_tagged_explicit<T, E, const CLASS: u8, const TAG: u32>(
304        &self,
305    ) -> Result<TaggedValue<T, E, Explicit, CLASS, TAG>, E>
306    where
307        T: FromBer<'a, E>,
308        E: From<Error>,
309    {
310        TryFrom::try_from(self)
311    }
312
313    /// Attempt to create a tagged value (IMPLICIT) from this object.
314    pub fn as_tagged_implicit<T, E, const CLASS: u8, const TAG: u32>(
315        &self,
316    ) -> Result<TaggedValue<T, E, Implicit, CLASS, TAG>, E>
317    where
318        T: TryFrom<Any<'a>, Error = E>,
319        T: Tagged,
320        E: From<Error>,
321    {
322        TryFrom::try_from(self)
323    }
324}
325
326pub(crate) fn parse_ber_any(input: &[u8]) -> ParseResult<Any> {
327    let (i, header) = Header::from_ber(input)?;
328    let (i, data) = BerParser::get_object_content(i, &header, MAX_RECURSION)?;
329    Ok((i, Any { header, data }))
330}
331
332pub(crate) fn parse_der_any(input: &[u8]) -> ParseResult<Any> {
333    let (i, header) = Header::from_der(input)?;
334    // X.690 section 10.1: The definite form of length encoding shall be used
335    header.length.assert_definite()?;
336    let (i, data) = DerParser::get_object_content(i, &header, MAX_RECURSION)?;
337    Ok((i, Any { header, data }))
338}
339
340impl<'a> FromBer<'a> for Any<'a> {
341    #[inline]
342    fn from_ber(bytes: &'a [u8]) -> ParseResult<Self> {
343        trace("Any", parse_ber_any, bytes)
344    }
345}
346
347impl<'a> FromDer<'a> for Any<'a> {
348    #[inline]
349    fn from_der(bytes: &'a [u8]) -> ParseResult<Self> {
350        trace("Any", parse_der_any, bytes)
351    }
352}
353
354impl CheckDerConstraints for Any<'_> {
355    fn check_constraints(any: &Any) -> Result<()> {
356        any.header.length().assert_definite()?;
357        // if len < 128, must use short form (10.1: minimum number of octets)
358        Ok(())
359    }
360}
361
362impl DerAutoDerive for Any<'_> {}
363
364impl DynTagged for Any<'_> {
365    fn tag(&self) -> Tag {
366        self.tag()
367    }
368}
369
370// impl<'a> ToStatic for Any<'a> {
371//     type Owned = Any<'static>;
372
373//     fn to_static(&self) -> Self::Owned {
374//         Any {
375//             header: self.header.to_static(),
376//             data: Cow::Owned(self.data.to_vec()),
377//         }
378//     }
379// }
380
381#[cfg(feature = "std")]
382impl ToDer for Any<'_> {
383    fn to_der_len(&self) -> Result<usize> {
384        let hdr_len = self.header.to_der_len()?;
385        Ok(hdr_len + self.data.len())
386    }
387
388    fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
389        // create fake header to have correct length
390        let header = Header::new(
391            self.header.class,
392            self.header.constructed,
393            self.header.tag,
394            Length::Definite(self.data.len()),
395        );
396        let sz = header.write_der_header(writer)?;
397        Ok(sz)
398    }
399
400    fn write_der_content(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
401        writer.write(self.data).map_err(Into::into)
402    }
403
404    /// Similar to using `to_der`, but uses header without computing length value
405    fn write_der_raw(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
406        let sz = self.header.write_der_header(writer)?;
407        let sz = sz + writer.write(self.data)?;
408        Ok(sz)
409    }
410}
411
412#[cfg(test)]
413mod tests {
414    use crate::*;
415    use hex_literal::hex;
416
417    #[test]
418    fn methods_any() {
419        let header = Header::new_simple(Tag::Integer);
420        let any = Any::new(header, &[])
421            .with_class(Class::ContextSpecific)
422            .with_tag(Tag(0));
423        assert_eq!(any.as_bytes(), &[]);
424
425        let input = &hex! {"80 03 02 01 01"};
426        let (_, any) = Any::from_ber(input).expect("parsing failed");
427
428        let (_, r) = any.parse_ber::<Integer>().expect("parse_ber failed");
429        assert_eq!(r.as_u32(), Ok(1));
430        let (_, r) = any.parse_der::<Integer>().expect("parse_der failed");
431        assert_eq!(r.as_u32(), Ok(1));
432
433        let header = &any.header;
434        let (_, content) = Any::parse_ber_content(&input[2..], header).unwrap();
435        assert_eq!(content.len(), 3);
436        let (_, content) = Any::parse_der_content(&input[2..], header).unwrap();
437        assert_eq!(content.len(), 3);
438
439        let (_, any) = Any::from_der(&input[2..]).unwrap();
440        Any::check_constraints(&any).unwrap();
441        assert_eq!(<Any as DynTagged>::tag(&any), any.tag());
442        let int = any.integer().unwrap();
443        assert_eq!(int.as_u16(), Ok(1));
444    }
445}