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