rasn/
ber.rs

1//! # Basic Encoding Rules
2
3pub mod de;
4pub mod enc;
5mod identifier;
6mod rules;
7
8pub use identifier::Identifier;
9pub(crate) use rules::EncodingRules;
10
11/// Attempts to decode `T` from `input` using BER.
12/// # Errors
13/// Returns error specific to BER decoder if decoding is not possible.
14pub fn decode<T: crate::Decode>(input: &[u8]) -> Result<T, crate::error::DecodeError> {
15    T::decode(&mut de::Decoder::new(input, de::DecoderOptions::ber()))
16}
17
18/// Attempts to encode `value` to BER.
19/// # Errors
20/// Returns error specific to BER encoder if encoding is not possible.
21pub fn encode<T: crate::Encode>(
22    value: &T,
23) -> Result<alloc::vec::Vec<u8>, crate::error::EncodeError> {
24    let mut enc = enc::Encoder::new(enc::EncoderOptions::ber());
25
26    value.encode(&mut enc)?;
27
28    Ok(enc.output())
29}
30
31/// Creates a new BER encoder that can be used to encode any value.
32/// # Errors
33/// Returns error specific to BER encoder if encoding is not possible.
34pub fn encode_scope(
35    encode_fn: impl FnOnce(&mut crate::ber::enc::Encoder) -> Result<(), crate::error::EncodeError>,
36) -> Result<alloc::vec::Vec<u8>, crate::error::EncodeError> {
37    let mut enc = crate::ber::enc::Encoder::new(crate::ber::enc::EncoderOptions::ber());
38
39    (encode_fn)(&mut enc)?;
40
41    Ok(enc.output())
42}
43
44#[cfg(test)]
45mod tests {
46    use alloc::borrow::ToOwned;
47    use alloc::vec;
48    use alloc::vec::Vec;
49    use chrono::{DateTime, FixedOffset, NaiveDate, Utc};
50    use de::DecodeErrorKind;
51
52    use crate::types::*;
53
54    use super::*;
55
56    #[derive(Clone, Copy, Hash, Debug, PartialEq)]
57    struct C0;
58    impl AsnType for C0 {
59        const TAG: Tag = Tag::new(Class::Context, 0);
60    }
61
62    #[test]
63    fn oversized_integer() {
64        const DATA: &[u8] = &[0x02, 0x06, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66];
65
66        assert!(matches!(
67            &*decode::<u32>(DATA).unwrap_err().kind,
68            DecodeErrorKind::IntegerOverflow { max_width: 32 }
69        ));
70
71        assert!(matches!(
72            &*decode::<i32>(DATA).unwrap_err().kind,
73            DecodeErrorKind::IntegerOverflow { max_width: 32 }
74        ));
75    }
76
77    #[test]
78    fn leading_integer_bytes() {
79        const DATA: &[u8] = &[0x02, 0x06, 0x00, 0x00, 0x33, 0x44, 0x55, 0x66];
80        assert_eq!(decode::<u32>(DATA).unwrap(), 0x33445566u32);
81
82        const SIGNED_DATA: &[u8] = &[0x02, 0x06, 0xFF, 0xFF, 0x83, 0x44, 0x55, 0x66];
83        assert_eq!(decode::<i32>(SIGNED_DATA).unwrap(), -2092673690);
84    }
85
86    #[test]
87    fn bit_string() {
88        const DATA: &[u8] = &[0, 0xD0];
89        let small = BitString::from_vec(DATA.to_owned());
90        let bits = BitString::from_vec([0x0A, 0x3B, 0x5F, 0x29, 0x1C, 0xD0][..].to_owned());
91        let padding_test = BitString::from_element(0x42);
92        let padding_expected: &[u8] = &[0x03, 0x02, 0x00, 0x42];
93        let trailing_test = bitvec::bitvec![u8, bitvec::prelude::Msb0; 1, 0, 0, 0, 0, 1, 1, 0];
94        let trailing_expected: &[u8] = &[0x03, 0x02, 0x00, 0x86];
95
96        assert_eq!(
97            small,
98            decode::<BitString>(&encode(&small).unwrap()).unwrap()
99        );
100        assert_eq!(bits, decode::<BitString>(&encode(&bits).unwrap()).unwrap());
101        assert_eq!(padding_expected, encode(&padding_test).unwrap());
102        assert_eq!(trailing_expected, encode(&trailing_test).unwrap());
103    }
104
105    #[test]
106    fn implicit_prefix() {
107        type MyInteger = Implicit<C0, u64>;
108
109        let new_int = MyInteger::new(5);
110
111        assert_eq!(new_int, decode(&encode(&new_int).unwrap()).unwrap());
112    }
113
114    #[test]
115    fn explicit_prefix() {
116        type MyInteger = Explicit<C0, u64>;
117
118        let new_int = MyInteger::new(5);
119        let data = &[0xA0, 3, 0x2, 0x1, 5][..];
120
121        assert_eq!(data, &encode(&new_int).unwrap());
122        assert_eq!(new_int, decode(&encode(&new_int).unwrap()).unwrap());
123    }
124
125    #[test]
126    fn implicit_tagged_constructed() {
127        type ImpVec = Implicit<C0, Vec<i32>>;
128
129        let value = ImpVec::new(vec![1, 2]);
130        let data = &[0xA0, 6, 2, 1, 1, 2, 1, 2][..];
131
132        assert_eq!(data, &*crate::ber::encode(&value).unwrap());
133        assert_eq!(value, crate::ber::decode::<ImpVec>(data).unwrap());
134    }
135
136    #[test]
137    fn explicit_empty_tag() {
138        type EmptyTag = Explicit<C0, Option<()>>;
139
140        let value = EmptyTag::new(None);
141        let data = &[0xA0, 0][..];
142
143        assert_eq!(data, &*crate::ber::encode(&value).unwrap());
144        assert_eq!(value, crate::ber::decode::<EmptyTag>(data).unwrap());
145    }
146
147    #[test]
148    #[allow(clippy::items_after_statements)]
149    fn set() {
150        #[derive(Debug, PartialEq)]
151        struct Set {
152            age: u32,
153            name: Utf8String,
154        }
155
156        impl AsnType for Set {
157            const TAG: Tag = Tag::SET;
158        }
159
160        impl crate::types::Constructed for Set {
161            const FIELDS: crate::types::fields::Fields =
162                crate::types::fields::Fields::from_static(&[
163                    crate::types::fields::Field::new_required(u32::TAG, u32::TAG_TREE, "age"),
164                    crate::types::fields::Field::new_required(
165                        Utf8String::TAG,
166                        Utf8String::TAG_TREE,
167                        "name",
168                    ),
169                ]);
170        }
171
172        let example = Set {
173            age: 1,
174            name: "Jane".into(),
175        };
176        let age_then_name = [0x31, 0x9, 0x2, 0x1, 0x1, 0xC, 0x4, 0x4a, 0x61, 0x6e, 0x65];
177        let name_then_age = [0x31, 0x9, 0xC, 0x4, 0x4a, 0x61, 0x6e, 0x65, 0x2, 0x1, 0x1];
178
179        assert_eq!(&age_then_name[..], crate::ber::encode(&example).unwrap());
180
181        assert_eq!(
182            crate::ber::decode::<Set>(&age_then_name).unwrap(),
183            crate::ber::decode::<Set>(&name_then_age).unwrap()
184        );
185
186        impl crate::Decode for Set {
187            fn decode_with_tag_and_constraints<D: crate::Decoder>(
188                decoder: &mut D,
189                tag: Tag,
190                _: Constraints,
191            ) -> Result<Self, D::Error> {
192                use crate::de::Error;
193
194                #[derive(crate::AsnType, crate::Decode)]
195                #[rasn(crate_root = "crate")]
196                #[rasn(choice)]
197                pub enum Fields {
198                    Age(u32),
199                    Name(Utf8String),
200                }
201                let codec = decoder.codec();
202                decoder.decode_set::<Fields, _, _, _>(
203                    tag,
204                    |decoder, indice, tag| match (indice, tag) {
205                        (0, u32::TAG) => <_>::decode(decoder).map(Fields::Age),
206                        (1, Utf8String::TAG) => <_>::decode(decoder).map(Fields::Name),
207                        (_, _) => Err(D::Error::custom("unknown field", codec)),
208                    },
209                    |fields| {
210                        let mut age = None;
211                        let mut name = None;
212
213                        for field in fields {
214                            match field {
215                                Fields::Age(value) => age = value.into(),
216                                Fields::Name(value) => name = value.into(),
217                            }
218                        }
219
220                        Ok(Self {
221                            age: age.ok_or_else(|| D::Error::missing_field("age", codec))?,
222                            name: name.ok_or_else(|| D::Error::missing_field("name", codec))?,
223                        })
224                    },
225                )
226            }
227        }
228
229        impl crate::Encode for Set {
230            fn encode_with_tag_and_constraints<EN: crate::Encoder>(
231                &self,
232                encoder: &mut EN,
233                tag: crate::Tag,
234                _: Constraints,
235            ) -> Result<(), EN::Error> {
236                encoder.encode_set::<Self, _>(tag, |encoder| {
237                    self.age.encode(encoder)?;
238                    self.name.encode(encoder)?;
239                    Ok(())
240                })?;
241
242                Ok(())
243            }
244        }
245    }
246    #[test]
247    fn test_generalized_time() {
248        // "20801009130005.342Z"
249        let offset = chrono::FixedOffset::east_opt(0).unwrap();
250        let dt = NaiveDate::from_ymd_opt(2080, 10, 9)
251            .unwrap()
252            .and_hms_micro_opt(13, 0, 5, 342_000)
253            .unwrap()
254            .and_local_timezone(offset);
255        round_trip!(
256            ber,
257            GeneralizedTime,
258            GeneralizedTime::from(dt.unwrap(),),
259            &[
260                0x18, 0x13, 0x32, 0x30, 0x38, 0x30, 0x31, 0x30, 0x30, 0x39, 0x31, 0x33, 0x30, 0x30,
261                0x30, 0x35, 0x2e, 0x33, 0x34, 0x32, 0x5a
262            ]
263        );
264
265        // https://github.com/XAMPPRocky/rasn/issues/57
266        let data = [
267            24, 19, 43, 53, 49, 54, 49, 53, 32, 32, 48, 53, 50, 52, 48, 57, 52, 48, 50, 48, 90,
268        ];
269        assert!(crate::der::decode::<crate::types::Open>(&data).is_err());
270        assert!(crate::ber::decode::<crate::types::Open>(&data).is_err());
271
272        // "20180122132900Z"
273        round_trip!(
274            ber,
275            GeneralizedTime,
276            GeneralizedTime::from(
277                NaiveDate::from_ymd_opt(2018, 1, 22)
278                    .unwrap()
279                    .and_hms_opt(13, 29, 0)
280                    .unwrap()
281                    .and_utc()
282            ),
283            &[
284                0x18, 0x0f, 0x32, 0x30, 0x31, 0x38, 0x30, 0x31, 0x32, 0x32, 0x31, 0x33, 0x32, 0x39,
285                0x30, 0x30, 0x5a
286            ]
287        );
288        // "20180122130000Z"
289        round_trip!(
290            ber,
291            GeneralizedTime,
292            GeneralizedTime::from(
293                NaiveDate::from_ymd_opt(2018, 1, 22)
294                    .unwrap()
295                    .and_hms_opt(13, 0, 0)
296                    .unwrap()
297                    .and_utc()
298            ),
299            &[
300                0x18, 0x0f, 0x32, 0x30, 0x31, 0x38, 0x30, 0x31, 0x32, 0x32, 0x31, 0x33, 0x30, 0x30,
301                0x30, 0x30, 0x5a
302            ]
303        );
304
305        // "20230122130000-0500" - converts to canonical form "20230122180000Z"
306        let offset = FixedOffset::east_opt(-3600 * 5).unwrap();
307        let dt1: DateTime<FixedOffset> = GeneralizedTime::from(DateTime::<Utc>::from(
308            NaiveDate::from_ymd_opt(2023, 1, 22)
309                .unwrap()
310                .and_hms_opt(13, 0, 0)
311                .unwrap()
312                .and_local_timezone(offset)
313                .unwrap(),
314        ));
315        round_trip!(
316            ber,
317            GeneralizedTime,
318            dt1,
319            &[
320                0x18, 0x0f, 0x32, 0x30, 0x32, 0x33, 0x30, 0x31, 0x32, 0x32, 0x31, 0x38, 0x30, 0x30,
321                0x30, 0x30, 0x5a
322            ]
323        );
324        // "20230122130000-0500" as bytes
325        let data = [
326            24, 19, 50, 48, 50, 51, 48, 49, 50, 50, 49, 51, 48, 48, 48, 48, 45, 48, 53, 48, 48,
327        ];
328        let result = crate::ber::decode::<crate::types::GeneralizedTime>(&data);
329        assert!(result.is_ok());
330        assert_eq!(dt1, result.unwrap());
331    }
332    #[test]
333    fn test_utc_time() {
334        // "180122132900Z"
335        round_trip!(
336            ber,
337            UtcTime,
338            UtcTime::from(
339                NaiveDate::from_ymd_opt(2018, 1, 22)
340                    .unwrap()
341                    .and_hms_opt(13, 29, 0)
342                    .unwrap()
343                    .and_utc()
344            ),
345            &[
346                0x17, 0x0d, 0x31, 0x38, 0x30, 0x31, 0x32, 0x32, 0x31, 0x33, 0x32, 0x39, 0x30, 0x30,
347                0x5a
348            ]
349        );
350        // "230122130000-0500" - converts to canonical form "230122180000Z"
351        let offset = FixedOffset::east_opt(-3600 * 5).unwrap();
352        let dt1 = DateTime::<FixedOffset>::from_naive_utc_and_offset(
353            NaiveDate::from_ymd_opt(2023, 1, 22)
354                .unwrap()
355                .and_hms_opt(18, 0, 0)
356                .unwrap(),
357            offset,
358        );
359        round_trip!(
360            ber,
361            UtcTime,
362            dt1.into(),
363            &[
364                0x17, 0x0d, 0x32, 0x33, 0x30, 0x31, 0x32, 0x32, 0x31, 0x38, 0x30, 0x30, 0x30, 0x30,
365                0x5a
366            ]
367        );
368        // "230122130000-0500" as bytes
369        let data = [
370            23, 17, 50, 51, 48, 49, 50, 50, 49, 51, 48, 48, 48, 48, 45, 48, 53, 48, 48,
371        ];
372        let result = crate::ber::decode::<crate::types::UtcTime>(&data);
373        assert!(result.is_ok());
374        assert_eq!(dt1, result.unwrap());
375    }
376}