summaryrefslogtreecommitdiffstats
path: root/vendor/der/src/asn1
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:47:55 +0000
commit2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4 (patch)
tree033cc839730fda84ff08db877037977be94e5e3a /vendor/der/src/asn1
parentInitial commit. (diff)
downloadcargo-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')
-rw-r--r--vendor/der/src/asn1/any.rs315
-rw-r--r--vendor/der/src/asn1/bit_string.rs552
-rw-r--r--vendor/der/src/asn1/bmp_string.rs164
-rw-r--r--vendor/der/src/asn1/boolean.rs82
-rw-r--r--vendor/der/src/asn1/choice.rs26
-rw-r--r--vendor/der/src/asn1/context_specific.rs354
-rw-r--r--vendor/der/src/asn1/generalized_time.rs330
-rw-r--r--vendor/der/src/asn1/ia5_string.rs195
-rw-r--r--vendor/der/src/asn1/integer.rs161
-rw-r--r--vendor/der/src/asn1/integer/int.rs442
-rw-r--r--vendor/der/src/asn1/integer/uint.rs428
-rw-r--r--vendor/der/src/asn1/internal_macros.rs75
-rw-r--r--vendor/der/src/asn1/null.rs102
-rw-r--r--vendor/der/src/asn1/octet_string.rs257
-rw-r--r--vendor/der/src/asn1/oid.rs100
-rw-r--r--vendor/der/src/asn1/optional.rs66
-rw-r--r--vendor/der/src/asn1/printable_string.rs252
-rw-r--r--vendor/der/src/asn1/real.rs990
-rw-r--r--vendor/der/src/asn1/sequence.rs53
-rw-r--r--vendor/der/src/asn1/sequence_of.rs230
-rw-r--r--vendor/der/src/asn1/set_of.rs539
-rw-r--r--vendor/der/src/asn1/teletex_string.rs217
-rw-r--r--vendor/der/src/asn1/utc_time.rs242
-rw-r--r--vendor/der/src/asn1/utf8_string.rs164
-rw-r--r--vendor/der/src/asn1/videotex_string.rs98
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");
+ }
+}