diff --git a/der/src/asn1/any.rs b/der/src/asn1/any.rs index 25dd957a5..52701e0cd 100644 --- a/der/src/asn1/any.rs +++ b/der/src/asn1/any.rs @@ -8,9 +8,6 @@ use crate::{ }; use core::cmp::Ordering; -#[cfg(feature = "alloc")] -use {crate::BytesOwned, alloc::boxed::Box}; - /// ASN.1 `ANY`: represents any explicitly tagged ASN.1 value. /// /// This is a zero-copy reference type which borrows from the input data. @@ -130,13 +127,6 @@ impl Tagged for AnyRef<'_> { } } -#[cfg(feature = "alloc")] -impl ValueOrd for Any { - fn value_cmp(&self, other: &Self) -> Result { - self.value.der_cmp(&other.value) - } -} - impl ValueOrd for AnyRef<'_> { fn value_cmp(&self, other: &Self) -> Result { self.value.der_cmp(&other.value) @@ -157,123 +147,124 @@ impl<'a> TryFrom<&'a [u8]> for AnyRef<'a> { } } -/// ASN.1 `ANY`: represents any explicitly tagged ASN.1 value. -/// -/// This type provides the same functionality as [`AnyRef`] but owns the -/// backing data. #[cfg(feature = "alloc")] -#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] -#[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, -} +pub use self::allocating::Any; #[cfg(feature = "alloc")] -impl Any { - /// Create a new [`Any`] from the provided [`Tag`] and DER bytes. - pub fn new(tag: Tag, bytes: impl Into>) -> Result { - let value = BytesOwned::new(bytes)?; - - // Ensure the tag and value are a valid `AnyRef`. - AnyRef::new(tag, value.as_slice())?; - Ok(Self { tag, value }) +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(docsrs, doc(cfg(feature = "alloc")))] + #[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, } - /// Allow access to value - pub fn value(&self) -> &[u8] { - self.value.as_slice() - } + impl Any { + /// Create a new [`Any`] from the provided [`Tag`] and DER bytes. + pub fn new(tag: Tag, bytes: impl Into>) -> Result { + let value = BytesOwned::new(bytes)?; - /// Attempt to decode this [`Any`] type into the inner value. - pub fn decode_as<'a, T>(&'a self) -> Result - where - T: Choice<'a> + DecodeValue<'a>, - { - AnyRef::from(self).decode_as() - } + // Ensure the tag and value are a valid `AnyRef`. + AnyRef::new(tag, value.as_slice())?; + Ok(Self { tag, value }) + } - /// 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 - where - F: FnOnce(&mut SliceReader<'a>) -> Result, - { - AnyRef::from(self).sequence(f) - } -} + /// Allow access to value + pub fn value(&self) -> &[u8] { + self.value.as_slice() + } -#[cfg(feature = "alloc")] -impl Choice<'_> for Any { - fn can_decode(_: Tag) -> bool { - true + /// Attempt to decode this [`Any`] type into the inner value. + pub fn decode_as<'a, T>(&'a self) -> Result + where + T: Choice<'a> + DecodeValue<'a>, + { + AnyRef::from(self).decode_as() + } + + /// 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 + where + F: FnOnce(&mut SliceReader<'a>) -> Result, + { + AnyRef::from(self).sequence(f) + } } -} -#[cfg(feature = "alloc")] -impl<'a> Decode<'a> for Any { - fn decode>(reader: &mut R) -> Result { - let header = Header::decode(reader)?; - Self::decode_value(reader, header) + impl Choice<'_> for Any { + fn can_decode(_: Tag) -> bool { + true + } } -} -#[cfg(feature = "alloc")] -impl<'a> DecodeValue<'a> for Any { - fn decode_value>(reader: &mut R, header: Header) -> Result { - let value = reader.read_vec(header.length)?; - Self::new(header.tag, value) + impl<'a> Decode<'a> for Any { + fn decode>(reader: &mut R) -> Result { + let header = Header::decode(reader)?; + Self::decode_value(reader, header) + } } -} -#[cfg(feature = "alloc")] -impl EncodeValue for Any { - fn value_len(&self) -> Result { - Ok(self.value.len()) + impl<'a> DecodeValue<'a> for Any { + fn decode_value>(reader: &mut R, header: Header) -> Result { + let value = reader.read_vec(header.length)?; + Self::new(header.tag, value) + } } - fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { - writer.write(self.value.as_slice()) + impl EncodeValue for Any { + fn value_len(&self) -> Result { + Ok(self.value.len()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.value.as_slice()) + } } -} -#[cfg(feature = "alloc")] -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<'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") + } } -} -#[cfg(feature = "alloc")] -impl Tagged for Any { - fn tag(&self) -> Tag { - self.tag + impl Tagged for Any { + fn tag(&self) -> Tag { + self.tag + } } -} -#[cfg(feature = "alloc")] -impl<'a, T> From for Any -where - T: Into>, -{ - fn from(input: T) -> Any { - let anyref: AnyRef<'a> = input.into(); - Self { - tag: anyref.tag(), - value: BytesOwned::from(anyref.value), + impl ValueOrd for Any { + fn value_cmp(&self, other: &Self) -> Result { + self.value.der_cmp(&other.value) } } -} -#[cfg(feature = "alloc")] -mod allocating { - use super::*; - use crate::referenced::*; + impl<'a, T> From for Any + where + T: Into>, + { + 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; diff --git a/der/src/asn1/bit_string.rs b/der/src/asn1/bit_string.rs index 99f28d7d1..4481a2eba 100644 --- a/der/src/asn1/bit_string.rs +++ b/der/src/asn1/bit_string.rs @@ -1,14 +1,11 @@ //! ASN.1 `BIT STRING` support. use crate::{ - asn1::AnyRef, BytesRef, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind, FixedTag, Header, - Length, Reader, Result, Tag, ValueOrd, Writer, + BytesRef, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, + Result, Tag, ValueOrd, Writer, }; use core::{cmp::Ordering, iter::FusedIterator}; -#[cfg(feature = "alloc")] -use alloc::vec::Vec; - /// ASN.1 `BIT STRING` type. /// /// This type contains a sequence of any number of bits, modeled internally as @@ -120,6 +117,8 @@ impl<'a> BitStringRef<'a> { } } +impl_type!(BitStringRef<'a>, 'a); + impl<'a> DecodeValue<'a> for BitStringRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { let header = Header { @@ -159,14 +158,6 @@ impl<'a> From<&BitStringRef<'a>> for BitStringRef<'a> { } } -impl<'a> TryFrom> for BitStringRef<'a> { - type Error = Error; - - fn try_from(any: AnyRef<'a>) -> Result> { - any.decode_as() - } -} - impl<'a> TryFrom<&'a [u8]> for BitStringRef<'a> { type Error = Error; @@ -215,167 +206,166 @@ impl<'a> arbitrary::Arbitrary<'a> for BitStringRef<'a> { } } -/// Owned form of ASN.1 `BIT STRING` type. -/// -/// This type provides the same functionality as [`BitStringRef`] but owns the -/// backing data. #[cfg(feature = "alloc")] -#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] -#[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, -} +pub use self::allocating::BitString; #[cfg(feature = "alloc")] -impl BitString { - /// Maximum number of unused bits allowed. - pub const MAX_UNUSED_BITS: u8 = 7; +mod allocating { + use super::*; + use crate::referenced::*; + use alloc::vec::Vec; - /// Create a new ASN.1 `BIT STRING` from a byte slice. + /// Owned form of ASN.1 `BIT STRING` type. /// - /// 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>) -> Result { - let inner = bytes.into(); + /// This type provides the same functionality as [`BitStringRef`] but owns the + /// backing data. + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + #[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, + } + + 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>) -> Result { + 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, + }) + } - // Ensure parameters parse successfully as a `BitStringRef`. - let bit_length = BitStringRef::new(unused_bits, &inner)?.bit_length; + /// 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::new(0, bytes) + } - Ok(BitString { - unused_bits, - bit_length, - inner, - }) - } + /// Get the number of unused bits in the octet serialization of this + /// `BIT STRING`. + pub fn unused_bits(&self) -> u8 { + self.unused_bits + } - /// 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::new(0, bytes) - } + /// Is the number of unused bits a value other than 0? + pub fn has_unused_bits(&self) -> bool { + self.unused_bits != 0 + } - /// Get the number of unused bits in the octet serialization of this - /// `BIT STRING`. - pub fn unused_bits(&self) -> u8 { - self.unused_bits - } + /// Get the length of this `BIT STRING` in bits. + pub fn bit_len(&self) -> usize { + self.bit_length + } - /// Is the number of unused bits a value other than 0? - pub fn has_unused_bits(&self) -> bool { - self.unused_bits != 0 - } + /// Is the inner byte slice empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } - /// Get the length of this `BIT STRING` in bits. - pub fn bit_len(&self) -> usize { - self.bit_length - } + /// 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()) + } + } - /// Is the inner byte slice empty? - pub fn is_empty(&self) -> bool { - self.inner.is_empty() - } + /// Borrow the raw bytes of this `BIT STRING`. + pub fn raw_bytes(&self) -> &[u8] { + self.inner.as_slice() + } - /// 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()) + /// Iterator over the bits of this `BIT STRING`. + pub fn bits(&self) -> BitStringIter<'_> { + BitStringRef::from(self).bits() } } - /// Borrow the raw bytes of this `BIT STRING`. - pub fn raw_bytes(&self) -> &[u8] { - self.inner.as_slice() - } + impl_type!(BitString); - /// Iterator over the bits of this `BIT STRING`. - pub fn bits(&self) -> BitStringIter<'_> { - BitStringRef::from(self).bits() + impl<'a> DecodeValue<'a> for BitString { + fn decode_value>(reader: &mut R, header: Header) -> Result { + 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) + } } -} -#[cfg(feature = "alloc")] -impl<'a> DecodeValue<'a> for BitString { - fn decode_value>(reader: &mut R, header: Header) -> Result { - 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::ONE + Length::try_from(self.inner.len())? + } -#[cfg(feature = "alloc")] -impl EncodeValue for BitString { - fn value_len(&self) -> Result { - 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) + } } - 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; } -} - -#[cfg(feature = "alloc")] -impl FixedTag for BitString { - const TAG: Tag = Tag::BitString; -} -#[cfg(feature = "alloc")] -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<'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") + } } -} -#[cfg(feature = "alloc")] -impl ValueOrd for BitString { - fn value_cmp(&self, other: &Self) -> Result { - match self.unused_bits.cmp(&other.unused_bits) { - Ordering::Equal => self.inner.der_cmp(&other.inner), - ordering => Ok(ordering), + impl ValueOrd for BitString { + fn value_cmp(&self, other: &Self) -> Result { + 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::new( - u.int_in_range(0..=Self::MAX_UNUSED_BITS)?, - BytesRef::arbitrary(u)?.as_slice(), - ) - .map_err(|_| arbitrary::Error::IncorrectFormat) - } + // 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::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) { - arbitrary::size_hint::and(u8::size_hint(depth), BytesRef::size_hint(depth)) + fn size_hint(depth: usize) -> (usize, Option) { + arbitrary::size_hint::and(u8::size_hint(depth), BytesRef::size_hint(depth)) + } } -} - -#[cfg(feature = "alloc")] -mod allocating { - use super::*; - use crate::referenced::*; - use alloc::vec::Vec; impl<'a> RefToOwned<'a> for BitStringRef<'a> { type Owned = BitString; diff --git a/der/src/asn1/generalized_time.rs b/der/src/asn1/generalized_time.rs index 7e7f0f5e9..9da47d510 100644 --- a/der/src/asn1/generalized_time.rs +++ b/der/src/asn1/generalized_time.rs @@ -2,16 +2,17 @@ #![cfg_attr(feature = "arbitrary", allow(clippy::integer_arithmetic))] use crate::{ - asn1::AnyRef, datetime::{self, DateTime}, ord::OrdIsValueOrd, - DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, - Writer, + DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; use core::time::Duration; #[cfg(feature = "std")] -use std::time::SystemTime; +use { + crate::{asn1::AnyRef, Error}, + std::time::SystemTime, +}; #[cfg(feature = "time")] use time::PrimitiveDateTime; @@ -75,6 +76,8 @@ impl GeneralizedTime { } } +impl_type!(GeneralizedTime); + impl<'a> DecodeValue<'a> for GeneralizedTime { fn decode_value>(reader: &mut R, header: Header) -> Result { if Self::LENGTH != usize::try_from(header.length)? { @@ -164,14 +167,6 @@ impl From<&DateTime> for GeneralizedTime { } } -impl TryFrom> for GeneralizedTime { - type Error = Error; - - fn try_from(any: AnyRef<'_>) -> Result { - any.decode_as() - } -} - impl<'a> DecodeValue<'a> for DateTime { fn decode_value>(reader: &mut R, header: Header) -> Result { Ok(GeneralizedTime::decode_value(reader, header)?.into()) diff --git a/der/src/asn1/integer/bigint.rs b/der/src/asn1/integer/bigint.rs index cfde2966e..33eb06922 100644 --- a/der/src/asn1/integer/bigint.rs +++ b/der/src/asn1/integer/bigint.rs @@ -2,8 +2,8 @@ use super::{int, uint}; use crate::{ - asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, DecodeValue, EncodeValue, Error, ErrorKind, - FixedTag, Header, Length, Reader, Result, Tag, Writer, + ord::OrdIsValueOrd, BytesRef, DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, + Reader, Result, Tag, Writer, }; /// "Big" signed ASN.1 `INTEGER` type. @@ -45,6 +45,11 @@ impl<'a> IntRef<'a> { } } +mod int_impl { + use super::*; + impl_type!(IntRef<'a>, 'a); +} + impl<'a> DecodeValue<'a> for IntRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { let bytes = BytesRef::decode_value(reader, header)?.as_slice(); @@ -75,14 +80,6 @@ impl<'a> From<&IntRef<'a>> for IntRef<'a> { } } -impl<'a> TryFrom> for IntRef<'a> { - type Error = Error; - - fn try_from(any: AnyRef<'a>) -> Result> { - any.decode_as() - } -} - impl<'a> FixedTag for IntRef<'a> { const TAG: Tag = Tag::Integer; } @@ -128,6 +125,11 @@ impl<'a> UintRef<'a> { } } +mod uint_impl { + use super::*; + impl_type!(UintRef<'a>, 'a); +} + impl<'a> DecodeValue<'a> for UintRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { let bytes = BytesRef::decode_value(reader, header)?.as_slice(); @@ -163,14 +165,6 @@ impl<'a> From<&UintRef<'a>> for UintRef<'a> { } } -impl<'a> TryFrom> for UintRef<'a> { - type Error = Error; - - fn try_from(any: AnyRef<'a>) -> Result> { - any.decode_as() - } -} - impl<'a> FixedTag for UintRef<'a> { const TAG: Tag = Tag::Integer; } @@ -184,11 +178,10 @@ pub use self::allocating::{Int, Uint}; mod allocating { use super::{super::int, super::uint, IntRef, UintRef}; use crate::{ - asn1::AnyRef, ord::OrdIsValueOrd, referenced::{OwnedToRef, RefToOwned}, - BytesOwned, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, - Result, Tag, Writer, + BytesOwned, DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result, + Tag, Writer, }; /// "Big" signed ASN.1 `INTEGER` type. @@ -230,6 +223,11 @@ mod allocating { } } + mod int_impl { + use super::*; + impl_type!(Int); + } + impl<'a> DecodeValue<'a> for Int { fn decode_value>(reader: &mut R, header: Header) -> Result { let bytes = BytesOwned::decode_value(reader, header)?; @@ -261,14 +259,6 @@ mod allocating { } } - impl<'a> TryFrom> for Int { - type Error = Error; - - fn try_from(any: AnyRef<'a>) -> Result { - any.decode_as() - } - } - impl FixedTag for Int { const TAG: Tag = Tag::Integer; } @@ -332,6 +322,11 @@ mod allocating { } } + mod uint_impl { + use super::*; + impl_type!(Uint); + } + impl<'a> DecodeValue<'a> for Uint { fn decode_value>(reader: &mut R, header: Header) -> Result { let bytes = BytesOwned::decode_value(reader, header)?; @@ -368,14 +363,6 @@ mod allocating { } } - impl<'a> TryFrom> for Uint { - type Error = Error; - - fn try_from(any: AnyRef<'a>) -> Result { - any.decode_as() - } - } - impl FixedTag for Uint { const TAG: Tag = Tag::Integer; } diff --git a/der/src/asn1/internal_macros.rs b/der/src/asn1/internal_macros.rs index 119af1d16..d8aa8c069 100644 --- a/der/src/asn1/internal_macros.rs +++ b/der/src/asn1/internal_macros.rs @@ -1,17 +1,50 @@ -macro_rules! impl_string_type { +macro_rules! impl_type { + ($type: ty) => { + impl_type!($type, ); + }; ($type: ty, $($li: lifetime)?) => { mod __impl { use super::*; + use crate::{asn1::AnyRef, Error, Result}; + + #[cfg(feature = "alloc")] + use crate::asn1::Any; + + #[cfg(feature = "alloc")] + impl<'__der: $($li),*, $($li),*> TryFrom<&'__der Any> for $type { + type Error = Error; + + fn try_from(any: &'__der Any) -> Result<$type> { + any.decode_as() + } + } + + impl<'__der: $($li),*, $($li),*> TryFrom> for $type { + type Error = Error; + + fn try_from(any: AnyRef<'__der>) -> Result<$type> { + any.decode_as() + } + } + + } + }; +} + +macro_rules! impl_string_type { + ($type: ty, $($li: lifetime)?) => { + impl_type!($type, $($li),*); + + mod __impl_string { + use super::*; + use crate::{ ord::OrdIsValueOrd, BytesRef, DecodeValue, EncodeValue, Header, Length, Reader, Result, Writer, }; use core::{fmt, str}; - #[cfg(feature = "alloc")] - use crate::{asn1::Any, Error}; - impl<$($li),*> AsRef for $type { fn as_ref(&self) -> &str { self.as_str() @@ -47,15 +80,6 @@ macro_rules! impl_string_type { f.write_str(self.as_str()) } } - - #[cfg(feature = "alloc")] - impl<'__der: $($li),*, $($li),*> TryFrom<&'__der Any> for $type { - type Error = Error; - - fn try_from(any: &'__der Any) -> Result<$type> { - any.decode_as() - } - } } }; } diff --git a/der/src/asn1/null.rs b/der/src/asn1/null.rs index 6bea65781..1047f4cc3 100644 --- a/der/src/asn1/null.rs +++ b/der/src/asn1/null.rs @@ -9,6 +9,8 @@ use crate::{ #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct Null; +impl_type!(Null); + impl<'a> DecodeValue<'a> for Null { fn decode_value>(reader: &mut R, header: Header) -> Result { if header.length.is_zero() { @@ -41,14 +43,6 @@ impl<'a> From for AnyRef<'a> { } } -impl TryFrom> for Null { - type Error = Error; - - fn try_from(any: AnyRef<'_>) -> Result { - any.decode_as() - } -} - impl TryFrom> for () { type Error = Error; diff --git a/der/src/asn1/octet_string.rs b/der/src/asn1/octet_string.rs index 3bbfd047b..f30d3d07c 100644 --- a/der/src/asn1/octet_string.rs +++ b/der/src/asn1/octet_string.rs @@ -1,13 +1,10 @@ //! ASN.1 `OCTET STRING` support. use crate::{ - asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, Decode, DecodeValue, EncodeValue, Error, ErrorKind, + asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, Decode, DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; -#[cfg(feature = "alloc")] -use alloc::vec::Vec; - /// ASN.1 `OCTET STRING` type: borrowed form. /// /// Octet strings represent contiguous sequences of octets, a.k.a. bytes. @@ -48,6 +45,8 @@ impl<'a> OctetStringRef<'a> { } } +impl_type!(OctetStringRef<'a>, 'a); + impl AsRef<[u8]> for OctetStringRef<'_> { fn as_ref(&self) -> &[u8] { self.as_bytes() @@ -83,14 +82,6 @@ impl<'a> From<&OctetStringRef<'a>> for OctetStringRef<'a> { } } -impl<'a> TryFrom> for OctetStringRef<'a> { - type Error = Error; - - fn try_from(any: AnyRef<'a>) -> Result> { - any.decode_as() - } -} - impl<'a> From> for AnyRef<'a> { fn from(octet_string: OctetStringRef<'a>) -> AnyRef<'a> { AnyRef::from_tag_and_value(Tag::OctetString, octet_string.inner) @@ -103,99 +94,119 @@ impl<'a> From> for &'a [u8] { } } -/// 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. #[cfg(feature = "alloc")] -#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub struct OctetString { - /// Bitstring represented as a slice of bytes. - inner: Vec, -} +pub use self::allocating::OctetString; #[cfg(feature = "alloc")] -impl OctetString { - /// Create a new ASN.1 `OCTET STRING`. - pub fn new(bytes: impl Into>) -> Result { - let inner = bytes.into(); - - // Ensure the bytes parse successfully as an `OctetStringRef` - OctetStringRef::new(&inner)?; +mod allocating { + use super::*; + use crate::referenced::*; + use alloc::vec::Vec; - Ok(Self { inner }) + /// 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. + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] + pub struct OctetString { + /// Bitstring represented as a slice of bytes. + inner: Vec, } - /// Borrow the inner byte slice. - pub fn as_bytes(&self) -> &[u8] { - self.inner.as_slice() - } + impl OctetString { + /// Create a new ASN.1 `OCTET STRING`. + pub fn new(bytes: impl Into>) -> Result { + let inner = bytes.into(); - /// Get the length of the inner byte slice. - pub fn len(&self) -> Length { - self.value_len().expect("invalid OCTET STRING length") + // 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() + } + + /// 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() + } } - /// Is the inner byte slice empty? - pub fn is_empty(&self) -> bool { - self.inner.is_empty() + impl_type!(OctetString); + + impl AsRef<[u8]> for OctetString { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } } -} -#[cfg(feature = "alloc")] -impl AsRef<[u8]> for OctetString { - fn as_ref(&self) -> &[u8] { - self.as_bytes() + impl<'a> DecodeValue<'a> for OctetString { + fn decode_value>(reader: &mut R, header: Header) -> Result { + Self::new(reader.read_vec(header.length)?) + } } -} -#[cfg(feature = "alloc")] -impl<'a> DecodeValue<'a> for OctetString { - fn decode_value>(reader: &mut R, header: Header) -> Result { - Self::new(reader.read_vec(header.length)?) + impl EncodeValue for OctetString { + fn value_len(&self) -> Result { + self.inner.len().try_into() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(&self.inner) + } } -} -#[cfg(feature = "alloc")] -impl EncodeValue for OctetString { - fn value_len(&self) -> Result { - self.inner.len().try_into() + impl FixedTag for OctetString { + const TAG: Tag = Tag::OctetString; } - fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { - writer.write(&self.inner) + 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") + } } -} -#[cfg(feature = "alloc")] -impl FixedTag for OctetString { - const TAG: Tag = Tag::OctetString; -} + impl OrdIsValueOrd for OctetString {} -#[cfg(feature = "alloc")] -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<'a> RefToOwned<'a> for OctetStringRef<'a> { + type Owned = OctetString; + fn ref_to_owned(&self) -> Self::Owned { + OctetString { + inner: Vec::from(self.inner.as_slice()), + } + } } -} -#[cfg(feature = "alloc")] -impl OrdIsValueOrd for OctetString {} - -// 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::new(Vec::arbitrary(u)?).map_err(|_| arbitrary::Error::IncorrectFormat) + impl OwnedToRef for OctetString { + type Borrowed<'a> = OctetStringRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + self.into() + } } - fn size_hint(depth: usize) -> (usize, Option) { - arbitrary::size_hint::and(u8::size_hint(depth), Vec::::size_hint(depth)) + // 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::new(Vec::arbitrary(u)?).map_err(|_| arbitrary::Error::IncorrectFormat) + } + + fn size_hint(depth: usize) -> (usize, Option) { + arbitrary::size_hint::and(u8::size_hint(depth), Vec::::size_hint(depth)) + } } } diff --git a/der/src/asn1/printable_string.rs b/der/src/asn1/printable_string.rs index 7a5bb8b6e..651c5ba23 100644 --- a/der/src/asn1/printable_string.rs +++ b/der/src/asn1/printable_string.rs @@ -1,6 +1,6 @@ //! ASN.1 `PrintableString` support. -use crate::{asn1::AnyRef, Error, FixedTag, Result, StrRef, Tag}; +use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag}; use core::{fmt, ops::Deref}; macro_rules! impl_printable_string { @@ -108,14 +108,6 @@ impl<'a> From<&PrintableStringRef<'a>> for PrintableStringRef<'a> { } } -impl<'a> TryFrom> for PrintableStringRef<'a> { - type Error = Error; - - fn try_from(any: AnyRef<'a>) -> Result> { - any.decode_as() - } -} - impl<'a> From> for AnyRef<'a> { fn from(printable_string: PrintableStringRef<'a>) -> AnyRef<'a> { AnyRef::from_tag_and_value(Tag::PrintableString, printable_string.inner.into()) @@ -132,7 +124,7 @@ mod allocation { use crate::{ asn1::AnyRef, referenced::{OwnedToRef, RefToOwned}, - BytesRef, Error, FixedTag, Result, StrOwned, Tag, + BytesRef, FixedTag, Result, StrOwned, Tag, }; use core::{fmt, ops::Deref}; @@ -202,14 +194,6 @@ mod allocation { } } - impl<'a> TryFrom<&AnyRef<'a>> for PrintableString { - type Error = Error; - - fn try_from(any: &AnyRef<'a>) -> Result { - (*any).decode_as() - } - } - impl<'a> From<&'a PrintableString> for AnyRef<'a> { fn from(printable_string: &'a PrintableString) -> AnyRef<'a> { AnyRef::from_tag_and_value( diff --git a/der/src/asn1/teletex_string.rs b/der/src/asn1/teletex_string.rs index b8e24f454..cedf727db 100644 --- a/der/src/asn1/teletex_string.rs +++ b/der/src/asn1/teletex_string.rs @@ -1,6 +1,6 @@ //! ASN.1 `TeletexString` support. //! -use crate::{asn1::AnyRef, Error, FixedTag, Result, StrRef, Tag}; +use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag}; use core::{fmt, ops::Deref}; macro_rules! impl_teletex_string { @@ -79,13 +79,6 @@ impl<'a> From<&TeletexStringRef<'a>> for TeletexStringRef<'a> { } } -impl<'a> TryFrom> for TeletexStringRef<'a> { - type Error = Error; - - fn try_from(any: AnyRef<'a>) -> Result> { - any.decode_as() - } -} impl<'a> From> for AnyRef<'a> { fn from(teletex_string: TeletexStringRef<'a>) -> AnyRef<'a> { AnyRef::from_tag_and_value(Tag::TeletexString, teletex_string.inner.into()) @@ -102,7 +95,7 @@ mod allocation { use crate::{ asn1::AnyRef, referenced::{OwnedToRef, RefToOwned}, - BytesRef, Error, FixedTag, Result, StrOwned, Tag, + BytesRef, FixedTag, Result, StrOwned, Tag, }; use core::{fmt, ops::Deref}; @@ -160,14 +153,6 @@ mod allocation { } } - impl<'a> TryFrom<&AnyRef<'a>> for TeletexString { - type Error = Error; - - fn try_from(any: &AnyRef<'a>) -> Result { - (*any).decode_as() - } - } - impl<'a> From<&'a TeletexString> for AnyRef<'a> { fn from(teletex_string: &'a TeletexString) -> AnyRef<'a> { AnyRef::from_tag_and_value( diff --git a/der/src/asn1/utc_time.rs b/der/src/asn1/utc_time.rs index 6d4b3b5bc..9c7af7b05 100644 --- a/der/src/asn1/utc_time.rs +++ b/der/src/asn1/utc_time.rs @@ -1,7 +1,6 @@ //! ASN.1 `UTCTime` support. use crate::{ - asn1::AnyRef, datetime::{self, DateTime}, ord::OrdIsValueOrd, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, @@ -79,6 +78,8 @@ impl UtcTime { } } +impl_type!(UtcTime); + impl<'a> DecodeValue<'a> for UtcTime { fn decode_value>(reader: &mut R, header: Header) -> Result { if Self::LENGTH != usize::try_from(header.length)? { @@ -187,14 +188,6 @@ impl From for SystemTime { } } -impl TryFrom> for UtcTime { - type Error = Error; - - fn try_from(any: AnyRef<'_>) -> Result { - any.decode_as() - } -} - // 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, diff --git a/der/src/asn1/utf8_string.rs b/der/src/asn1/utf8_string.rs index 7ec5f6c7f..c194202db 100644 --- a/der/src/asn1/utf8_string.rs +++ b/der/src/asn1/utf8_string.rs @@ -1,14 +1,14 @@ //! ASN.1 `UTF8String` support. use crate::{ - asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, DecodeValue, EncodeValue, Error, FixedTag, Header, - Length, Reader, Result, StrRef, Tag, Writer, + asn1::AnyRef, ord::OrdIsValueOrd, EncodeValue, Error, FixedTag, Length, Result, StrRef, Tag, + Writer, }; use core::{fmt, ops::Deref, str}; #[cfg(feature = "alloc")] use { - crate::asn1::Any, + crate::{DecodeValue, Header, Reader}, alloc::{borrow::ToOwned, string::String}, }; @@ -42,6 +42,8 @@ impl<'a> Utf8StringRef<'a> { } } +impl_string_type!(Utf8StringRef<'a>, 'a); + impl<'a> Deref for Utf8StringRef<'a> { type Target = StrRef<'a>; @@ -50,75 +52,22 @@ impl<'a> Deref for Utf8StringRef<'a> { } } -impl AsRef for Utf8StringRef<'_> { - fn as_ref(&self) -> &str { - self.as_str() - } -} - -impl AsRef<[u8]> for Utf8StringRef<'_> { - fn as_ref(&self) -> &[u8] { - self.as_bytes() - } -} - -impl<'a> DecodeValue<'a> for Utf8StringRef<'a> { - fn decode_value>(reader: &mut R, header: Header) -> Result { - Self::new(BytesRef::decode_value(reader, header)?.as_slice()) - } -} - -impl EncodeValue for Utf8StringRef<'_> { - fn value_len(&self) -> Result { - self.inner.value_len() - } - - fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { - self.inner.encode_value(writer) - } -} - impl FixedTag for Utf8StringRef<'_> { const TAG: Tag = Tag::Utf8String; } -impl OrdIsValueOrd for Utf8StringRef<'_> {} - impl<'a> From<&Utf8StringRef<'a>> for Utf8StringRef<'a> { fn from(value: &Utf8StringRef<'a>) -> Utf8StringRef<'a> { *value } } -impl<'a> TryFrom> for Utf8StringRef<'a> { - type Error = Error; - - fn try_from(any: AnyRef<'a>) -> Result> { - any.decode_as() - } -} - -#[cfg(feature = "alloc")] -impl<'a> TryFrom<&'a Any> for Utf8StringRef<'a> { - type Error = Error; - - fn try_from(any: &'a Any) -> Result> { - any.decode_as() - } -} - impl<'a> From> 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::Display for Utf8StringRef<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } -} - impl<'a> fmt::Debug for Utf8StringRef<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Utf8String({:?})", self.as_str()) diff --git a/der/src/asn1/videotex_string.rs b/der/src/asn1/videotex_string.rs index 672f657df..55b1a49cf 100644 --- a/der/src/asn1/videotex_string.rs +++ b/der/src/asn1/videotex_string.rs @@ -1,13 +1,7 @@ //! ASN.1 `VideotexString` support. -use crate::{ - asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, DecodeValue, EncodeValue, Error, FixedTag, Header, - Length, Reader, Result, StrRef, Tag, Writer, -}; -use core::{fmt, ops::Deref, str}; - -#[cfg(feature = "alloc")] -use crate::asn1::Any; +use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag}; +use core::{fmt, ops::Deref}; /// ASN.1 `VideotexString` type. /// @@ -49,6 +43,8 @@ impl<'a> VideotexStringRef<'a> { } } +impl_string_type!(VideotexStringRef<'a>, 'a); + impl<'a> Deref for VideotexStringRef<'a> { type Target = StrRef<'a>; @@ -57,63 +53,16 @@ impl<'a> Deref for VideotexStringRef<'a> { } } -impl AsRef for VideotexStringRef<'_> { - fn as_ref(&self) -> &str { - self.as_str() - } -} - -impl AsRef<[u8]> for VideotexStringRef<'_> { - fn as_ref(&self) -> &[u8] { - self.as_bytes() - } -} - -impl<'a> DecodeValue<'a> for VideotexStringRef<'a> { - fn decode_value>(reader: &mut R, header: Header) -> Result { - Self::new(BytesRef::decode_value(reader, header)?.as_slice()) - } -} - -impl<'a> EncodeValue for VideotexStringRef<'a> { - fn value_len(&self) -> Result { - self.inner.value_len() - } - - fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { - self.inner.encode_value(writer) - } -} - impl FixedTag for VideotexStringRef<'_> { const TAG: Tag = Tag::VideotexString; } -impl OrdIsValueOrd for VideotexStringRef<'_> {} - impl<'a> From<&VideotexStringRef<'a>> for VideotexStringRef<'a> { fn from(value: &VideotexStringRef<'a>) -> VideotexStringRef<'a> { *value } } -impl<'a> TryFrom> for VideotexStringRef<'a> { - type Error = Error; - - fn try_from(any: AnyRef<'a>) -> Result> { - any.decode_as() - } -} - -#[cfg(feature = "alloc")] -impl<'a> TryFrom<&'a Any> for VideotexStringRef<'a> { - type Error = Error; - - fn try_from(any: &'a Any) -> Result> { - any.decode_as() - } -} - impl<'a> From> for AnyRef<'a> { fn from(printable_string: VideotexStringRef<'a>) -> AnyRef<'a> { AnyRef::from_tag_and_value(Tag::VideotexString, printable_string.inner.into()) @@ -126,12 +75,6 @@ impl<'a> From> for &'a [u8] { } } -impl<'a> fmt::Display for VideotexStringRef<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } -} - impl<'a> fmt::Debug for VideotexStringRef<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VideotexString({:?})", self.as_str())