asn1_rs/asn1_types/
integer.rs

1use crate::*;
2use alloc::borrow::Cow;
3use alloc::vec;
4use core::convert::{TryFrom, TryInto};
5
6#[cfg(feature = "bigint")]
7#[cfg_attr(docsrs, doc(cfg(feature = "bigint")))]
8pub use num_bigint::{BigInt, BigUint, Sign};
9
10/// Decode an unsigned integer into a big endian byte slice with all leading
11/// zeroes removed (if positive) and extra 0xff remove (if negative)
12fn trim_slice<'a>(any: &'a Any<'_>) -> Result<&'a [u8]> {
13    let bytes = any.data;
14
15    if bytes.is_empty() || (bytes[0] != 0x00 && bytes[0] != 0xff) {
16        return Ok(bytes);
17    }
18
19    match bytes.iter().position(|&b| b != 0) {
20        // first byte is not 0
21        Some(0) => (),
22        // all bytes are 0
23        None => return Ok(&bytes[bytes.len() - 1..]),
24        Some(first) => return Ok(&bytes[first..]),
25    }
26
27    // same for negative integers : skip byte 0->n if byte 0->n = 0xff AND byte n+1 >= 0x80
28    match bytes.windows(2).position(|s| match s {
29        &[a, b] => !(a == 0xff && b >= 0x80),
30        _ => true,
31    }) {
32        // first byte is not 0xff
33        Some(0) => (),
34        // all bytes are 0xff
35        None => return Ok(&bytes[bytes.len() - 1..]),
36        Some(first) => return Ok(&bytes[first..]),
37    }
38
39    Ok(bytes)
40}
41
42/// Decode an unsigned integer into a byte array of the requested size
43/// containing a big endian integer.
44fn decode_array_uint<const N: usize>(any: &Any<'_>) -> Result<[u8; N]> {
45    if is_highest_bit_set(any.data) {
46        return Err(Error::IntegerNegative);
47    }
48    let input = trim_slice(any)?;
49
50    if input.len() > N {
51        return Err(Error::IntegerTooLarge);
52    }
53
54    // Input has leading zeroes removed, so we need to add them back
55    let mut output = [0u8; N];
56    assert!(input.len() <= N);
57    output[N.saturating_sub(input.len())..].copy_from_slice(input);
58    Ok(output)
59}
60
61/// Decode an unsigned integer of the specified size.
62///
63/// Returns a byte array of the requested size containing a big endian integer.
64fn decode_array_int<const N: usize>(any: &Any<'_>) -> Result<[u8; N]> {
65    if any.data.len() > N {
66        return Err(Error::IntegerTooLarge);
67    }
68
69    // any.tag().assert_eq(Tag::Integer)?;
70    let mut output = [0xFFu8; N];
71    let offset = N.saturating_sub(any.as_bytes().len());
72    output[offset..].copy_from_slice(any.as_bytes());
73    Ok(output)
74}
75
76/// Is the highest bit of the first byte in the slice 1? (if present)
77#[inline]
78fn is_highest_bit_set(bytes: &[u8]) -> bool {
79    bytes
80        .first()
81        .map(|byte| byte & 0b10000000 != 0)
82        .unwrap_or(false)
83}
84
85macro_rules! impl_int {
86    ($uint:ty => $int:ty) => {
87        impl<'a> TryFrom<Any<'a>> for $int {
88            type Error = Error;
89
90            fn try_from(any: Any<'a>) -> Result<Self> {
91                TryFrom::try_from(&any)
92            }
93        }
94
95        impl<'a, 'b> TryFrom<&'b Any<'a>> for $int {
96            type Error = Error;
97
98            fn try_from(any: &'b Any<'a>) -> Result<Self> {
99                $crate::debug::trace_generic(
100                    core::any::type_name::<$int>(),
101                    "Conversion to int",
102                    |any| {
103                        any.tag().assert_eq(Self::TAG)?;
104                        any.header.assert_primitive()?;
105                        let uint = if is_highest_bit_set(any.as_bytes()) {
106                            <$uint>::from_be_bytes(decode_array_int(&any)?)
107                        } else {
108                            // read as uint, but check if the value will fit in a signed integer
109                            let u = <$uint>::from_be_bytes(decode_array_uint(&any)?);
110                            if u > <$int>::MAX as $uint {
111                                return Err(Error::IntegerTooLarge);
112                            }
113                            u
114                        };
115                        Ok(uint as $int)
116                    },
117                    any,
118                )
119            }
120        }
121
122        impl CheckDerConstraints for $int {
123            fn check_constraints(any: &Any) -> Result<()> {
124                check_der_int_constraints(any)
125            }
126        }
127
128        impl DerAutoDerive for $int {}
129
130        impl Tagged for $int {
131            const TAG: Tag = Tag::Integer;
132        }
133
134        #[cfg(feature = "std")]
135        impl ToDer for $int {
136            fn to_der_len(&self) -> Result<usize> {
137                let int = Integer::from(*self);
138                int.to_der_len()
139            }
140
141            fn write_der(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
142                let int = Integer::from(*self);
143                int.write_der(writer)
144            }
145
146            fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
147                let int = Integer::from(*self);
148                int.write_der_header(writer)
149            }
150
151            fn write_der_content(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
152                let int = Integer::from(*self);
153                int.write_der_content(writer)
154            }
155        }
156    };
157}
158
159macro_rules! impl_uint {
160    ($ty:ty) => {
161        impl<'a> TryFrom<Any<'a>> for $ty {
162            type Error = Error;
163
164            fn try_from(any: Any<'a>) -> Result<Self> {
165                TryFrom::try_from(&any)
166            }
167        }
168        impl<'a, 'b> TryFrom<&'b Any<'a>> for $ty {
169            type Error = Error;
170
171            fn try_from(any: &'b Any<'a>) -> Result<Self> {
172                $crate::debug::trace_generic(
173                    core::any::type_name::<$ty>(),
174                    "Conversion to uint",
175                    |any| {
176                        any.tag().assert_eq(Self::TAG)?;
177                        any.header.assert_primitive()?;
178                        let result = Self::from_be_bytes(decode_array_uint(any)?);
179                        Ok(result)
180                    },
181                    any,
182                )
183            }
184        }
185        impl CheckDerConstraints for $ty {
186            fn check_constraints(any: &Any) -> Result<()> {
187                check_der_int_constraints(any)
188            }
189        }
190
191        impl DerAutoDerive for $ty {}
192
193        impl Tagged for $ty {
194            const TAG: Tag = Tag::Integer;
195        }
196
197        #[cfg(feature = "std")]
198        impl ToDer for $ty {
199            fn to_der_len(&self) -> Result<usize> {
200                let int = Integer::from(*self);
201                int.to_der_len()
202            }
203
204            fn write_der(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
205                let int = Integer::from(*self);
206                int.write_der(writer)
207            }
208
209            fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
210                let int = Integer::from(*self);
211                int.write_der_header(writer)
212            }
213
214            fn write_der_content(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
215                let int = Integer::from(*self);
216                int.write_der_content(writer)
217            }
218        }
219    };
220}
221
222impl_uint!(u8);
223impl_uint!(u16);
224impl_uint!(u32);
225impl_uint!(u64);
226impl_uint!(u128);
227impl_int!(u8 => i8);
228impl_int!(u16 => i16);
229impl_int!(u32 => i32);
230impl_int!(u64 => i64);
231impl_int!(u128 => i128);
232
233/// ASN.1 `INTEGER` type
234///
235/// Generic representation for integer types.
236/// BER/DER integers can be of any size, so it is not possible to store them as simple integers (they
237/// are stored as raw bytes).
238///
239/// The internal representation can be obtained using `.as_ref()`.
240///
241/// # Note
242///
243/// Methods from/to BER and DER encodings are also implemented for primitive types
244/// (`u8`, `u16` to `u128`, and `i8` to `i128`).
245/// In most cases, it is easier to use these types directly.
246///
247/// # Examples
248///
249/// Creating an `Integer`
250///
251/// ```
252/// use asn1_rs::Integer;
253///
254/// // unsigned
255/// let i = Integer::from(4);
256/// assert_eq!(i.as_ref(), &[4]);
257/// // signed
258/// let j = Integer::from(-2);
259/// assert_eq!(j.as_ref(), &[0xfe]);
260/// ```
261///
262/// Converting an `Integer` to a primitive type (using the `TryInto` trait)
263///
264/// ```
265/// use asn1_rs::{Error, Integer};
266/// use std::convert::TryInto;
267///
268/// let i = Integer::new(&[0x12, 0x34, 0x56, 0x78]);
269/// // converts to an u32
270/// let n: u32 = i.try_into().unwrap();
271///
272/// // Same, but converting to an u16: will fail, value cannot fit into an u16
273/// let i = Integer::new(&[0x12, 0x34, 0x56, 0x78]);
274/// assert_eq!(i.try_into() as Result<u16, _>, Err(Error::IntegerTooLarge));
275/// ```
276///
277/// Encoding an `Integer` to DER
278///
279#[cfg_attr(feature = "std", doc = r#"```"#)]
280#[cfg_attr(not(feature = "std"), doc = r#"```rust,compile_fail"#)]
281/// use asn1_rs::{Integer, ToDer};
282///
283/// let i = Integer::from(4);
284/// let v = i.to_der_vec().unwrap();
285/// assert_eq!(&v, &[2, 1, 4]);
286///
287/// // same, with primitive types
288/// let v = 4.to_der_vec().unwrap();
289/// assert_eq!(&v, &[2, 1, 4]);
290/// ```
291#[derive(Debug, Eq, PartialEq)]
292pub struct Integer<'a> {
293    pub(crate) data: Cow<'a, [u8]>,
294}
295
296impl<'a> Integer<'a> {
297    /// Creates a new `Integer` containing the given value (borrowed).
298    #[inline]
299    pub const fn new(s: &'a [u8]) -> Self {
300        Integer {
301            data: Cow::Borrowed(s),
302        }
303    }
304
305    /// Creates a borrowed `Any` for this object
306    #[inline]
307    pub fn any(&'a self) -> Any<'a> {
308        Any::from_tag_and_data(Self::TAG, &self.data)
309    }
310
311    /// Returns a `BigInt` built from this `Integer` value.
312    #[cfg(feature = "bigint")]
313    #[cfg_attr(docsrs, doc(cfg(feature = "bigint")))]
314    pub fn as_bigint(&self) -> BigInt {
315        BigInt::from_signed_bytes_be(&self.data)
316    }
317
318    /// Returns a `BigUint` built from this `Integer` value.
319    #[cfg(feature = "bigint")]
320    #[cfg_attr(docsrs, doc(cfg(feature = "bigint")))]
321    pub fn as_biguint(&self) -> Result<BigUint> {
322        if is_highest_bit_set(&self.data) {
323            Err(Error::IntegerNegative)
324        } else {
325            Ok(BigUint::from_bytes_be(&self.data))
326        }
327    }
328
329    /// Build an `Integer` from a constant array of bytes representation of an integer.
330    pub fn from_const_array<const N: usize>(b: [u8; N]) -> Self {
331        // if high bit set -> add leading 0 to ensure unsigned
332        if is_highest_bit_set(&b) {
333            let mut bytes = vec![0];
334            bytes.extend_from_slice(&b);
335
336            Integer {
337                data: Cow::Owned(bytes),
338            }
339        }
340        // otherwise -> remove 0 unless next has high bit set
341        else {
342            let mut idx = 0;
343
344            while idx < b.len() - 1 {
345                if b[idx] == 0 && b[idx + 1] < 0x80 {
346                    idx += 1;
347                    continue;
348                }
349                break;
350            }
351
352            Integer {
353                data: Cow::Owned(b[idx..].to_vec()),
354            }
355        }
356    }
357
358    fn from_const_array_negative<const N: usize>(b: [u8; N]) -> Self {
359        let mut idx = 0;
360
361        // Skip leading FF unless next has high bit clear
362        while idx < b.len() - 1 {
363            if b[idx] == 0xFF && b[idx + 1] >= 0x80 {
364                idx += 1;
365                continue;
366            }
367            break;
368        }
369
370        if idx == b.len() {
371            Integer {
372                data: Cow::Borrowed(&[0]),
373            }
374        } else {
375            Integer {
376                data: Cow::Owned(b[idx..].to_vec()),
377            }
378        }
379    }
380}
381
382macro_rules! impl_from_to {
383    ($ty:ty, $sty:expr, $from:ident, $to:ident) => {
384        impl From<$ty> for Integer<'_> {
385            fn from(i: $ty) -> Self {
386                Self::$from(i)
387            }
388        }
389
390        impl TryFrom<Integer<'_>> for $ty {
391            type Error = Error;
392
393            fn try_from(value: Integer<'_>) -> Result<Self> {
394                value.$to()
395            }
396        }
397
398        impl Integer<'_> {
399            #[doc = "Attempts to convert an `Integer` to a `"]
400            #[doc = $sty]
401            #[doc = "`."]
402            #[doc = ""]
403            #[doc = "This function returns an `IntegerTooLarge` error if the integer will not fit into the output type."]
404            pub fn $to(&self) -> Result<$ty> {
405                self.any().try_into()
406            }
407        }
408    };
409    (IMPL SIGNED $ty:ty, $sty:expr, $from:ident, $to:ident) => {
410        impl_from_to!($ty, $sty, $from, $to);
411
412        impl Integer<'_> {
413            #[doc = "Converts a `"]
414            #[doc = $sty]
415            #[doc = "` to an `Integer`"]
416            #[doc = ""]
417            #[doc = "Note: this function allocates data."]
418            pub fn $from(i: $ty) -> Self {
419                let b = i.to_be_bytes();
420                if i >= 0 {
421                    Self::from_const_array(b)
422                } else {
423                    Self::from_const_array_negative(b)
424                }
425            }
426        }
427    };
428    (IMPL UNSIGNED $ty:ty, $sty:expr, $from:ident, $to:ident) => {
429        impl_from_to!($ty, $sty, $from, $to);
430
431        impl Integer<'_> {
432            #[doc = "Converts a `"]
433            #[doc = $sty]
434            #[doc = "` to an `Integer`"]
435            #[doc = ""]
436            #[doc = "Note: this function allocates data."]
437            pub fn $from(i: $ty) -> Self {
438                Self::from_const_array(i.to_be_bytes())
439            }
440        }
441    };
442    (SIGNED $ty:ty, $from:ident, $to:ident) => {
443        impl_from_to!(IMPL SIGNED $ty, stringify!($ty), $from, $to);
444    };
445    (UNSIGNED $ty:ty, $from:ident, $to:ident) => {
446        impl_from_to!(IMPL UNSIGNED $ty, stringify!($ty), $from, $to);
447    };
448}
449
450impl_from_to!(SIGNED i8, from_i8, as_i8);
451impl_from_to!(SIGNED i16, from_i16, as_i16);
452impl_from_to!(SIGNED i32, from_i32, as_i32);
453impl_from_to!(SIGNED i64, from_i64, as_i64);
454impl_from_to!(SIGNED i128, from_i128, as_i128);
455
456impl_from_to!(UNSIGNED u8, from_u8, as_u8);
457impl_from_to!(UNSIGNED u16, from_u16, as_u16);
458impl_from_to!(UNSIGNED u32, from_u32, as_u32);
459impl_from_to!(UNSIGNED u64, from_u64, as_u64);
460impl_from_to!(UNSIGNED u128, from_u128, as_u128);
461
462impl AsRef<[u8]> for Integer<'_> {
463    fn as_ref(&self) -> &[u8] {
464        &self.data
465    }
466}
467
468impl<'a> TryFrom<Any<'a>> for Integer<'a> {
469    type Error = Error;
470
471    fn try_from(any: Any<'a>) -> Result<Integer<'a>> {
472        TryFrom::try_from(&any)
473    }
474}
475
476impl<'a, 'b> TryFrom<&'b Any<'a>> for Integer<'a> {
477    type Error = Error;
478
479    fn try_from(any: &'b Any<'a>) -> Result<Integer<'a>> {
480        any.tag().assert_eq(Self::TAG)?;
481        Ok(Integer {
482            data: Cow::Borrowed(any.data),
483        })
484    }
485}
486
487impl CheckDerConstraints for Integer<'_> {
488    fn check_constraints(any: &Any) -> Result<()> {
489        check_der_int_constraints(any)
490    }
491}
492
493fn check_der_int_constraints(any: &Any) -> Result<()> {
494    any.header.assert_primitive()?;
495    any.header.length.assert_definite()?;
496    match any.as_bytes() {
497        [] => Err(Error::DerConstraintFailed(DerConstraint::IntegerEmpty)),
498        [0] => Ok(()),
499        // leading zeroes
500        [0, byte, ..] if *byte < 0x80 => Err(Error::DerConstraintFailed(
501            DerConstraint::IntegerLeadingZeroes,
502        )),
503        // negative integer with non-minimal encoding
504        [0xff, byte, ..] if *byte >= 0x80 => {
505            Err(Error::DerConstraintFailed(DerConstraint::IntegerLeadingFF))
506        }
507        _ => Ok(()),
508    }
509}
510
511impl DerAutoDerive for Integer<'_> {}
512
513impl Tagged for Integer<'_> {
514    const TAG: Tag = Tag::Integer;
515}
516
517#[cfg(feature = "std")]
518impl ToDer for Integer<'_> {
519    fn to_der_len(&self) -> Result<usize> {
520        let sz = self.data.len();
521        if sz < 127 {
522            // 1 (class+tag) + 1 (length) + len
523            Ok(2 + sz)
524        } else {
525            // hmm, a very long integer. anyway:
526            // 1 (class+tag) + n (length) + len
527            let n = Length::Definite(sz).to_der_len()?;
528            Ok(1 + n + sz)
529        }
530    }
531
532    fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
533        let header = Header::new(
534            Class::Universal,
535            false,
536            Self::TAG,
537            Length::Definite(self.data.len()),
538        );
539        header.write_der_header(writer)
540    }
541
542    fn write_der_content(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
543        writer.write(&self.data).map_err(Into::into)
544    }
545}
546
547/// Helper macro to declare integers at compile-time
548///
549/// [`Integer`] stores the encoded representation of the integer, so declaring
550/// an integer requires to either use a runtime function or provide the encoded value.
551/// This macro simplifies this task by encoding the value.
552/// It can be used the following ways:
553///
554/// - `int!(1234)`: Create a const expression for the corresponding `Integer<'static>`
555/// - `int!(raw 1234)`: Return the DER encoded form as a byte array (hex-encoded, big-endian
556///   representation from the integer, with leading zeroes removed).
557///
558/// # Examples
559///
560/// ```rust
561/// use asn1_rs::{int, Integer};
562///
563/// const INT0: Integer = int!(1234);
564/// ```
565#[macro_export]
566macro_rules! int {
567    (raw $item:expr) => {
568        $crate::exports::asn1_rs_impl::encode_int!($item)
569    };
570    (rel $item:expr) => {
571        $crate::exports::asn1_rs_impl::encode_int!(rel $item)
572    };
573    ($item:expr) => {
574        $crate::Integer::new(
575            &$crate::int!(raw $item),
576        )
577    };
578}
579
580#[cfg(all(test, feature = "std"))]
581mod tests {
582    use crate::{Any, FromDer, Header, Tag, ToDer};
583    use std::convert::TryInto;
584
585    // Vectors from Section 5.7 of:
586    // https://luca.ntop.org/Teaching/Appunti/asn1.html
587    pub(crate) const I0_BYTES: &[u8] = &[0x02, 0x01, 0x00];
588    pub(crate) const I127_BYTES: &[u8] = &[0x02, 0x01, 0x7F];
589    pub(crate) const I128_BYTES: &[u8] = &[0x02, 0x02, 0x00, 0x80];
590    pub(crate) const I256_BYTES: &[u8] = &[0x02, 0x02, 0x01, 0x00];
591    pub(crate) const INEG128_BYTES: &[u8] = &[0x02, 0x01, 0x80];
592    pub(crate) const INEG129_BYTES: &[u8] = &[0x02, 0x02, 0xFF, 0x7F];
593
594    // Additional vectors
595    pub(crate) const I255_BYTES: &[u8] = &[0x02, 0x02, 0x00, 0xFF];
596    pub(crate) const I32767_BYTES: &[u8] = &[0x02, 0x02, 0x7F, 0xFF];
597    pub(crate) const I65535_BYTES: &[u8] = &[0x02, 0x03, 0x00, 0xFF, 0xFF];
598    pub(crate) const INEG32768_BYTES: &[u8] = &[0x02, 0x02, 0x80, 0x00];
599
600    #[test]
601    fn decode_i8() {
602        assert_eq!(0, i8::from_der(I0_BYTES).unwrap().1);
603        assert_eq!(127, i8::from_der(I127_BYTES).unwrap().1);
604        assert_eq!(-128, i8::from_der(INEG128_BYTES).unwrap().1);
605    }
606
607    #[test]
608    fn encode_i8() {
609        assert_eq!(0i8.to_der_vec().unwrap(), I0_BYTES);
610        assert_eq!(127i8.to_der_vec().unwrap(), I127_BYTES);
611        assert_eq!((-128i8).to_der_vec().unwrap(), INEG128_BYTES);
612    }
613
614    #[test]
615    fn decode_i16() {
616        assert_eq!(0, i16::from_der(I0_BYTES).unwrap().1);
617        assert_eq!(127, i16::from_der(I127_BYTES).unwrap().1);
618        assert_eq!(128, i16::from_der(I128_BYTES).unwrap().1);
619        assert_eq!(255, i16::from_der(I255_BYTES).unwrap().1);
620        assert_eq!(256, i16::from_der(I256_BYTES).unwrap().1);
621        assert_eq!(32767, i16::from_der(I32767_BYTES).unwrap().1);
622        assert_eq!(-128, i16::from_der(INEG128_BYTES).unwrap().1);
623        assert_eq!(-129, i16::from_der(INEG129_BYTES).unwrap().1);
624        assert_eq!(-32768, i16::from_der(INEG32768_BYTES).unwrap().1);
625    }
626
627    #[test]
628    fn encode_i16() {
629        assert_eq!(0i16.to_der_vec().unwrap(), I0_BYTES);
630        assert_eq!(127i16.to_der_vec().unwrap(), I127_BYTES);
631        assert_eq!(128i16.to_der_vec().unwrap(), I128_BYTES);
632        assert_eq!(255i16.to_der_vec().unwrap(), I255_BYTES);
633        assert_eq!(256i16.to_der_vec().unwrap(), I256_BYTES);
634        assert_eq!(32767i16.to_der_vec().unwrap(), I32767_BYTES);
635        assert_eq!((-128i16).to_der_vec().unwrap(), INEG128_BYTES);
636        assert_eq!((-129i16).to_der_vec().unwrap(), INEG129_BYTES);
637        assert_eq!((-32768i16).to_der_vec().unwrap(), INEG32768_BYTES);
638    }
639
640    #[test]
641    fn decode_u8() {
642        assert_eq!(0, u8::from_der(I0_BYTES).unwrap().1);
643        assert_eq!(127, u8::from_der(I127_BYTES).unwrap().1);
644        assert_eq!(255, u8::from_der(I255_BYTES).unwrap().1);
645    }
646
647    #[test]
648    fn encode_u8() {
649        assert_eq!(0u8.to_der_vec().unwrap(), I0_BYTES);
650        assert_eq!(127u8.to_der_vec().unwrap(), I127_BYTES);
651        assert_eq!(255u8.to_der_vec().unwrap(), I255_BYTES);
652    }
653
654    #[test]
655    fn decode_u16() {
656        assert_eq!(0, u16::from_der(I0_BYTES).unwrap().1);
657        assert_eq!(127, u16::from_der(I127_BYTES).unwrap().1);
658        assert_eq!(255, u16::from_der(I255_BYTES).unwrap().1);
659        assert_eq!(256, u16::from_der(I256_BYTES).unwrap().1);
660        assert_eq!(32767, u16::from_der(I32767_BYTES).unwrap().1);
661        assert_eq!(65535, u16::from_der(I65535_BYTES).unwrap().1);
662    }
663
664    #[test]
665    fn encode_u16() {
666        assert_eq!(0u16.to_der_vec().unwrap(), I0_BYTES);
667        assert_eq!(127u16.to_der_vec().unwrap(), I127_BYTES);
668        assert_eq!(255u16.to_der_vec().unwrap(), I255_BYTES);
669        assert_eq!(256u16.to_der_vec().unwrap(), I256_BYTES);
670        assert_eq!(32767u16.to_der_vec().unwrap(), I32767_BYTES);
671        assert_eq!(65535u16.to_der_vec().unwrap(), I65535_BYTES);
672    }
673
674    /// Integers must be encoded with a minimum number of octets
675    #[test]
676    fn reject_non_canonical() {
677        assert!(i8::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err());
678        assert!(i16::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err());
679        assert!(u8::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err());
680        assert!(u16::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err());
681    }
682
683    #[test]
684    fn declare_int() {
685        let int = super::int!(1234);
686        assert_eq!(int.try_into(), Ok(1234));
687    }
688
689    #[test]
690    fn trim_slice() {
691        use super::trim_slice;
692        let h = Header::new_simple(Tag(0));
693        // no zero nor ff - nothing to remove
694        let input: &[u8] = &[0x7f, 0xff, 0x00, 0x02];
695        assert_eq!(Ok(input), trim_slice(&Any::new(h.clone(), input)));
696        //
697        // 0x00
698        //
699        // empty - nothing to remove
700        let input: &[u8] = &[];
701        assert_eq!(Ok(input), trim_slice(&Any::new(h.clone(), input)));
702        // one zero - nothing to remove
703        let input: &[u8] = &[0];
704        assert_eq!(Ok(input), trim_slice(&Any::new(h.clone(), input)));
705        // all zeroes - keep only one
706        let input: &[u8] = &[0, 0, 0];
707        assert_eq!(Ok(&input[2..]), trim_slice(&Any::new(h.clone(), input)));
708        // some zeroes - keep only the non-zero part
709        let input: &[u8] = &[0, 0, 1];
710        assert_eq!(Ok(&input[2..]), trim_slice(&Any::new(h.clone(), input)));
711        //
712        // 0xff
713        //
714        // one ff - nothing to remove
715        let input: &[u8] = &[0xff];
716        assert_eq!(Ok(input), trim_slice(&Any::new(h.clone(), input)));
717        // all ff - keep only one
718        let input: &[u8] = &[0xff, 0xff, 0xff];
719        assert_eq!(Ok(&input[2..]), trim_slice(&Any::new(h.clone(), input)));
720        // some ff - keep only the non-zero part
721        let input: &[u8] = &[0xff, 0xff, 1];
722        assert_eq!(Ok(&input[1..]), trim_slice(&Any::new(h.clone(), input)));
723        // some ff and a MSB 1 - keep only the non-zero part
724        let input: &[u8] = &[0xff, 0xff, 0x80, 1];
725        assert_eq!(Ok(&input[2..]), trim_slice(&Any::new(h.clone(), input)));
726    }
727}