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/// ```
280/// use asn1_rs::{Integer, ToDer};
281///
282/// let i = Integer::from(4);
283/// let v = i.to_der_vec().unwrap();
284/// assert_eq!(&v, &[2, 1, 4]);
285///
286/// // same, with primitive types
287/// let v = 4.to_der_vec().unwrap();
288/// assert_eq!(&v, &[2, 1, 4]);
289/// ```
290#[derive(Debug, Eq, PartialEq)]
291pub struct Integer<'a> {
292    pub(crate) data: Cow<'a, [u8]>,
293}
294
295impl<'a> Integer<'a> {
296    /// Creates a new `Integer` containing the given value (borrowed).
297    #[inline]
298    pub const fn new(s: &'a [u8]) -> Self {
299        Integer {
300            data: Cow::Borrowed(s),
301        }
302    }
303
304    /// Creates a borrowed `Any` for this object
305    #[inline]
306    pub fn any(&'a self) -> Any<'a> {
307        Any::from_tag_and_data(Self::TAG, &self.data)
308    }
309
310    /// Returns a `BigInt` built from this `Integer` value.
311    #[cfg(feature = "bigint")]
312    #[cfg_attr(docsrs, doc(cfg(feature = "bigint")))]
313    pub fn as_bigint(&self) -> BigInt {
314        BigInt::from_signed_bytes_be(&self.data)
315    }
316
317    /// Returns a `BigUint` built from this `Integer` value.
318    #[cfg(feature = "bigint")]
319    #[cfg_attr(docsrs, doc(cfg(feature = "bigint")))]
320    pub fn as_biguint(&self) -> Result<BigUint> {
321        if is_highest_bit_set(&self.data) {
322            Err(Error::IntegerNegative)
323        } else {
324            Ok(BigUint::from_bytes_be(&self.data))
325        }
326    }
327
328    /// Build an `Integer` from a constant array of bytes representation of an integer.
329    pub fn from_const_array<const N: usize>(b: [u8; N]) -> Self {
330        // if high bit set -> add leading 0 to ensure unsigned
331        if is_highest_bit_set(&b) {
332            let mut bytes = vec![0];
333            bytes.extend_from_slice(&b);
334
335            Integer {
336                data: Cow::Owned(bytes),
337            }
338        }
339        // otherwise -> remove 0 unless next has high bit set
340        else {
341            let mut idx = 0;
342
343            while idx < b.len() - 1 {
344                if b[idx] == 0 && b[idx + 1] < 0x80 {
345                    idx += 1;
346                    continue;
347                }
348                break;
349            }
350
351            Integer {
352                data: Cow::Owned(b[idx..].to_vec()),
353            }
354        }
355    }
356
357    fn from_const_array_negative<const N: usize>(b: [u8; N]) -> Self {
358        let mut idx = 0;
359
360        // Skip leading FF unless next has high bit clear
361        while idx < b.len() - 1 {
362            if b[idx] == 0xFF && b[idx + 1] >= 0x80 {
363                idx += 1;
364                continue;
365            }
366            break;
367        }
368
369        if idx == b.len() {
370            Integer {
371                data: Cow::Borrowed(&[0]),
372            }
373        } else {
374            Integer {
375                data: Cow::Owned(b[idx..].to_vec()),
376            }
377        }
378    }
379}
380
381macro_rules! impl_from_to {
382    ($ty:ty, $sty:expr, $from:ident, $to:ident) => {
383        impl From<$ty> for Integer<'_> {
384            fn from(i: $ty) -> Self {
385                Self::$from(i)
386            }
387        }
388
389        impl TryFrom<Integer<'_>> for $ty {
390            type Error = Error;
391
392            fn try_from(value: Integer<'_>) -> Result<Self> {
393                value.$to()
394            }
395        }
396
397        impl Integer<'_> {
398            #[doc = "Attempts to convert an `Integer` to a `"]
399            #[doc = $sty]
400            #[doc = "`."]
401            #[doc = ""]
402            #[doc = "This function returns an `IntegerTooLarge` error if the integer will not fit into the output type."]
403            pub fn $to(&self) -> Result<$ty> {
404                self.any().try_into()
405            }
406        }
407    };
408    (IMPL SIGNED $ty:ty, $sty:expr, $from:ident, $to:ident) => {
409        impl_from_to!($ty, $sty, $from, $to);
410
411        impl Integer<'_> {
412            #[doc = "Converts a `"]
413            #[doc = $sty]
414            #[doc = "` to an `Integer`"]
415            #[doc = ""]
416            #[doc = "Note: this function allocates data."]
417            pub fn $from(i: $ty) -> Self {
418                let b = i.to_be_bytes();
419                if i >= 0 {
420                    Self::from_const_array(b)
421                } else {
422                    Self::from_const_array_negative(b)
423                }
424            }
425        }
426    };
427    (IMPL UNSIGNED $ty:ty, $sty:expr, $from:ident, $to:ident) => {
428        impl_from_to!($ty, $sty, $from, $to);
429
430        impl Integer<'_> {
431            #[doc = "Converts a `"]
432            #[doc = $sty]
433            #[doc = "` to an `Integer`"]
434            #[doc = ""]
435            #[doc = "Note: this function allocates data."]
436            pub fn $from(i: $ty) -> Self {
437                Self::from_const_array(i.to_be_bytes())
438            }
439        }
440    };
441    (SIGNED $ty:ty, $from:ident, $to:ident) => {
442        impl_from_to!(IMPL SIGNED $ty, stringify!($ty), $from, $to);
443    };
444    (UNSIGNED $ty:ty, $from:ident, $to:ident) => {
445        impl_from_to!(IMPL UNSIGNED $ty, stringify!($ty), $from, $to);
446    };
447}
448
449impl_from_to!(SIGNED i8, from_i8, as_i8);
450impl_from_to!(SIGNED i16, from_i16, as_i16);
451impl_from_to!(SIGNED i32, from_i32, as_i32);
452impl_from_to!(SIGNED i64, from_i64, as_i64);
453impl_from_to!(SIGNED i128, from_i128, as_i128);
454
455impl_from_to!(UNSIGNED u8, from_u8, as_u8);
456impl_from_to!(UNSIGNED u16, from_u16, as_u16);
457impl_from_to!(UNSIGNED u32, from_u32, as_u32);
458impl_from_to!(UNSIGNED u64, from_u64, as_u64);
459impl_from_to!(UNSIGNED u128, from_u128, as_u128);
460
461impl<'a> AsRef<[u8]> for Integer<'a> {
462    fn as_ref(&self) -> &[u8] {
463        &self.data
464    }
465}
466
467impl<'a> TryFrom<Any<'a>> for Integer<'a> {
468    type Error = Error;
469
470    fn try_from(any: Any<'a>) -> Result<Integer<'a>> {
471        TryFrom::try_from(&any)
472    }
473}
474
475impl<'a, 'b> TryFrom<&'b Any<'a>> for Integer<'a> {
476    type Error = Error;
477
478    fn try_from(any: &'b Any<'a>) -> Result<Integer<'a>> {
479        any.tag().assert_eq(Self::TAG)?;
480        Ok(Integer {
481            data: Cow::Borrowed(any.data),
482        })
483    }
484}
485
486impl<'a> CheckDerConstraints for Integer<'a> {
487    fn check_constraints(any: &Any) -> Result<()> {
488        check_der_int_constraints(any)
489    }
490}
491
492fn check_der_int_constraints(any: &Any) -> Result<()> {
493    any.header.assert_primitive()?;
494    any.header.length.assert_definite()?;
495    match any.as_bytes() {
496        [] => Err(Error::DerConstraintFailed(DerConstraint::IntegerEmpty)),
497        [0] => Ok(()),
498        // leading zeroes
499        [0, byte, ..] if *byte < 0x80 => Err(Error::DerConstraintFailed(
500            DerConstraint::IntegerLeadingZeroes,
501        )),
502        // negative integer with non-minimal encoding
503        [0xff, byte, ..] if *byte >= 0x80 => {
504            Err(Error::DerConstraintFailed(DerConstraint::IntegerLeadingFF))
505        }
506        _ => Ok(()),
507    }
508}
509
510impl DerAutoDerive for Integer<'_> {}
511
512impl<'a> Tagged for Integer<'a> {
513    const TAG: Tag = Tag::Integer;
514}
515
516#[cfg(feature = "std")]
517impl ToDer for Integer<'_> {
518    fn to_der_len(&self) -> Result<usize> {
519        let sz = self.data.len();
520        if sz < 127 {
521            // 1 (class+tag) + 1 (length) + len
522            Ok(2 + sz)
523        } else {
524            // hmm, a very long integer. anyway:
525            // 1 (class+tag) + n (length) + len
526            let n = Length::Definite(sz).to_der_len()?;
527            Ok(1 + n + sz)
528        }
529    }
530
531    fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
532        let header = Header::new(
533            Class::Universal,
534            false,
535            Self::TAG,
536            Length::Definite(self.data.len()),
537        );
538        header.write_der_header(writer).map_err(Into::into)
539    }
540
541    fn write_der_content(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
542        writer.write(&self.data).map_err(Into::into)
543    }
544}
545
546/// Helper macro to declare integers at compile-time
547///
548/// [`Integer`] stores the encoded representation of the integer, so declaring
549/// an integer requires to either use a runtime function or provide the encoded value.
550/// This macro simplifies this task by encoding the value.
551/// It can be used the following ways:
552///
553/// - `int!(1234)`: Create a const expression for the corresponding `Integer<'static>`
554/// - `int!(raw 1234)`: Return the DER encoded form as a byte array (hex-encoded, big-endian
555///    representation from the integer, with leading zeroes removed).
556///
557/// # Examples
558///
559/// ```rust
560/// use asn1_rs::{int, Integer};
561///
562/// const INT0: Integer = int!(1234);
563/// ```
564#[macro_export]
565macro_rules! int {
566    (raw $item:expr) => {
567        $crate::exports::asn1_rs_impl::encode_int!($item)
568    };
569    (rel $item:expr) => {
570        $crate::exports::asn1_rs_impl::encode_int!(rel $item)
571    };
572    ($item:expr) => {
573        $crate::Integer::new(
574            &$crate::int!(raw $item),
575        )
576    };
577}
578
579#[cfg(test)]
580mod tests {
581    use crate::{Any, FromDer, Header, Tag, ToDer};
582    use std::convert::TryInto;
583
584    // Vectors from Section 5.7 of:
585    // https://luca.ntop.org/Teaching/Appunti/asn1.html
586    pub(crate) const I0_BYTES: &[u8] = &[0x02, 0x01, 0x00];
587    pub(crate) const I127_BYTES: &[u8] = &[0x02, 0x01, 0x7F];
588    pub(crate) const I128_BYTES: &[u8] = &[0x02, 0x02, 0x00, 0x80];
589    pub(crate) const I256_BYTES: &[u8] = &[0x02, 0x02, 0x01, 0x00];
590    pub(crate) const INEG128_BYTES: &[u8] = &[0x02, 0x01, 0x80];
591    pub(crate) const INEG129_BYTES: &[u8] = &[0x02, 0x02, 0xFF, 0x7F];
592
593    // Additional vectors
594    pub(crate) const I255_BYTES: &[u8] = &[0x02, 0x02, 0x00, 0xFF];
595    pub(crate) const I32767_BYTES: &[u8] = &[0x02, 0x02, 0x7F, 0xFF];
596    pub(crate) const I65535_BYTES: &[u8] = &[0x02, 0x03, 0x00, 0xFF, 0xFF];
597    pub(crate) const INEG32768_BYTES: &[u8] = &[0x02, 0x02, 0x80, 0x00];
598
599    #[test]
600    fn decode_i8() {
601        assert_eq!(0, i8::from_der(I0_BYTES).unwrap().1);
602        assert_eq!(127, i8::from_der(I127_BYTES).unwrap().1);
603        assert_eq!(-128, i8::from_der(INEG128_BYTES).unwrap().1);
604    }
605
606    #[test]
607    fn encode_i8() {
608        assert_eq!(0i8.to_der_vec().unwrap(), I0_BYTES);
609        assert_eq!(127i8.to_der_vec().unwrap(), I127_BYTES);
610        assert_eq!((-128i8).to_der_vec().unwrap(), INEG128_BYTES);
611    }
612
613    #[test]
614    fn decode_i16() {
615        assert_eq!(0, i16::from_der(I0_BYTES).unwrap().1);
616        assert_eq!(127, i16::from_der(I127_BYTES).unwrap().1);
617        assert_eq!(128, i16::from_der(I128_BYTES).unwrap().1);
618        assert_eq!(255, i16::from_der(I255_BYTES).unwrap().1);
619        assert_eq!(256, i16::from_der(I256_BYTES).unwrap().1);
620        assert_eq!(32767, i16::from_der(I32767_BYTES).unwrap().1);
621        assert_eq!(-128, i16::from_der(INEG128_BYTES).unwrap().1);
622        assert_eq!(-129, i16::from_der(INEG129_BYTES).unwrap().1);
623        assert_eq!(-32768, i16::from_der(INEG32768_BYTES).unwrap().1);
624    }
625
626    #[test]
627    fn encode_i16() {
628        assert_eq!(0i16.to_der_vec().unwrap(), I0_BYTES);
629        assert_eq!(127i16.to_der_vec().unwrap(), I127_BYTES);
630        assert_eq!(128i16.to_der_vec().unwrap(), I128_BYTES);
631        assert_eq!(255i16.to_der_vec().unwrap(), I255_BYTES);
632        assert_eq!(256i16.to_der_vec().unwrap(), I256_BYTES);
633        assert_eq!(32767i16.to_der_vec().unwrap(), I32767_BYTES);
634        assert_eq!((-128i16).to_der_vec().unwrap(), INEG128_BYTES);
635        assert_eq!((-129i16).to_der_vec().unwrap(), INEG129_BYTES);
636        assert_eq!((-32768i16).to_der_vec().unwrap(), INEG32768_BYTES);
637    }
638
639    #[test]
640    fn decode_u8() {
641        assert_eq!(0, u8::from_der(I0_BYTES).unwrap().1);
642        assert_eq!(127, u8::from_der(I127_BYTES).unwrap().1);
643        assert_eq!(255, u8::from_der(I255_BYTES).unwrap().1);
644    }
645
646    #[test]
647    fn encode_u8() {
648        assert_eq!(0u8.to_der_vec().unwrap(), I0_BYTES);
649        assert_eq!(127u8.to_der_vec().unwrap(), I127_BYTES);
650        assert_eq!(255u8.to_der_vec().unwrap(), I255_BYTES);
651    }
652
653    #[test]
654    fn decode_u16() {
655        assert_eq!(0, u16::from_der(I0_BYTES).unwrap().1);
656        assert_eq!(127, u16::from_der(I127_BYTES).unwrap().1);
657        assert_eq!(255, u16::from_der(I255_BYTES).unwrap().1);
658        assert_eq!(256, u16::from_der(I256_BYTES).unwrap().1);
659        assert_eq!(32767, u16::from_der(I32767_BYTES).unwrap().1);
660        assert_eq!(65535, u16::from_der(I65535_BYTES).unwrap().1);
661    }
662
663    #[test]
664    fn encode_u16() {
665        assert_eq!(0u16.to_der_vec().unwrap(), I0_BYTES);
666        assert_eq!(127u16.to_der_vec().unwrap(), I127_BYTES);
667        assert_eq!(255u16.to_der_vec().unwrap(), I255_BYTES);
668        assert_eq!(256u16.to_der_vec().unwrap(), I256_BYTES);
669        assert_eq!(32767u16.to_der_vec().unwrap(), I32767_BYTES);
670        assert_eq!(65535u16.to_der_vec().unwrap(), I65535_BYTES);
671    }
672
673    /// Integers must be encoded with a minimum number of octets
674    #[test]
675    fn reject_non_canonical() {
676        assert!(i8::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err());
677        assert!(i16::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err());
678        assert!(u8::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err());
679        assert!(u16::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err());
680    }
681
682    #[test]
683    fn declare_int() {
684        let int = super::int!(1234);
685        assert_eq!(int.try_into(), Ok(1234));
686    }
687
688    #[test]
689    fn trim_slice() {
690        use super::trim_slice;
691        let h = Header::new_simple(Tag(0));
692        // no zero nor ff - nothing to remove
693        let input: &[u8] = &[0x7f, 0xff, 0x00, 0x02];
694        assert_eq!(Ok(input), trim_slice(&Any::new(h.clone(), input)));
695        //
696        // 0x00
697        //
698        // empty - nothing to remove
699        let input: &[u8] = &[];
700        assert_eq!(Ok(input), trim_slice(&Any::new(h.clone(), input)));
701        // one zero - nothing to remove
702        let input: &[u8] = &[0];
703        assert_eq!(Ok(input), trim_slice(&Any::new(h.clone(), input)));
704        // all zeroes - keep only one
705        let input: &[u8] = &[0, 0, 0];
706        assert_eq!(Ok(&input[2..]), trim_slice(&Any::new(h.clone(), input)));
707        // some zeroes - keep only the non-zero part
708        let input: &[u8] = &[0, 0, 1];
709        assert_eq!(Ok(&input[2..]), trim_slice(&Any::new(h.clone(), input)));
710        //
711        // 0xff
712        //
713        // one ff - nothing to remove
714        let input: &[u8] = &[0xff];
715        assert_eq!(Ok(input), trim_slice(&Any::new(h.clone(), input)));
716        // all ff - keep only one
717        let input: &[u8] = &[0xff, 0xff, 0xff];
718        assert_eq!(Ok(&input[2..]), trim_slice(&Any::new(h.clone(), input)));
719        // some ff - keep only the non-zero part
720        let input: &[u8] = &[0xff, 0xff, 1];
721        assert_eq!(Ok(&input[1..]), trim_slice(&Any::new(h.clone(), input)));
722        // some ff and a MSB 1 - keep only the non-zero part
723        let input: &[u8] = &[0xff, 0xff, 0x80, 1];
724        assert_eq!(Ok(&input[2..]), trim_slice(&Any::new(h.clone(), input)));
725    }
726}