rasn/
aper.rs

1//! # Aligned Packed Encoding Rules
2//!
3//! Codec functions for APER, rasn provides a "basic" decoder, and canonical encoder.
4//! This means that users are able decode any valid APER value, and that rasn's
5//! encoding will always produce the same output for the same value.
6use crate::types::Constraints;
7
8pub use super::per::*;
9
10/// Attempts to decode `T` from `input` using APER-BASIC.
11pub fn decode<T: crate::Decode>(input: &[u8]) -> Result<T, crate::error::DecodeError> {
12    crate::per::decode(de::DecoderOptions::aligned(), input)
13}
14
15/// Attempts to encode `value` to APER-CANONICAL.
16pub fn encode<T: crate::Encode>(
17    value: &T,
18) -> Result<alloc::vec::Vec<u8>, crate::error::EncodeError> {
19    crate::per::encode(enc::EncoderOptions::aligned(), value)
20}
21
22/// Attempts to decode `T` from `input` using APER-BASIC.
23pub fn decode_with_constraints<T: crate::Decode>(
24    constraints: Constraints,
25    input: &[u8],
26) -> Result<T, crate::error::DecodeError> {
27    crate::per::decode_with_constraints(de::DecoderOptions::aligned(), constraints, input)
28}
29
30/// Attempts to encode `value` to APER-CANONICAL.
31pub fn encode_with_constraints<T: crate::Encode>(
32    constraints: Constraints,
33    value: &T,
34) -> Result<alloc::vec::Vec<u8>, crate::error::EncodeError> {
35    crate::per::encode_with_constraints(enc::EncoderOptions::aligned(), constraints, value)
36}
37
38#[cfg(test)]
39mod tests {
40    use crate::{
41        prelude::*,
42        types::{constraints::*, *},
43    };
44
45    #[test]
46    fn bitstring() {
47        use bitvec::prelude::*;
48        // B ::= BIT STRING (SIZE (9))
49        // C ::= BIT STRING (SIZE (5..7))
50
51        #[derive(Debug, AsnType, Decode, Encode, PartialEq)]
52        #[rasn(crate_root = "crate")]
53        struct D {
54            a: bool,
55            b: BitString,
56        }
57
58        #[derive(Debug, AsnType, Decode, Encode, PartialEq)]
59        #[rasn(crate_root = "crate")]
60        struct E {
61            a: bool,
62            #[rasn(size(1))]
63            b: BitString,
64            #[rasn(size(16))]
65            c: BitString,
66        }
67
68        #[derive(Debug, AsnType, Decode, Encode, PartialEq)]
69        #[rasn(crate_root = "crate")]
70        struct G {
71            a: BitString,
72            b: bool,
73        }
74
75        // H ::= SEQUENCE SIZE (0..2) OF BIT STRING (SIZE(1..255))
76        // I ::= SEQUENCE SIZE (0..2) OF BIT STRING (SIZE(1..256))
77        // J ::= SEQUENCE SIZE (0..2) OF BIT STRING (SIZE(2..256))
78        // K ::= SEQUENCE SIZE (0..2) OF BIT STRING (SIZE(2..257))
79        // L ::= BIT STRING (SIZE (1..160, ...))
80
81        #[derive(Debug, AsnType, Decode, Encode, PartialEq)]
82        #[rasn(crate_root = "crate")]
83        struct M {
84            a: bool,
85            #[rasn(size("1..=160", extensible))]
86            b: BitString,
87        }
88
89        // N ::= BIT STRING (SIZE(0..65535))
90        // O ::= BIT STRING (SIZE(0..65536))
91
92        round_trip!(
93            aper,
94            BitString,
95            bitvec::bitvec![u8, Msb0; 0, 1, 0, 0],
96            &[0x04, 0x40]
97        );
98        // round_trip!(aper, BitString, BitString::from_vec({
99        //     let mut bytes = vec![0x55; 300];
100        //     bytes[299] = 0x54;
101        //     bytes
102        // }), &*{
103        //     let mut bytes = vec![0x89, 0x5f];
104        //     bytes.extend([0x55; 299]);
105        //     bytes.push(0x54);
106        //     bytes
107        // });
108        round_trip!(
109            aper,
110            BitString,
111            BitString::from_vec([0x55; 2048].into()),
112            &*{
113                let mut bytes = vec![0xc1];
114                bytes.extend([0x55; 2048]);
115                bytes.push(0x00);
116                bytes
117            }
118        );
119        // round_trip!(aper, B, (b'\x12\x80', 9), b'\x12\x80');
120        // round_trip!(aper, C, (b'\x34', 6), b'\x40\x34');
121        // round_trip!(aper, D, {'a': True, 'b': (b'\x40', 4)}, b'\x80\x04\x40');
122        // round_trip!(aper, E, {'a': True, 'b': (b'\x80', 1), 'c': (b'\x7f\x01', 16)}, b'\xdf\xc0\x40');
123        // round_trip!(aper, F, (b'\x80', 1), b'\x01\x80');
124        // round_trip!(aper, F, (b'\xe0', 3), b'\x03\xe0');
125        // round_trip!(aper, F, (b'\x01', 8), b'\x08\x01');
126        // round_trip!(aper, G, {'a': (b'\x80', 2), 'b': True}, b'\x02\xa0');
127        // round_trip!(aper, G, {'a': (b'', 0), 'b': True}, b'\x00\x80');
128        // round_trip!(aper, H, [(b'\x40', 2)], b'\x40\x40\x40');
129        // round_trip!(aper, I, [(b'\x40', 2)], b'\x40\x01\x40');
130        // round_trip!(aper, J, [(b'\x40', 2)], b'\x40\x00\x40');
131        // round_trip!(aper, K, [(b'\x40', 2)], b'\x40\x00\x40');
132        // round_trip!(aper, L, (b'\x80', 1), b'\x00\x00\x80');
133        // round_trip!(aper, M, {'a': True, 'b': (b'\xe0', 3)}, b'\x80\x80\xe0');
134        // round_trip!(aper, N, (b'', 0), b'\x00\x00');
135        // round_trip!(aper, O, (b'', 0), b'\x00');
136    }
137
138    #[test]
139    fn integer() {
140        type B = ConstrainedInteger<5, 99>;
141
142        #[derive(Debug, AsnType, Decode, Encode, PartialEq)]
143        #[rasn(crate_root = "crate")]
144        struct C {
145            a: bool,
146            b: Integer,
147            c: bool,
148            #[rasn(value("-10..=400"))]
149            d: Integer,
150        }
151
152        type D = ConstrainedInteger<0, 254>;
153        type E = ConstrainedInteger<0, 255>;
154        type F = ConstrainedInteger<0, 256>;
155        type G = ConstrainedInteger<0, 65535>;
156        type H = ConstrainedInteger<0, 65536>;
157        type I = ConstrainedInteger<0, 10000000000>;
158
159        #[derive(Debug, AsnType, Decode, Encode, PartialEq)]
160        #[rasn(crate_root = "crate")]
161        struct J {
162            a: bool,
163            #[rasn(value("0..=254"))]
164            b: Integer,
165            #[rasn(value("0..=255"))]
166            c: Integer,
167            d: bool,
168            #[rasn(value("0..=256"))]
169            e: Integer,
170        }
171
172        #[derive(Debug, AsnType, Decode, Encode, PartialEq)]
173        #[rasn(crate_root = "crate")]
174        struct L {
175            #[rasn(value("7..=7"))]
176            a: Integer,
177        }
178
179        type N = ConstrainedInteger<0, 65535>;
180        type O = ConstrainedInteger<0, 65536>;
181        type P = ConstrainedInteger<0, 2147483647>;
182        type Q = ConstrainedInteger<0, 4294967295>;
183        type R = ConstrainedInteger<0, 4294967296>;
184
185        #[derive(Debug, AsnType, Decode, Encode, PartialEq)]
186        #[rasn(crate_root = "crate")]
187        struct S {
188            a: bool,
189            #[rasn(value("-10000..=704000000000000001"))]
190            b: Integer,
191            c: bool,
192        }
193
194        round_trip!(aper, Integer, 32768.into(), &[0x03, 0x00, 0x80, 0x00]);
195        round_trip!(aper, Integer, 32767.into(), &[0x02, 0x7f, 0xff]);
196        round_trip!(aper, Integer, 256.into(), &[0x02, 0x01, 0x00]);
197        round_trip!(aper, Integer, 255.into(), &[0x02, 0x00, 0xff]);
198        round_trip!(aper, Integer, 128.into(), &[0x02, 0x00, 0x80]);
199        round_trip!(aper, Integer, 127.into(), &[0x01, 0x7f]);
200        round_trip!(aper, Integer, 1.into(), &[0x01, 0x01]);
201        round_trip!(aper, Integer, 0.into(), &[0x01, 0x00]);
202        round_trip!(aper, Integer, (-1).into(), &[0x01, 0xff]);
203        round_trip!(aper, Integer, (-128).into(), &[0x01, 0x80]);
204        round_trip!(aper, Integer, (-129).into(), &[0x02, 0xff, 0x7f]);
205        round_trip!(aper, Integer, (-256).into(), &[0x02, 0xff, 0x00]);
206        round_trip!(aper, Integer, (-32768).into(), &[0x02, 0x80, 0x00]);
207        round_trip!(aper, Integer, (-32769).into(), &[0x03, 0xff, 0x7f, 0xff]);
208        round_trip!(aper, B, 5.into(), &[0x00]);
209        round_trip!(aper, B, 6.into(), &[0x02]);
210        round_trip!(aper, B, 99.into(), &[0xbc]);
211        round_trip!(
212            aper,
213            C,
214            C {
215                a: true,
216                b: Integer::from(43554344223i64),
217                c: false,
218                d: Integer::from(-9)
219            },
220            &[0x80, 0x05, 0x0a, 0x24, 0x0a, 0x8d, 0x1f, 0x00, 0x00, 0x01]
221        );
222        round_trip!(aper, D, 253.into(), &[0xfd]);
223        round_trip!(aper, E, 253.into(), &[0xfd]);
224        round_trip!(aper, F, 253.into(), &[0x00, 0xfd]);
225        round_trip!(aper, G, 253.into(), &[0x00, 0xfd]);
226        round_trip!(aper, H, 253.into(), &[0x00, 0xfd]);
227        round_trip!(aper, H, 256.into(), &[0x40, 0x01, 0x00]);
228        round_trip!(aper, H, 65536.into(), &[0x80, 0x01, 0x00, 0x00]);
229        round_trip!(aper, I, 0.into(), &[0x00, 0x00]);
230        round_trip!(aper, I, 1.into(), &[0x00, 0x01]);
231        round_trip!(
232            aper,
233            I,
234            10000000000i64.into(),
235            &[0x80, 0x02, 0x54, 0x0b, 0xe4, 0x00]
236        );
237        round_trip!(
238            aper,
239            J,
240            J {
241                a: false,
242                b: 253.into(),
243                c: 253.into(),
244                d: false,
245                e: 253.into()
246            },
247            &[0x7e, 0x80, 0xfd, 0x00, 0x00, 0xfd]
248        );
249        round_trip!(aper, L, L { a: 7.into() }, &[]);
250        // round_trip!(aper, M, 103.into(), &[0x80, 0x01, 0x67]);
251        round_trip!(aper, N, 1.into(), &[0x00, 0x01]);
252        round_trip!(aper, N, 255.into(), &[0x00, 0xff]);
253        round_trip!(aper, N, 256.into(), &[0x01, 0x00]);
254        round_trip!(aper, N, 65535.into(), &[0xff, 0xff]);
255        round_trip!(aper, O, 1.into(), &[0x00, 0x01]);
256        round_trip!(aper, O, 255.into(), &[0x00, 0xff]);
257        round_trip!(aper, O, 256.into(), &[0x40, 0x01, 0x00]);
258        round_trip!(aper, O, 65535.into(), &[0x40, 0xff, 0xff]);
259        round_trip!(aper, O, 65536.into(), &[0x80, 0x01, 0x00, 0x00]);
260        round_trip!(aper, P, 1.into(), &[0x00, 0x01]);
261        round_trip!(aper, P, 255.into(), &[0x00, 0xff]);
262        round_trip!(aper, P, 256.into(), &[0x40, 0x01, 0x00]);
263        round_trip!(aper, P, 65535.into(), &[0x40, 0xff, 0xff]);
264        round_trip!(aper, P, 65536.into(), &[0x80, 0x01, 0x00, 0x00]);
265        round_trip!(aper, P, 16777215.into(), &[0x80, 0xff, 0xff, 0xff]);
266        round_trip!(aper, P, 16777216.into(), &[0xc0, 0x01, 0x00, 0x00, 0x00]);
267        round_trip!(aper, P, 100000000.into(), &[0xc0, 0x05, 0xf5, 0xe1, 0x00]);
268        round_trip!(
269            aper,
270            Q,
271            4294967295u64.into(),
272            &[0xc0, 0xff, 0xff, 0xff, 0xff]
273        );
274        round_trip!(
275            aper,
276            R,
277            4294967296u64.into(),
278            &[0x80, 0x01, 0x00, 0x00, 0x00, 0x00]
279        );
280        round_trip!(
281            aper,
282            S,
283            S {
284                a: true,
285                b: 0.into(),
286                c: true
287            },
288            &[0x90, 0x27, 0x10, 0x80]
289        );
290    }
291
292    #[test]
293    fn visible_string() {
294        // B ::= VisibleString (SIZE (5))
295        // C ::= VisibleString (SIZE (19..1000))
296        // D ::= SEQUENCE {
297        //   a BOOLEAN,
298        //   b VisibleString (SIZE (1))
299        // }
300        // H ::= SEQUENCE {
301        //   a BOOLEAN,
302        //   b VisibleString (SIZE (0..2))
303        // }
304        // I ::= VisibleString (FROM (\a\..\z\)) (SIZE (1..255))
305
306        #[derive(Debug, AsnType, Decode, Encode, PartialEq)]
307        #[rasn(crate_root = "crate")]
308        struct D {
309            a: bool,
310            #[rasn(size(1))]
311            b: VisibleString,
312        }
313
314        #[derive(Debug, AsnType, Decode, Encode, PartialEq)]
315        #[rasn(crate_root = "crate")]
316        struct E {
317            a: bool,
318            #[rasn(size(2))]
319            b: VisibleString,
320        }
321
322        #[derive(Debug, AsnType, Decode, Encode, PartialEq)]
323        #[rasn(crate_root = "crate")]
324        struct F {
325            a: bool,
326            #[rasn(size(3))]
327            b: VisibleString,
328        }
329
330        #[derive(Debug, AsnType, Decode, Encode, PartialEq)]
331        #[rasn(crate_root = "crate")]
332        struct G {
333            a: bool,
334            #[rasn(size("0..=1"))]
335            b: VisibleString,
336        }
337
338        #[derive(Debug, AsnType, Decode, Encode, PartialEq)]
339        #[rasn(crate_root = "crate")]
340        struct H {
341            a: bool,
342            #[rasn(size("0..=2"))]
343            b: VisibleString,
344        }
345        // J ::= VisibleString (FROM (\a\))
346        // K ::= VisibleString (FROM (\a\..\a\))
347
348        // round_trip_with_constraints!(
349        //     aper,
350        //     VisibleString,
351        //     Constraints::new(&[Constraint::Size(Size::new(Bounded::new(19, 133)).into())]),
352        //     VisibleString::try_from("HejHoppHappHippAbcde").unwrap(),
353        //     &[
354        //         0x02, 0x48, 0x65, 0x6a, 0x48, 0x6f, 0x70, 0x70, 0x48, 0x61, 0x70, 0x70, 0x48, 0x69,
355        //         0x70, 0x70, 0x41, 0x62, 0x63, 0x64, 0x65
356        //     ]
357        // );
358        // round_trip_with_constraints!(
359        //     aper,
360        //     VisibleString,
361        //     Constraints::new(&[Constraint::Size(Size::new(Bounded::Single(5)).into())]),
362        //     VisibleString::try_from("Hejaa").unwrap(),
363        //     &[0x48, 0x65, 0x6a, 0x61, 0x61]
364        // );
365        // round_trip_with_constraints!(
366        //     aper,
367        //     VisibleString,
368        //     Constraints::new(&[Constraint::Size(Size::new(Bounded::new(19, 1000)).into())]),
369        //     VisibleString::try_from(str::repeat("HejHoppHappHippAbcde", 17)).unwrap(),
370        //     &*{
371        //         let mut bytes = vec![0x01, 0x41];
372        //         for _ in 0..17 {
373        //             bytes.extend([
374        //                 0x48, 0x65, 0x6a, 0x48, 0x6f, 0x70, 0x70, 0x48, 0x61,
375        //                 0x70, 0x70, 0x48, 0x69, 0x70, 0x70, 0x41, 0x62, 0x63,
376        //                 0x64, 0x65
377        //             ]);
378        //         }
379        //         bytes
380        //     }
381        // );
382        // round_trip!(aper, D, D { a: true, b: "1".try_into().unwrap() }, &[0x98, 0x80]);
383        // round_trip!(aper, E, E { a: true, b: "12".try_into().unwrap() }, &[0x98, 0x99, 0x00]);
384        // round_trip!(aper, F, F { a: true, b: "123".try_into().unwrap() }, &[0x80, 0x31, 0x32, 0x33]);
385        // round_trip!(aper, G, G { a: true, b: "1".try_into().unwrap() }, &[0xcc, 0x40]);
386        // round_trip!(aper, H, H { a: true, b: "1".try_into().unwrap() }, &[0xa0, 0x31]);
387        round_trip_with_constraints!(
388            aper,
389            VisibleString,
390            Constraints::new(&[
391                Constraint::PermittedAlphabet(
392                    PermittedAlphabet::new(&[
393                        b'a' as u32,
394                        b'b' as u32,
395                        b'c' as u32,
396                        b'd' as u32,
397                        b'e' as u32,
398                        b'f' as u32,
399                        b'g' as u32,
400                        b'h' as u32,
401                        b'i' as u32,
402                        b'j' as u32,
403                        b'k' as u32,
404                        b'l' as u32,
405                        b'm' as u32,
406                        b'n' as u32,
407                        b'o' as u32,
408                        b'p' as u32,
409                        b'q' as u32,
410                        b'r' as u32,
411                        b's' as u32,
412                        b't' as u32,
413                        b'u' as u32,
414                        b'v' as u32,
415                        b'w' as u32,
416                        b'x' as u32,
417                        b'y' as u32,
418                        b'z' as u32,
419                    ])
420                    .into()
421                ),
422                Constraint::Size(Size::new(Bounded::new(1, 255)).into())
423            ]),
424            VisibleString::try_from("hej").unwrap(),
425            &[0x02, 0x68, 0x65, 0x6a]
426        );
427        round_trip_with_constraints!(
428            aper,
429            VisibleString,
430            Constraints::new(&[Constraint::PermittedAlphabet(
431                PermittedAlphabet::new(&[b'a' as u32,]).into()
432            ),]),
433            VisibleString::try_from("a").unwrap(),
434            &[0x01]
435        );
436    }
437
438    #[test]
439    fn issue_192() {
440        // https://github.com/XAMPPRocky/rasn/issues/192
441        use crate as rasn;
442
443        use rasn::AsnType;
444
445        #[derive(rasn::AsnType, rasn::Encode, rasn::Decode, Debug, Clone, PartialEq, Eq)]
446        #[rasn(automatic_tags, option_type(Option))]
447        #[non_exhaustive]
448        pub struct Updates {
449            pub updates: Vec<u8>,
450        }
451
452        #[derive(rasn::AsnType, rasn::Encode, rasn::Decode, Debug, Clone, PartialEq, Eq)]
453        #[rasn(automatic_tags, option_type(Option))]
454        #[rasn(choice)]
455        #[non_exhaustive]
456        pub enum Message {
457            Updates(Updates),
458        }
459
460        let msg = Message::Updates(Updates { updates: vec![1] });
461
462        round_trip!(aper, Message, msg, &[0, 1, 1]);
463    }
464
465    #[test]
466    fn issue_201() {
467        use crate as rasn;
468        use crate::prelude::*;
469
470        const T124_IDENTIFIER_KEY: &Oid = Oid::const_new(&[0, 0, 20, 124, 0, 1]);
471        #[derive(Debug, AsnType, Encode, rasn::Decode)]
472        #[rasn(choice, automatic_tags)]
473        enum Key {
474            #[rasn(tag(explicit(5)))]
475            Object(ObjectIdentifier),
476            H221NonStandard(OctetString),
477        }
478
479        #[derive(Debug, AsnType, rasn::Encode, rasn::Decode)]
480        #[rasn(automatic_tags)]
481        struct ConnectData {
482            t124_identifier_key: Key,
483            connect_pdu: OctetString,
484        }
485
486        let connect_pdu: OctetString = vec![0u8, 1u8, 2u8, 3u8].into();
487        let connect_data = ConnectData {
488            t124_identifier_key: Key::Object(T124_IDENTIFIER_KEY.into()),
489            connect_pdu,
490        };
491
492        let encoded = rasn::aper::encode(&connect_data).expect("failed to encode");
493        let _: ConnectData = rasn::aper::decode(&encoded).expect("failed to decode");
494    }
495}