diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
commit | 2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4 (patch) | |
tree | 033cc839730fda84ff08db877037977be94e5e3a /vendor/der/src/asn1 | |
parent | Initial commit. (diff) | |
download | cargo-upstream.tar.xz cargo-upstream.zip |
Adding upstream version 0.70.1+ds1.upstream/0.70.1+ds1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/der/src/asn1')
25 files changed, 6434 insertions, 0 deletions
diff --git a/vendor/der/src/asn1/any.rs b/vendor/der/src/asn1/any.rs new file mode 100644 index 0000000..017a909 --- /dev/null +++ b/vendor/der/src/asn1/any.rs @@ -0,0 +1,315 @@ +//! ASN.1 `ANY` type. + +#![cfg_attr(feature = "arbitrary", allow(clippy::integer_arithmetic))] + +use crate::{ + BytesRef, Choice, Decode, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind, Header, Length, + Reader, Result, SliceReader, Tag, Tagged, ValueOrd, Writer, +}; +use core::cmp::Ordering; + +#[cfg(feature = "alloc")] +use crate::SliceWriter; + +/// ASN.1 `ANY`: represents any explicitly tagged ASN.1 value. +/// +/// This is a zero-copy reference type which borrows from the input data. +/// +/// Technically `ANY` hasn't been a recommended part of ASN.1 since the X.209 +/// revision from 1988. It was deprecated and replaced by Information Object +/// Classes in X.680 in 1994, and X.690 no longer refers to it whatsoever. +/// +/// Nevertheless, this crate defines an `ANY` type as it remains a familiar +/// and useful concept which is still extensively used in things like +/// PKI-related RFCs. +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct AnyRef<'a> { + /// Tag representing the type of the encoded value. + tag: Tag, + + /// Inner value encoded as bytes. + value: BytesRef<'a>, +} + +impl<'a> AnyRef<'a> { + /// [`AnyRef`] representation of the ASN.1 `NULL` type. + pub const NULL: Self = Self { + tag: Tag::Null, + value: BytesRef::EMPTY, + }; + + /// Create a new [`AnyRef`] from the provided [`Tag`] and DER bytes. + pub fn new(tag: Tag, bytes: &'a [u8]) -> Result<Self> { + let value = BytesRef::new(bytes).map_err(|_| ErrorKind::Length { tag })?; + Ok(Self { tag, value }) + } + + /// Infallible creation of an [`AnyRef`] from a [`BytesRef`]. + pub(crate) fn from_tag_and_value(tag: Tag, value: BytesRef<'a>) -> Self { + Self { tag, value } + } + + /// Get the raw value for this [`AnyRef`] type as a byte slice. + pub fn value(self) -> &'a [u8] { + self.value.as_slice() + } + + /// Attempt to decode this [`AnyRef`] type into the inner value. + pub fn decode_as<T>(self) -> Result<T> + where + T: Choice<'a> + DecodeValue<'a>, + { + if !T::can_decode(self.tag) { + return Err(self.tag.unexpected_error(None)); + } + + let header = Header { + tag: self.tag, + length: self.value.len(), + }; + + let mut decoder = SliceReader::new(self.value())?; + let result = T::decode_value(&mut decoder, header)?; + decoder.finish(result) + } + + /// Is this value an ASN.1 `NULL` value? + pub fn is_null(self) -> bool { + self == Self::NULL + } + + /// Attempt to decode this value an ASN.1 `SEQUENCE`, creating a new + /// nested reader and calling the provided argument with it. + pub fn sequence<F, T>(self, f: F) -> Result<T> + where + F: FnOnce(&mut SliceReader<'a>) -> Result<T>, + { + self.tag.assert_eq(Tag::Sequence)?; + let mut reader = SliceReader::new(self.value.as_slice())?; + let result = f(&mut reader)?; + reader.finish(result) + } +} + +impl<'a> Choice<'a> for AnyRef<'a> { + fn can_decode(_: Tag) -> bool { + true + } +} + +impl<'a> Decode<'a> for AnyRef<'a> { + fn decode<R: Reader<'a>>(reader: &mut R) -> Result<AnyRef<'a>> { + let header = Header::decode(reader)?; + Self::decode_value(reader, header) + } +} + +impl<'a> DecodeValue<'a> for AnyRef<'a> { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + Ok(Self { + tag: header.tag, + value: BytesRef::decode_value(reader, header)?, + }) + } +} + +impl EncodeValue for AnyRef<'_> { + fn value_len(&self) -> Result<Length> { + Ok(self.value.len()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.value()) + } +} + +impl Tagged for AnyRef<'_> { + fn tag(&self) -> Tag { + self.tag + } +} + +impl ValueOrd for AnyRef<'_> { + fn value_cmp(&self, other: &Self) -> Result<Ordering> { + self.value.der_cmp(&other.value) + } +} + +impl<'a> From<AnyRef<'a>> for BytesRef<'a> { + fn from(any: AnyRef<'a>) -> BytesRef<'a> { + any.value + } +} + +impl<'a> TryFrom<&'a [u8]> for AnyRef<'a> { + type Error = Error; + + fn try_from(bytes: &'a [u8]) -> Result<AnyRef<'a>> { + AnyRef::from_der(bytes) + } +} + +#[cfg(feature = "alloc")] +pub use self::allocating::Any; + +#[cfg(feature = "alloc")] +mod allocating { + use super::*; + use crate::{referenced::*, BytesOwned}; + use alloc::boxed::Box; + + /// ASN.1 `ANY`: represents any explicitly tagged ASN.1 value. + /// + /// This type provides the same functionality as [`AnyRef`] but owns the + /// backing data. + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] + #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] + pub struct Any { + /// Tag representing the type of the encoded value. + tag: Tag, + + /// Inner value encoded as bytes. + value: BytesOwned, + } + + impl Any { + /// Create a new [`Any`] from the provided [`Tag`] and DER bytes. + pub fn new(tag: Tag, bytes: impl Into<Box<[u8]>>) -> Result<Self> { + let value = BytesOwned::new(bytes)?; + + // Ensure the tag and value are a valid `AnyRef`. + AnyRef::new(tag, value.as_slice())?; + Ok(Self { tag, value }) + } + + /// Allow access to value + pub fn value(&self) -> &[u8] { + self.value.as_slice() + } + + /// Attempt to decode this [`Any`] type into the inner value. + pub fn decode_as<'a, T>(&'a self) -> Result<T> + where + T: Choice<'a> + DecodeValue<'a>, + { + AnyRef::from(self).decode_as() + } + + /// Encode the provided type as an [`Any`] value. + pub fn encode_from<T>(msg: &T) -> Result<Self> + where + T: Tagged + EncodeValue, + { + let encoded_len = usize::try_from(msg.value_len()?)?; + let mut buf = vec![0u8; encoded_len]; + let mut writer = SliceWriter::new(&mut buf); + msg.encode_value(&mut writer)?; + writer.finish()?; + Any::new(msg.tag(), buf) + } + + /// Attempt to decode this value an ASN.1 `SEQUENCE`, creating a new + /// nested reader and calling the provided argument with it. + pub fn sequence<'a, F, T>(&'a self, f: F) -> Result<T> + where + F: FnOnce(&mut SliceReader<'a>) -> Result<T>, + { + AnyRef::from(self).sequence(f) + } + + /// [`Any`] representation of the ASN.1 `NULL` type. + pub fn null() -> Self { + Self { + tag: Tag::Null, + value: BytesOwned::default(), + } + } + } + + impl Choice<'_> for Any { + fn can_decode(_: Tag) -> bool { + true + } + } + + impl<'a> Decode<'a> for Any { + fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self> { + let header = Header::decode(reader)?; + Self::decode_value(reader, header) + } + } + + impl<'a> DecodeValue<'a> for Any { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + let value = reader.read_vec(header.length)?; + Self::new(header.tag, value) + } + } + + impl EncodeValue for Any { + fn value_len(&self) -> Result<Length> { + Ok(self.value.len()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.value.as_slice()) + } + } + + impl<'a> From<&'a Any> for AnyRef<'a> { + fn from(any: &'a Any) -> AnyRef<'a> { + // Ensured to parse successfully in constructor + AnyRef::new(any.tag, any.value.as_slice()).expect("invalid ANY") + } + } + + impl Tagged for Any { + fn tag(&self) -> Tag { + self.tag + } + } + + impl ValueOrd for Any { + fn value_cmp(&self, other: &Self) -> Result<Ordering> { + self.value.der_cmp(&other.value) + } + } + + impl<'a, T> From<T> for Any + where + T: Into<AnyRef<'a>>, + { + fn from(input: T) -> Any { + let anyref: AnyRef<'a> = input.into(); + Self { + tag: anyref.tag(), + value: BytesOwned::from(anyref.value), + } + } + } + + impl<'a> RefToOwned<'a> for AnyRef<'a> { + type Owned = Any; + fn ref_to_owned(&self) -> Self::Owned { + Any { + tag: self.tag(), + value: BytesOwned::from(self.value), + } + } + } + + impl OwnedToRef for Any { + type Borrowed<'a> = AnyRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + self.into() + } + } + + impl Any { + /// Is this value an ASN.1 `NULL` value? + pub fn is_null(&self) -> bool { + self.owned_to_ref() == AnyRef::NULL + } + } +} diff --git a/vendor/der/src/asn1/bit_string.rs b/vendor/der/src/asn1/bit_string.rs new file mode 100644 index 0000000..bf3371c --- /dev/null +++ b/vendor/der/src/asn1/bit_string.rs @@ -0,0 +1,552 @@ +//! ASN.1 `BIT STRING` support. + +use crate::{ + BytesRef, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, + Result, Tag, ValueOrd, Writer, +}; +use core::{cmp::Ordering, iter::FusedIterator}; + +/// ASN.1 `BIT STRING` type. +/// +/// This type contains a sequence of any number of bits, modeled internally as +/// a sequence of bytes with a known number of "unused bits". +/// +/// This is a zero-copy reference type which borrows from the input data. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct BitStringRef<'a> { + /// Number of unused bits in the final octet. + unused_bits: u8, + + /// Length of this `BIT STRING` in bits. + bit_length: usize, + + /// Bitstring represented as a slice of bytes. + inner: BytesRef<'a>, +} + +impl<'a> BitStringRef<'a> { + /// Maximum number of unused bits allowed. + pub const MAX_UNUSED_BITS: u8 = 7; + + /// Create a new ASN.1 `BIT STRING` from a byte slice. + /// + /// Accepts an optional number of "unused bits" (0-7) which are omitted + /// from the final octet. This number is 0 if the value is octet-aligned. + pub fn new(unused_bits: u8, bytes: &'a [u8]) -> Result<Self> { + if (unused_bits > Self::MAX_UNUSED_BITS) || (unused_bits != 0 && bytes.is_empty()) { + return Err(Self::TAG.value_error()); + } + + let inner = BytesRef::new(bytes).map_err(|_| Self::TAG.length_error())?; + + let bit_length = usize::try_from(inner.len())? + .checked_mul(8) + .and_then(|n| n.checked_sub(usize::from(unused_bits))) + .ok_or(ErrorKind::Overflow)?; + + Ok(Self { + unused_bits, + bit_length, + inner, + }) + } + + /// Create a new ASN.1 `BIT STRING` from the given bytes. + /// + /// The "unused bits" are set to 0. + pub fn from_bytes(bytes: &'a [u8]) -> Result<Self> { + Self::new(0, bytes) + } + + /// Get the number of unused bits in this byte slice. + pub fn unused_bits(&self) -> u8 { + self.unused_bits + } + + /// Is the number of unused bits a value other than 0? + pub fn has_unused_bits(&self) -> bool { + self.unused_bits != 0 + } + + /// Get the length of this `BIT STRING` in bits. + pub fn bit_len(&self) -> usize { + self.bit_length + } + + /// Get the number of bytes/octets needed to represent this `BIT STRING` + /// when serialized in an octet-aligned manner. + pub fn byte_len(&self) -> Length { + self.inner.len() + } + + /// Is the inner byte slice empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + /// Borrow the inner byte slice. + /// + /// Returns `None` if the number of unused bits is *not* equal to zero, + /// i.e. if the `BIT STRING` is not octet aligned. + /// + /// Use [`BitString::raw_bytes`] to obtain access to the raw value + /// regardless of the presence of unused bits. + pub fn as_bytes(&self) -> Option<&'a [u8]> { + if self.has_unused_bits() { + None + } else { + Some(self.raw_bytes()) + } + } + + /// Borrow the raw bytes of this `BIT STRING`. + /// + /// Note that the byte string may contain extra unused bits in the final + /// octet. If the number of unused bits is expected to be 0, the + /// [`BitStringRef::as_bytes`] function can be used instead. + pub fn raw_bytes(&self) -> &'a [u8] { + self.inner.as_slice() + } + + /// Iterator over the bits of this `BIT STRING`. + pub fn bits(self) -> BitStringIter<'a> { + BitStringIter { + bit_string: self, + position: 0, + } + } +} + +impl_any_conversions!(BitStringRef<'a>, 'a); + +impl<'a> DecodeValue<'a> for BitStringRef<'a> { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + let header = Header { + tag: header.tag, + length: (header.length - Length::ONE)?, + }; + + let unused_bits = reader.read_byte()?; + let inner = BytesRef::decode_value(reader, header)?; + Self::new(unused_bits, inner.as_slice()) + } +} + +impl EncodeValue for BitStringRef<'_> { + fn value_len(&self) -> Result<Length> { + self.byte_len() + Length::ONE + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write_byte(self.unused_bits)?; + writer.write(self.raw_bytes()) + } +} + +impl ValueOrd for BitStringRef<'_> { + fn value_cmp(&self, other: &Self) -> Result<Ordering> { + match self.unused_bits.cmp(&other.unused_bits) { + Ordering::Equal => self.inner.der_cmp(&other.inner), + ordering => Ok(ordering), + } + } +} + +impl<'a> From<&BitStringRef<'a>> for BitStringRef<'a> { + fn from(value: &BitStringRef<'a>) -> BitStringRef<'a> { + *value + } +} + +impl<'a> TryFrom<&'a [u8]> for BitStringRef<'a> { + type Error = Error; + + fn try_from(bytes: &'a [u8]) -> Result<BitStringRef<'a>> { + BitStringRef::from_bytes(bytes) + } +} + +/// Hack for simplifying the custom derive use case. +impl<'a> TryFrom<&&'a [u8]> for BitStringRef<'a> { + type Error = Error; + + fn try_from(bytes: &&'a [u8]) -> Result<BitStringRef<'a>> { + BitStringRef::from_bytes(bytes) + } +} + +impl<'a> TryFrom<BitStringRef<'a>> for &'a [u8] { + type Error = Error; + + fn try_from(bit_string: BitStringRef<'a>) -> Result<&'a [u8]> { + bit_string + .as_bytes() + .ok_or_else(|| Tag::BitString.value_error()) + } +} + +impl<'a> FixedTag for BitStringRef<'a> { + const TAG: Tag = Tag::BitString; +} + +// Implement by hand because the derive would create invalid values. +// Use the constructor to create a valid value. +#[cfg(feature = "arbitrary")] +impl<'a> arbitrary::Arbitrary<'a> for BitStringRef<'a> { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { + Self::new( + u.int_in_range(0..=Self::MAX_UNUSED_BITS)?, + BytesRef::arbitrary(u)?.as_slice(), + ) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } + + fn size_hint(depth: usize) -> (usize, Option<usize>) { + arbitrary::size_hint::and(u8::size_hint(depth), BytesRef::size_hint(depth)) + } +} + +#[cfg(feature = "alloc")] +pub use self::allocating::BitString; + +#[cfg(feature = "alloc")] +mod allocating { + use super::*; + use crate::referenced::*; + use alloc::vec::Vec; + + /// Owned form of ASN.1 `BIT STRING` type. + /// + /// This type provides the same functionality as [`BitStringRef`] but owns the + /// backing data. + #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] + pub struct BitString { + /// Number of unused bits in the final octet. + unused_bits: u8, + + /// Length of this `BIT STRING` in bits. + bit_length: usize, + + /// Bitstring represented as a slice of bytes. + inner: Vec<u8>, + } + + impl BitString { + /// Maximum number of unused bits allowed. + pub const MAX_UNUSED_BITS: u8 = 7; + + /// Create a new ASN.1 `BIT STRING` from a byte slice. + /// + /// Accepts an optional number of "unused bits" (0-7) which are omitted + /// from the final octet. This number is 0 if the value is octet-aligned. + pub fn new(unused_bits: u8, bytes: impl Into<Vec<u8>>) -> Result<Self> { + let inner = bytes.into(); + + // Ensure parameters parse successfully as a `BitStringRef`. + let bit_length = BitStringRef::new(unused_bits, &inner)?.bit_length; + + Ok(BitString { + unused_bits, + bit_length, + inner, + }) + } + + /// Create a new ASN.1 `BIT STRING` from the given bytes. + /// + /// The "unused bits" are set to 0. + pub fn from_bytes(bytes: &[u8]) -> Result<Self> { + Self::new(0, bytes) + } + + /// Get the number of unused bits in the octet serialization of this + /// `BIT STRING`. + pub fn unused_bits(&self) -> u8 { + self.unused_bits + } + + /// Is the number of unused bits a value other than 0? + pub fn has_unused_bits(&self) -> bool { + self.unused_bits != 0 + } + + /// Get the length of this `BIT STRING` in bits. + pub fn bit_len(&self) -> usize { + self.bit_length + } + + /// Is the inner byte slice empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + /// Borrow the inner byte slice. + /// + /// Returns `None` if the number of unused bits is *not* equal to zero, + /// i.e. if the `BIT STRING` is not octet aligned. + /// + /// Use [`BitString::raw_bytes`] to obtain access to the raw value + /// regardless of the presence of unused bits. + pub fn as_bytes(&self) -> Option<&[u8]> { + if self.has_unused_bits() { + None + } else { + Some(self.raw_bytes()) + } + } + + /// Borrow the raw bytes of this `BIT STRING`. + pub fn raw_bytes(&self) -> &[u8] { + self.inner.as_slice() + } + + /// Iterator over the bits of this `BIT STRING`. + pub fn bits(&self) -> BitStringIter<'_> { + BitStringRef::from(self).bits() + } + } + + impl_any_conversions!(BitString); + + impl<'a> DecodeValue<'a> for BitString { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + let inner_len = (header.length - Length::ONE)?; + let unused_bits = reader.read_byte()?; + let inner = reader.read_vec(inner_len)?; + Self::new(unused_bits, inner) + } + } + + impl EncodeValue for BitString { + fn value_len(&self) -> Result<Length> { + Length::ONE + Length::try_from(self.inner.len())? + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write_byte(self.unused_bits)?; + writer.write(&self.inner) + } + } + + impl FixedTag for BitString { + const TAG: Tag = Tag::BitString; + } + + impl<'a> From<&'a BitString> for BitStringRef<'a> { + fn from(bit_string: &'a BitString) -> BitStringRef<'a> { + // Ensured to parse successfully in constructor + BitStringRef::new(bit_string.unused_bits, &bit_string.inner) + .expect("invalid BIT STRING") + } + } + + impl ValueOrd for BitString { + fn value_cmp(&self, other: &Self) -> Result<Ordering> { + match self.unused_bits.cmp(&other.unused_bits) { + Ordering::Equal => self.inner.der_cmp(&other.inner), + ordering => Ok(ordering), + } + } + } + + // Implement by hand because the derive would create invalid values. + // Use the constructor to create a valid value. + #[cfg(feature = "arbitrary")] + impl<'a> arbitrary::Arbitrary<'a> for BitString { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { + Self::new( + u.int_in_range(0..=Self::MAX_UNUSED_BITS)?, + BytesRef::arbitrary(u)?.as_slice(), + ) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } + + fn size_hint(depth: usize) -> (usize, Option<usize>) { + arbitrary::size_hint::and(u8::size_hint(depth), BytesRef::size_hint(depth)) + } + } + + impl<'a> RefToOwned<'a> for BitStringRef<'a> { + type Owned = BitString; + fn ref_to_owned(&self) -> Self::Owned { + BitString { + unused_bits: self.unused_bits, + bit_length: self.bit_length, + inner: Vec::from(self.inner.as_slice()), + } + } + } + + impl OwnedToRef for BitString { + type Borrowed<'a> = BitStringRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + self.into() + } + } +} + +/// Iterator over the bits of a [`BitString`]. +pub struct BitStringIter<'a> { + /// [`BitString`] being iterated over. + bit_string: BitStringRef<'a>, + + /// Current bit position within the iterator. + position: usize, +} + +impl<'a> Iterator for BitStringIter<'a> { + type Item = bool; + + #[allow(clippy::integer_arithmetic)] + fn next(&mut self) -> Option<bool> { + if self.position >= self.bit_string.bit_len() { + return None; + } + + let byte = self.bit_string.raw_bytes().get(self.position / 8)?; + let bit = 1u8 << (7 - (self.position % 8)); + self.position = self.position.checked_add(1)?; + Some(byte & bit != 0) + } +} + +impl<'a> ExactSizeIterator for BitStringIter<'a> { + fn len(&self) -> usize { + self.bit_string.bit_len() + } +} + +impl<'a> FusedIterator for BitStringIter<'a> {} + +#[cfg(feature = "flagset")] +impl<T: flagset::Flags> FixedTag for flagset::FlagSet<T> { + const TAG: Tag = BitStringRef::TAG; +} + +#[cfg(feature = "flagset")] +impl<T> ValueOrd for flagset::FlagSet<T> +where + T: flagset::Flags, + T::Type: Ord, +{ + fn value_cmp(&self, other: &Self) -> Result<Ordering> { + Ok(self.bits().cmp(&other.bits())) + } +} + +#[cfg(feature = "flagset")] +#[allow(clippy::integer_arithmetic)] +impl<'a, T> DecodeValue<'a> for flagset::FlagSet<T> +where + T: flagset::Flags, + T::Type: From<bool>, + T::Type: core::ops::Shl<usize, Output = T::Type>, +{ + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + let position = reader.position(); + let bits = BitStringRef::decode_value(reader, header)?; + + let mut flags = T::none().bits(); + + if bits.bit_len() > core::mem::size_of_val(&flags) * 8 { + return Err(Error::new(ErrorKind::Overlength, position)); + } + + for (i, bit) in bits.bits().enumerate() { + flags |= T::Type::from(bit) << i; + } + + Ok(Self::new_truncated(flags)) + } +} + +#[cfg(feature = "flagset")] +#[allow(clippy::integer_arithmetic)] +#[inline(always)] +fn encode_flagset<T>(set: &flagset::FlagSet<T>) -> (usize, [u8; 16]) +where + T: flagset::Flags, + u128: From<T::Type>, +{ + let bits: u128 = set.bits().into(); + let mut swap = 0u128; + + for i in 0..128 { + let on = bits & (1 << i); + swap |= on >> i << (128 - i - 1); + } + + (bits.leading_zeros() as usize, swap.to_be_bytes()) +} + +#[cfg(feature = "flagset")] +#[allow(clippy::cast_possible_truncation, clippy::integer_arithmetic)] +impl<T: flagset::Flags> EncodeValue for flagset::FlagSet<T> +where + T::Type: From<bool>, + T::Type: core::ops::Shl<usize, Output = T::Type>, + u128: From<T::Type>, +{ + fn value_len(&self) -> Result<Length> { + let (lead, buff) = encode_flagset(self); + let buff = &buff[..buff.len() - lead / 8]; + BitStringRef::new((lead % 8) as u8, buff)?.value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + let (lead, buff) = encode_flagset(self); + let buff = &buff[..buff.len() - lead / 8]; + BitStringRef::new((lead % 8) as u8, buff)?.encode_value(writer) + } +} + +#[cfg(test)] +mod tests { + use super::{BitStringRef, Result, Tag}; + use crate::asn1::AnyRef; + use hex_literal::hex; + + /// Parse a `BitString` from an ASN.1 `Any` value to test decoding behaviors. + fn parse_bitstring(bytes: &[u8]) -> Result<BitStringRef<'_>> { + AnyRef::new(Tag::BitString, bytes)?.try_into() + } + + #[test] + fn decode_empty_bitstring() { + let bs = parse_bitstring(&hex!("00")).unwrap(); + assert_eq!(bs.as_bytes().unwrap(), &[]); + } + + #[test] + fn decode_non_empty_bitstring() { + let bs = parse_bitstring(&hex!("00010203")).unwrap(); + assert_eq!(bs.as_bytes().unwrap(), &[0x01, 0x02, 0x03]); + } + + #[test] + fn decode_bitstring_with_unused_bits() { + let bs = parse_bitstring(&hex!("066e5dc0")).unwrap(); + assert_eq!(bs.unused_bits(), 6); + assert_eq!(bs.raw_bytes(), &hex!("6e5dc0")); + + // Expected: 011011100101110111 + let mut bits = bs.bits(); + assert_eq!(bits.len(), 18); + + for bit in [0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1] { + assert_eq!(u8::from(bits.next().unwrap()), bit) + } + + // Ensure `None` is returned on successive calls + assert_eq!(bits.next(), None); + assert_eq!(bits.next(), None); + } + + #[test] + fn reject_unused_bits_in_empty_string() { + assert_eq!( + parse_bitstring(&[0x03]).err().unwrap().kind(), + Tag::BitString.value_error().kind() + ) + } +} diff --git a/vendor/der/src/asn1/bmp_string.rs b/vendor/der/src/asn1/bmp_string.rs new file mode 100644 index 0000000..b4135d5 --- /dev/null +++ b/vendor/der/src/asn1/bmp_string.rs @@ -0,0 +1,164 @@ +//! ASN.1 `BMPString` support. + +use crate::{ + BytesOwned, DecodeValue, EncodeValue, Error, FixedTag, Header, Length, Reader, Result, Tag, + Writer, +}; +use alloc::{boxed::Box, vec::Vec}; +use core::{fmt, str::FromStr}; + +/// ASN.1 `BMPString` type. +/// +/// Encodes Basic Multilingual Plane (BMP) subset of Unicode (ISO 10646), +/// a.k.a. UCS-2. +#[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] +pub struct BmpString { + bytes: BytesOwned, +} + +impl BmpString { + /// Create a new [`BmpString`] from its UCS-2 encoding. + pub fn from_ucs2(bytes: impl Into<Box<[u8]>>) -> Result<Self> { + let bytes = bytes.into(); + + if bytes.len() % 2 != 0 { + return Err(Tag::BmpString.length_error()); + } + + let ret = Self { + bytes: bytes.try_into()?, + }; + + for maybe_char in char::decode_utf16(ret.codepoints()) { + match maybe_char { + // All surrogates paired and character is in the Basic Multilingual Plane + Ok(c) if (c as u64) < u64::from(u16::MAX) => (), + // Unpaired surrogates or characters outside Basic Multilingual Plane + _ => return Err(Tag::BmpString.value_error()), + } + } + + Ok(ret) + } + + /// Create a new [`BmpString`] from a UTF-8 string. + pub fn from_utf8(utf8: &str) -> Result<Self> { + let capacity = utf8 + .len() + .checked_mul(2) + .ok_or_else(|| Tag::BmpString.length_error())?; + + let mut bytes = Vec::with_capacity(capacity); + + for code_point in utf8.encode_utf16() { + bytes.extend(code_point.to_be_bytes()); + } + + Self::from_ucs2(bytes) + } + + /// Borrow the encoded UCS-2 as bytes. + pub fn as_bytes(&self) -> &[u8] { + self.bytes.as_ref() + } + + /// Obtain the inner bytes. + #[inline] + pub fn into_bytes(self) -> Box<[u8]> { + self.bytes.into() + } + + /// Get an iterator over characters in the string. + pub fn chars(&self) -> impl Iterator<Item = char> + '_ { + char::decode_utf16(self.codepoints()) + .map(|maybe_char| maybe_char.expect("unpaired surrogates checked in constructor")) + } + + /// Get an iterator over the `u16` codepoints. + pub fn codepoints(&self) -> impl Iterator<Item = u16> + '_ { + // TODO(tarcieri): use `array_chunks` + self.as_bytes() + .chunks_exact(2) + .map(|chunk| u16::from_be_bytes([chunk[0], chunk[1]])) + } +} + +impl AsRef<[u8]> for BmpString { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<'a> DecodeValue<'a> for BmpString { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + Self::from_ucs2(reader.read_vec(header.length)?) + } +} + +impl EncodeValue for BmpString { + fn value_len(&self) -> Result<Length> { + Ok(self.bytes.len()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.as_bytes()) + } +} + +impl FixedTag for BmpString { + const TAG: Tag = Tag::BmpString; +} + +impl FromStr for BmpString { + type Err = Error; + + fn from_str(s: &str) -> Result<Self> { + Self::from_utf8(s) + } +} + +impl fmt::Debug for BmpString { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "BmpString(\"{}\")", self) + } +} + +impl fmt::Display for BmpString { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for c in self.chars() { + write!(f, "{}", c)?; + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::BmpString; + use crate::{Decode, Encode}; + use alloc::string::ToString; + use hex_literal::hex; + + const EXAMPLE_BYTES: &[u8] = &hex!( + "1e 26 00 43 00 65 00 72 00 74" + " 00 69 00 66 00 69 00 63" + " 00 61 00 74 00 65 00 54" + " 00 65 00 6d 00 70 00 6c" + " 00 61 00 74 00 65" + ); + + const EXAMPLE_UTF8: &str = "CertificateTemplate"; + + #[test] + fn decode() { + let bmp_string = BmpString::from_der(EXAMPLE_BYTES).unwrap(); + assert_eq!(bmp_string.to_string(), EXAMPLE_UTF8); + } + + #[test] + fn encode() { + let bmp_string = BmpString::from_utf8(EXAMPLE_UTF8).unwrap(); + let encoded = bmp_string.to_der().unwrap(); + assert_eq!(encoded, EXAMPLE_BYTES); + } +} diff --git a/vendor/der/src/asn1/boolean.rs b/vendor/der/src/asn1/boolean.rs new file mode 100644 index 0000000..3eb0f2e --- /dev/null +++ b/vendor/der/src/asn1/boolean.rs @@ -0,0 +1,82 @@ +//! ASN.1 `BOOLEAN` support. + +use crate::{ + asn1::AnyRef, ord::OrdIsValueOrd, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, + Length, Reader, Result, Tag, Writer, +}; + +/// Byte used to encode `true` in ASN.1 DER. From X.690 Section 11.1: +/// +/// > If the encoding represents the boolean value TRUE, its single contents +/// > octet shall have all eight bits set to one. +const TRUE_OCTET: u8 = 0b11111111; + +/// Byte used to encode `false` in ASN.1 DER. +const FALSE_OCTET: u8 = 0b00000000; + +impl<'a> DecodeValue<'a> for bool { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + if header.length != Length::ONE { + return Err(reader.error(ErrorKind::Length { tag: Self::TAG })); + } + + match reader.read_byte()? { + FALSE_OCTET => Ok(false), + TRUE_OCTET => Ok(true), + _ => Err(Self::TAG.non_canonical_error()), + } + } +} + +impl EncodeValue for bool { + fn value_len(&self) -> Result<Length> { + Ok(Length::ONE) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write_byte(if *self { TRUE_OCTET } else { FALSE_OCTET }) + } +} + +impl FixedTag for bool { + const TAG: Tag = Tag::Boolean; +} + +impl OrdIsValueOrd for bool {} + +impl TryFrom<AnyRef<'_>> for bool { + type Error = Error; + + fn try_from(any: AnyRef<'_>) -> Result<bool> { + any.try_into() + } +} + +#[cfg(test)] +mod tests { + use crate::{Decode, Encode}; + + #[test] + fn decode() { + assert_eq!(true, bool::from_der(&[0x01, 0x01, 0xFF]).unwrap()); + assert_eq!(false, bool::from_der(&[0x01, 0x01, 0x00]).unwrap()); + } + + #[test] + fn encode() { + let mut buffer = [0u8; 3]; + assert_eq!( + &[0x01, 0x01, 0xFF], + true.encode_to_slice(&mut buffer).unwrap() + ); + assert_eq!( + &[0x01, 0x01, 0x00], + false.encode_to_slice(&mut buffer).unwrap() + ); + } + + #[test] + fn reject_non_canonical() { + assert!(bool::from_der(&[0x01, 0x01, 0x01]).is_err()); + } +} diff --git a/vendor/der/src/asn1/choice.rs b/vendor/der/src/asn1/choice.rs new file mode 100644 index 0000000..40c7720 --- /dev/null +++ b/vendor/der/src/asn1/choice.rs @@ -0,0 +1,26 @@ +//! ASN.1 `CHOICE` support. + +use crate::{Decode, FixedTag, Tag, Tagged}; + +/// ASN.1 `CHOICE` denotes a union of one or more possible alternatives. +/// +/// The types MUST have distinct tags. +/// +/// This crate models choice as a trait, with a blanket impl for all types +/// which impl `Decode + FixedTag` (i.e. they are modeled as a `CHOICE` +/// with only one possible variant) +pub trait Choice<'a>: Decode<'a> + Tagged { + /// Is the provided [`Tag`] decodable as a variant of this `CHOICE`? + fn can_decode(tag: Tag) -> bool; +} + +/// This blanket impl allows any [`Tagged`] type to function as a [`Choice`] +/// with a single alternative. +impl<'a, T> Choice<'a> for T +where + T: Decode<'a> + FixedTag, +{ + fn can_decode(tag: Tag) -> bool { + T::TAG == tag + } +} diff --git a/vendor/der/src/asn1/context_specific.rs b/vendor/der/src/asn1/context_specific.rs new file mode 100644 index 0000000..101ddf0 --- /dev/null +++ b/vendor/der/src/asn1/context_specific.rs @@ -0,0 +1,354 @@ +//! Context-specific field. + +use crate::{ + asn1::AnyRef, Choice, Decode, DecodeValue, DerOrd, Encode, EncodeValue, EncodeValueRef, Error, + Header, Length, Reader, Result, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer, +}; +use core::cmp::Ordering; + +/// Context-specific field which wraps an owned inner value. +/// +/// This type decodes/encodes a field which is specific to a particular context +/// and is identified by a [`TagNumber`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct ContextSpecific<T> { + /// Context-specific tag number sans the leading `0b10000000` class + /// identifier bit and `0b100000` constructed flag. + pub tag_number: TagNumber, + + /// Tag mode: `EXPLICIT` VS `IMPLICIT`. + pub tag_mode: TagMode, + + /// Value of the field. + pub value: T, +} + +impl<T> ContextSpecific<T> { + /// Attempt to decode an `EXPLICIT` ASN.1 `CONTEXT-SPECIFIC` field with the + /// provided [`TagNumber`]. + /// + /// This method has the following behavior which is designed to simplify + /// handling of extension fields, which are denoted in an ASN.1 schema + /// using the `...` ellipsis extension marker: + /// + /// - Skips over [`ContextSpecific`] fields with a tag number lower than + /// the current one, consuming and ignoring them. + /// - Returns `Ok(None)` if a [`ContextSpecific`] field with a higher tag + /// number is encountered. These fields are not consumed in this case, + /// allowing a field with a lower tag number to be omitted, then the + /// higher numbered field consumed as a follow-up. + /// - Returns `Ok(None)` if anything other than a [`ContextSpecific`] field + /// is encountered. + pub fn decode_explicit<'a, R: Reader<'a>>( + reader: &mut R, + tag_number: TagNumber, + ) -> Result<Option<Self>> + where + T: Decode<'a>, + { + Self::decode_with(reader, tag_number, |reader| Self::decode(reader)) + } + + /// Attempt to decode an `IMPLICIT` ASN.1 `CONTEXT-SPECIFIC` field with the + /// provided [`TagNumber`]. + /// + /// This method otherwise behaves the same as `decode_explicit`, + /// but should be used in cases where the particular fields are `IMPLICIT` + /// as opposed to `EXPLICIT`. + pub fn decode_implicit<'a, R: Reader<'a>>( + reader: &mut R, + tag_number: TagNumber, + ) -> Result<Option<Self>> + where + T: DecodeValue<'a> + Tagged, + { + Self::decode_with(reader, tag_number, |reader| { + let header = Header::decode(reader)?; + let value = T::decode_value(reader, header)?; + + if header.tag.is_constructed() != value.tag().is_constructed() { + return Err(header.tag.non_canonical_error()); + } + + Ok(Self { + tag_number, + tag_mode: TagMode::Implicit, + value, + }) + }) + } + + /// Attempt to decode a context-specific field with the given + /// helper callback. + fn decode_with<'a, F, R: Reader<'a>>( + reader: &mut R, + tag_number: TagNumber, + f: F, + ) -> Result<Option<Self>> + where + F: FnOnce(&mut R) -> Result<Self>, + { + while let Some(octet) = reader.peek_byte() { + let tag = Tag::try_from(octet)?; + + if !tag.is_context_specific() || (tag.number() > tag_number) { + break; + } else if tag.number() == tag_number { + return Some(f(reader)).transpose(); + } else { + AnyRef::decode(reader)?; + } + } + + Ok(None) + } +} + +impl<'a, T> Choice<'a> for ContextSpecific<T> +where + T: Decode<'a> + Tagged, +{ + fn can_decode(tag: Tag) -> bool { + tag.is_context_specific() + } +} + +impl<'a, T> Decode<'a> for ContextSpecific<T> +where + T: Decode<'a>, +{ + fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self> { + let header = Header::decode(reader)?; + + match header.tag { + Tag::ContextSpecific { + number, + constructed: true, + } => Ok(Self { + tag_number: number, + tag_mode: TagMode::default(), + value: reader.read_nested(header.length, |reader| T::decode(reader))?, + }), + tag => Err(tag.unexpected_error(None)), + } + } +} + +impl<T> EncodeValue for ContextSpecific<T> +where + T: EncodeValue + Tagged, +{ + fn value_len(&self) -> Result<Length> { + match self.tag_mode { + TagMode::Explicit => self.value.encoded_len(), + TagMode::Implicit => self.value.value_len(), + } + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + match self.tag_mode { + TagMode::Explicit => self.value.encode(writer), + TagMode::Implicit => self.value.encode_value(writer), + } + } +} + +impl<T> Tagged for ContextSpecific<T> +where + T: Tagged, +{ + fn tag(&self) -> Tag { + let constructed = match self.tag_mode { + TagMode::Explicit => true, + TagMode::Implicit => self.value.tag().is_constructed(), + }; + + Tag::ContextSpecific { + number: self.tag_number, + constructed, + } + } +} + +impl<'a, T> TryFrom<AnyRef<'a>> for ContextSpecific<T> +where + T: Decode<'a>, +{ + type Error = Error; + + fn try_from(any: AnyRef<'a>) -> Result<ContextSpecific<T>> { + match any.tag() { + Tag::ContextSpecific { + number, + constructed: true, + } => Ok(Self { + tag_number: number, + tag_mode: TagMode::default(), + value: T::from_der(any.value())?, + }), + tag => Err(tag.unexpected_error(None)), + } + } +} + +impl<T> ValueOrd for ContextSpecific<T> +where + T: EncodeValue + ValueOrd + Tagged, +{ + fn value_cmp(&self, other: &Self) -> Result<Ordering> { + match self.tag_mode { + TagMode::Explicit => self.der_cmp(other), + TagMode::Implicit => self.value_cmp(other), + } + } +} + +/// Context-specific field reference. +/// +/// This type encodes a field which is specific to a particular context +/// and is identified by a [`TagNumber`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct ContextSpecificRef<'a, T> { + /// Context-specific tag number sans the leading `0b10000000` class + /// identifier bit and `0b100000` constructed flag. + pub tag_number: TagNumber, + + /// Tag mode: `EXPLICIT` VS `IMPLICIT`. + pub tag_mode: TagMode, + + /// Value of the field. + pub value: &'a T, +} + +impl<'a, T> ContextSpecificRef<'a, T> { + /// Convert to a [`ContextSpecific`]. + fn encoder(&self) -> ContextSpecific<EncodeValueRef<'a, T>> { + ContextSpecific { + tag_number: self.tag_number, + tag_mode: self.tag_mode, + value: EncodeValueRef(self.value), + } + } +} + +impl<'a, T> EncodeValue for ContextSpecificRef<'a, T> +where + T: EncodeValue + Tagged, +{ + fn value_len(&self) -> Result<Length> { + self.encoder().value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + self.encoder().encode_value(writer) + } +} + +impl<'a, T> Tagged for ContextSpecificRef<'a, T> +where + T: Tagged, +{ + fn tag(&self) -> Tag { + self.encoder().tag() + } +} + +#[cfg(test)] +mod tests { + use super::ContextSpecific; + use crate::{asn1::BitStringRef, Decode, Encode, SliceReader, TagMode, TagNumber}; + use hex_literal::hex; + + // Public key data from `pkcs8` crate's `ed25519-pkcs8-v2.der` + const EXAMPLE_BYTES: &[u8] = + &hex!("A123032100A3A7EAE3A8373830BC47E1167BC50E1DB551999651E0E2DC587623438EAC3F31"); + + #[test] + fn round_trip() { + let field = ContextSpecific::<BitStringRef<'_>>::from_der(EXAMPLE_BYTES).unwrap(); + assert_eq!(field.tag_number.value(), 1); + assert_eq!( + field.value, + BitStringRef::from_bytes(&EXAMPLE_BYTES[5..]).unwrap() + ); + + let mut buf = [0u8; 128]; + let encoded = field.encode_to_slice(&mut buf).unwrap(); + assert_eq!(encoded, EXAMPLE_BYTES); + } + + #[test] + fn context_specific_with_explicit_field() { + let tag_number = TagNumber::new(0); + + // Empty message + let mut reader = SliceReader::new(&[]).unwrap(); + assert_eq!( + ContextSpecific::<u8>::decode_explicit(&mut reader, tag_number).unwrap(), + None + ); + + // Message containing a non-context-specific type + let mut reader = SliceReader::new(&hex!("020100")).unwrap(); + assert_eq!( + ContextSpecific::<u8>::decode_explicit(&mut reader, tag_number).unwrap(), + None + ); + + // Message containing an EXPLICIT context-specific field + let mut reader = SliceReader::new(&hex!("A003020100")).unwrap(); + let field = ContextSpecific::<u8>::decode_explicit(&mut reader, tag_number) + .unwrap() + .unwrap(); + + assert_eq!(field.tag_number, tag_number); + assert_eq!(field.tag_mode, TagMode::Explicit); + assert_eq!(field.value, 0); + } + + #[test] + fn context_specific_with_implicit_field() { + // From RFC8410 Section 10.3: + // <https://datatracker.ietf.org/doc/html/rfc8410#section-10.3> + // + // 81 33: [1] 00 19 BF 44 09 69 84 CD FE 85 41 BA C1 67 DC 3B + // 96 C8 50 86 AA 30 B6 B6 CB 0C 5C 38 AD 70 31 66 + // E1 + let context_specific_implicit_bytes = + hex!("81210019BF44096984CDFE8541BAC167DC3B96C85086AA30B6B6CB0C5C38AD703166E1"); + + let tag_number = TagNumber::new(1); + + let mut reader = SliceReader::new(&context_specific_implicit_bytes).unwrap(); + let field = ContextSpecific::<BitStringRef<'_>>::decode_implicit(&mut reader, tag_number) + .unwrap() + .unwrap(); + + assert_eq!(field.tag_number, tag_number); + assert_eq!(field.tag_mode, TagMode::Implicit); + assert_eq!( + field.value.as_bytes().unwrap(), + &context_specific_implicit_bytes[3..] + ); + } + + #[test] + fn context_specific_skipping_unknown_field() { + let tag = TagNumber::new(1); + let mut reader = SliceReader::new(&hex!("A003020100A103020101")).unwrap(); + let field = ContextSpecific::<u8>::decode_explicit(&mut reader, tag) + .unwrap() + .unwrap(); + assert_eq!(field.value, 1); + } + + #[test] + fn context_specific_returns_none_on_greater_tag_number() { + let tag = TagNumber::new(0); + let mut reader = SliceReader::new(&hex!("A103020101")).unwrap(); + assert_eq!( + ContextSpecific::<u8>::decode_explicit(&mut reader, tag).unwrap(), + None + ); + } +} diff --git a/vendor/der/src/asn1/generalized_time.rs b/vendor/der/src/asn1/generalized_time.rs new file mode 100644 index 0000000..eba05f0 --- /dev/null +++ b/vendor/der/src/asn1/generalized_time.rs @@ -0,0 +1,330 @@ +//! ASN.1 `GeneralizedTime` support. +#![cfg_attr(feature = "arbitrary", allow(clippy::integer_arithmetic))] + +use crate::{ + datetime::{self, DateTime}, + ord::OrdIsValueOrd, + DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, +}; +use core::time::Duration; + +#[cfg(any(feature = "std", feature = "time"))] +use crate::Error; + +#[cfg(feature = "std")] +use { + crate::asn1::AnyRef, + std::time::SystemTime, +}; + +#[cfg(feature = "time")] +use time::PrimitiveDateTime; + +/// ASN.1 `GeneralizedTime` type. +/// +/// This type implements the validity requirements specified in +/// [RFC 5280 Section 4.1.2.5.2][1], namely: +/// +/// > For the purposes of this profile, GeneralizedTime values MUST be +/// > expressed in Greenwich Mean Time (Zulu) and MUST include seconds +/// > (i.e., times are `YYYYMMDDHHMMSSZ`), even where the number of seconds +/// > is zero. GeneralizedTime values MUST NOT include fractional seconds. +/// +/// [1]: https://tools.ietf.org/html/rfc5280#section-4.1.2.5.2 +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct GeneralizedTime(DateTime); + +impl GeneralizedTime { + /// Length of an RFC 5280-flavored ASN.1 DER-encoded [`GeneralizedTime`]. + const LENGTH: usize = 15; + + /// Create a [`GeneralizedTime`] from a [`DateTime`]. + pub const fn from_date_time(datetime: DateTime) -> Self { + Self(datetime) + } + + /// Convert this [`GeneralizedTime`] into a [`DateTime`]. + pub fn to_date_time(&self) -> DateTime { + self.0 + } + + /// Create a new [`GeneralizedTime`] given a [`Duration`] since `UNIX_EPOCH` + /// (a.k.a. "Unix time") + pub fn from_unix_duration(unix_duration: Duration) -> Result<Self> { + DateTime::from_unix_duration(unix_duration) + .map(Into::into) + .map_err(|_| Self::TAG.value_error()) + } + + /// Get the duration of this timestamp since `UNIX_EPOCH`. + pub fn to_unix_duration(&self) -> Duration { + self.0.unix_duration() + } + + /// Instantiate from [`SystemTime`]. + #[cfg(feature = "std")] + pub fn from_system_time(time: SystemTime) -> Result<Self> { + DateTime::try_from(time) + .map(Into::into) + .map_err(|_| Self::TAG.value_error()) + } + + /// Convert to [`SystemTime`]. + #[cfg(feature = "std")] + pub fn to_system_time(&self) -> SystemTime { + self.0.to_system_time() + } +} + +impl_any_conversions!(GeneralizedTime); + +impl<'a> DecodeValue<'a> for GeneralizedTime { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + if Self::LENGTH != usize::try_from(header.length)? { + return Err(Self::TAG.value_error()); + } + + let mut bytes = [0u8; Self::LENGTH]; + reader.read_into(&mut bytes)?; + + match bytes { + // RFC 5280 requires mandatory seconds and Z-normalized time zone + [y1, y2, y3, y4, mon1, mon2, day1, day2, hour1, hour2, min1, min2, sec1, sec2, b'Z'] => { + let year = u16::from(datetime::decode_decimal(Self::TAG, y1, y2)?) + .checked_mul(100) + .and_then(|y| { + y.checked_add(datetime::decode_decimal(Self::TAG, y3, y4).ok()?.into()) + }) + .ok_or(ErrorKind::DateTime)?; + let month = datetime::decode_decimal(Self::TAG, mon1, mon2)?; + let day = datetime::decode_decimal(Self::TAG, day1, day2)?; + let hour = datetime::decode_decimal(Self::TAG, hour1, hour2)?; + let minute = datetime::decode_decimal(Self::TAG, min1, min2)?; + let second = datetime::decode_decimal(Self::TAG, sec1, sec2)?; + + DateTime::new(year, month, day, hour, minute, second) + .map_err(|_| Self::TAG.value_error()) + .and_then(|dt| Self::from_unix_duration(dt.unix_duration())) + } + _ => Err(Self::TAG.value_error()), + } + } +} + +impl EncodeValue for GeneralizedTime { + fn value_len(&self) -> Result<Length> { + Self::LENGTH.try_into() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + let year_hi = u8::try_from(self.0.year() / 100)?; + let year_lo = u8::try_from(self.0.year() % 100)?; + + datetime::encode_decimal(writer, Self::TAG, year_hi)?; + datetime::encode_decimal(writer, Self::TAG, year_lo)?; + datetime::encode_decimal(writer, Self::TAG, self.0.month())?; + datetime::encode_decimal(writer, Self::TAG, self.0.day())?; + datetime::encode_decimal(writer, Self::TAG, self.0.hour())?; + datetime::encode_decimal(writer, Self::TAG, self.0.minutes())?; + datetime::encode_decimal(writer, Self::TAG, self.0.seconds())?; + writer.write_byte(b'Z') + } +} + +impl FixedTag for GeneralizedTime { + const TAG: Tag = Tag::GeneralizedTime; +} + +impl OrdIsValueOrd for GeneralizedTime {} + +impl From<&GeneralizedTime> for GeneralizedTime { + fn from(value: &GeneralizedTime) -> GeneralizedTime { + *value + } +} + +impl From<GeneralizedTime> for DateTime { + fn from(utc_time: GeneralizedTime) -> DateTime { + utc_time.0 + } +} + +impl From<&GeneralizedTime> for DateTime { + fn from(utc_time: &GeneralizedTime) -> DateTime { + utc_time.0 + } +} + +impl From<DateTime> for GeneralizedTime { + fn from(datetime: DateTime) -> Self { + Self::from_date_time(datetime) + } +} + +impl From<&DateTime> for GeneralizedTime { + fn from(datetime: &DateTime) -> Self { + Self::from_date_time(*datetime) + } +} + +impl<'a> DecodeValue<'a> for DateTime { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + Ok(GeneralizedTime::decode_value(reader, header)?.into()) + } +} + +impl EncodeValue for DateTime { + fn value_len(&self) -> Result<Length> { + GeneralizedTime::from(self).value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + GeneralizedTime::from(self).encode_value(writer) + } +} + +impl FixedTag for DateTime { + const TAG: Tag = Tag::GeneralizedTime; +} + +impl OrdIsValueOrd for DateTime {} + +#[cfg(feature = "std")] +impl<'a> DecodeValue<'a> for SystemTime { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + Ok(GeneralizedTime::decode_value(reader, header)?.into()) + } +} + +#[cfg(feature = "std")] +impl EncodeValue for SystemTime { + fn value_len(&self) -> Result<Length> { + GeneralizedTime::try_from(self)?.value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + GeneralizedTime::try_from(self)?.encode_value(writer) + } +} + +#[cfg(feature = "std")] +impl From<GeneralizedTime> for SystemTime { + fn from(time: GeneralizedTime) -> SystemTime { + time.to_system_time() + } +} + +#[cfg(feature = "std")] +impl From<&GeneralizedTime> for SystemTime { + fn from(time: &GeneralizedTime) -> SystemTime { + time.to_system_time() + } +} + +#[cfg(feature = "std")] +impl TryFrom<SystemTime> for GeneralizedTime { + type Error = Error; + + fn try_from(time: SystemTime) -> Result<GeneralizedTime> { + GeneralizedTime::from_system_time(time) + } +} + +#[cfg(feature = "std")] +impl TryFrom<&SystemTime> for GeneralizedTime { + type Error = Error; + + fn try_from(time: &SystemTime) -> Result<GeneralizedTime> { + GeneralizedTime::from_system_time(*time) + } +} + +#[cfg(feature = "std")] +impl<'a> TryFrom<AnyRef<'a>> for SystemTime { + type Error = Error; + + fn try_from(any: AnyRef<'a>) -> Result<SystemTime> { + GeneralizedTime::try_from(any).map(|s| s.to_system_time()) + } +} + +#[cfg(feature = "std")] +impl FixedTag for SystemTime { + const TAG: Tag = Tag::GeneralizedTime; +} + +#[cfg(feature = "std")] +impl OrdIsValueOrd for SystemTime {} + +#[cfg(feature = "time")] +impl<'a> DecodeValue<'a> for PrimitiveDateTime { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + GeneralizedTime::decode_value(reader, header)?.try_into() + } +} + +#[cfg(feature = "time")] +impl EncodeValue for PrimitiveDateTime { + fn value_len(&self) -> Result<Length> { + GeneralizedTime::try_from(self)?.value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + GeneralizedTime::try_from(self)?.encode_value(writer) + } +} + +#[cfg(feature = "time")] +impl FixedTag for PrimitiveDateTime { + const TAG: Tag = Tag::GeneralizedTime; +} + +#[cfg(feature = "time")] +impl OrdIsValueOrd for PrimitiveDateTime {} + +#[cfg(feature = "time")] +impl TryFrom<PrimitiveDateTime> for GeneralizedTime { + type Error = Error; + + fn try_from(time: PrimitiveDateTime) -> Result<GeneralizedTime> { + Ok(GeneralizedTime::from_date_time(DateTime::try_from(time)?)) + } +} + +#[cfg(feature = "time")] +impl TryFrom<&PrimitiveDateTime> for GeneralizedTime { + type Error = Error; + + fn try_from(time: &PrimitiveDateTime) -> Result<GeneralizedTime> { + Self::try_from(*time) + } +} + +#[cfg(feature = "time")] +impl TryFrom<GeneralizedTime> for PrimitiveDateTime { + type Error = Error; + + fn try_from(time: GeneralizedTime) -> Result<PrimitiveDateTime> { + time.to_date_time().try_into() + } +} + +#[cfg(test)] +mod tests { + use super::GeneralizedTime; + use crate::{Decode, Encode, SliceWriter}; + use hex_literal::hex; + + #[test] + fn round_trip() { + let example_bytes = hex!("18 0f 31 39 39 31 30 35 30 36 32 33 34 35 34 30 5a"); + let utc_time = GeneralizedTime::from_der(&example_bytes).unwrap(); + assert_eq!(utc_time.to_unix_duration().as_secs(), 673573540); + + let mut buf = [0u8; 128]; + let mut encoder = SliceWriter::new(&mut buf); + utc_time.encode(&mut encoder).unwrap(); + assert_eq!(example_bytes, encoder.finish().unwrap()); + } +} diff --git a/vendor/der/src/asn1/ia5_string.rs b/vendor/der/src/asn1/ia5_string.rs new file mode 100644 index 0000000..1b06dce --- /dev/null +++ b/vendor/der/src/asn1/ia5_string.rs @@ -0,0 +1,195 @@ +//! ASN.1 `IA5String` support. + +use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag}; +use core::{fmt, ops::Deref}; + +macro_rules! impl_ia5_string { + ($type: ty) => { + impl_ia5_string!($type,); + }; + ($type: ty, $($li: lifetime)?) => { + impl_string_type!($type, $($li),*); + + impl<$($li),*> FixedTag for $type { + const TAG: Tag = Tag::Ia5String; + } + + impl<$($li),*> fmt::Debug for $type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Ia5String({:?})", self.as_str()) + } + } + }; +} + +/// ASN.1 `IA5String` type. +/// +/// Supports the [International Alphabet No. 5 (IA5)] character encoding, i.e. +/// the lower 128 characters of the ASCII alphabet. (Note: IA5 is now +/// technically known as the International Reference Alphabet or IRA as +/// specified in the ITU-T's T.50 recommendation). +/// +/// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`]. +/// +/// This is a zero-copy reference type which borrows from the input data. +/// +/// [International Alphabet No. 5 (IA5)]: https://en.wikipedia.org/wiki/T.50_%28standard%29 +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] +pub struct Ia5StringRef<'a> { + /// Inner value + inner: StrRef<'a>, +} + +impl<'a> Ia5StringRef<'a> { + /// Create a new `IA5String`. + pub fn new<T>(input: &'a T) -> Result<Self> + where + T: AsRef<[u8]> + ?Sized, + { + let input = input.as_ref(); + + // Validate all characters are within IA5String's allowed set + if input.iter().any(|&c| c > 0x7F) { + return Err(Self::TAG.value_error()); + } + + StrRef::from_bytes(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } +} + +impl_ia5_string!(Ia5StringRef<'a>, 'a); + +impl<'a> Deref for Ia5StringRef<'a> { + type Target = StrRef<'a>; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl<'a> From<&Ia5StringRef<'a>> for Ia5StringRef<'a> { + fn from(value: &Ia5StringRef<'a>) -> Ia5StringRef<'a> { + *value + } +} + +impl<'a> From<Ia5StringRef<'a>> for AnyRef<'a> { + fn from(internationalized_string: Ia5StringRef<'a>) -> AnyRef<'a> { + AnyRef::from_tag_and_value(Tag::Ia5String, internationalized_string.inner.into()) + } +} + +#[cfg(feature = "alloc")] +pub use self::allocation::Ia5String; + +#[cfg(feature = "alloc")] +mod allocation { + use super::Ia5StringRef; + use crate::{ + asn1::AnyRef, + referenced::{OwnedToRef, RefToOwned}, + Error, FixedTag, Result, StrOwned, Tag, + }; + use alloc::string::String; + use core::{fmt, ops::Deref}; + + /// ASN.1 `IA5String` type. + /// + /// Supports the [International Alphabet No. 5 (IA5)] character encoding, i.e. + /// the lower 128 characters of the ASCII alphabet. (Note: IA5 is now + /// technically known as the International Reference Alphabet or IRA as + /// specified in the ITU-T's T.50 recommendation). + /// + /// For UTF-8, use [`String`][`alloc::string::String`]. + /// + /// [International Alphabet No. 5 (IA5)]: https://en.wikipedia.org/wiki/T.50_%28standard%29 + #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] + pub struct Ia5String { + /// Inner value + inner: StrOwned, + } + + impl Ia5String { + /// Create a new `IA5String`. + pub fn new<T>(input: &T) -> Result<Self> + where + T: AsRef<[u8]> + ?Sized, + { + let input = input.as_ref(); + Ia5StringRef::new(input)?; + + StrOwned::from_bytes(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } + } + + impl_ia5_string!(Ia5String); + + impl Deref for Ia5String { + type Target = StrOwned; + + fn deref(&self) -> &Self::Target { + &self.inner + } + } + + impl<'a> From<Ia5StringRef<'a>> for Ia5String { + fn from(international_string: Ia5StringRef<'a>) -> Ia5String { + let inner = international_string.inner.into(); + Self { inner } + } + } + + impl<'a> From<&'a Ia5String> for AnyRef<'a> { + fn from(international_string: &'a Ia5String) -> AnyRef<'a> { + AnyRef::from_tag_and_value(Tag::Ia5String, (&international_string.inner).into()) + } + } + + impl<'a> RefToOwned<'a> for Ia5StringRef<'a> { + type Owned = Ia5String; + fn ref_to_owned(&self) -> Self::Owned { + Ia5String { + inner: self.inner.ref_to_owned(), + } + } + } + + impl OwnedToRef for Ia5String { + type Borrowed<'a> = Ia5StringRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + Ia5StringRef { + inner: self.inner.owned_to_ref(), + } + } + } + + impl TryFrom<String> for Ia5String { + type Error = Error; + + fn try_from(input: String) -> Result<Self> { + Ia5StringRef::new(&input)?; + + StrOwned::new(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } + } +} + +#[cfg(test)] +mod tests { + use super::Ia5StringRef; + use crate::Decode; + use hex_literal::hex; + + #[test] + fn parse_bytes() { + let example_bytes = hex!("16 0d 74 65 73 74 31 40 72 73 61 2e 63 6f 6d"); + let internationalized_string = Ia5StringRef::from_der(&example_bytes).unwrap(); + assert_eq!(internationalized_string.as_str(), "test1@rsa.com"); + } +} diff --git a/vendor/der/src/asn1/integer.rs b/vendor/der/src/asn1/integer.rs new file mode 100644 index 0000000..a6e913d --- /dev/null +++ b/vendor/der/src/asn1/integer.rs @@ -0,0 +1,161 @@ +//! ASN.1 `INTEGER` support. + +pub(super) mod int; +pub(super) mod uint; + +use core::{cmp::Ordering, mem}; + +use crate::{EncodeValue, Result, SliceWriter}; + +/// Is the highest bit of the first byte in the slice set to `1`? (if present) +#[inline] +fn is_highest_bit_set(bytes: &[u8]) -> bool { + bytes + .first() + .map(|byte| byte & 0b10000000 != 0) + .unwrap_or(false) +} + +/// Compare two integer values +fn value_cmp<T>(a: T, b: T) -> Result<Ordering> +where + T: Copy + EncodeValue + Sized, +{ + const MAX_INT_SIZE: usize = 16; + debug_assert!(mem::size_of::<T>() <= MAX_INT_SIZE); + + let mut buf1 = [0u8; MAX_INT_SIZE]; + let mut encoder1 = SliceWriter::new(&mut buf1); + a.encode_value(&mut encoder1)?; + + let mut buf2 = [0u8; MAX_INT_SIZE]; + let mut encoder2 = SliceWriter::new(&mut buf2); + b.encode_value(&mut encoder2)?; + + Ok(encoder1.finish()?.cmp(encoder2.finish()?)) +} + +#[cfg(test)] +pub(crate) mod tests { + use crate::{Decode, Encode}; + + // Vectors from Section 5.7 of: + // https://luca.ntop.org/Teaching/Appunti/asn1.html + pub(crate) const I0_BYTES: &[u8] = &[0x02, 0x01, 0x00]; + pub(crate) const I127_BYTES: &[u8] = &[0x02, 0x01, 0x7F]; + pub(crate) const I128_BYTES: &[u8] = &[0x02, 0x02, 0x00, 0x80]; + pub(crate) const I256_BYTES: &[u8] = &[0x02, 0x02, 0x01, 0x00]; + pub(crate) const INEG128_BYTES: &[u8] = &[0x02, 0x01, 0x80]; + pub(crate) const INEG129_BYTES: &[u8] = &[0x02, 0x02, 0xFF, 0x7F]; + + // Additional vectors + pub(crate) const I255_BYTES: &[u8] = &[0x02, 0x02, 0x00, 0xFF]; + pub(crate) const I32767_BYTES: &[u8] = &[0x02, 0x02, 0x7F, 0xFF]; + pub(crate) const I65535_BYTES: &[u8] = &[0x02, 0x03, 0x00, 0xFF, 0xFF]; + pub(crate) const INEG32768_BYTES: &[u8] = &[0x02, 0x02, 0x80, 0x00]; + + #[test] + fn decode_i8() { + assert_eq!(0, i8::from_der(I0_BYTES).unwrap()); + assert_eq!(127, i8::from_der(I127_BYTES).unwrap()); + assert_eq!(-128, i8::from_der(INEG128_BYTES).unwrap()); + } + + #[test] + fn decode_i16() { + assert_eq!(0, i16::from_der(I0_BYTES).unwrap()); + assert_eq!(127, i16::from_der(I127_BYTES).unwrap()); + assert_eq!(128, i16::from_der(I128_BYTES).unwrap()); + assert_eq!(255, i16::from_der(I255_BYTES).unwrap()); + assert_eq!(256, i16::from_der(I256_BYTES).unwrap()); + assert_eq!(32767, i16::from_der(I32767_BYTES).unwrap()); + assert_eq!(-128, i16::from_der(INEG128_BYTES).unwrap()); + assert_eq!(-129, i16::from_der(INEG129_BYTES).unwrap()); + assert_eq!(-32768, i16::from_der(INEG32768_BYTES).unwrap()); + } + + #[test] + fn decode_u8() { + assert_eq!(0, u8::from_der(I0_BYTES).unwrap()); + assert_eq!(127, u8::from_der(I127_BYTES).unwrap()); + assert_eq!(255, u8::from_der(I255_BYTES).unwrap()); + } + + #[test] + fn decode_u16() { + assert_eq!(0, u16::from_der(I0_BYTES).unwrap()); + assert_eq!(127, u16::from_der(I127_BYTES).unwrap()); + assert_eq!(255, u16::from_der(I255_BYTES).unwrap()); + assert_eq!(256, u16::from_der(I256_BYTES).unwrap()); + assert_eq!(32767, u16::from_der(I32767_BYTES).unwrap()); + assert_eq!(65535, u16::from_der(I65535_BYTES).unwrap()); + } + + #[test] + fn encode_i8() { + let mut buffer = [0u8; 3]; + + assert_eq!(I0_BYTES, 0i8.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I127_BYTES, 127i8.encode_to_slice(&mut buffer).unwrap()); + + assert_eq!( + INEG128_BYTES, + (-128i8).encode_to_slice(&mut buffer).unwrap() + ); + } + + #[test] + fn encode_i16() { + let mut buffer = [0u8; 4]; + assert_eq!(I0_BYTES, 0i16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I127_BYTES, 127i16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I128_BYTES, 128i16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I255_BYTES, 255i16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I256_BYTES, 256i16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I32767_BYTES, 32767i16.encode_to_slice(&mut buffer).unwrap()); + + assert_eq!( + INEG128_BYTES, + (-128i16).encode_to_slice(&mut buffer).unwrap() + ); + + assert_eq!( + INEG129_BYTES, + (-129i16).encode_to_slice(&mut buffer).unwrap() + ); + + assert_eq!( + INEG32768_BYTES, + (-32768i16).encode_to_slice(&mut buffer).unwrap() + ); + } + + #[test] + fn encode_u8() { + let mut buffer = [0u8; 4]; + assert_eq!(I0_BYTES, 0u8.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I127_BYTES, 127u8.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I255_BYTES, 255u8.encode_to_slice(&mut buffer).unwrap()); + } + + #[test] + fn encode_u16() { + let mut buffer = [0u8; 5]; + assert_eq!(I0_BYTES, 0u16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I127_BYTES, 127u16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I128_BYTES, 128u16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I255_BYTES, 255u16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I256_BYTES, 256u16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I32767_BYTES, 32767u16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I65535_BYTES, 65535u16.encode_to_slice(&mut buffer).unwrap()); + } + + /// Integers must be encoded with a minimum number of octets + #[test] + fn reject_non_canonical() { + assert!(i8::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err()); + assert!(i16::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err()); + assert!(u8::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err()); + assert!(u16::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err()); + } +} 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 }); + } +} diff --git a/vendor/der/src/asn1/internal_macros.rs b/vendor/der/src/asn1/internal_macros.rs new file mode 100644 index 0000000..10ad99d --- /dev/null +++ b/vendor/der/src/asn1/internal_macros.rs @@ -0,0 +1,75 @@ +macro_rules! impl_any_conversions { + ($type: ty) => { + impl_any_conversions!($type, ); + }; + ($type: ty, $($li: lifetime)?) => { + impl<'__der: $($li),*, $($li),*> TryFrom<$crate::AnyRef<'__der>> for $type { + type Error = $crate::Error; + + fn try_from(any: $crate::AnyRef<'__der>) -> Result<$type> { + any.decode_as() + } + } + + #[cfg(feature = "alloc")] + impl<'__der: $($li),*, $($li),*> TryFrom<&'__der $crate::Any> for $type { + type Error = $crate::Error; + + fn try_from(any: &'__der $crate::Any) -> Result<$type> { + any.decode_as() + } + } + }; +} + +macro_rules! impl_string_type { + ($type: ty, $($li: lifetime)?) => { + impl_any_conversions!($type, $($li),*); + + mod __impl_string { + use super::*; + + use crate::{ + ord::OrdIsValueOrd, BytesRef, DecodeValue, EncodeValue, Header, Length, Reader, + Result, Writer, + }; + use core::{fmt, str}; + + impl<$($li),*> AsRef<str> for $type { + fn as_ref(&self) -> &str { + self.as_str() + } + } + + impl<$($li),*> AsRef<[u8]> for $type { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } + } + + impl<'__der: $($li),*, $($li),*> DecodeValue<'__der> for $type { + fn decode_value<R: Reader<'__der>>(reader: &mut R, header: Header) -> Result<Self> { + Self::new(BytesRef::decode_value(reader, header)?.as_slice()) + } + } + + impl<$($li),*> EncodeValue for $type { + fn value_len(&self) -> Result<Length> { + self.inner.value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + self.inner.encode_value(writer) + } + } + + impl<$($li),*> OrdIsValueOrd for $type {} + + impl<$($li),*> fmt::Display for $type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } + } + } + }; +} diff --git a/vendor/der/src/asn1/null.rs b/vendor/der/src/asn1/null.rs new file mode 100644 index 0000000..7c1e205 --- /dev/null +++ b/vendor/der/src/asn1/null.rs @@ -0,0 +1,102 @@ +//! ASN.1 `NULL` support. + +use crate::{ + asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, DecodeValue, EncodeValue, Error, ErrorKind, + FixedTag, Header, Length, Reader, Result, Tag, Writer, +}; + +/// ASN.1 `NULL` type. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct Null; + +impl_any_conversions!(Null); + +impl<'a> DecodeValue<'a> for Null { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + if header.length.is_zero() { + Ok(Null) + } else { + Err(reader.error(ErrorKind::Length { tag: Self::TAG })) + } + } +} + +impl EncodeValue for Null { + fn value_len(&self) -> Result<Length> { + Ok(Length::ZERO) + } + + fn encode_value(&self, _writer: &mut impl Writer) -> Result<()> { + Ok(()) + } +} + +impl FixedTag for Null { + const TAG: Tag = Tag::Null; +} + +impl OrdIsValueOrd for Null {} + +impl<'a> From<Null> for AnyRef<'a> { + fn from(_: Null) -> AnyRef<'a> { + AnyRef::from_tag_and_value(Tag::Null, BytesRef::default()) + } +} + +impl TryFrom<AnyRef<'_>> for () { + type Error = Error; + + fn try_from(any: AnyRef<'_>) -> Result<()> { + Null::try_from(any).map(|_| ()) + } +} + +impl<'a> From<()> for AnyRef<'a> { + fn from(_: ()) -> AnyRef<'a> { + Null.into() + } +} + +impl<'a> DecodeValue<'a> for () { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + Null::decode_value(reader, header)?; + Ok(()) + } +} + +impl EncodeValue for () { + fn value_len(&self) -> Result<Length> { + Ok(Length::ZERO) + } + + fn encode_value(&self, _writer: &mut impl Writer) -> Result<()> { + Ok(()) + } +} + +impl FixedTag for () { + const TAG: Tag = Tag::Null; +} + +#[cfg(test)] +mod tests { + use super::Null; + use crate::{Decode, Encode}; + + #[test] + fn decode() { + Null::from_der(&[0x05, 0x00]).unwrap(); + } + + #[test] + fn encode() { + let mut buffer = [0u8; 2]; + assert_eq!(&[0x05, 0x00], Null.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(&[0x05, 0x00], ().encode_to_slice(&mut buffer).unwrap()); + } + + #[test] + fn reject_non_canonical() { + assert!(Null::from_der(&[0x05, 0x81, 0x00]).is_err()); + } +} diff --git a/vendor/der/src/asn1/octet_string.rs b/vendor/der/src/asn1/octet_string.rs new file mode 100644 index 0000000..53d8ecb --- /dev/null +++ b/vendor/der/src/asn1/octet_string.rs @@ -0,0 +1,257 @@ +//! ASN.1 `OCTET STRING` support. + +use crate::{ + asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, Decode, DecodeValue, EncodeValue, ErrorKind, + FixedTag, Header, Length, Reader, Result, Tag, Writer, +}; + +/// ASN.1 `OCTET STRING` type: borrowed form. +/// +/// Octet strings represent contiguous sequences of octets, a.k.a. bytes. +/// +/// This is a zero-copy reference type which borrows from the input data. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct OctetStringRef<'a> { + /// Inner value + inner: BytesRef<'a>, +} + +impl<'a> OctetStringRef<'a> { + /// Create a new ASN.1 `OCTET STRING` from a byte slice. + pub fn new(slice: &'a [u8]) -> Result<Self> { + BytesRef::new(slice) + .map(|inner| Self { inner }) + .map_err(|_| ErrorKind::Length { tag: Self::TAG }.into()) + } + + /// Borrow the inner byte slice. + pub fn as_bytes(&self) -> &'a [u8] { + self.inner.as_slice() + } + + /// Get the length of the inner byte slice. + pub fn len(&self) -> Length { + self.inner.len() + } + + /// Is the inner byte slice empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + /// Parse `T` from this `OCTET STRING`'s contents. + pub fn decode_into<T: Decode<'a>>(&self) -> Result<T> { + Decode::from_der(self.as_bytes()) + } +} + +impl_any_conversions!(OctetStringRef<'a>, 'a); + +impl AsRef<[u8]> for OctetStringRef<'_> { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<'a> DecodeValue<'a> for OctetStringRef<'a> { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + let inner = BytesRef::decode_value(reader, header)?; + Ok(Self { inner }) + } +} + +impl EncodeValue for OctetStringRef<'_> { + fn value_len(&self) -> Result<Length> { + self.inner.value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + self.inner.encode_value(writer) + } +} + +impl FixedTag for OctetStringRef<'_> { + const TAG: Tag = Tag::OctetString; +} + +impl OrdIsValueOrd for OctetStringRef<'_> {} + +impl<'a> From<&OctetStringRef<'a>> for OctetStringRef<'a> { + fn from(value: &OctetStringRef<'a>) -> OctetStringRef<'a> { + *value + } +} + +impl<'a> From<OctetStringRef<'a>> for AnyRef<'a> { + fn from(octet_string: OctetStringRef<'a>) -> AnyRef<'a> { + AnyRef::from_tag_and_value(Tag::OctetString, octet_string.inner) + } +} + +impl<'a> From<OctetStringRef<'a>> for &'a [u8] { + fn from(octet_string: OctetStringRef<'a>) -> &'a [u8] { + octet_string.as_bytes() + } +} + +#[cfg(feature = "alloc")] +pub use self::allocating::OctetString; + +#[cfg(feature = "alloc")] +mod allocating { + use super::*; + use crate::referenced::*; + use alloc::vec::Vec; + + /// ASN.1 `OCTET STRING` type: owned form.. + /// + /// Octet strings represent contiguous sequences of octets, a.k.a. bytes. + /// + /// This type provides the same functionality as [`OctetStringRef`] but owns + /// the backing data. + #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] + pub struct OctetString { + /// Bitstring represented as a slice of bytes. + pub(super) inner: Vec<u8>, + } + + impl OctetString { + /// Create a new ASN.1 `OCTET STRING`. + pub fn new(bytes: impl Into<Vec<u8>>) -> Result<Self> { + let inner = bytes.into(); + + // Ensure the bytes parse successfully as an `OctetStringRef` + OctetStringRef::new(&inner)?; + + Ok(Self { inner }) + } + + /// Borrow the inner byte slice. + pub fn as_bytes(&self) -> &[u8] { + self.inner.as_slice() + } + + /// Take ownership of the octet string. + pub fn into_bytes(self) -> Vec<u8> { + self.inner + } + + /// Get the length of the inner byte slice. + pub fn len(&self) -> Length { + self.value_len().expect("invalid OCTET STRING length") + } + + /// Is the inner byte slice empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + } + + impl_any_conversions!(OctetString); + + impl AsRef<[u8]> for OctetString { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } + } + + impl<'a> DecodeValue<'a> for OctetString { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + Self::new(reader.read_vec(header.length)?) + } + } + + impl EncodeValue for OctetString { + fn value_len(&self) -> Result<Length> { + self.inner.len().try_into() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(&self.inner) + } + } + + impl FixedTag for OctetString { + const TAG: Tag = Tag::OctetString; + } + + impl<'a> From<&'a OctetString> for OctetStringRef<'a> { + fn from(octet_string: &'a OctetString) -> OctetStringRef<'a> { + // Ensured to parse successfully in constructor + OctetStringRef::new(&octet_string.inner).expect("invalid OCTET STRING") + } + } + + impl OrdIsValueOrd for OctetString {} + + impl<'a> RefToOwned<'a> for OctetStringRef<'a> { + type Owned = OctetString; + fn ref_to_owned(&self) -> Self::Owned { + OctetString { + inner: Vec::from(self.inner.as_slice()), + } + } + } + + impl OwnedToRef for OctetString { + type Borrowed<'a> = OctetStringRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + self.into() + } + } + + // Implement by hand because the derive would create invalid values. + // Use the constructor to create a valid value. + #[cfg(feature = "arbitrary")] + impl<'a> arbitrary::Arbitrary<'a> for OctetString { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { + Self::new(Vec::arbitrary(u)?).map_err(|_| arbitrary::Error::IncorrectFormat) + } + + fn size_hint(depth: usize) -> (usize, Option<usize>) { + arbitrary::size_hint::and(u8::size_hint(depth), Vec::<u8>::size_hint(depth)) + } + } +} + +#[cfg(feature = "bytes")] +mod bytes { + use super::OctetString; + use crate::{DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, Result, Tag, Writer}; + use bytes::Bytes; + + impl<'a> DecodeValue<'a> for Bytes { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + OctetString::decode_value(reader, header).map(|octet_string| octet_string.inner.into()) + } + } + + impl EncodeValue for Bytes { + fn value_len(&self) -> Result<Length> { + self.len().try_into() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.as_ref()) + } + } + + impl FixedTag for Bytes { + const TAG: Tag = Tag::OctetString; + } +} + +#[cfg(test)] +mod tests { + use crate::asn1::{OctetStringRef, PrintableStringRef}; + + #[test] + fn octet_string_decode_into() { + // PrintableString "hi" + let der = b"\x13\x02\x68\x69"; + let oct = OctetStringRef::new(der).unwrap(); + + let res = oct.decode_into::<PrintableStringRef<'_>>().unwrap(); + assert_eq!(AsRef::<str>::as_ref(&res), "hi"); + } +} diff --git a/vendor/der/src/asn1/oid.rs b/vendor/der/src/asn1/oid.rs new file mode 100644 index 0000000..3daa452 --- /dev/null +++ b/vendor/der/src/asn1/oid.rs @@ -0,0 +1,100 @@ +//! ASN.1 `OBJECT IDENTIFIER` + +use crate::{ + asn1::AnyRef, ord::OrdIsValueOrd, DecodeValue, EncodeValue, Error, FixedTag, Header, Length, + Reader, Result, Tag, Tagged, Writer, +}; +use const_oid::ObjectIdentifier; + +#[cfg(feature = "alloc")] +use super::Any; + +impl<'a> DecodeValue<'a> for ObjectIdentifier { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + let mut buf = [0u8; ObjectIdentifier::MAX_SIZE]; + let slice = buf + .get_mut(..header.length.try_into()?) + .ok_or_else(|| Self::TAG.length_error())?; + + let actual_len = reader.read_into(slice)?.len(); + debug_assert_eq!(actual_len, header.length.try_into()?); + Ok(Self::from_bytes(slice)?) + } +} + +impl EncodeValue for ObjectIdentifier { + fn value_len(&self) -> Result<Length> { + Length::try_from(self.as_bytes().len()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.as_bytes()) + } +} + +impl FixedTag for ObjectIdentifier { + const TAG: Tag = Tag::ObjectIdentifier; +} + +impl OrdIsValueOrd for ObjectIdentifier {} + +impl<'a> From<&'a ObjectIdentifier> for AnyRef<'a> { + fn from(oid: &'a ObjectIdentifier) -> AnyRef<'a> { + // Note: ensuring an infallible conversion is possible relies on the + // invariant that `const_oid::MAX_LEN <= Length::max()`. + // + // The `length()` test below ensures this is the case. + let value = oid + .as_bytes() + .try_into() + .expect("OID length invariant violated"); + + AnyRef::from_tag_and_value(Tag::ObjectIdentifier, value) + } +} + +#[cfg(feature = "alloc")] +impl From<ObjectIdentifier> for Any { + fn from(oid: ObjectIdentifier) -> Any { + AnyRef::from(&oid).into() + } +} + +impl TryFrom<AnyRef<'_>> for ObjectIdentifier { + type Error = Error; + + fn try_from(any: AnyRef<'_>) -> Result<ObjectIdentifier> { + any.tag().assert_eq(Tag::ObjectIdentifier)?; + Ok(ObjectIdentifier::from_bytes(any.value())?) + } +} + +#[cfg(test)] +mod tests { + use super::ObjectIdentifier; + use crate::{Decode, Encode, Length}; + + const EXAMPLE_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549"); + const EXAMPLE_OID_BYTES: &[u8; 8] = &[0x06, 0x06, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d]; + + #[test] + fn decode() { + let oid = ObjectIdentifier::from_der(EXAMPLE_OID_BYTES).unwrap(); + assert_eq!(EXAMPLE_OID, oid); + } + + #[test] + fn encode() { + let mut buffer = [0u8; 8]; + assert_eq!( + EXAMPLE_OID_BYTES, + EXAMPLE_OID.encode_to_slice(&mut buffer).unwrap() + ); + } + + #[test] + fn length() { + // Ensure an infallible `From` conversion to `Any` will never panic + assert!(ObjectIdentifier::MAX_SIZE <= Length::MAX.try_into().unwrap()); + } +} diff --git a/vendor/der/src/asn1/optional.rs b/vendor/der/src/asn1/optional.rs new file mode 100644 index 0000000..ecda4f8 --- /dev/null +++ b/vendor/der/src/asn1/optional.rs @@ -0,0 +1,66 @@ +//! ASN.1 `OPTIONAL` as mapped to Rust's `Option` type + +use crate::{Choice, Decode, DerOrd, Encode, Length, Reader, Result, Tag, Writer}; +use core::cmp::Ordering; + +impl<'a, T> Decode<'a> for Option<T> +where + T: Choice<'a>, // NOTE: all `Decode + Tagged` types receive a blanket `Choice` impl +{ + fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Option<T>> { + if let Some(byte) = reader.peek_byte() { + if T::can_decode(Tag::try_from(byte)?) { + return T::decode(reader).map(Some); + } + } + + Ok(None) + } +} + +impl<T> DerOrd for Option<T> +where + T: DerOrd, +{ + fn der_cmp(&self, other: &Self) -> Result<Ordering> { + match self { + Some(a) => match other { + Some(b) => a.der_cmp(b), + None => Ok(Ordering::Greater), + }, + None => Ok(Ordering::Less), + } + } +} + +impl<T> Encode for Option<T> +where + T: Encode, +{ + fn encoded_len(&self) -> Result<Length> { + (&self).encoded_len() + } + + fn encode(&self, writer: &mut impl Writer) -> Result<()> { + (&self).encode(writer) + } +} + +impl<T> Encode for &Option<T> +where + T: Encode, +{ + fn encoded_len(&self) -> Result<Length> { + match self { + Some(encodable) => encodable.encoded_len(), + None => Ok(0u8.into()), + } + } + + fn encode(&self, encoder: &mut impl Writer) -> Result<()> { + match self { + Some(encodable) => encodable.encode(encoder), + None => Ok(()), + } + } +} diff --git a/vendor/der/src/asn1/printable_string.rs b/vendor/der/src/asn1/printable_string.rs new file mode 100644 index 0000000..d2e51d7 --- /dev/null +++ b/vendor/der/src/asn1/printable_string.rs @@ -0,0 +1,252 @@ +//! ASN.1 `PrintableString` support. + +use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag}; +use core::{fmt, ops::Deref}; + +macro_rules! impl_printable_string { + ($type: ty) => { + impl_printable_string!($type,); + }; + ($type: ty, $($li: lifetime)?) => { + impl_string_type!($type, $($li),*); + + impl<$($li),*> FixedTag for $type { + const TAG: Tag = Tag::PrintableString; + } + + impl<$($li),*> fmt::Debug for $type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "PrintableString({:?})", self.as_str()) + } + } + }; +} + +/// ASN.1 `PrintableString` type. +/// +/// Supports a subset the ASCII character set (described below). +/// +/// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead. +/// For the full ASCII character set, use +/// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`]. +/// +/// This is a zero-copy reference type which borrows from the input data. +/// +/// # Supported characters +/// +/// The following ASCII characters/ranges are supported: +/// +/// - `A..Z` +/// - `a..z` +/// - `0..9` +/// - "` `" (i.e. space) +/// - `\` +/// - `(` +/// - `)` +/// - `+` +/// - `,` +/// - `-` +/// - `.` +/// - `/` +/// - `:` +/// - `=` +/// - `?` +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] +pub struct PrintableStringRef<'a> { + /// Inner value + inner: StrRef<'a>, +} + +impl<'a> PrintableStringRef<'a> { + /// Create a new ASN.1 `PrintableString`. + pub fn new<T>(input: &'a T) -> Result<Self> + where + T: AsRef<[u8]> + ?Sized, + { + let input = input.as_ref(); + + // Validate all characters are within PrintableString's allowed set + for &c in input.iter() { + match c { + b'A'..=b'Z' + | b'a'..=b'z' + | b'0'..=b'9' + | b' ' + | b'\'' + | b'(' + | b')' + | b'+' + | b',' + | b'-' + | b'.' + | b'/' + | b':' + | b'=' + | b'?' => (), + _ => return Err(Self::TAG.value_error()), + } + } + + StrRef::from_bytes(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } +} + +impl_printable_string!(PrintableStringRef<'a>, 'a); + +impl<'a> Deref for PrintableStringRef<'a> { + type Target = StrRef<'a>; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} +impl<'a> From<&PrintableStringRef<'a>> for PrintableStringRef<'a> { + fn from(value: &PrintableStringRef<'a>) -> PrintableStringRef<'a> { + *value + } +} + +impl<'a> From<PrintableStringRef<'a>> for AnyRef<'a> { + fn from(printable_string: PrintableStringRef<'a>) -> AnyRef<'a> { + AnyRef::from_tag_and_value(Tag::PrintableString, printable_string.inner.into()) + } +} + +#[cfg(feature = "alloc")] +pub use self::allocation::PrintableString; + +#[cfg(feature = "alloc")] +mod allocation { + use super::PrintableStringRef; + + use crate::{ + asn1::AnyRef, + referenced::{OwnedToRef, RefToOwned}, + BytesRef, Error, FixedTag, Result, StrOwned, Tag, + }; + use alloc::string::String; + use core::{fmt, ops::Deref}; + + /// ASN.1 `PrintableString` type. + /// + /// Supports a subset the ASCII character set (described below). + /// + /// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead. + /// For the full ASCII character set, use + /// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`]. + /// + /// # Supported characters + /// + /// The following ASCII characters/ranges are supported: + /// + /// - `A..Z` + /// - `a..z` + /// - `0..9` + /// - "` `" (i.e. space) + /// - `\` + /// - `(` + /// - `)` + /// - `+` + /// - `,` + /// - `-` + /// - `.` + /// - `/` + /// - `:` + /// - `=` + /// - `?` + #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] + pub struct PrintableString { + /// Inner value + inner: StrOwned, + } + + impl PrintableString { + /// Create a new ASN.1 `PrintableString`. + pub fn new<T>(input: &T) -> Result<Self> + where + T: AsRef<[u8]> + ?Sized, + { + let input = input.as_ref(); + PrintableStringRef::new(input)?; + + StrOwned::from_bytes(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } + } + + impl_printable_string!(PrintableString); + + impl Deref for PrintableString { + type Target = StrOwned; + + fn deref(&self) -> &Self::Target { + &self.inner + } + } + + impl<'a> From<PrintableStringRef<'a>> for PrintableString { + fn from(value: PrintableStringRef<'a>) -> PrintableString { + let inner = + StrOwned::from_bytes(value.inner.as_bytes()).expect("Invalid PrintableString"); + Self { inner } + } + } + + impl<'a> From<&'a PrintableString> for AnyRef<'a> { + fn from(printable_string: &'a PrintableString) -> AnyRef<'a> { + AnyRef::from_tag_and_value( + Tag::PrintableString, + BytesRef::new(printable_string.inner.as_bytes()).expect("Invalid PrintableString"), + ) + } + } + + impl<'a> RefToOwned<'a> for PrintableStringRef<'a> { + type Owned = PrintableString; + fn ref_to_owned(&self) -> Self::Owned { + PrintableString { + inner: self.inner.ref_to_owned(), + } + } + } + + impl OwnedToRef for PrintableString { + type Borrowed<'a> = PrintableStringRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + PrintableStringRef { + inner: self.inner.owned_to_ref(), + } + } + } + + impl TryFrom<String> for PrintableString { + type Error = Error; + + fn try_from(input: String) -> Result<Self> { + PrintableStringRef::new(&input)?; + + StrOwned::new(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } + } +} + +#[cfg(test)] +mod tests { + use super::PrintableStringRef; + use crate::Decode; + + #[test] + fn parse_bytes() { + let example_bytes = &[ + 0x13, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31, + ]; + + let printable_string = PrintableStringRef::from_der(example_bytes).unwrap(); + assert_eq!(printable_string.as_str(), "Test User 1"); + } +} diff --git a/vendor/der/src/asn1/real.rs b/vendor/der/src/asn1/real.rs new file mode 100644 index 0000000..b9f2e67 --- /dev/null +++ b/vendor/der/src/asn1/real.rs @@ -0,0 +1,990 @@ +//! ASN.1 `REAL` support. + +// TODO(tarcieri): checked arithmetic +#![allow( + clippy::cast_lossless, + clippy::cast_sign_loss, + clippy::integer_arithmetic +)] + +use crate::{ + BytesRef, DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, Result, StrRef, Tag, + Writer, +}; + +use super::integer::uint::strip_leading_zeroes; + +impl<'a> DecodeValue<'a> for f64 { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + let bytes = BytesRef::decode_value(reader, header)?.as_slice(); + + if header.length == Length::ZERO { + Ok(0.0) + } else if is_nth_bit_one::<7>(bytes) { + // Binary encoding from section 8.5.7 applies + let sign: u64 = u64::from(is_nth_bit_one::<6>(bytes)); + + // Section 8.5.7.2: Check the base -- the DER specs say that only base 2 should be supported in DER + let base = mnth_bits_to_u8::<5, 4>(bytes); + + if base != 0 { + // Real related error: base is not DER compliant (base encoded in enum) + return Err(Tag::Real.value_error()); + } + + // Section 8.5.7.3 + let scaling_factor = mnth_bits_to_u8::<3, 2>(bytes); + + // Section 8.5.7.4 + let mantissa_start; + let exponent = match mnth_bits_to_u8::<1, 0>(bytes) { + 0 => { + mantissa_start = 2; + let ebytes = (i16::from_be_bytes([0x0, bytes[1]])).to_be_bytes(); + u64::from_be_bytes([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ebytes[0], ebytes[1]]) + } + 1 => { + mantissa_start = 3; + let ebytes = (i16::from_be_bytes([bytes[1], bytes[2]])).to_be_bytes(); + u64::from_be_bytes([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ebytes[0], ebytes[1]]) + } + _ => { + // Real related error: encoded exponent cannot be represented on an IEEE-754 double + return Err(Tag::Real.value_error()); + } + }; + // Section 8.5.7.5: Read the remaining bytes for the mantissa + let mut n_bytes = [0x0; 8]; + for (pos, byte) in bytes[mantissa_start..].iter().rev().enumerate() { + n_bytes[7 - pos] = *byte; + } + let n = u64::from_be_bytes(n_bytes); + // Multiply byt 2^F corresponds to just a left shift + let mantissa = n << scaling_factor; + // Create the f64 + Ok(encode_f64(sign, exponent, mantissa)) + } else if is_nth_bit_one::<6>(bytes) { + // This either a special value, or it's the value minus zero is encoded, section 8.5.9 applies + match mnth_bits_to_u8::<1, 0>(bytes) { + 0 => Ok(f64::INFINITY), + 1 => Ok(f64::NEG_INFINITY), + 2 => Ok(f64::NAN), + 3 => Ok(-0.0_f64), + _ => Err(Tag::Real.value_error()), + } + } else { + let astr = StrRef::from_bytes(&bytes[1..])?; + match astr.inner.parse::<f64>() { + Ok(val) => Ok(val), + // Real related error: encoding not supported or malformed + Err(_) => Err(Tag::Real.value_error()), + } + } + } +} + +impl EncodeValue for f64 { + fn value_len(&self) -> Result<Length> { + if self.is_sign_positive() && (*self) < f64::MIN_POSITIVE { + // Zero: positive yet smaller than the minimum positive number + Ok(Length::ZERO) + } else if self.is_nan() + || self.is_infinite() + || (self.is_sign_negative() && -self < f64::MIN_POSITIVE) + { + // NaN, infinite (positive or negative), or negative zero (negative but its negative is less than the min positive number) + Ok(Length::ONE) + } else { + // The length is that of the first octets plus those needed for the exponent plus those needed for the mantissa + let (_sign, exponent, mantissa) = decode_f64(*self); + + let exponent_len = if exponent == 0 { + // Section 8.5.7.4: there must be at least one octet for exponent encoding + // But, if the exponent is zero, it'll be skipped, so we make sure force it to 1 + Length::ONE + } else { + let ebytes = exponent.to_be_bytes(); + Length::try_from(strip_leading_zeroes(&ebytes).len())? + }; + + let mantissa_len = if mantissa == 0 { + Length::ONE + } else { + let mbytes = mantissa.to_be_bytes(); + Length::try_from(strip_leading_zeroes(&mbytes).len())? + }; + + exponent_len + mantissa_len + Length::ONE + } + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + // Check if special value + // Encode zero first, if it's zero + // Special value from section 8.5.9 if non zero + if self.is_nan() + || self.is_infinite() + || (self.is_sign_negative() && -self < f64::MIN_POSITIVE) + || (self.is_sign_positive() && (*self) < f64::MIN_POSITIVE) + { + if self.is_sign_positive() && (*self) < f64::MIN_POSITIVE { + // Zero + return Ok(()); + } else if self.is_nan() { + // Not a number + writer.write_byte(0b0100_0010)?; + } else if self.is_infinite() { + if self.is_sign_negative() { + // Negative infinity + writer.write_byte(0b0100_0001)?; + } else { + // Plus infinity + writer.write_byte(0b0100_0000)?; + } + } else { + // Minus zero + writer.write_byte(0b0100_0011)?; + } + } else { + // Always use binary encoding, set bit 8 to 1 + let mut first_byte = 0b1000_0000; + + if self.is_sign_negative() { + // Section 8.5.7.1: set bit 7 to 1 if negative + first_byte |= 0b0100_0000; + } + + // Bits 6 and 5 are set to 0 to specify that binary encoding is used + // + // NOTE: the scaling factor is only used to align the implicit point of the mantissa. + // This is unnecessary in DER because the base is 2, and therefore necessarily aligned. + // Therefore, we do not modify the mantissa in anyway after this function call, which + // already adds the implicit one of the IEEE 754 representation. + let (_sign, exponent, mantissa) = decode_f64(*self); + + // Encode the exponent as two's complement on 16 bits and remove the bias + let exponent_bytes = exponent.to_be_bytes(); + let ebytes = strip_leading_zeroes(&exponent_bytes); + + match ebytes.len() { + 0 | 1 => {} + 2 => first_byte |= 0b0000_0001, + 3 => first_byte |= 0b0000_0010, + _ => { + // TODO: support multi octet exponent encoding? + return Err(Tag::Real.value_error()); + } + } + + writer.write_byte(first_byte)?; + + // Encode both bytes or just the last one, handled by encode_bytes directly + // Rust already encodes the data as two's complement, so no further processing is needed + writer.write(ebytes)?; + + // Now, encode the mantissa as unsigned binary number + let mantissa_bytes = mantissa.to_be_bytes(); + let mbytes = strip_leading_zeroes(&mantissa_bytes); + writer.write(mbytes)?; + } + + Ok(()) + } +} + +impl FixedTag for f64 { + const TAG: Tag = Tag::Real; +} + +/// Is the N-th bit 1 in the first octet? +/// NOTE: this function is zero indexed +pub(crate) fn is_nth_bit_one<const N: usize>(bytes: &[u8]) -> bool { + if N < 8 { + bytes + .first() + .map(|byte| byte & (1 << N) != 0) + .unwrap_or(false) + } else { + false + } +} + +/// Convert bits M, N into a u8, in the first octet only +pub(crate) fn mnth_bits_to_u8<const M: usize, const N: usize>(bytes: &[u8]) -> u8 { + let bit_m = is_nth_bit_one::<M>(bytes); + let bit_n = is_nth_bit_one::<N>(bytes); + (bit_m as u8) << 1 | bit_n as u8 +} + +/// Decode an f64 as its sign, exponent, and mantissa in u64 and in that order, using bit shifts and masks. +/// Note: this function **removes** the 1023 bias from the exponent and adds the implicit 1 +#[allow(clippy::cast_possible_truncation)] +pub(crate) fn decode_f64(f: f64) -> (u64, u64, u64) { + let bits = f.to_bits(); + let sign = bits >> 63; + let exponent = bits >> 52 & 0x7ff; + let exponent_bytes_no_bias = (exponent as i16 - 1023).to_be_bytes(); + let exponent_no_bias = u64::from_be_bytes([ + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + exponent_bytes_no_bias[0], + exponent_bytes_no_bias[1], + ]); + let mantissa = bits & 0xfffffffffffff; + (sign, exponent_no_bias, mantissa + 1) +} + +/// Encode an f64 from its sign, exponent (**without** the 1023 bias), and (mantissa - 1) using bit shifts as received by ASN1 +pub(crate) fn encode_f64(sign: u64, exponent: u64, mantissa: u64) -> f64 { + // Add the bias to the exponent + let exponent_with_bias = + (i16::from_be_bytes([exponent.to_be_bytes()[6], exponent.to_be_bytes()[7]]) + 1023) as u64; + let bits = sign << 63 | exponent_with_bias << 52 | (mantissa - 1); + f64::from_bits(bits) +} + +#[cfg(test)] +mod tests { + use crate::{Decode, Encode}; + + #[test] + fn decode_subnormal() { + assert!(f64::from_der(&[0x09, 0x01, 0b0100_0010]).unwrap().is_nan()); + let plus_infty = f64::from_der(&[0x09, 0x01, 0b0100_0000]).unwrap(); + assert!(plus_infty.is_infinite() && plus_infty.is_sign_positive()); + let neg_infty = f64::from_der(&[0x09, 0x01, 0b0100_0001]).unwrap(); + assert!(neg_infty.is_infinite() && neg_infty.is_sign_negative()); + let neg_zero = f64::from_der(&[0x09, 0x01, 0b0100_0011]).unwrap(); + assert!(neg_zero.is_sign_negative() && neg_zero.abs() < f64::EPSILON); + } + + #[test] + fn encode_subnormal() { + // All subnormal fit in three bytes + let mut buffer = [0u8; 3]; + assert_eq!( + &[0x09, 0x01, 0b0100_0010], + f64::NAN.encode_to_slice(&mut buffer).unwrap() + ); + assert_eq!( + &[0x09, 0x01, 0b0100_0000], + f64::INFINITY.encode_to_slice(&mut buffer).unwrap() + ); + assert_eq!( + &[0x09, 0x01, 0b0100_0001], + f64::NEG_INFINITY.encode_to_slice(&mut buffer).unwrap() + ); + assert_eq!( + &[0x09, 0x01, 0b0100_0011], + (-0.0_f64).encode_to_slice(&mut buffer).unwrap() + ); + } + + #[test] + fn encdec_normal() { + // The comments correspond to the decoded value from the ASN.1 playground when the bytes are inputed. + { + // rec1value R ::= 0 + let val = 0.0; + let expected = &[0x09, 0x0]; + let mut buffer = [0u8; 2]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec1value R ::= { mantissa 1, base 2, exponent 0 } + let val = 1.0; + let expected = &[0x09, 0x03, 0x80, 0x00, 0x01]; + let mut buffer = [0u8; 5]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec1value R ::= { mantissa -1, base 2, exponent 0 } + let val = -1.0; + let expected = &[0x09, 0x03, 0xc0, 0x00, 0x01]; + let mut buffer = [0u8; 5]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec1value R ::= { mantissa -1, base 2, exponent 1 } + let val = -1.0000000000000002; + let expected = &[0x09, 0x03, 0xc0, 0x00, 0x02]; + let mut buffer = [0u8; 5]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec1value R ::= { mantissa 1, base 2, exponent -1022 } + // NOTE: f64::MIN_EXP == -1021 so the exponent decoded by ASN.1 is what we expect + let val = f64::MIN_POSITIVE; + let expected = &[0x09, 0x04, 0x81, 0xfc, 0x02, 0x01]; + let mut buffer = [0u8; 7]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec4value R ::= { mantissa 1, base 2, exponent 3 } + let val = 1.0000000000000016; + let expected = &[0x09, 0x03, 0x80, 0x00, 0x08]; + let mut buffer = [0u8; 5]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec5value R ::= { mantissa 4222124650659841, base 2, exponent 4 } + let val = 31.0; + let expected = &[ + 0x9, 0x9, 0x80, 0x04, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + ]; + let mut buffer = [0u8; 11]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + } + + #[test] + fn encdec_irrationals() { + { + let val = core::f64::consts::PI; + let expected = &[ + 0x09, 0x09, 0x80, 0x01, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x19, + ]; + let mut buffer = [0u8; 11]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = core::f64::consts::E; + let expected = &[ + 0x09, 0x09, 0x80, 0x01, 0x05, 0xbf, 0x0a, 0x8b, 0x14, 0x57, 0x6a, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + { + let val = core::f64::consts::LN_2; + let expected = &[ + 0x09, 0x0a, 0x81, 0xff, 0xff, 0x6, 0x2e, 0x42, 0xfe, 0xfa, 0x39, 0xf0, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + } + + #[test] + fn encdec_reasonable_f64() { + // Tests the encoding and decoding of reals with some arbitrary numbers + { + // rec1value R ::= { mantissa 2414341043715239, base 2, exponent 21 } + let val = 3221417.1584163485; + let expected = &[ + 0x9, 0x9, 0x80, 0x15, 0x8, 0x93, 0xd4, 0x94, 0x46, 0xfc, 0xa7, + ]; + let mut buffer = [0u8; 11]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec1value R ::= { mantissa 2671155248072715, base 2, exponent 23 } + let val = 13364022.365665454; + let expected = &[ + 0x09, 0x09, 0x80, 0x17, 0x09, 0x7d, 0x66, 0xcb, 0xb3, 0x88, 0x0b, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec1value R ::= { mantissa -4386812962460287, base 2, exponent 14 } + let val = -32343.132588105735; + let expected = &[ + 0x09, 0x09, 0xc0, 0x0e, 0x0f, 0x95, 0xc8, 0x7c, 0x52, 0xd2, 0x7f, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = -27084.866751869475; + let expected = &[ + 0x09, 0x09, 0xc0, 0x0e, 0x0a, 0x73, 0x37, 0x78, 0xdc, 0xd5, 0x4a, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec1value R ::= { mantissa -4372913134428149, base 2, exponent 7 } + let val = -252.28566647111404; + let expected = &[ + 0x09, 0x09, 0xc0, 0x07, 0x0f, 0x89, 0x24, 0x2e, 0x02, 0xdf, 0xf5, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = -14.399709612928548; + let expected = &[ + 0x09, 0x09, 0xc0, 0x03, 0x0c, 0xcc, 0xa6, 0xbd, 0x06, 0xd9, 0x92, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = -0.08340570261832964; + let expected = &[ + 0x09, 0x0a, 0xc1, 0xff, 0xfc, 0x05, 0x5a, 0x13, 0x7d, 0x0b, 0xae, 0x3d, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = 0.00536851453803701; + let expected = &[ + 0x09, 0x0a, 0x81, 0xff, 0xf8, 0x05, 0xfd, 0x4b, 0xa5, 0xe7, 0x4c, 0x93, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = 0.00045183525648866433; + let expected = &[ + 0x09, 0x0a, 0x81, 0xff, 0xf4, 0x0d, 0x9c, 0x89, 0xa6, 0x59, 0x33, 0x39, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = 0.000033869092002682955; + let expected = &[ + 0x09, 0x0a, 0x81, 0xff, 0xf1, 0x01, 0xc1, 0xd5, 0x23, 0xd5, 0x54, 0x7c, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = 0.0000011770891033600088; + let expected = &[ + 0x09, 0x0a, 0x81, 0xff, 0xec, 0x03, 0xbf, 0x8f, 0x27, 0xf4, 0x62, 0x56, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = 0.00000005549514041997082; + let expected = &[ + 0x09, 0x0a, 0x81, 0xff, 0xe7, 0x0d, 0xcb, 0x31, 0xab, 0x6e, 0xb8, 0xd7, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = 0.0000000012707044685547803; + let expected = &[ + 0x09, 0x0a, 0x81, 0xff, 0xe2, 0x05, 0xd4, 0x9e, 0x0a, 0xf2, 0xff, 0x1f, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = 0.00000000002969611878378562; + let expected = &[ + 0x09, 0x09, 0x81, 0xff, 0xdd, 0x53, 0x5b, 0x6f, 0x97, 0xee, 0xb6, + ]; + let mut buffer = [0u8; 11]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + } + + #[test] + fn reject_non_canonical() { + assert!(f64::from_der(&[0x09, 0x81, 0x00]).is_err()); + } + + #[test] + fn encdec_f64() { + use super::{decode_f64, encode_f64}; + // Test that the extraction and recreation works + for val in [ + 1.0, + 0.1, + -0.1, + -1.0, + 0.0, + f64::MIN_POSITIVE, + f64::MAX, + f64::MIN, + 3.1415, + 951.2357864, + -3.1415, + -951.2357864, + ] { + let (s, e, m) = decode_f64(val); + let val2 = encode_f64(s, e, m); + assert!( + (val - val2).abs() < f64::EPSILON, + "fail - want {}\tgot {}", + val, + val2 + ); + } + } + + #[test] + fn validation_cases() { + // Caveat: these test cases are validated on the ASN.1 playground: https://asn1.io/asn1playground/ . + // The test case consists in inputing the bytes in the "decode" field and checking that the decoded + // value corresponds to the one encoded here. + // This tool encodes _all_ values that are non-zero in the ISO 6093 NR3 representation. + // This does not seem to perfectly adhere to the ITU specifications, Special Cases section. + // The implementation of this crate correctly supports decoding such values. It will, however, + // systematically encode REALs in their base 2 form, with a scaling factor where needed to + // ensure that the mantissa is either odd or zero (as per section 11.3.1). + + // Positive trivial numbers + { + let expect = 10.0; + let testcase = &[0x09, 0x05, 0x03, 0x31, 0x2E, 0x45, 0x31]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = 100.0; + let testcase = &[0x09, 0x05, 0x03, 0x31, 0x2E, 0x45, 0x32]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = 101.0; + let testcase = &[0x09, 0x08, 0x03, 0x31, 0x30, 0x31, 0x2E, 0x45, 0x2B, 0x30]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = 101.0; + let testcase = &[0x09, 0x08, 0x03, 0x31, 0x30, 0x31, 0x2E, 0x45, 0x2B, 0x30]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = 0.0; + let testcase = &[0x09, 0x00]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = 951.2357864; + let testcase = &[ + 0x09, 0x0F, 0x03, 0x39, 0x35, 0x31, 0x32, 0x33, 0x35, 0x37, 0x38, 0x36, 0x34, 0x2E, + 0x45, 0x2D, 0x37, + ]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + // Negative trivial numbers + { + let expect = -10.0; + let testcase = &[0x09, 0x06, 0x03, 0x2D, 0x31, 0x2E, 0x45, 0x31]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = -100.0; + let testcase = &[0x09, 0x06, 0x03, 0x2D, 0x31, 0x2E, 0x45, 0x32]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = -101.0; + let testcase = &[ + 0x09, 0x09, 0x03, 0x2D, 0x31, 0x30, 0x31, 0x2E, 0x45, 0x2B, 0x30, + ]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = -0.5; + let testcase = &[0x09, 0x07, 0x03, 0x2D, 0x35, 0x2E, 0x45, 0x2D, 0x31]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = -0.0; + let testcase = &[0x09, 0x03, 0x01, 0x2D, 0x30]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + // Test NR3 decoding + let expect = -951.2357864; + let testcase = &[ + 0x09, 0x10, 0x03, 0x2D, 0x39, 0x35, 0x31, 0x32, 0x33, 0x35, 0x37, 0x38, 0x36, 0x34, + 0x2E, 0x45, 0x2D, 0x37, + ]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + } +} diff --git a/vendor/der/src/asn1/sequence.rs b/vendor/der/src/asn1/sequence.rs new file mode 100644 index 0000000..ad4a5d5 --- /dev/null +++ b/vendor/der/src/asn1/sequence.rs @@ -0,0 +1,53 @@ +//! The [`Sequence`] trait simplifies writing decoders/encoders which map ASN.1 +//! `SEQUENCE`s to Rust structs. + +use crate::{ + BytesRef, DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, Result, Tag, Writer, +}; + +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + +/// Marker trait for ASN.1 `SEQUENCE`s. +/// +/// This is mainly used for custom derive. +pub trait Sequence<'a>: DecodeValue<'a> + EncodeValue {} + +impl<'a, S> FixedTag for S +where + S: Sequence<'a>, +{ + const TAG: Tag = Tag::Sequence; +} + +#[cfg(feature = "alloc")] +impl<'a, T> Sequence<'a> for Box<T> where T: Sequence<'a> {} + +/// The [`SequenceRef`] type provides raw access to the octets which comprise a +/// DER-encoded `SEQUENCE`. +/// +/// This is a zero-copy reference type which borrows from the input data. +pub struct SequenceRef<'a> { + /// Body of the `SEQUENCE`. + body: BytesRef<'a>, +} + +impl<'a> DecodeValue<'a> for SequenceRef<'a> { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + Ok(Self { + body: BytesRef::decode_value(reader, header)?, + }) + } +} + +impl EncodeValue for SequenceRef<'_> { + fn value_len(&self) -> Result<Length> { + Ok(self.body.len()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + self.body.encode_value(writer) + } +} + +impl<'a> Sequence<'a> for SequenceRef<'a> {} diff --git a/vendor/der/src/asn1/sequence_of.rs b/vendor/der/src/asn1/sequence_of.rs new file mode 100644 index 0000000..befb029 --- /dev/null +++ b/vendor/der/src/asn1/sequence_of.rs @@ -0,0 +1,230 @@ +//! ASN.1 `SEQUENCE OF` support. + +use crate::{ + arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, DerOrd, Encode, EncodeValue, FixedTag, + Header, Length, Reader, Result, Tag, ValueOrd, Writer, +}; +use core::cmp::Ordering; + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +/// ASN.1 `SEQUENCE OF` backed by an array. +/// +/// This type implements an append-only `SEQUENCE OF` type which is stack-based +/// and does not depend on `alloc` support. +// TODO(tarcieri): use `ArrayVec` when/if it's merged into `core` +// See: https://github.com/rust-lang/rfcs/pull/2990 +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SequenceOf<T, const N: usize> { + inner: ArrayVec<T, N>, +} + +impl<T, const N: usize> SequenceOf<T, N> { + /// Create a new [`SequenceOf`]. + pub fn new() -> Self { + Self { + inner: ArrayVec::new(), + } + } + + /// Add an element to this [`SequenceOf`]. + pub fn add(&mut self, element: T) -> Result<()> { + self.inner.push(element) + } + + /// Get an element of this [`SequenceOf`]. + pub fn get(&self, index: usize) -> Option<&T> { + self.inner.get(index) + } + + /// Iterate over the elements in this [`SequenceOf`]. + pub fn iter(&self) -> SequenceOfIter<'_, T> { + SequenceOfIter { + inner: self.inner.iter(), + } + } + + /// Is this [`SequenceOf`] empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + /// Number of elements in this [`SequenceOf`]. + pub fn len(&self) -> usize { + self.inner.len() + } +} + +impl<T, const N: usize> Default for SequenceOf<T, N> { + fn default() -> Self { + Self::new() + } +} + +impl<'a, T, const N: usize> DecodeValue<'a> for SequenceOf<T, N> +where + T: Decode<'a>, +{ + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + reader.read_nested(header.length, |reader| { + let mut sequence_of = Self::new(); + + while !reader.is_finished() { + sequence_of.add(T::decode(reader)?)?; + } + + Ok(sequence_of) + }) + } +} + +impl<T, const N: usize> EncodeValue for SequenceOf<T, N> +where + T: Encode, +{ + fn value_len(&self) -> Result<Length> { + self.iter() + .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + for elem in self.iter() { + elem.encode(writer)?; + } + + Ok(()) + } +} + +impl<T, const N: usize> FixedTag for SequenceOf<T, N> { + const TAG: Tag = Tag::Sequence; +} + +impl<T, const N: usize> ValueOrd for SequenceOf<T, N> +where + T: DerOrd, +{ + fn value_cmp(&self, other: &Self) -> Result<Ordering> { + iter_cmp(self.iter(), other.iter()) + } +} + +/// Iterator over the elements of an [`SequenceOf`]. +#[derive(Clone, Debug)] +pub struct SequenceOfIter<'a, T> { + /// Inner iterator. + inner: arrayvec::Iter<'a, T>, +} + +impl<'a, T> Iterator for SequenceOfIter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { + self.inner.next() + } +} + +impl<'a, T> ExactSizeIterator for SequenceOfIter<'a, T> {} + +impl<'a, T, const N: usize> DecodeValue<'a> for [T; N] +where + T: Decode<'a>, +{ + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + let sequence_of = SequenceOf::<T, N>::decode_value(reader, header)?; + + // TODO(tarcieri): use `[T; N]::try_map` instead of `expect` when stable + if sequence_of.inner.len() == N { + Ok(sequence_of + .inner + .into_array() + .map(|elem| elem.expect("arrayvec length mismatch"))) + } else { + Err(Self::TAG.length_error()) + } + } +} + +impl<T, const N: usize> EncodeValue for [T; N] +where + T: Encode, +{ + fn value_len(&self) -> Result<Length> { + self.iter() + .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + for elem in self { + elem.encode(writer)?; + } + + Ok(()) + } +} + +impl<T, const N: usize> FixedTag for [T; N] { + const TAG: Tag = Tag::Sequence; +} + +impl<T, const N: usize> ValueOrd for [T; N] +where + T: DerOrd, +{ + fn value_cmp(&self, other: &Self) -> Result<Ordering> { + iter_cmp(self.iter(), other.iter()) + } +} + +#[cfg(feature = "alloc")] +impl<'a, T> DecodeValue<'a> for Vec<T> +where + T: Decode<'a>, +{ + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + reader.read_nested(header.length, |reader| { + let mut sequence_of = Self::new(); + + while !reader.is_finished() { + sequence_of.push(T::decode(reader)?); + } + + Ok(sequence_of) + }) + } +} + +#[cfg(feature = "alloc")] +impl<T> EncodeValue for Vec<T> +where + T: Encode, +{ + fn value_len(&self) -> Result<Length> { + self.iter() + .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + for elem in self { + elem.encode(writer)?; + } + + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl<T> FixedTag for Vec<T> { + const TAG: Tag = Tag::Sequence; +} + +#[cfg(feature = "alloc")] +impl<T> ValueOrd for Vec<T> +where + T: DerOrd, +{ + fn value_cmp(&self, other: &Self) -> Result<Ordering> { + iter_cmp(self.iter(), other.iter()) + } +} diff --git a/vendor/der/src/asn1/set_of.rs b/vendor/der/src/asn1/set_of.rs new file mode 100644 index 0000000..ff01312 --- /dev/null +++ b/vendor/der/src/asn1/set_of.rs @@ -0,0 +1,539 @@ +//! ASN.1 `SET OF` support. +//! +//! # Ordering Notes +//! +//! Some DER serializer implementations fail to properly sort elements of a +//! `SET OF`. This is technically non-canonical, but occurs frequently +//! enough that most DER decoders tolerate it. Unfortunately because +//! of that, we must also follow suit. +//! +//! However, all types in this module sort elements of a set at decode-time, +//! ensuring they'll be in the proper order if reserialized. + +use crate::{ + arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, DerOrd, Encode, EncodeValue, Error, + ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd, Writer, +}; +use core::cmp::Ordering; + +#[cfg(feature = "alloc")] +use {alloc::vec::Vec, core::slice}; + +/// ASN.1 `SET OF` backed by an array. +/// +/// This type implements an append-only `SET OF` type which is stack-based +/// and does not depend on `alloc` support. +// TODO(tarcieri): use `ArrayVec` when/if it's merged into `core` +// See: https://github.com/rust-lang/rfcs/pull/2990 +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct SetOf<T, const N: usize> +where + T: DerOrd, +{ + inner: ArrayVec<T, N>, +} + +impl<T, const N: usize> SetOf<T, N> +where + T: DerOrd, +{ + /// Create a new [`SetOf`]. + pub fn new() -> Self { + Self { + inner: ArrayVec::default(), + } + } + + /// Add an item to this [`SetOf`]. + /// + /// Items MUST be added in lexicographical order according to the + /// [`DerOrd`] impl on `T`. + #[deprecated(since = "0.7.6", note = "use `insert` or `insert_ordered` instead")] + pub fn add(&mut self, new_elem: T) -> Result<()> { + self.insert_ordered(new_elem) + } + + /// Insert an item into this [`SetOf`]. + pub fn insert(&mut self, item: T) -> Result<()> { + self.inner.push(item)?; + der_sort(self.inner.as_mut()) + } + + /// Insert an item into this [`SetOf`]. + /// + /// Items MUST be added in lexicographical order according to the + /// [`DerOrd`] impl on `T`. + pub fn insert_ordered(&mut self, item: T) -> Result<()> { + // Ensure set elements are lexicographically ordered + if let Some(last) = self.inner.last() { + check_der_ordering(last, &item)?; + } + + self.inner.push(item) + } + + /// Get the nth element from this [`SetOf`]. + pub fn get(&self, index: usize) -> Option<&T> { + self.inner.get(index) + } + + /// Iterate over the elements of this [`SetOf`]. + pub fn iter(&self) -> SetOfIter<'_, T> { + SetOfIter { + inner: self.inner.iter(), + } + } + + /// Is this [`SetOf`] empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + /// Number of elements in this [`SetOf`]. + pub fn len(&self) -> usize { + self.inner.len() + } +} + +impl<T, const N: usize> Default for SetOf<T, N> +where + T: DerOrd, +{ + fn default() -> Self { + Self::new() + } +} + +impl<'a, T, const N: usize> DecodeValue<'a> for SetOf<T, N> +where + T: Decode<'a> + DerOrd, +{ + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + reader.read_nested(header.length, |reader| { + let mut result = Self::new(); + + while !reader.is_finished() { + result.inner.push(T::decode(reader)?)?; + } + + der_sort(result.inner.as_mut())?; + validate(result.inner.as_ref())?; + Ok(result) + }) + } +} + +impl<'a, T, const N: usize> EncodeValue for SetOf<T, N> +where + T: 'a + Decode<'a> + Encode + DerOrd, +{ + fn value_len(&self) -> Result<Length> { + self.iter() + .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + for elem in self.iter() { + elem.encode(writer)?; + } + + Ok(()) + } +} + +impl<'a, T, const N: usize> FixedTag for SetOf<T, N> +where + T: Decode<'a> + DerOrd, +{ + const TAG: Tag = Tag::Set; +} + +impl<T, const N: usize> TryFrom<[T; N]> for SetOf<T, N> +where + T: DerOrd, +{ + type Error = Error; + + fn try_from(mut arr: [T; N]) -> Result<SetOf<T, N>> { + der_sort(&mut arr)?; + + let mut result = SetOf::new(); + + for elem in arr { + result.insert_ordered(elem)?; + } + + Ok(result) + } +} + +impl<T, const N: usize> ValueOrd for SetOf<T, N> +where + T: DerOrd, +{ + fn value_cmp(&self, other: &Self) -> Result<Ordering> { + iter_cmp(self.iter(), other.iter()) + } +} + +/// Iterator over the elements of an [`SetOf`]. +#[derive(Clone, Debug)] +pub struct SetOfIter<'a, T> { + /// Inner iterator. + inner: arrayvec::Iter<'a, T>, +} + +impl<'a, T> Iterator for SetOfIter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { + self.inner.next() + } +} + +impl<'a, T> ExactSizeIterator for SetOfIter<'a, T> {} + +/// ASN.1 `SET OF` backed by a [`Vec`]. +/// +/// This type implements an append-only `SET OF` type which is heap-backed +/// and depends on `alloc` support. +#[cfg(feature = "alloc")] +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct SetOfVec<T> +where + T: DerOrd, +{ + inner: Vec<T>, +} + +#[cfg(feature = "alloc")] +impl<T: DerOrd> Default for SetOfVec<T> { + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} + +#[cfg(feature = "alloc")] +impl<T> SetOfVec<T> +where + T: DerOrd, +{ + /// Create a new [`SetOfVec`]. + pub fn new() -> Self { + Self { + inner: Vec::default(), + } + } + + /// Create a new [`SetOfVec`] from the given iterator. + /// + /// Note: this is an inherent method instead of an impl of the + /// [`FromIterator`] trait in order to be fallible. + #[allow(clippy::should_implement_trait)] + pub fn from_iter<I>(iter: I) -> Result<Self> + where + I: IntoIterator<Item = T>, + { + Vec::from_iter(iter).try_into() + } + + /// Add an element to this [`SetOfVec`]. + /// + /// Items MUST be added in lexicographical order according to the + /// [`DerOrd`] impl on `T`. + #[deprecated(since = "0.7.6", note = "use `insert` or `insert_ordered` instead")] + pub fn add(&mut self, item: T) -> Result<()> { + self.insert_ordered(item) + } + + /// Extend a [`SetOfVec`] using an iterator. + /// + /// Note: this is an inherent method instead of an impl of the + /// [`Extend`] trait in order to be fallible. + pub fn extend<I>(&mut self, iter: I) -> Result<()> + where + I: IntoIterator<Item = T>, + { + self.inner.extend(iter); + der_sort(&mut self.inner) + } + + /// Insert an item into this [`SetOfVec`]. Must be unique. + pub fn insert(&mut self, item: T) -> Result<()> { + self.inner.push(item); + der_sort(&mut self.inner) + } + + /// Insert an item into this [`SetOfVec`]. Must be unique. + /// + /// Items MUST be added in lexicographical order according to the + /// [`DerOrd`] impl on `T`. + pub fn insert_ordered(&mut self, item: T) -> Result<()> { + // Ensure set elements are lexicographically ordered + if let Some(last) = self.inner.last() { + check_der_ordering(last, &item)?; + } + + self.inner.push(item); + Ok(()) + } + + /// Borrow the elements of this [`SetOfVec`] as a slice. + pub fn as_slice(&self) -> &[T] { + self.inner.as_slice() + } + + /// Get the nth element from this [`SetOfVec`]. + pub fn get(&self, index: usize) -> Option<&T> { + self.inner.get(index) + } + + /// Convert this [`SetOfVec`] into the inner [`Vec`]. + pub fn into_vec(self) -> Vec<T> { + self.inner + } + + /// Iterate over the elements of this [`SetOfVec`]. + pub fn iter(&self) -> slice::Iter<'_, T> { + self.inner.iter() + } + + /// Is this [`SetOfVec`] empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + /// Number of elements in this [`SetOfVec`]. + pub fn len(&self) -> usize { + self.inner.len() + } +} + +#[cfg(feature = "alloc")] +impl<T> AsRef<[T]> for SetOfVec<T> +where + T: DerOrd, +{ + fn as_ref(&self) -> &[T] { + self.as_slice() + } +} + +#[cfg(feature = "alloc")] +impl<'a, T> DecodeValue<'a> for SetOfVec<T> +where + T: Decode<'a> + DerOrd, +{ + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + reader.read_nested(header.length, |reader| { + let mut inner = Vec::new(); + + while !reader.is_finished() { + inner.push(T::decode(reader)?); + } + + der_sort(inner.as_mut())?; + validate(inner.as_ref())?; + Ok(Self { inner }) + }) + } +} + +#[cfg(feature = "alloc")] +impl<'a, T> EncodeValue for SetOfVec<T> +where + T: 'a + Decode<'a> + Encode + DerOrd, +{ + fn value_len(&self) -> Result<Length> { + self.iter() + .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + for elem in self.iter() { + elem.encode(writer)?; + } + + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl<T> FixedTag for SetOfVec<T> +where + T: DerOrd, +{ + const TAG: Tag = Tag::Set; +} + +#[cfg(feature = "alloc")] +impl<T> From<SetOfVec<T>> for Vec<T> +where + T: DerOrd, +{ + fn from(set: SetOfVec<T>) -> Vec<T> { + set.into_vec() + } +} + +#[cfg(feature = "alloc")] +impl<T> TryFrom<Vec<T>> for SetOfVec<T> +where + T: DerOrd, +{ + type Error = Error; + + fn try_from(mut vec: Vec<T>) -> Result<SetOfVec<T>> { + der_sort(vec.as_mut_slice())?; + Ok(SetOfVec { inner: vec }) + } +} + +#[cfg(feature = "alloc")] +impl<T, const N: usize> TryFrom<[T; N]> for SetOfVec<T> +where + T: DerOrd, +{ + type Error = Error; + + fn try_from(arr: [T; N]) -> Result<SetOfVec<T>> { + Vec::from(arr).try_into() + } +} + +#[cfg(feature = "alloc")] +impl<T> ValueOrd for SetOfVec<T> +where + T: DerOrd, +{ + fn value_cmp(&self, other: &Self) -> Result<Ordering> { + iter_cmp(self.iter(), other.iter()) + } +} + +// Implement by hand because the derive would create invalid values. +// Use the conversion from Vec to create a valid value. +#[cfg(feature = "arbitrary")] +impl<'a, T> arbitrary::Arbitrary<'a> for SetOfVec<T> +where + T: DerOrd + arbitrary::Arbitrary<'a>, +{ + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { + Self::try_from( + u.arbitrary_iter()? + .collect::<std::result::Result<Vec<_>, _>>()?, + ) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } + + fn size_hint(_depth: usize) -> (usize, Option<usize>) { + (0, None) + } +} + +/// Ensure set elements are lexicographically ordered using [`DerOrd`]. +fn check_der_ordering<T: DerOrd>(a: &T, b: &T) -> Result<()> { + match a.der_cmp(b)? { + Ordering::Less => Ok(()), + Ordering::Equal => Err(ErrorKind::SetDuplicate.into()), + Ordering::Greater => Err(ErrorKind::SetOrdering.into()), + } +} + +/// Sort a mut slice according to its [`DerOrd`], returning any errors which +/// might occur during the comparison. +/// +/// The algorithm is insertion sort, which should perform well when the input +/// is mostly sorted to begin with. +/// +/// This function is used rather than Rust's built-in `[T]::sort_by` in order +/// to support heapless `no_std` targets as well as to enable bubbling up +/// sorting errors. +#[allow(clippy::integer_arithmetic)] +fn der_sort<T: DerOrd>(slice: &mut [T]) -> Result<()> { + for i in 0..slice.len() { + let mut j = i; + + while j > 0 { + match slice[j - 1].der_cmp(&slice[j])? { + Ordering::Less => break, + Ordering::Equal => return Err(ErrorKind::SetDuplicate.into()), + Ordering::Greater => { + slice.swap(j - 1, j); + j -= 1; + } + } + } + } + + Ok(()) +} + +/// Validate the elements of a `SET OF`, ensuring that they are all in order +/// and that there are no duplicates. +fn validate<T: DerOrd>(slice: &[T]) -> Result<()> { + if let Some(len) = slice.len().checked_sub(1) { + for i in 0..len { + let j = i.checked_add(1).ok_or(ErrorKind::Overflow)?; + + match slice.get(i..=j) { + Some([a, b]) => { + if a.der_cmp(b)? != Ordering::Less { + return Err(ErrorKind::SetOrdering.into()); + } + } + _ => return Err(Tag::Set.value_error()), + } + } + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::SetOf; + #[cfg(feature = "alloc")] + use super::SetOfVec; + use crate::ErrorKind; + + #[test] + fn setof_tryfrom_array() { + let arr = [3u16, 2, 1, 65535, 0]; + let set = SetOf::try_from(arr).unwrap(); + assert!(set.iter().copied().eq([0, 1, 2, 3, 65535])); + } + + #[test] + fn setof_tryfrom_array_reject_duplicates() { + let arr = [1u16, 1]; + let err = SetOf::try_from(arr).err().unwrap(); + assert_eq!(err.kind(), ErrorKind::SetDuplicate); + } + + #[cfg(feature = "alloc")] + #[test] + fn setofvec_tryfrom_array() { + let arr = [3u16, 2, 1, 65535, 0]; + let set = SetOfVec::try_from(arr).unwrap(); + assert_eq!(set.as_ref(), &[0, 1, 2, 3, 65535]); + } + + #[cfg(feature = "alloc")] + #[test] + fn setofvec_tryfrom_vec() { + let vec = vec![3u16, 2, 1, 65535, 0]; + let set = SetOfVec::try_from(vec).unwrap(); + assert_eq!(set.as_ref(), &[0, 1, 2, 3, 65535]); + } + + #[cfg(feature = "alloc")] + #[test] + fn setofvec_tryfrom_vec_reject_duplicates() { + let vec = vec![1u16, 1]; + let err = SetOfVec::try_from(vec).err().unwrap(); + assert_eq!(err.kind(), ErrorKind::SetDuplicate); + } +} diff --git a/vendor/der/src/asn1/teletex_string.rs b/vendor/der/src/asn1/teletex_string.rs new file mode 100644 index 0000000..337c071 --- /dev/null +++ b/vendor/der/src/asn1/teletex_string.rs @@ -0,0 +1,217 @@ +//! ASN.1 `TeletexString` support. +//! +use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag}; +use core::{fmt, ops::Deref}; + +macro_rules! impl_teletex_string { + ($type: ty) => { + impl_teletex_string!($type,); + }; + ($type: ty, $($li: lifetime)?) => { + impl_string_type!($type, $($li),*); + + impl<$($li),*> FixedTag for $type { + const TAG: Tag = Tag::TeletexString; + } + + impl<$($li),*> fmt::Debug for $type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "TeletexString({:?})", self.as_str()) + } + } + }; +} + +/// ASN.1 `TeletexString` type. +/// +/// Supports a subset the ASCII character set (described below). +/// +/// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead. +/// For the full ASCII character set, use +/// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`]. +/// +/// This is a zero-copy reference type which borrows from the input data. +/// +/// # Supported characters +/// +/// The standard defines a complex character set allowed in this type. However, quoting the ASN.1 +/// mailing list, "a sizable volume of software in the world treats TeletexString (T61String) as a +/// simple 8-bit string with mostly Windows Latin 1 (superset of iso-8859-1) encoding". +/// +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] +pub struct TeletexStringRef<'a> { + /// Inner value + inner: StrRef<'a>, +} + +impl<'a> TeletexStringRef<'a> { + /// Create a new ASN.1 `TeletexString`. + pub fn new<T>(input: &'a T) -> Result<Self> + where + T: AsRef<[u8]> + ?Sized, + { + let input = input.as_ref(); + + // FIXME: support higher part of the charset + if input.iter().any(|&c| c > 0x7F) { + return Err(Self::TAG.value_error()); + } + + StrRef::from_bytes(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } +} + +impl_teletex_string!(TeletexStringRef<'a>, 'a); + +impl<'a> Deref for TeletexStringRef<'a> { + type Target = StrRef<'a>; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl<'a> From<&TeletexStringRef<'a>> for TeletexStringRef<'a> { + fn from(value: &TeletexStringRef<'a>) -> TeletexStringRef<'a> { + *value + } +} + +impl<'a> From<TeletexStringRef<'a>> for AnyRef<'a> { + fn from(teletex_string: TeletexStringRef<'a>) -> AnyRef<'a> { + AnyRef::from_tag_and_value(Tag::TeletexString, teletex_string.inner.into()) + } +} + +#[cfg(feature = "alloc")] +pub use self::allocation::TeletexString; + +#[cfg(feature = "alloc")] +mod allocation { + use super::TeletexStringRef; + + use crate::{ + asn1::AnyRef, + referenced::{OwnedToRef, RefToOwned}, + BytesRef, Error, FixedTag, Result, StrOwned, Tag, + }; + use alloc::string::String; + use core::{fmt, ops::Deref}; + + /// ASN.1 `TeletexString` type. + /// + /// Supports a subset the ASCII character set (described below). + /// + /// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead. + /// For the full ASCII character set, use + /// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`]. + /// + /// # Supported characters + /// + /// The standard defines a complex character set allowed in this type. However, quoting the ASN.1 + /// mailing list, "a sizable volume of software in the world treats TeletexString (T61String) as a + /// simple 8-bit string with mostly Windows Latin 1 (superset of iso-8859-1) encoding". + /// + #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] + pub struct TeletexString { + /// Inner value + inner: StrOwned, + } + + impl TeletexString { + /// Create a new ASN.1 `TeletexString`. + pub fn new<T>(input: &T) -> Result<Self> + where + T: AsRef<[u8]> + ?Sized, + { + let input = input.as_ref(); + + TeletexStringRef::new(input)?; + + StrOwned::from_bytes(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } + } + + impl_teletex_string!(TeletexString); + + impl Deref for TeletexString { + type Target = StrOwned; + + fn deref(&self) -> &Self::Target { + &self.inner + } + } + + impl<'a> From<TeletexStringRef<'a>> for TeletexString { + fn from(value: TeletexStringRef<'a>) -> TeletexString { + let inner = + StrOwned::from_bytes(value.inner.as_bytes()).expect("Invalid TeletexString"); + Self { inner } + } + } + + impl<'a> From<&'a TeletexString> for AnyRef<'a> { + fn from(teletex_string: &'a TeletexString) -> AnyRef<'a> { + AnyRef::from_tag_and_value( + Tag::TeletexString, + BytesRef::new(teletex_string.inner.as_bytes()).expect("Invalid TeletexString"), + ) + } + } + + impl<'a> RefToOwned<'a> for TeletexStringRef<'a> { + type Owned = TeletexString; + fn ref_to_owned(&self) -> Self::Owned { + TeletexString { + inner: self.inner.ref_to_owned(), + } + } + } + + impl OwnedToRef for TeletexString { + type Borrowed<'a> = TeletexStringRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + TeletexStringRef { + inner: self.inner.owned_to_ref(), + } + } + } + + impl TryFrom<String> for TeletexString { + type Error = Error; + + fn try_from(input: String) -> Result<Self> { + TeletexStringRef::new(&input)?; + + StrOwned::new(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } + } +} + +#[cfg(test)] +mod tests { + use super::TeletexStringRef; + use crate::Decode; + use crate::SliceWriter; + + #[test] + fn parse_bytes() { + let example_bytes = &[ + 0x14, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31, + ]; + + let teletex_string = TeletexStringRef::from_der(example_bytes).unwrap(); + assert_eq!(teletex_string.as_str(), "Test User 1"); + let mut out = [0_u8; 30]; + let mut writer = SliceWriter::new(&mut out); + writer.encode(&teletex_string).unwrap(); + let encoded = writer.finish().unwrap(); + assert_eq!(encoded, example_bytes); + } +} diff --git a/vendor/der/src/asn1/utc_time.rs b/vendor/der/src/asn1/utc_time.rs new file mode 100644 index 0000000..9f2f171 --- /dev/null +++ b/vendor/der/src/asn1/utc_time.rs @@ -0,0 +1,242 @@ +//! ASN.1 `UTCTime` support. + +use crate::{ + datetime::{self, DateTime}, + ord::OrdIsValueOrd, + DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, + Writer, +}; +use core::time::Duration; + +#[cfg(feature = "std")] +use std::time::SystemTime; + +/// ASN.1 `UTCTime` type. +/// +/// This type implements the validity requirements specified in +/// [RFC 5280 Section 4.1.2.5.1][1], namely: +/// +/// > For the purposes of this profile, UTCTime values MUST be expressed in +/// > Greenwich Mean Time (Zulu) and MUST include seconds (i.e., times are +/// > `YYMMDDHHMMSSZ`), even where the number of seconds is zero. Conforming +/// > systems MUST interpret the year field (`YY`) as follows: +/// > +/// > - Where `YY` is greater than or equal to 50, the year SHALL be +/// > interpreted as `19YY`; and +/// > - Where `YY` is less than 50, the year SHALL be interpreted as `20YY`. +/// +/// Note: Due to common operations working on `UNIX_EPOCH` [`UtcTime`]s are +/// only supported for the years 1970-2049. +/// +/// [1]: https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1 +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct UtcTime(DateTime); + +impl UtcTime { + /// Length of an RFC 5280-flavored ASN.1 DER-encoded [`UtcTime`]. + pub const LENGTH: usize = 13; + + /// Maximum year that can be represented as a `UTCTime`. + pub const MAX_YEAR: u16 = 2049; + + /// Create a [`UtcTime`] from a [`DateTime`]. + pub fn from_date_time(datetime: DateTime) -> Result<Self> { + if datetime.year() <= UtcTime::MAX_YEAR { + Ok(Self(datetime)) + } else { + Err(Self::TAG.value_error()) + } + } + + /// Convert this [`UtcTime`] into a [`DateTime`]. + pub fn to_date_time(&self) -> DateTime { + self.0 + } + + /// Create a new [`UtcTime`] given a [`Duration`] since `UNIX_EPOCH` + /// (a.k.a. "Unix time") + pub fn from_unix_duration(unix_duration: Duration) -> Result<Self> { + DateTime::from_unix_duration(unix_duration)?.try_into() + } + + /// Get the duration of this timestamp since `UNIX_EPOCH`. + pub fn to_unix_duration(&self) -> Duration { + self.0.unix_duration() + } + + /// Instantiate from [`SystemTime`]. + #[cfg(feature = "std")] + pub fn from_system_time(time: SystemTime) -> Result<Self> { + DateTime::try_from(time) + .map_err(|_| Self::TAG.value_error())? + .try_into() + } + + /// Convert to [`SystemTime`]. + #[cfg(feature = "std")] + pub fn to_system_time(&self) -> SystemTime { + self.0.to_system_time() + } +} + +impl_any_conversions!(UtcTime); + +impl<'a> DecodeValue<'a> for UtcTime { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + if Self::LENGTH != usize::try_from(header.length)? { + return Err(Self::TAG.value_error()); + } + + let mut bytes = [0u8; Self::LENGTH]; + reader.read_into(&mut bytes)?; + + match bytes { + // RFC 5280 requires mandatory seconds and Z-normalized time zone + [year1, year2, mon1, mon2, day1, day2, hour1, hour2, min1, min2, sec1, sec2, b'Z'] => { + let year = u16::from(datetime::decode_decimal(Self::TAG, year1, year2)?); + let month = datetime::decode_decimal(Self::TAG, mon1, mon2)?; + let day = datetime::decode_decimal(Self::TAG, day1, day2)?; + let hour = datetime::decode_decimal(Self::TAG, hour1, hour2)?; + let minute = datetime::decode_decimal(Self::TAG, min1, min2)?; + let second = datetime::decode_decimal(Self::TAG, sec1, sec2)?; + + // RFC 5280 rules for interpreting the year + let year = if year >= 50 { + year.checked_add(1900) + } else { + year.checked_add(2000) + } + .ok_or(ErrorKind::DateTime)?; + + DateTime::new(year, month, day, hour, minute, second) + .map_err(|_| Self::TAG.value_error()) + .and_then(|dt| Self::from_unix_duration(dt.unix_duration())) + } + _ => Err(Self::TAG.value_error()), + } + } +} + +impl EncodeValue for UtcTime { + fn value_len(&self) -> Result<Length> { + Self::LENGTH.try_into() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + let year = match self.0.year() { + y @ 1950..=1999 => y.checked_sub(1900), + y @ 2000..=2049 => y.checked_sub(2000), + _ => return Err(Self::TAG.value_error()), + } + .and_then(|y| u8::try_from(y).ok()) + .ok_or(ErrorKind::DateTime)?; + + datetime::encode_decimal(writer, Self::TAG, year)?; + datetime::encode_decimal(writer, Self::TAG, self.0.month())?; + datetime::encode_decimal(writer, Self::TAG, self.0.day())?; + datetime::encode_decimal(writer, Self::TAG, self.0.hour())?; + datetime::encode_decimal(writer, Self::TAG, self.0.minutes())?; + datetime::encode_decimal(writer, Self::TAG, self.0.seconds())?; + writer.write_byte(b'Z') + } +} + +impl FixedTag for UtcTime { + const TAG: Tag = Tag::UtcTime; +} + +impl OrdIsValueOrd for UtcTime {} + +impl From<&UtcTime> for UtcTime { + fn from(value: &UtcTime) -> UtcTime { + *value + } +} + +impl From<UtcTime> for DateTime { + fn from(utc_time: UtcTime) -> DateTime { + utc_time.0 + } +} + +impl From<&UtcTime> for DateTime { + fn from(utc_time: &UtcTime) -> DateTime { + utc_time.0 + } +} + +impl TryFrom<DateTime> for UtcTime { + type Error = Error; + + fn try_from(datetime: DateTime) -> Result<Self> { + Self::from_date_time(datetime) + } +} + +impl TryFrom<&DateTime> for UtcTime { + type Error = Error; + + fn try_from(datetime: &DateTime) -> Result<Self> { + Self::from_date_time(*datetime) + } +} + +#[cfg(feature = "std")] +impl From<UtcTime> for SystemTime { + fn from(utc_time: UtcTime) -> SystemTime { + utc_time.to_system_time() + } +} + +// Implement by hand because the derive would create invalid values. +// Use the conversion from DateTime to create a valid value. +// The DateTime type has a way bigger range of valid years than UtcTime, +// so the DateTime year is mapped into a valid range to throw away less inputs. +#[cfg(feature = "arbitrary")] +impl<'a> arbitrary::Arbitrary<'a> for UtcTime { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { + const MIN_YEAR: u16 = 1970; + const VALID_YEAR_COUNT: u16 = UtcTime::MAX_YEAR - MIN_YEAR + 1; + const AVERAGE_SECONDS_IN_YEAR: u64 = 31_556_952; + + let datetime = DateTime::arbitrary(u)?; + let year = datetime.year(); + let duration = datetime.unix_duration(); + + // Clamp the year into a valid range to not throw away too much input + let valid_year = (year.saturating_sub(MIN_YEAR)) + .rem_euclid(VALID_YEAR_COUNT) + .saturating_add(MIN_YEAR); + let year_to_remove = year.saturating_sub(valid_year); + let valid_duration = duration + - Duration::from_secs( + u64::from(year_to_remove).saturating_mul(AVERAGE_SECONDS_IN_YEAR), + ); + + Self::from_date_time(DateTime::from_unix_duration(valid_duration).expect("supported range")) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } + + fn size_hint(depth: usize) -> (usize, Option<usize>) { + DateTime::size_hint(depth) + } +} + +#[cfg(test)] +mod tests { + use super::UtcTime; + use crate::{Decode, Encode, SliceWriter}; + use hex_literal::hex; + + #[test] + fn round_trip_vector() { + let example_bytes = hex!("17 0d 39 31 30 35 30 36 32 33 34 35 34 30 5a"); + let utc_time = UtcTime::from_der(&example_bytes).unwrap(); + assert_eq!(utc_time.to_unix_duration().as_secs(), 673573540); + + let mut buf = [0u8; 128]; + let mut encoder = SliceWriter::new(&mut buf); + utc_time.encode(&mut encoder).unwrap(); + assert_eq!(example_bytes, encoder.finish().unwrap()); + } +} diff --git a/vendor/der/src/asn1/utf8_string.rs b/vendor/der/src/asn1/utf8_string.rs new file mode 100644 index 0000000..6018750 --- /dev/null +++ b/vendor/der/src/asn1/utf8_string.rs @@ -0,0 +1,164 @@ +//! ASN.1 `UTF8String` support. + +use crate::{ + asn1::AnyRef, ord::OrdIsValueOrd, EncodeValue, Error, FixedTag, Length, Result, StrRef, Tag, + Writer, +}; +use core::{fmt, ops::Deref, str}; + +#[cfg(feature = "alloc")] +use { + crate::{DecodeValue, Header, Reader}, + alloc::{borrow::ToOwned, string::String}, +}; + +/// ASN.1 `UTF8String` type. +/// +/// Supports the full UTF-8 encoding. +/// +/// Note that the [`Decode`][`crate::Decode`] and [`Encode`][`crate::Encode`] +/// traits are impl'd for Rust's [`str`][`prim@str`] primitive, which +/// decodes/encodes as a [`Utf8StringRef`]. +/// +/// You are free to use [`str`][`prim@str`] instead of this type, however it's +/// still provided for explicitness in cases where it might be ambiguous with +/// other ASN.1 string encodings such as +/// [`PrintableStringRef`][`crate::asn1::PrintableStringRef`]. +/// +/// This is a zero-copy reference type which borrows from the input data. +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] +pub struct Utf8StringRef<'a> { + /// Inner value + inner: StrRef<'a>, +} + +impl<'a> Utf8StringRef<'a> { + /// Create a new ASN.1 `UTF8String`. + pub fn new<T>(input: &'a T) -> Result<Self> + where + T: AsRef<[u8]> + ?Sized, + { + StrRef::from_bytes(input.as_ref()).map(|inner| Self { inner }) + } +} + +impl_string_type!(Utf8StringRef<'a>, 'a); + +impl<'a> Deref for Utf8StringRef<'a> { + type Target = StrRef<'a>; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl FixedTag for Utf8StringRef<'_> { + const TAG: Tag = Tag::Utf8String; +} + +impl<'a> From<&Utf8StringRef<'a>> for Utf8StringRef<'a> { + fn from(value: &Utf8StringRef<'a>) -> Utf8StringRef<'a> { + *value + } +} + +impl<'a> From<Utf8StringRef<'a>> for AnyRef<'a> { + fn from(utf_string: Utf8StringRef<'a>) -> AnyRef<'a> { + AnyRef::from_tag_and_value(Tag::Utf8String, utf_string.inner.into()) + } +} + +impl<'a> fmt::Debug for Utf8StringRef<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Utf8String({:?})", self.as_str()) + } +} + +impl<'a> TryFrom<AnyRef<'a>> for &'a str { + type Error = Error; + + fn try_from(any: AnyRef<'a>) -> Result<&'a str> { + Utf8StringRef::try_from(any).map(|s| s.as_str()) + } +} + +impl EncodeValue for str { + fn value_len(&self) -> Result<Length> { + Utf8StringRef::new(self)?.value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + Utf8StringRef::new(self)?.encode_value(writer) + } +} + +impl FixedTag for str { + const TAG: Tag = Tag::Utf8String; +} + +impl OrdIsValueOrd for str {} + +#[cfg(feature = "alloc")] +impl<'a> From<Utf8StringRef<'a>> for String { + fn from(s: Utf8StringRef<'a>) -> String { + s.as_str().to_owned() + } +} + +#[cfg(feature = "alloc")] +impl<'a> TryFrom<AnyRef<'a>> for String { + type Error = Error; + + fn try_from(any: AnyRef<'a>) -> Result<String> { + Utf8StringRef::try_from(any).map(|s| s.as_str().to_owned()) + } +} + +#[cfg(feature = "alloc")] +impl<'a> DecodeValue<'a> for String { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + Ok(String::from_utf8(reader.read_vec(header.length)?)?) + } +} + +#[cfg(feature = "alloc")] +impl EncodeValue for String { + fn value_len(&self) -> Result<Length> { + Utf8StringRef::new(self)?.value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + Utf8StringRef::new(self)?.encode_value(writer) + } +} + +#[cfg(feature = "alloc")] +impl FixedTag for String { + const TAG: Tag = Tag::Utf8String; +} + +#[cfg(feature = "alloc")] +impl OrdIsValueOrd for String {} + +#[cfg(test)] +mod tests { + use super::Utf8StringRef; + use crate::Decode; + + #[test] + fn parse_ascii_bytes() { + let example_bytes = &[ + 0x0c, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31, + ]; + + let utf8_string = Utf8StringRef::from_der(example_bytes).unwrap(); + assert_eq!(utf8_string.as_str(), "Test User 1"); + } + + #[test] + fn parse_utf8_bytes() { + let example_bytes = &[0x0c, 0x06, 0x48, 0x65, 0x6c, 0x6c, 0xc3, 0xb3]; + let utf8_string = Utf8StringRef::from_der(example_bytes).unwrap(); + assert_eq!(utf8_string.as_str(), "Helló"); + } +} diff --git a/vendor/der/src/asn1/videotex_string.rs b/vendor/der/src/asn1/videotex_string.rs new file mode 100644 index 0000000..55b1a49 --- /dev/null +++ b/vendor/der/src/asn1/videotex_string.rs @@ -0,0 +1,98 @@ +//! ASN.1 `VideotexString` support. + +use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag}; +use core::{fmt, ops::Deref}; + +/// ASN.1 `VideotexString` type. +/// +/// Supports a subset the ASCII character set (described below). +/// +/// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead. +/// For the full ASCII character set, use +/// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`]. +/// +/// This is a zero-copy reference type which borrows from the input data. +/// +/// # Supported characters +/// +/// For the practical purposes VideotexString is treated as IA5string, disallowing non-ASCII chars. +/// +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] +pub struct VideotexStringRef<'a> { + /// Inner value + inner: StrRef<'a>, +} + +impl<'a> VideotexStringRef<'a> { + /// Create a new ASN.1 `VideotexString`. + pub fn new<T>(input: &'a T) -> Result<Self> + where + T: AsRef<[u8]> + ?Sized, + { + let input = input.as_ref(); + + // Validate all characters are within VideotexString's allowed set + // FIXME: treat as if it were IA5String + if input.iter().any(|&c| c > 0x7F) { + return Err(Self::TAG.value_error()); + } + + StrRef::from_bytes(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } +} + +impl_string_type!(VideotexStringRef<'a>, 'a); + +impl<'a> Deref for VideotexStringRef<'a> { + type Target = StrRef<'a>; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl FixedTag for VideotexStringRef<'_> { + const TAG: Tag = Tag::VideotexString; +} + +impl<'a> From<&VideotexStringRef<'a>> for VideotexStringRef<'a> { + fn from(value: &VideotexStringRef<'a>) -> VideotexStringRef<'a> { + *value + } +} + +impl<'a> From<VideotexStringRef<'a>> for AnyRef<'a> { + fn from(printable_string: VideotexStringRef<'a>) -> AnyRef<'a> { + AnyRef::from_tag_and_value(Tag::VideotexString, printable_string.inner.into()) + } +} + +impl<'a> From<VideotexStringRef<'a>> for &'a [u8] { + fn from(printable_string: VideotexStringRef<'a>) -> &'a [u8] { + printable_string.as_bytes() + } +} + +impl<'a> fmt::Debug for VideotexStringRef<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "VideotexString({:?})", self.as_str()) + } +} + +#[cfg(test)] +mod tests { + use super::VideotexStringRef; + use crate::Decode; + + #[test] + fn parse_bytes() { + let example_bytes = &[ + 0x15, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31, + ]; + + let printable_string = VideotexStringRef::from_der(example_bytes).unwrap(); + assert_eq!(printable_string.as_str(), "Test User 1"); + } +} |