diff options
Diffstat (limited to 'vendor/der/src/asn1/integer')
-rw-r--r-- | vendor/der/src/asn1/integer/int.rs | 442 | ||||
-rw-r--r-- | vendor/der/src/asn1/integer/uint.rs | 428 |
2 files changed, 870 insertions, 0 deletions
diff --git a/vendor/der/src/asn1/integer/int.rs b/vendor/der/src/asn1/integer/int.rs new file mode 100644 index 0000000..bccc521 --- /dev/null +++ b/vendor/der/src/asn1/integer/int.rs @@ -0,0 +1,442 @@ +//! Support for encoding signed integers + +use super::{is_highest_bit_set, uint, value_cmp}; +use crate::{ + ord::OrdIsValueOrd, AnyRef, BytesRef, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, + Header, Length, Reader, Result, Tag, ValueOrd, Writer, +}; +use core::cmp::Ordering; + +#[cfg(feature = "alloc")] +pub use allocating::Int; + +macro_rules! impl_encoding_traits { + ($($int:ty => $uint:ty),+) => { + $( + impl<'a> DecodeValue<'a> for $int { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + let mut buf = [0u8; Self::BITS as usize / 8]; + let max_length = u32::from(header.length) as usize; + + if max_length > buf.len() { + return Err(Self::TAG.non_canonical_error()); + } + + let bytes = reader.read_into(&mut buf[..max_length])?; + + let result = if is_highest_bit_set(bytes) { + <$uint>::from_be_bytes(decode_to_array(bytes)?) as $int + } else { + Self::from_be_bytes(uint::decode_to_array(bytes)?) + }; + + // Ensure we compute the same encoded length as the original any value + if header.length != result.value_len()? { + return Err(Self::TAG.non_canonical_error()); + } + + Ok(result) + } + } + + impl EncodeValue for $int { + fn value_len(&self) -> Result<Length> { + if *self < 0 { + negative_encoded_len(&(*self as $uint).to_be_bytes()) + } else { + uint::encoded_len(&self.to_be_bytes()) + } + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + if *self < 0 { + encode_bytes(writer, &(*self as $uint).to_be_bytes()) + } else { + uint::encode_bytes(writer, &self.to_be_bytes()) + } + } + } + + impl FixedTag for $int { + const TAG: Tag = Tag::Integer; + } + + impl ValueOrd for $int { + fn value_cmp(&self, other: &Self) -> Result<Ordering> { + value_cmp(*self, *other) + } + } + + impl TryFrom<AnyRef<'_>> for $int { + type Error = Error; + + fn try_from(any: AnyRef<'_>) -> Result<Self> { + any.decode_as() + } + } + )+ + }; +} + +impl_encoding_traits!(i8 => u8, i16 => u16, i32 => u32, i64 => u64, i128 => u128); + +/// Signed arbitrary precision ASN.1 `INTEGER` reference type. +/// +/// Provides direct access to the underlying big endian bytes which comprise +/// an signed integer value. +/// +/// Intended for use cases like very large integers that are used in +/// cryptographic applications (e.g. keys, signatures). +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct IntRef<'a> { + /// Inner value + inner: BytesRef<'a>, +} + +impl<'a> IntRef<'a> { + /// Create a new [`IntRef`] from a byte slice. + pub fn new(bytes: &'a [u8]) -> Result<Self> { + let inner = BytesRef::new(strip_leading_ones(bytes)) + .map_err(|_| ErrorKind::Length { tag: Self::TAG })?; + + Ok(Self { inner }) + } + + /// Borrow the inner byte slice which contains the least significant bytes + /// of a big endian integer value with all leading ones stripped. + pub fn as_bytes(&self) -> &'a [u8] { + self.inner.as_slice() + } + + /// Get the length of this [`IntRef`] in bytes. + pub fn len(&self) -> Length { + self.inner.len() + } + + /// Is the inner byte slice empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } +} + +impl_any_conversions!(IntRef<'a>, 'a); + +impl<'a> DecodeValue<'a> for IntRef<'a> { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + let bytes = BytesRef::decode_value(reader, header)?; + validate_canonical(bytes.as_slice())?; + + let result = Self::new(bytes.as_slice())?; + + // Ensure we compute the same encoded length as the original any value. + if result.value_len()? != header.length { + return Err(Self::TAG.non_canonical_error()); + } + + Ok(result) + } +} + +impl<'a> EncodeValue for IntRef<'a> { + fn value_len(&self) -> Result<Length> { + // Signed integers always hold their full encoded form. + Ok(self.inner.len()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.as_bytes()) + } +} + +impl<'a> From<&IntRef<'a>> for IntRef<'a> { + fn from(value: &IntRef<'a>) -> IntRef<'a> { + *value + } +} + +impl<'a> FixedTag for IntRef<'a> { + const TAG: Tag = Tag::Integer; +} + +impl<'a> OrdIsValueOrd for IntRef<'a> {} + +#[cfg(feature = "alloc")] +mod allocating { + use super::{strip_leading_ones, validate_canonical, IntRef}; + use crate::{ + asn1::Uint, + ord::OrdIsValueOrd, + referenced::{OwnedToRef, RefToOwned}, + BytesOwned, DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result, + Tag, Writer, + }; + use alloc::vec::Vec; + + /// Signed arbitrary precision ASN.1 `INTEGER` type. + /// + /// Provides heap-allocated storage for big endian bytes which comprise an + /// signed integer value. + /// + /// Intended for use cases like very large integers that are used in + /// cryptographic applications (e.g. keys, signatures). + #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] + pub struct Int { + /// Inner value + inner: BytesOwned, + } + + impl Int { + /// Create a new [`Int`] from a byte slice. + pub fn new(bytes: &[u8]) -> Result<Self> { + let inner = BytesOwned::new(strip_leading_ones(bytes)) + .map_err(|_| ErrorKind::Length { tag: Self::TAG })?; + + Ok(Self { inner }) + } + + /// Borrow the inner byte slice which contains the least significant bytes + /// of a big endian integer value with all leading ones stripped. + pub fn as_bytes(&self) -> &[u8] { + self.inner.as_slice() + } + + /// Get the length of this [`Int`] in bytes. + pub fn len(&self) -> Length { + self.inner.len() + } + + /// Is the inner byte slice empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + } + + impl_any_conversions!(Int); + + impl<'a> DecodeValue<'a> for Int { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + let bytes = BytesOwned::decode_value(reader, header)?; + validate_canonical(bytes.as_slice())?; + + let result = Self::new(bytes.as_slice())?; + + // Ensure we compute the same encoded length as the original any value. + if result.value_len()? != header.length { + return Err(Self::TAG.non_canonical_error()); + } + + Ok(result) + } + } + + impl EncodeValue for Int { + fn value_len(&self) -> Result<Length> { + // Signed integers always hold their full encoded form. + Ok(self.inner.len()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.as_bytes()) + } + } + + impl<'a> From<&IntRef<'a>> for Int { + fn from(value: &IntRef<'a>) -> Int { + let inner = BytesOwned::new(value.as_bytes()).expect("Invalid Int"); + Int { inner } + } + } + + impl From<Uint> for Int { + fn from(value: Uint) -> Self { + let mut inner: Vec<u8> = Vec::new(); + + // Add leading `0x00` byte if required + if value.value_len().expect("invalid Uint") > value.len() { + inner.push(0x00); + } + + inner.extend_from_slice(value.as_bytes()); + let inner = BytesOwned::new(inner).expect("invalid Uint"); + + Int { inner } + } + } + + impl FixedTag for Int { + const TAG: Tag = Tag::Integer; + } + + impl OrdIsValueOrd for Int {} + + impl<'a> RefToOwned<'a> for IntRef<'a> { + type Owned = Int; + fn ref_to_owned(&self) -> Self::Owned { + let inner = self.inner.ref_to_owned(); + + Int { inner } + } + } + + impl OwnedToRef for Int { + type Borrowed<'a> = IntRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + let inner = self.inner.owned_to_ref(); + + IntRef { inner } + } + } +} + +/// Ensure `INTEGER` is canonically encoded. +fn validate_canonical(bytes: &[u8]) -> Result<()> { + // The `INTEGER` type always encodes a signed value and we're decoding + // as signed here, so we allow a zero extension or sign extension byte, + // but only as permitted under DER canonicalization. + match bytes { + [] => Err(Tag::Integer.non_canonical_error()), + [0x00, byte, ..] if *byte < 0x80 => Err(Tag::Integer.non_canonical_error()), + [0xFF, byte, ..] if *byte >= 0x80 => Err(Tag::Integer.non_canonical_error()), + _ => Ok(()), + } +} + +/// Decode an signed integer of the specified size. +/// +/// Returns a byte array of the requested size containing a big endian integer. +fn decode_to_array<const N: usize>(bytes: &[u8]) -> Result<[u8; N]> { + match N.checked_sub(bytes.len()) { + Some(offset) => { + let mut output = [0xFFu8; N]; + output[offset..].copy_from_slice(bytes); + Ok(output) + } + None => { + let expected_len = Length::try_from(N)?; + let actual_len = Length::try_from(bytes.len())?; + + Err(ErrorKind::Incomplete { + expected_len, + actual_len, + } + .into()) + } + } +} + +/// Encode the given big endian bytes representing an integer as ASN.1 DER. +fn encode_bytes<W>(writer: &mut W, bytes: &[u8]) -> Result<()> +where + W: Writer + ?Sized, +{ + writer.write(strip_leading_ones(bytes)) +} + +/// Get the encoded length for the given **negative** integer serialized as bytes. +#[inline] +fn negative_encoded_len(bytes: &[u8]) -> Result<Length> { + Length::try_from(strip_leading_ones(bytes).len()) +} + +/// Strip the leading all-ones bytes from the given byte slice. +pub(crate) fn strip_leading_ones(mut bytes: &[u8]) -> &[u8] { + while let Some((byte, rest)) = bytes.split_first() { + if *byte == 0xFF && is_highest_bit_set(rest) { + bytes = rest; + continue; + } + + break; + } + + bytes +} + +#[cfg(test)] +mod tests { + use super::{validate_canonical, IntRef}; + use crate::{asn1::integer::tests::*, Decode, Encode, SliceWriter}; + + #[test] + fn validate_canonical_ok() { + assert_eq!(validate_canonical(&[0x00]), Ok(())); + assert_eq!(validate_canonical(&[0x01]), Ok(())); + assert_eq!(validate_canonical(&[0x00, 0x80]), Ok(())); + assert_eq!(validate_canonical(&[0xFF, 0x00]), Ok(())); + } + + #[test] + fn validate_canonical_err() { + // Empty integers are always non-canonical. + assert!(validate_canonical(&[]).is_err()); + + // Positives with excessive zero extension are non-canonical. + assert!(validate_canonical(&[0x00, 0x00]).is_err()); + + // Negatives with excessive sign extension are non-canonical. + assert!(validate_canonical(&[0xFF, 0x80]).is_err()); + } + + #[test] + fn decode_intref() { + // Positive numbers decode, but have zero extensions as necessary + // (to distinguish them from negative representations). + assert_eq!(&[0], IntRef::from_der(I0_BYTES).unwrap().as_bytes()); + assert_eq!(&[127], IntRef::from_der(I127_BYTES).unwrap().as_bytes()); + assert_eq!(&[0, 128], IntRef::from_der(I128_BYTES).unwrap().as_bytes()); + assert_eq!(&[0, 255], IntRef::from_der(I255_BYTES).unwrap().as_bytes()); + + assert_eq!( + &[0x01, 0x00], + IntRef::from_der(I256_BYTES).unwrap().as_bytes() + ); + + assert_eq!( + &[0x7F, 0xFF], + IntRef::from_der(I32767_BYTES).unwrap().as_bytes() + ); + + // Negative integers decode. + assert_eq!(&[128], IntRef::from_der(INEG128_BYTES).unwrap().as_bytes()); + assert_eq!( + &[255, 127], + IntRef::from_der(INEG129_BYTES).unwrap().as_bytes() + ); + assert_eq!( + &[128, 0], + IntRef::from_der(INEG32768_BYTES).unwrap().as_bytes() + ); + } + + #[test] + fn encode_intref() { + for &example in &[ + I0_BYTES, + I127_BYTES, + I128_BYTES, + I255_BYTES, + I256_BYTES, + I32767_BYTES, + ] { + let uint = IntRef::from_der(example).unwrap(); + + let mut buf = [0u8; 128]; + let mut encoder = SliceWriter::new(&mut buf); + uint.encode(&mut encoder).unwrap(); + + let result = encoder.finish().unwrap(); + assert_eq!(example, result); + } + + for &example in &[INEG128_BYTES, INEG129_BYTES, INEG32768_BYTES] { + let uint = IntRef::from_der(example).unwrap(); + + let mut buf = [0u8; 128]; + let mut encoder = SliceWriter::new(&mut buf); + uint.encode(&mut encoder).unwrap(); + + let result = encoder.finish().unwrap(); + assert_eq!(example, result); + } + } +} diff --git a/vendor/der/src/asn1/integer/uint.rs b/vendor/der/src/asn1/integer/uint.rs new file mode 100644 index 0000000..95c6297 --- /dev/null +++ b/vendor/der/src/asn1/integer/uint.rs @@ -0,0 +1,428 @@ +//! Unsigned integer decoders/encoders. + +use super::value_cmp; +use crate::{ + ord::OrdIsValueOrd, AnyRef, BytesRef, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, + Header, Length, Reader, Result, Tag, ValueOrd, Writer, +}; +use core::cmp::Ordering; + +#[cfg(feature = "alloc")] +pub use allocating::Uint; + +macro_rules! impl_encoding_traits { + ($($uint:ty),+) => { + $( + impl<'a> DecodeValue<'a> for $uint { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + // Integers always encodes as a signed value, unsigned gets a leading 0x00 that + // needs to be stripped off. We need to provide room for it. + const UNSIGNED_HEADROOM: usize = 1; + + let mut buf = [0u8; (Self::BITS as usize / 8) + UNSIGNED_HEADROOM]; + let max_length = u32::from(header.length) as usize; + + if max_length > buf.len() { + return Err(Self::TAG.non_canonical_error()); + } + + let bytes = reader.read_into(&mut buf[..max_length])?; + + let result = Self::from_be_bytes(decode_to_array(bytes)?); + + // Ensure we compute the same encoded length as the original any value + if header.length != result.value_len()? { + return Err(Self::TAG.non_canonical_error()); + } + + Ok(result) + } + } + + impl EncodeValue for $uint { + fn value_len(&self) -> Result<Length> { + encoded_len(&self.to_be_bytes()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + encode_bytes(writer, &self.to_be_bytes()) + } + } + + impl FixedTag for $uint { + const TAG: Tag = Tag::Integer; + } + + impl ValueOrd for $uint { + fn value_cmp(&self, other: &Self) -> Result<Ordering> { + value_cmp(*self, *other) + } + } + + impl TryFrom<AnyRef<'_>> for $uint { + type Error = Error; + + fn try_from(any: AnyRef<'_>) -> Result<Self> { + any.decode_as() + } + } + )+ + }; +} + +impl_encoding_traits!(u8, u16, u32, u64, u128); + +/// Unsigned arbitrary precision ASN.1 `INTEGER` reference type. +/// +/// Provides direct access to the underlying big endian bytes which comprise an +/// unsigned integer value. +/// +/// Intended for use cases like very large integers that are used in +/// cryptographic applications (e.g. keys, signatures). +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct UintRef<'a> { + /// Inner value + inner: BytesRef<'a>, +} + +impl<'a> UintRef<'a> { + /// Create a new [`UintRef`] from a byte slice. + pub fn new(bytes: &'a [u8]) -> Result<Self> { + let inner = BytesRef::new(strip_leading_zeroes(bytes)) + .map_err(|_| ErrorKind::Length { tag: Self::TAG })?; + + Ok(Self { inner }) + } + + /// Borrow the inner byte slice which contains the least significant bytes + /// of a big endian integer value with all leading zeros stripped. + pub fn as_bytes(&self) -> &'a [u8] { + self.inner.as_slice() + } + + /// Get the length of this [`UintRef`] in bytes. + pub fn len(&self) -> Length { + self.inner.len() + } + + /// Is the inner byte slice empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } +} + +impl_any_conversions!(UintRef<'a>, 'a); + +impl<'a> DecodeValue<'a> for UintRef<'a> { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + let bytes = BytesRef::decode_value(reader, header)?.as_slice(); + let result = Self::new(decode_to_slice(bytes)?)?; + + // Ensure we compute the same encoded length as the original any value. + if result.value_len()? != header.length { + return Err(Self::TAG.non_canonical_error()); + } + + Ok(result) + } +} + +impl<'a> EncodeValue for UintRef<'a> { + fn value_len(&self) -> Result<Length> { + encoded_len(self.inner.as_slice()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + // Add leading `0x00` byte if required + if self.value_len()? > self.len() { + writer.write_byte(0)?; + } + + writer.write(self.as_bytes()) + } +} + +impl<'a> From<&UintRef<'a>> for UintRef<'a> { + fn from(value: &UintRef<'a>) -> UintRef<'a> { + *value + } +} + +impl<'a> FixedTag for UintRef<'a> { + const TAG: Tag = Tag::Integer; +} + +impl<'a> OrdIsValueOrd for UintRef<'a> {} + +#[cfg(feature = "alloc")] +mod allocating { + use super::{decode_to_slice, encoded_len, strip_leading_zeroes, UintRef}; + use crate::{ + ord::OrdIsValueOrd, + referenced::{OwnedToRef, RefToOwned}, + BytesOwned, DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result, + Tag, Writer, + }; + + /// Unsigned arbitrary precision ASN.1 `INTEGER` type. + /// + /// Provides heap-allocated storage for big endian bytes which comprise an + /// unsigned integer value. + /// + /// Intended for use cases like very large integers that are used in + /// cryptographic applications (e.g. keys, signatures). + #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] + pub struct Uint { + /// Inner value + inner: BytesOwned, + } + + impl Uint { + /// Create a new [`Uint`] from a byte slice. + pub fn new(bytes: &[u8]) -> Result<Self> { + let inner = BytesOwned::new(strip_leading_zeroes(bytes)) + .map_err(|_| ErrorKind::Length { tag: Self::TAG })?; + + Ok(Self { inner }) + } + + /// Borrow the inner byte slice which contains the least significant bytes + /// of a big endian integer value with all leading zeros stripped. + pub fn as_bytes(&self) -> &[u8] { + self.inner.as_slice() + } + + /// Get the length of this [`Uint`] in bytes. + pub fn len(&self) -> Length { + self.inner.len() + } + + /// Is the inner byte slice empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + } + + impl_any_conversions!(Uint); + + impl<'a> DecodeValue<'a> for Uint { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + let bytes = BytesOwned::decode_value(reader, header)?; + let result = Self::new(decode_to_slice(bytes.as_slice())?)?; + + // Ensure we compute the same encoded length as the original any value. + if result.value_len()? != header.length { + return Err(Self::TAG.non_canonical_error()); + } + + Ok(result) + } + } + + impl EncodeValue for Uint { + fn value_len(&self) -> Result<Length> { + encoded_len(self.inner.as_slice()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + // Add leading `0x00` byte if required + if self.value_len()? > self.len() { + writer.write_byte(0)?; + } + + writer.write(self.as_bytes()) + } + } + + impl<'a> From<&UintRef<'a>> for Uint { + fn from(value: &UintRef<'a>) -> Uint { + let inner = BytesOwned::new(value.as_bytes()).expect("Invalid Uint"); + Uint { inner } + } + } + + impl FixedTag for Uint { + const TAG: Tag = Tag::Integer; + } + + impl OrdIsValueOrd for Uint {} + + impl<'a> RefToOwned<'a> for UintRef<'a> { + type Owned = Uint; + fn ref_to_owned(&self) -> Self::Owned { + let inner = self.inner.ref_to_owned(); + + Uint { inner } + } + } + + impl OwnedToRef for Uint { + type Borrowed<'a> = UintRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + let inner = self.inner.owned_to_ref(); + + UintRef { inner } + } + } +} + +/// Decode an unsigned integer into a big endian byte slice with all leading +/// zeroes removed. +/// +/// Returns a byte array of the requested size containing a big endian integer. +pub(crate) fn decode_to_slice(bytes: &[u8]) -> Result<&[u8]> { + // The `INTEGER` type always encodes a signed value, so for unsigned + // values the leading `0x00` byte may need to be removed. + // + // We also disallow a leading byte which would overflow a signed ASN.1 + // integer (since we're decoding an unsigned integer). + // We expect all such cases to have a leading `0x00` byte. + match bytes { + [] => Err(Tag::Integer.non_canonical_error()), + [0] => Ok(bytes), + [0, byte, ..] if *byte < 0x80 => Err(Tag::Integer.non_canonical_error()), + [0, rest @ ..] => Ok(rest), + [byte, ..] if *byte >= 0x80 => Err(Tag::Integer.value_error()), + _ => Ok(bytes), + } +} + +/// Decode an unsigned integer into a byte array of the requested size +/// containing a big endian integer. +pub(super) fn decode_to_array<const N: usize>(bytes: &[u8]) -> Result<[u8; N]> { + let input = decode_to_slice(bytes)?; + + // Compute number of leading zeroes to add + let num_zeroes = N + .checked_sub(input.len()) + .ok_or_else(|| Tag::Integer.length_error())?; + + // Copy input into `N`-sized output buffer with leading zeroes + let mut output = [0u8; N]; + output[num_zeroes..].copy_from_slice(input); + Ok(output) +} + +/// Encode the given big endian bytes representing an integer as ASN.1 DER. +pub(crate) fn encode_bytes<W>(encoder: &mut W, bytes: &[u8]) -> Result<()> +where + W: Writer + ?Sized, +{ + let bytes = strip_leading_zeroes(bytes); + + if needs_leading_zero(bytes) { + encoder.write_byte(0)?; + } + + encoder.write(bytes) +} + +/// Get the encoded length for the given unsigned integer serialized as bytes. +#[inline] +pub(crate) fn encoded_len(bytes: &[u8]) -> Result<Length> { + let bytes = strip_leading_zeroes(bytes); + Length::try_from(bytes.len())? + u8::from(needs_leading_zero(bytes)) +} + +/// Strip the leading zeroes from the given byte slice +pub(crate) fn strip_leading_zeroes(mut bytes: &[u8]) -> &[u8] { + while let Some((byte, rest)) = bytes.split_first() { + if *byte == 0 && !rest.is_empty() { + bytes = rest; + } else { + break; + } + } + + bytes +} + +/// Does the given integer need a leading zero? +fn needs_leading_zero(bytes: &[u8]) -> bool { + matches!(bytes.first(), Some(byte) if *byte >= 0x80) +} + +#[cfg(test)] +mod tests { + use super::{decode_to_array, UintRef}; + use crate::{asn1::integer::tests::*, AnyRef, Decode, Encode, ErrorKind, SliceWriter, Tag}; + + #[test] + fn decode_to_array_no_leading_zero() { + let arr = decode_to_array::<4>(&[1, 2]).unwrap(); + assert_eq!(arr, [0, 0, 1, 2]); + } + + #[test] + fn decode_to_array_leading_zero() { + let arr = decode_to_array::<4>(&[0x00, 0xFF, 0xFE]).unwrap(); + assert_eq!(arr, [0x00, 0x00, 0xFF, 0xFE]); + } + + #[test] + fn decode_to_array_extra_zero() { + let err = decode_to_array::<4>(&[0, 1, 2]).err().unwrap(); + assert_eq!(err.kind(), ErrorKind::Noncanonical { tag: Tag::Integer }); + } + + #[test] + fn decode_to_array_missing_zero() { + // We're decoding an unsigned integer, but this value would be signed + let err = decode_to_array::<4>(&[0xFF, 0xFE]).err().unwrap(); + assert_eq!(err.kind(), ErrorKind::Value { tag: Tag::Integer }); + } + + #[test] + fn decode_to_array_oversized_input() { + let err = decode_to_array::<1>(&[1, 2, 3]).err().unwrap(); + assert_eq!(err.kind(), ErrorKind::Length { tag: Tag::Integer }); + } + + #[test] + fn decode_uintref() { + assert_eq!(&[0], UintRef::from_der(I0_BYTES).unwrap().as_bytes()); + assert_eq!(&[127], UintRef::from_der(I127_BYTES).unwrap().as_bytes()); + assert_eq!(&[128], UintRef::from_der(I128_BYTES).unwrap().as_bytes()); + assert_eq!(&[255], UintRef::from_der(I255_BYTES).unwrap().as_bytes()); + + assert_eq!( + &[0x01, 0x00], + UintRef::from_der(I256_BYTES).unwrap().as_bytes() + ); + + assert_eq!( + &[0x7F, 0xFF], + UintRef::from_der(I32767_BYTES).unwrap().as_bytes() + ); + } + + #[test] + fn encode_uintref() { + for &example in &[ + I0_BYTES, + I127_BYTES, + I128_BYTES, + I255_BYTES, + I256_BYTES, + I32767_BYTES, + ] { + let uint = UintRef::from_der(example).unwrap(); + + let mut buf = [0u8; 128]; + let mut encoder = SliceWriter::new(&mut buf); + uint.encode(&mut encoder).unwrap(); + + let result = encoder.finish().unwrap(); + assert_eq!(example, result); + } + } + + #[test] + fn reject_oversize_without_extra_zero() { + let err = UintRef::try_from(AnyRef::new(Tag::Integer, &[0x81]).unwrap()) + .err() + .unwrap(); + + assert_eq!(err.kind(), ErrorKind::Value { tag: Tag::Integer }); + } +} |