diff --git a/der/src/asn1.rs b/der/src/asn1.rs index 947966ec8..2d24ee404 100644 --- a/der/src/asn1.rs +++ b/der/src/asn1.rs @@ -1,6 +1,9 @@ //! Module containing all of the various ASN.1 built-in types supported by //! this library. +#[macro_use] +mod internal_macros; + mod any; mod bit_string; mod boolean; @@ -32,8 +35,9 @@ pub use const_oid::ObjectIdentifier; #[cfg(feature = "alloc")] #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] pub use self::{ - any::Any, bit_string::BitString, integer::bigint::Int, integer::bigint::Uint, - octet_string::OctetString, set_of::SetOfVec, + any::Any, bit_string::BitString, ia5_string::Ia5String, integer::bigint::Int, + integer::bigint::Uint, octet_string::OctetString, printable_string::PrintableString, + set_of::SetOfVec, teletex_string::TeletexString, }; pub use self::{ any::AnyRef, diff --git a/der/src/asn1/any.rs b/der/src/asn1/any.rs index b9b88ad7e..dc098e4b4 100644 --- a/der/src/asn1/any.rs +++ b/der/src/asn1/any.rs @@ -2,13 +2,13 @@ #![cfg_attr(feature = "arbitrary", allow(clippy::integer_arithmetic))] use crate::{ - asn1::*, ByteSlice, Choice, Decode, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind, + asn1::*, BytesRef, Choice, Decode, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, SliceReader, Tag, Tagged, ValueOrd, Writer, }; use core::cmp::Ordering; #[cfg(feature = "alloc")] -use crate::Bytes; +use crate::BytesOwned; #[cfg(feature = "oid")] use crate::asn1::ObjectIdentifier; @@ -31,24 +31,24 @@ pub struct AnyRef<'a> { tag: Tag, /// Inner value encoded as bytes. - value: ByteSlice<'a>, + value: BytesRef<'a>, } impl<'a> AnyRef<'a> { /// [`AnyRef`] representation of the ASN.1 `NULL` type. pub const NULL: Self = Self { tag: Tag::Null, - value: ByteSlice::EMPTY, + value: BytesRef::EMPTY, }; /// Create a new [`AnyRef`] from the provided [`Tag`] and DER bytes. pub fn new(tag: Tag, bytes: &'a [u8]) -> Result { - let value = ByteSlice::new(bytes).map_err(|_| ErrorKind::Length { tag })?; + let value = BytesRef::new(bytes).map_err(|_| ErrorKind::Length { tag })?; Ok(Self { tag, value }) } - /// Infallible creation of an [`AnyRef`] from a [`ByteSlice`]. - pub(crate) fn from_tag_and_value(tag: Tag, value: ByteSlice<'a>) -> Self { + /// Infallible creation of an [`AnyRef`] from a [`BytesRef`]. + pub(crate) fn from_tag_and_value(tag: Tag, value: BytesRef<'a>) -> Self { Self { tag, value } } @@ -150,7 +150,7 @@ impl<'a> Decode<'a> for AnyRef<'a> { Ok(Self { tag: header.tag, - value: ByteSlice::decode_value(reader, header)?, + value: BytesRef::decode_value(reader, header)?, }) } } @@ -184,8 +184,8 @@ impl ValueOrd for AnyRef<'_> { } } -impl<'a> From> for ByteSlice<'a> { - fn from(any: AnyRef<'a>) -> ByteSlice<'a> { +impl<'a> From> for BytesRef<'a> { + fn from(any: AnyRef<'a>) -> BytesRef<'a> { any.value } } @@ -211,14 +211,14 @@ pub struct Any { tag: Tag, /// Inner value encoded as bytes. - value: Bytes, + value: BytesOwned, } #[cfg(feature = "alloc")] impl Any { /// Create a new [`Any`] from the provided [`Tag`] and DER bytes. pub fn new(tag: Tag, bytes: &[u8]) -> Result { - let value = Bytes::new(bytes)?; + let value = BytesOwned::new(bytes)?; // Ensure the tag and value are a valid `AnyRef`. AnyRef::new(tag, value.as_slice())?; @@ -293,7 +293,7 @@ where let anyref: AnyRef<'a> = input.into(); Self { tag: anyref.tag(), - value: Bytes::from(anyref.value), + value: BytesOwned::from(anyref.value), } } } @@ -308,7 +308,7 @@ mod allocating { fn to_owned(&self) -> Self::Owned { Any { tag: self.tag(), - value: Bytes::from(self.value), + value: BytesOwned::from(self.value), } } } @@ -319,4 +319,11 @@ mod allocating { self.into() } } + + impl Any { + /// Is this value an ASN.1 `NULL` value? + pub fn is_null(&self) -> bool { + self.to_ref() == AnyRef::NULL + } + } } diff --git a/der/src/asn1/bit_string.rs b/der/src/asn1/bit_string.rs index 7839ca42f..3a09d5d85 100644 --- a/der/src/asn1/bit_string.rs +++ b/der/src/asn1/bit_string.rs @@ -1,7 +1,7 @@ //! ASN.1 `BIT STRING` support. use crate::{ - asn1::AnyRef, ByteSlice, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind, FixedTag, Header, + asn1::AnyRef, BytesRef, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd, Writer, }; use core::{cmp::Ordering, iter::FusedIterator}; @@ -24,7 +24,7 @@ pub struct BitStringRef<'a> { bit_length: usize, /// Bitstring represented as a slice of bytes. - inner: ByteSlice<'a>, + inner: BytesRef<'a>, } impl<'a> BitStringRef<'a> { @@ -40,7 +40,7 @@ impl<'a> BitStringRef<'a> { return Err(Self::TAG.value_error()); } - let inner = ByteSlice::new(bytes).map_err(|_| Self::TAG.length_error())?; + let inner = BytesRef::new(bytes).map_err(|_| Self::TAG.length_error())?; let bit_length = usize::try_from(inner.len())? .checked_mul(8) @@ -128,7 +128,7 @@ impl<'a> DecodeValue<'a> for BitStringRef<'a> { }; let unused_bits = reader.read_byte()?; - let inner = ByteSlice::decode_value(reader, header)?; + let inner = BytesRef::decode_value(reader, header)?; Self::new(unused_bits, inner.as_slice()) } } @@ -205,13 +205,13 @@ impl<'a> arbitrary::Arbitrary<'a> for BitStringRef<'a> { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { Self::new( u.int_in_range(0..=Self::MAX_UNUSED_BITS)?, - ByteSlice::arbitrary(u)?.as_slice(), + 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), ByteSlice::size_hint(depth)) + arbitrary::size_hint::and(u8::size_hint(depth), BytesRef::size_hint(depth)) } } @@ -354,6 +354,23 @@ impl ValueOrd for 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 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)) + } +} + #[cfg(feature = "alloc")] mod allocating { use super::*; diff --git a/der/src/asn1/ia5_string.rs b/der/src/asn1/ia5_string.rs index 5dca812e8..39e1b733d 100644 --- a/der/src/asn1/ia5_string.rs +++ b/der/src/asn1/ia5_string.rs @@ -1,13 +1,26 @@ //! ASN.1 `IA5String` support. -use crate::{ - asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, FixedTag, Header, - Length, Reader, Result, StrSlice, Tag, Writer, -}; -use core::{fmt, ops::Deref, str}; +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; + } -#[cfg(feature = "alloc")] -use crate::asn1::Any; + 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. /// @@ -24,7 +37,7 @@ use crate::asn1::Any; #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct Ia5StringRef<'a> { /// Inner value - inner: StrSlice<'a>, + inner: StrRef<'a>, } impl<'a> Ia5StringRef<'a> { @@ -40,92 +53,117 @@ impl<'a> Ia5StringRef<'a> { return Err(Self::TAG.value_error()); } - StrSlice::from_bytes(input) + 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 = StrSlice<'a>; + type Target = StrRef<'a>; fn deref(&self) -> &Self::Target { &self.inner } } -impl AsRef for Ia5StringRef<'_> { - fn as_ref(&self) -> &str { - self.as_str() +impl<'a> From<&Ia5StringRef<'a>> for Ia5StringRef<'a> { + fn from(value: &Ia5StringRef<'a>) -> Ia5StringRef<'a> { + *value } } -impl AsRef<[u8]> for Ia5StringRef<'_> { - fn as_ref(&self) -> &[u8] { - self.as_bytes() +impl<'a> From> for AnyRef<'a> { + fn from(internationalized_string: Ia5StringRef<'a>) -> AnyRef<'a> { + AnyRef::from_tag_and_value(Tag::Ia5String, internationalized_string.inner.into()) } } -impl<'a> DecodeValue<'a> for Ia5StringRef<'a> { - fn decode_value>(reader: &mut R, header: Header) -> Result { - Self::new(ByteSlice::decode_value(reader, header)?.as_slice()) - } -} +#[cfg(feature = "alloc")] +pub use self::allocation::Ia5String; -impl EncodeValue for Ia5StringRef<'_> { - fn value_len(&self) -> Result { - self.inner.value_len() +#[cfg(feature = "alloc")] +mod allocation { + use super::Ia5StringRef; + use crate::{ + asn1::AnyRef, + referenced::{OwnedToRef, RefToOwned}, + FixedTag, Result, StrOwned, Tag, + }; + 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, } - fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> { - self.inner.encode_value(writer) + impl Ia5String { + /// Create a new `IA5String`. + pub fn new(input: &T) -> Result + 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<'a> FixedTag for Ia5StringRef<'a> { - const TAG: Tag = Tag::Ia5String; -} -impl OrdIsValueOrd for Ia5StringRef<'_> {} + impl_ia5_string!(Ia5String); -impl<'a> From<&Ia5StringRef<'a>> for Ia5StringRef<'a> { - fn from(value: &Ia5StringRef<'a>) -> Ia5StringRef<'a> { - *value - } -} + impl Deref for Ia5String { + type Target = StrOwned; -impl<'a> TryFrom> for Ia5StringRef<'a> { - type Error = Error; - - fn try_from(any: AnyRef<'a>) -> Result> { - any.decode_into() + fn deref(&self) -> &Self::Target { + &self.inner + } } -} - -#[cfg(feature = "alloc")] -impl<'a> TryFrom<&'a Any> for Ia5StringRef<'a> { - type Error = Error; - fn try_from(any: &'a Any) -> Result> { - any.decode_into() + impl<'a> From> for Ia5String { + fn from(international_string: Ia5StringRef<'a>) -> Ia5String { + let inner = international_string.inner.into(); + Self { inner } + } } -} -impl<'a> From> for AnyRef<'a> { - fn from(printable_string: Ia5StringRef<'a>) -> AnyRef<'a> { - AnyRef::from_tag_and_value(Tag::Ia5String, printable_string.inner.into()) + 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> fmt::Display for Ia5StringRef<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) + impl<'a> RefToOwned<'a> for Ia5StringRef<'a> { + type Owned = Ia5String; + fn to_owned(&self) -> Self::Owned { + Ia5String { + inner: self.inner.to_owned(), + } + } } -} -impl<'a> fmt::Debug for Ia5StringRef<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Ia5String({:?})", self.as_str()) + impl OwnedToRef for Ia5String { + type Borrowed<'a> = Ia5StringRef<'a>; + fn to_ref(&self) -> Self::Borrowed<'_> { + Ia5StringRef { + inner: self.inner.to_ref(), + } + } } } @@ -138,7 +176,7 @@ mod tests { #[test] fn parse_bytes() { let example_bytes = hex!("16 0d 74 65 73 74 31 40 72 73 61 2e 63 6f 6d"); - let printable_string = Ia5StringRef::from_der(&example_bytes).unwrap(); - assert_eq!(printable_string.as_str(), "test1@rsa.com"); + let internationalized_string = Ia5StringRef::from_der(&example_bytes).unwrap(); + assert_eq!(internationalized_string.as_str(), "test1@rsa.com"); } } diff --git a/der/src/asn1/integer.rs b/der/src/asn1/integer.rs index f594aa1e6..a0d5134c5 100644 --- a/der/src/asn1/integer.rs +++ b/der/src/asn1/integer.rs @@ -7,7 +7,7 @@ pub(super) mod uint; use core::{cmp::Ordering, mem}; use crate::{ - asn1::AnyRef, ByteSlice, DecodeValue, EncodeValue, Error, FixedTag, Header, Length, Reader, + asn1::AnyRef, BytesRef, DecodeValue, EncodeValue, Error, FixedTag, Header, Length, Reader, Result, SliceWriter, Tag, ValueOrd, Writer, }; @@ -16,7 +16,7 @@ macro_rules! impl_int_encoding { $( impl<'a> DecodeValue<'a> for $int { fn decode_value>(reader: &mut R, header: Header) -> Result { - let bytes = ByteSlice::decode_value(reader, header)?.as_slice(); + let bytes = BytesRef::decode_value(reader, header)?.as_slice(); let result = if is_highest_bit_set(bytes) { <$uint>::from_be_bytes(int::decode_to_array(bytes)?) as $int @@ -77,7 +77,7 @@ macro_rules! impl_uint_encoding { $( impl<'a> DecodeValue<'a> for $uint { fn decode_value>(reader: &mut R, header: Header) -> Result { - let bytes = ByteSlice::decode_value(reader, header)?.as_slice(); + let bytes = BytesRef::decode_value(reader, header)?.as_slice(); let result = Self::from_be_bytes(uint::decode_to_array(bytes)?); // Ensure we compute the same encoded length as the original any value diff --git a/der/src/asn1/integer/bigint.rs b/der/src/asn1/integer/bigint.rs index f7b107df6..c5d7ff877 100644 --- a/der/src/asn1/integer/bigint.rs +++ b/der/src/asn1/integer/bigint.rs @@ -2,7 +2,7 @@ use super::{int, uint}; use crate::{ - asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, ErrorKind, + asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; @@ -16,13 +16,13 @@ use crate::{ #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct IntRef<'a> { /// Inner value - inner: ByteSlice<'a>, + inner: BytesRef<'a>, } impl<'a> IntRef<'a> { /// Create a new [`IntRef`] from a byte slice. pub fn new(bytes: &'a [u8]) -> Result { - let inner = ByteSlice::new(int::strip_leading_ones(bytes)) + let inner = BytesRef::new(int::strip_leading_ones(bytes)) .map_err(|_| ErrorKind::Length { tag: Self::TAG })?; Ok(Self { inner }) @@ -47,7 +47,7 @@ impl<'a> IntRef<'a> { impl<'a> DecodeValue<'a> for IntRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { - let bytes = ByteSlice::decode_value(reader, header)?.as_slice(); + let bytes = BytesRef::decode_value(reader, header)?.as_slice(); let result = Self::new(int::decode_to_slice(bytes)?)?; // Ensure we compute the same encoded length as the original any value. @@ -99,13 +99,13 @@ impl<'a> OrdIsValueOrd for IntRef<'a> {} #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct UintRef<'a> { /// Inner value - inner: ByteSlice<'a>, + inner: BytesRef<'a>, } impl<'a> UintRef<'a> { /// Create a new [`UintRef`] from a byte slice. pub fn new(bytes: &'a [u8]) -> Result { - let inner = ByteSlice::new(uint::strip_leading_zeroes(bytes)) + let inner = BytesRef::new(uint::strip_leading_zeroes(bytes)) .map_err(|_| ErrorKind::Length { tag: Self::TAG })?; Ok(Self { inner }) @@ -130,7 +130,7 @@ impl<'a> UintRef<'a> { impl<'a> DecodeValue<'a> for UintRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { - let bytes = ByteSlice::decode_value(reader, header)?.as_slice(); + let bytes = BytesRef::decode_value(reader, header)?.as_slice(); let result = Self::new(uint::decode_to_slice(bytes)?)?; // Ensure we compute the same encoded length as the original any value. @@ -187,7 +187,7 @@ mod allocating { asn1::AnyRef, ord::OrdIsValueOrd, referenced::{OwnedToRef, RefToOwned}, - Bytes, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, + BytesOwned, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; @@ -201,13 +201,13 @@ mod allocating { #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct Int { /// Inner value - inner: Bytes, + inner: BytesOwned, } impl Int { /// Create a new [`Int`] from a byte slice. pub fn new(bytes: &[u8]) -> Result { - let inner = Bytes::new(int::strip_leading_ones(bytes)) + let inner = BytesOwned::new(int::strip_leading_ones(bytes)) .map_err(|_| ErrorKind::Length { tag: Self::TAG })?; Ok(Self { inner }) @@ -232,7 +232,7 @@ mod allocating { impl<'a> DecodeValue<'a> for Int { fn decode_value>(reader: &mut R, header: Header) -> Result { - let bytes = Bytes::decode_value(reader, header)?; + let bytes = BytesOwned::decode_value(reader, header)?; let result = Self::new(int::decode_to_slice(bytes.as_slice())?)?; // Ensure we compute the same encoded length as the original any value. @@ -256,7 +256,7 @@ mod allocating { impl<'a> From<&IntRef<'a>> for Int { fn from(value: &IntRef<'a>) -> Int { - let inner = Bytes::new(value.as_bytes()).expect("Invalid Int"); + let inner = BytesOwned::new(value.as_bytes()).expect("Invalid Int"); Int { inner } } } @@ -303,13 +303,13 @@ mod allocating { #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct Uint { /// Inner value - inner: Bytes, + inner: BytesOwned, } impl Uint { /// Create a new [`Uint`] from a byte slice. pub fn new(bytes: &[u8]) -> Result { - let inner = Bytes::new(uint::strip_leading_zeroes(bytes)) + let inner = BytesOwned::new(uint::strip_leading_zeroes(bytes)) .map_err(|_| ErrorKind::Length { tag: Self::TAG })?; Ok(Self { inner }) @@ -334,7 +334,7 @@ mod allocating { impl<'a> DecodeValue<'a> for Uint { fn decode_value>(reader: &mut R, header: Header) -> Result { - let bytes = Bytes::decode_value(reader, header)?; + let bytes = BytesOwned::decode_value(reader, header)?; let result = Self::new(uint::decode_to_slice(bytes.as_slice())?)?; // Ensure we compute the same encoded length as the original any value. @@ -363,7 +363,7 @@ mod allocating { impl<'a> From<&UintRef<'a>> for Uint { fn from(value: &UintRef<'a>) -> Uint { - let inner = Bytes::new(value.as_bytes()).expect("Invalid Uint"); + let inner = BytesOwned::new(value.as_bytes()).expect("Invalid Uint"); Uint { inner } } } diff --git a/der/src/asn1/internal_macros.rs b/der/src/asn1/internal_macros.rs new file mode 100644 index 000000000..ad385db27 --- /dev/null +++ b/der/src/asn1/internal_macros.rs @@ -0,0 +1,61 @@ +macro_rules! impl_string_type { + ($type: ty, $($li: lifetime)?) => { + mod __impl { + 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() + } + } + + 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>(reader: &mut R, header: Header) -> Result { + Self::new(BytesRef::decode_value(reader, header)?.as_slice()) + } + } + + impl<$($li),*> EncodeValue for $type { + fn value_len(&self) -> Result { + self.inner.value_len() + } + + fn encode_value(&self, writer: &mut dyn 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()) + } + } + + #[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_into() + } + } + } + }; +} diff --git a/der/src/asn1/null.rs b/der/src/asn1/null.rs index e87729f18..8ff142985 100644 --- a/der/src/asn1/null.rs +++ b/der/src/asn1/null.rs @@ -1,7 +1,7 @@ //! ASN.1 `NULL` support. use crate::{ - asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, ErrorKind, + asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; @@ -37,7 +37,7 @@ impl OrdIsValueOrd for Null {} impl<'a> From for AnyRef<'a> { fn from(_: Null) -> AnyRef<'a> { - AnyRef::from_tag_and_value(Tag::Null, ByteSlice::default()) + AnyRef::from_tag_and_value(Tag::Null, BytesRef::default()) } } diff --git a/der/src/asn1/octet_string.rs b/der/src/asn1/octet_string.rs index 1bea0e68c..b0535773b 100644 --- a/der/src/asn1/octet_string.rs +++ b/der/src/asn1/octet_string.rs @@ -1,8 +1,8 @@ //! ASN.1 `OCTET STRING` support. use crate::{ - asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, Decode, DecodeValue, EncodeValue, Error, - ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, + asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, Decode, DecodeValue, EncodeValue, Error, ErrorKind, + FixedTag, Header, Length, Reader, Result, Tag, Writer, }; #[cfg(feature = "alloc")] @@ -16,13 +16,13 @@ use alloc::vec::Vec; #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct OctetStringRef<'a> { /// Inner value - inner: ByteSlice<'a>, + 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 { - ByteSlice::new(slice) + BytesRef::new(slice) .map(|inner| Self { inner }) .map_err(|_| ErrorKind::Length { tag: Self::TAG }.into()) } @@ -56,7 +56,7 @@ impl AsRef<[u8]> for OctetStringRef<'_> { impl<'a> DecodeValue<'a> for OctetStringRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { - let inner = ByteSlice::decode_value(reader, header)?; + let inner = BytesRef::decode_value(reader, header)?; Ok(Self { inner }) } } @@ -186,6 +186,19 @@ impl<'a> From<&'a OctetString> for OctetStringRef<'a> { #[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) + } + + fn size_hint(depth: usize) -> (usize, Option) { + arbitrary::size_hint::and(u8::size_hint(depth), Vec::::size_hint(depth)) + } +} + #[cfg(test)] mod tests { use crate::asn1::{OctetStringRef, PrintableStringRef}; diff --git a/der/src/asn1/printable_string.rs b/der/src/asn1/printable_string.rs index 51360b50f..69fff9fd0 100644 --- a/der/src/asn1/printable_string.rs +++ b/der/src/asn1/printable_string.rs @@ -1,13 +1,26 @@ //! ASN.1 `PrintableString` support. -use crate::{ - asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, FixedTag, Header, - Length, Reader, Result, StrSlice, Tag, Writer, -}; -use core::{fmt, ops::Deref, str}; +use crate::{asn1::AnyRef, Error, 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; + } -#[cfg(feature = "alloc")] -use crate::asn1::Any; + 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. /// @@ -41,7 +54,7 @@ use crate::asn1::Any; #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct PrintableStringRef<'a> { /// Inner value - inner: StrSlice<'a>, + inner: StrRef<'a>, } impl<'a> PrintableStringRef<'a> { @@ -74,92 +87,154 @@ impl<'a> PrintableStringRef<'a> { } } - StrSlice::from_bytes(input) + 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 = StrSlice<'a>; + type Target = StrRef<'a>; fn deref(&self) -> &Self::Target { &self.inner } } - -impl AsRef for PrintableStringRef<'_> { - fn as_ref(&self) -> &str { - self.as_str() +impl<'a> From<&PrintableStringRef<'a>> for PrintableStringRef<'a> { + fn from(value: &PrintableStringRef<'a>) -> PrintableStringRef<'a> { + *value } } -impl AsRef<[u8]> for PrintableStringRef<'_> { - fn as_ref(&self) -> &[u8] { - self.as_bytes() +impl<'a> TryFrom> for PrintableStringRef<'a> { + type Error = Error; + + fn try_from(any: AnyRef<'a>) -> Result> { + any.decode_into() } } -impl<'a> DecodeValue<'a> for PrintableStringRef<'a> { - fn decode_value>(reader: &mut R, header: Header) -> Result { - Self::new(ByteSlice::decode_value(reader, header)?.as_slice()) +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()) } } -impl<'a> EncodeValue for PrintableStringRef<'a> { - fn value_len(&self) -> Result { - self.inner.value_len() +#[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 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, } - fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> { - self.inner.encode_value(writer) + impl PrintableString { + /// Create a new ASN.1 `PrintableString`. + pub fn new(input: &T) -> Result + 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 FixedTag for PrintableStringRef<'_> { - const TAG: Tag = Tag::PrintableString; -} + impl_printable_string!(PrintableString); -impl OrdIsValueOrd for PrintableStringRef<'_> {} + impl Deref for PrintableString { + type Target = StrOwned; -impl<'a> From<&PrintableStringRef<'a>> for PrintableStringRef<'a> { - fn from(value: &PrintableStringRef<'a>) -> PrintableStringRef<'a> { - *value + fn deref(&self) -> &Self::Target { + &self.inner + } } -} - -impl<'a> TryFrom> for PrintableStringRef<'a> { - type Error = Error; - fn try_from(any: AnyRef<'a>) -> Result> { - any.decode_into() + impl<'a> From> for PrintableString { + fn from(value: PrintableStringRef<'a>) -> PrintableString { + let inner = + StrOwned::from_bytes(value.inner.as_bytes()).expect("Invalid PrintableString"); + Self { inner } + } } -} -#[cfg(feature = "alloc")] -impl<'a> TryFrom<&'a Any> for PrintableStringRef<'a> { - type Error = Error; + impl<'a> TryFrom<&AnyRef<'a>> for PrintableString { + type Error = Error; - fn try_from(any: &'a Any) -> Result> { - any.decode_into() + fn try_from(any: &AnyRef<'a>) -> Result { + (*any).decode_into() + } } -} -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()) + 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> fmt::Display for PrintableStringRef<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) + impl<'a> RefToOwned<'a> for PrintableStringRef<'a> { + type Owned = PrintableString; + fn to_owned(&self) -> Self::Owned { + PrintableString { + inner: self.inner.to_owned(), + } + } } -} -impl<'a> fmt::Debug for PrintableStringRef<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "PrintableString({:?})", self.as_str()) + impl OwnedToRef for PrintableString { + type Borrowed<'a> = PrintableStringRef<'a>; + fn to_ref(&self) -> Self::Borrowed<'_> { + PrintableStringRef { + inner: self.inner.to_ref(), + } + } } } diff --git a/der/src/asn1/real.rs b/der/src/asn1/real.rs index fd5297e67..d7627b910 100644 --- a/der/src/asn1/real.rs +++ b/der/src/asn1/real.rs @@ -8,8 +8,8 @@ )] use crate::{ - str_slice::StrSlice, ByteSlice, DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, - Result, Tag, Writer, + BytesRef, DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, Result, StrRef, Tag, + Writer, }; use super::integer::uint::strip_leading_zeroes; @@ -17,7 +17,7 @@ use super::integer::uint::strip_leading_zeroes; #[cfg_attr(docsrs, doc(cfg(feature = "real")))] impl<'a> DecodeValue<'a> for f64 { fn decode_value>(reader: &mut R, header: Header) -> Result { - let bytes = ByteSlice::decode_value(reader, header)?.as_slice(); + let bytes = BytesRef::decode_value(reader, header)?.as_slice(); if header.length == Length::ZERO { Ok(0.0) @@ -74,7 +74,7 @@ impl<'a> DecodeValue<'a> for f64 { _ => Err(Tag::Real.value_error()), } } else { - let astr = StrSlice::from_bytes(&bytes[1..])?; + let astr = StrRef::from_bytes(&bytes[1..])?; match astr.inner.parse::() { Ok(val) => Ok(val), // Real related error: encoding not supported or malformed diff --git a/der/src/asn1/sequence.rs b/der/src/asn1/sequence.rs index d2f6bc5d1..40c58e7e4 100644 --- a/der/src/asn1/sequence.rs +++ b/der/src/asn1/sequence.rs @@ -2,7 +2,7 @@ //! `SEQUENCE`s to Rust structs. use crate::{ - ByteSlice, Decode, DecodeValue, Encode, EncodeValue, FixedTag, Header, Length, Reader, Result, + BytesRef, Decode, DecodeValue, Encode, EncodeValue, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; @@ -58,13 +58,13 @@ where /// This is a zero-copy reference type which borrows from the input data. pub struct SequenceRef<'a> { /// Body of the `SEQUENCE`. - body: ByteSlice<'a>, + body: BytesRef<'a>, } impl<'a> DecodeValue<'a> for SequenceRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { Ok(Self { - body: ByteSlice::decode_value(reader, header)?, + body: BytesRef::decode_value(reader, header)?, }) } } diff --git a/der/src/asn1/teletex_string.rs b/der/src/asn1/teletex_string.rs index 5113d42c7..1aa8a4495 100644 --- a/der/src/asn1/teletex_string.rs +++ b/der/src/asn1/teletex_string.rs @@ -1,13 +1,26 @@ //! ASN.1 `TeletexString` support. +//! +use crate::{asn1::AnyRef, Error, 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; + } -use crate::{ - asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, FixedTag, Header, - Length, Reader, Result, StrSlice, Tag, Writer, -}; -use core::{fmt, ops::Deref, str}; - -#[cfg(feature = "alloc")] -use crate::asn1::Any; + 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. /// @@ -28,7 +41,7 @@ use crate::asn1::Any; #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct TeletexStringRef<'a> { /// Inner value - inner: StrSlice<'a>, + inner: StrRef<'a>, } impl<'a> TeletexStringRef<'a> { @@ -44,92 +57,142 @@ impl<'a> TeletexStringRef<'a> { return Err(Self::TAG.value_error()); } - StrSlice::from_bytes(input) + 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 = StrSlice<'a>; + type Target = StrRef<'a>; fn deref(&self) -> &Self::Target { &self.inner } } -impl AsRef for TeletexStringRef<'_> { - fn as_ref(&self) -> &str { - self.as_str() +impl<'a> From<&TeletexStringRef<'a>> for TeletexStringRef<'a> { + fn from(value: &TeletexStringRef<'a>) -> TeletexStringRef<'a> { + *value } } -impl AsRef<[u8]> for TeletexStringRef<'_> { - fn as_ref(&self) -> &[u8] { - self.as_bytes() +impl<'a> TryFrom> for TeletexStringRef<'a> { + type Error = Error; + + fn try_from(any: AnyRef<'a>) -> Result> { + any.decode_into() } } - -impl<'a> DecodeValue<'a> for TeletexStringRef<'a> { - fn decode_value>(reader: &mut R, header: Header) -> Result { - Self::new(ByteSlice::decode_value(reader, header)?.as_slice()) +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()) } } -impl<'a> EncodeValue for TeletexStringRef<'a> { - fn value_len(&self) -> Result { - self.inner.value_len() - } +#[cfg(feature = "alloc")] +pub use self::allocation::TeletexString; - fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> { - self.inner.encode_value(writer) +#[cfg(feature = "alloc")] +mod allocation { + use super::TeletexStringRef; + + use crate::{ + asn1::AnyRef, + referenced::{OwnedToRef, RefToOwned}, + BytesRef, Error, FixedTag, Result, StrOwned, Tag, + }; + 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 FixedTag for TeletexStringRef<'_> { - const TAG: Tag = Tag::TeletexString; -} + impl TeletexString { + /// Create a new ASN.1 `TeletexString`. + pub fn new(input: &T) -> Result + where + T: AsRef<[u8]> + ?Sized, + { + let input = input.as_ref(); -impl OrdIsValueOrd for TeletexStringRef<'_> {} + TeletexStringRef::new(input)?; -impl<'a> From<&TeletexStringRef<'a>> for TeletexStringRef<'a> { - fn from(value: &TeletexStringRef<'a>) -> TeletexStringRef<'a> { - *value + StrOwned::from_bytes(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } } -} -impl<'a> TryFrom> for TeletexStringRef<'a> { - type Error = Error; + impl_teletex_string!(TeletexString); - fn try_from(any: AnyRef<'a>) -> Result> { - any.decode_into() + impl Deref for TeletexString { + type Target = StrOwned; + + fn deref(&self) -> &Self::Target { + &self.inner + } } -} -#[cfg(feature = "alloc")] -impl<'a> TryFrom<&'a Any> for TeletexStringRef<'a> { - type Error = Error; + impl<'a> From> for TeletexString { + fn from(value: TeletexStringRef<'a>) -> TeletexString { + let inner = + StrOwned::from_bytes(value.inner.as_bytes()).expect("Invalid TeletexString"); + Self { inner } + } + } - fn try_from(any: &'a Any) -> Result> { - any.decode_into() + impl<'a> TryFrom<&AnyRef<'a>> for TeletexString { + type Error = Error; + + fn try_from(any: &AnyRef<'a>) -> Result { + (*any).decode_into() + } } -} -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()) + 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> fmt::Display for TeletexStringRef<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) + impl<'a> RefToOwned<'a> for TeletexStringRef<'a> { + type Owned = TeletexString; + fn to_owned(&self) -> Self::Owned { + TeletexString { + inner: self.inner.to_owned(), + } + } } -} -impl<'a> fmt::Debug for TeletexStringRef<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "TeletexString({:?})", self.as_str()) + impl OwnedToRef for TeletexString { + type Borrowed<'a> = TeletexStringRef<'a>; + fn to_ref(&self) -> Self::Borrowed<'_> { + TeletexStringRef { + inner: self.inner.to_ref(), + } + } } } diff --git a/der/src/asn1/utf8_string.rs b/der/src/asn1/utf8_string.rs index c529feb1e..ef9ed4079 100644 --- a/der/src/asn1/utf8_string.rs +++ b/der/src/asn1/utf8_string.rs @@ -1,8 +1,8 @@ //! ASN.1 `UTF8String` support. use crate::{ - asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, FixedTag, Header, - Length, Reader, Result, StrSlice, Tag, Writer, + asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, DecodeValue, EncodeValue, Error, FixedTag, Header, + Length, Reader, Result, StrRef, Tag, Writer, }; use core::{fmt, ops::Deref, str}; @@ -29,7 +29,7 @@ use { #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct Utf8StringRef<'a> { /// Inner value - inner: StrSlice<'a>, + inner: StrRef<'a>, } impl<'a> Utf8StringRef<'a> { @@ -38,12 +38,12 @@ impl<'a> Utf8StringRef<'a> { where T: AsRef<[u8]> + ?Sized, { - StrSlice::from_bytes(input.as_ref()).map(|inner| Self { inner }) + StrRef::from_bytes(input.as_ref()).map(|inner| Self { inner }) } } impl<'a> Deref for Utf8StringRef<'a> { - type Target = StrSlice<'a>; + type Target = StrRef<'a>; fn deref(&self) -> &Self::Target { &self.inner @@ -64,7 +64,7 @@ impl AsRef<[u8]> for Utf8StringRef<'_> { impl<'a> DecodeValue<'a> for Utf8StringRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { - Self::new(ByteSlice::decode_value(reader, header)?.as_slice()) + Self::new(BytesRef::decode_value(reader, header)?.as_slice()) } } diff --git a/der/src/asn1/videotex_string.rs b/der/src/asn1/videotex_string.rs index f1c9ba3b4..506edbd1a 100644 --- a/der/src/asn1/videotex_string.rs +++ b/der/src/asn1/videotex_string.rs @@ -1,8 +1,8 @@ //! ASN.1 `VideotexString` support. use crate::{ - asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, FixedTag, Header, - Length, Reader, Result, StrSlice, Tag, Writer, + asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, DecodeValue, EncodeValue, Error, FixedTag, Header, + Length, Reader, Result, StrRef, Tag, Writer, }; use core::{fmt, ops::Deref, str}; @@ -26,7 +26,7 @@ use crate::asn1::Any; #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct VideotexStringRef<'a> { /// Inner value - inner: StrSlice<'a>, + inner: StrRef<'a>, } impl<'a> VideotexStringRef<'a> { @@ -43,14 +43,14 @@ impl<'a> VideotexStringRef<'a> { return Err(Self::TAG.value_error()); } - StrSlice::from_bytes(input) + StrRef::from_bytes(input) .map(|inner| Self { inner }) .map_err(|_| Self::TAG.value_error()) } } impl<'a> Deref for VideotexStringRef<'a> { - type Target = StrSlice<'a>; + type Target = StrRef<'a>; fn deref(&self) -> &Self::Target { &self.inner @@ -71,7 +71,7 @@ impl AsRef<[u8]> for VideotexStringRef<'_> { impl<'a> DecodeValue<'a> for VideotexStringRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { - Self::new(ByteSlice::decode_value(reader, header)?.as_slice()) + Self::new(BytesRef::decode_value(reader, header)?.as_slice()) } } diff --git a/der/src/bytes.rs b/der/src/bytes_owned.rs similarity index 74% rename from der/src/bytes.rs rename to der/src/bytes_owned.rs index ea261373a..47105813a 100644 --- a/der/src/bytes.rs +++ b/der/src/bytes_owned.rs @@ -2,15 +2,15 @@ //! library-level length limitation i.e. `Length::max()`. use crate::{ - referenced::OwnedToRef, str_slice::StrSlice, ByteSlice, DecodeValue, DerOrd, EncodeValue, - Error, Header, Length, Reader, Result, Writer, + referenced::OwnedToRef, BytesRef, DecodeValue, DerOrd, EncodeValue, Error, Header, Length, + Reader, Result, StrRef, Writer, }; use alloc::boxed::Box; use core::cmp::Ordering; /// Byte slice newtype which respects the `Length::max()` limit. #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub(crate) struct Bytes { +pub(crate) struct BytesOwned { /// Precomputed `Length` (avoids possible panicking conversions) length: Length, @@ -18,8 +18,8 @@ pub(crate) struct Bytes { inner: Box<[u8]>, } -impl Bytes { - /// Create a new [`Bytes`], ensuring that the provided `slice` value +impl BytesOwned { + /// Create a new [`BytesOwned`], ensuring that the provided `slice` value /// is shorter than `Length::max()`. pub fn new(data: impl Into>) -> Result { let inner: Box<[u8]> = data.into(); @@ -35,30 +35,30 @@ impl Bytes { &self.inner } - /// Get the [`Length`] of this [`ByteSlice`] + /// Get the [`Length`] of this [`BytesRef`] pub fn len(&self) -> Length { self.length } - /// Is this [`Bytes`] empty? + /// Is this [`BytesOwned`] empty? pub fn is_empty(&self) -> bool { self.len() == Length::ZERO } } -impl AsRef<[u8]> for Bytes { +impl AsRef<[u8]> for BytesOwned { fn as_ref(&self) -> &[u8] { self.as_slice() } } -impl<'a> DecodeValue<'a> for Bytes { +impl<'a> DecodeValue<'a> for BytesOwned { fn decode_value>(reader: &mut R, header: Header) -> Result { reader.read_vec(header.length).and_then(Self::new) } } -impl EncodeValue for Bytes { +impl EncodeValue for BytesOwned { fn value_len(&self) -> Result { Ok(self.length) } @@ -68,7 +68,7 @@ impl EncodeValue for Bytes { } } -impl Default for Bytes { +impl Default for BytesOwned { fn default() -> Self { Self { length: Length::ZERO, @@ -77,44 +77,44 @@ impl Default for Bytes { } } -impl DerOrd for Bytes { +impl DerOrd for BytesOwned { fn der_cmp(&self, other: &Self) -> Result { Ok(self.as_slice().cmp(other.as_slice())) } } -impl From> for Bytes { - fn from(s: StrSlice<'_>) -> Bytes { +impl From> for BytesOwned { + fn from(s: StrRef<'_>) -> BytesOwned { let bytes = s.as_bytes(); debug_assert_eq!(bytes.len(), usize::try_from(s.length).expect("overflow")); - Bytes { + BytesOwned { inner: Box::from(bytes), length: s.length, } } } -impl OwnedToRef for Bytes { - type Borrowed<'a> = ByteSlice<'a>; +impl OwnedToRef for BytesOwned { + type Borrowed<'a> = BytesRef<'a>; fn to_ref(&self) -> Self::Borrowed<'_> { - ByteSlice { + BytesRef { length: self.length, inner: self.inner.as_ref(), } } } -impl From> for Bytes { - fn from(s: ByteSlice<'_>) -> Bytes { - Bytes { +impl From> for BytesOwned { + fn from(s: BytesRef<'_>) -> BytesOwned { + BytesOwned { length: s.length, inner: Box::from(s.inner), } } } -impl TryFrom<&[u8]> for Bytes { +impl TryFrom<&[u8]> for BytesOwned { type Error = Error; fn try_from(slice: &[u8]) -> Result { @@ -125,7 +125,7 @@ impl TryFrom<&[u8]> for Bytes { // Implement by hand because the derive would create invalid values. // Make sure the length and the inner.len matches. #[cfg(feature = "arbitrary")] -impl<'a> arbitrary::Arbitrary<'a> for Bytes { +impl<'a> arbitrary::Arbitrary<'a> for BytesOwned { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { let length = u.arbitrary()?; Ok(Self { diff --git a/der/src/byte_slice.rs b/der/src/bytes_ref.rs similarity index 67% rename from der/src/byte_slice.rs rename to der/src/bytes_ref.rs index 7a462496d..e6a9b5821 100644 --- a/der/src/byte_slice.rs +++ b/der/src/bytes_ref.rs @@ -2,14 +2,16 @@ //! library-level length limitation i.e. `Length::max()`. use crate::{ - str_slice::StrSlice, DecodeValue, DerOrd, EncodeValue, Error, Header, Length, Reader, Result, - Writer, + DecodeValue, DerOrd, EncodeValue, Error, Header, Length, Reader, Result, StrRef, Writer, }; use core::cmp::Ordering; +#[cfg(feature = "alloc")] +use crate::StrOwned; + /// Byte slice newtype which respects the `Length::max()` limit. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub(crate) struct ByteSlice<'a> { +pub(crate) struct BytesRef<'a> { /// Precomputed `Length` (avoids possible panicking conversions) pub length: Length, @@ -17,14 +19,14 @@ pub(crate) struct ByteSlice<'a> { pub inner: &'a [u8], } -impl<'a> ByteSlice<'a> { +impl<'a> BytesRef<'a> { /// Constant value representing an empty byte slice. pub const EMPTY: Self = Self { length: Length::ZERO, inner: &[], }; - /// Create a new [`ByteSlice`], ensuring that the provided `slice` value + /// Create a new [`BytesRef`], ensuring that the provided `slice` value /// is shorter than `Length::max()`. pub fn new(slice: &'a [u8]) -> Result { Ok(Self { @@ -38,30 +40,30 @@ impl<'a> ByteSlice<'a> { self.inner } - /// Get the [`Length`] of this [`ByteSlice`] + /// Get the [`Length`] of this [`BytesRef`] pub fn len(self) -> Length { self.length } - /// Is this [`ByteSlice`] empty? + /// Is this [`BytesRef`] empty? pub fn is_empty(self) -> bool { self.len() == Length::ZERO } } -impl AsRef<[u8]> for ByteSlice<'_> { +impl AsRef<[u8]> for BytesRef<'_> { fn as_ref(&self) -> &[u8] { self.as_slice() } } -impl<'a> DecodeValue<'a> for ByteSlice<'a> { +impl<'a> DecodeValue<'a> for BytesRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { reader.read_slice(header.length).and_then(Self::new) } } -impl EncodeValue for ByteSlice<'_> { +impl EncodeValue for BytesRef<'_> { fn value_len(&self) -> Result { Ok(self.length) } @@ -71,7 +73,7 @@ impl EncodeValue for ByteSlice<'_> { } } -impl Default for ByteSlice<'_> { +impl Default for BytesRef<'_> { fn default() -> Self { Self { length: Length::ZERO, @@ -80,25 +82,38 @@ impl Default for ByteSlice<'_> { } } -impl DerOrd for ByteSlice<'_> { +impl DerOrd for BytesRef<'_> { fn der_cmp(&self, other: &Self) -> Result { Ok(self.as_slice().cmp(other.as_slice())) } } -impl<'a> From> for ByteSlice<'a> { - fn from(s: StrSlice<'a>) -> ByteSlice<'a> { +impl<'a> From> for BytesRef<'a> { + fn from(s: StrRef<'a>) -> BytesRef<'a> { + let bytes = s.as_bytes(); + debug_assert_eq!(bytes.len(), usize::try_from(s.length).expect("overflow")); + + BytesRef { + inner: bytes, + length: s.length, + } + } +} + +#[cfg(feature = "alloc")] +impl<'a> From<&'a StrOwned> for BytesRef<'a> { + fn from(s: &'a StrOwned) -> BytesRef<'a> { let bytes = s.as_bytes(); debug_assert_eq!(bytes.len(), usize::try_from(s.length).expect("overflow")); - ByteSlice { + BytesRef { inner: bytes, length: s.length, } } } -impl<'a> TryFrom<&'a [u8]> for ByteSlice<'a> { +impl<'a> TryFrom<&'a [u8]> for BytesRef<'a> { type Error = Error; fn try_from(slice: &'a [u8]) -> Result { @@ -109,7 +124,7 @@ impl<'a> TryFrom<&'a [u8]> for ByteSlice<'a> { // Implement by hand because the derive would create invalid values. // Make sure the length and the inner.len matches. #[cfg(feature = "arbitrary")] -impl<'a> arbitrary::Arbitrary<'a> for ByteSlice<'a> { +impl<'a> arbitrary::Arbitrary<'a> for BytesRef<'a> { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { let length = u.arbitrary()?; Ok(Self { @@ -125,13 +140,13 @@ impl<'a> arbitrary::Arbitrary<'a> for ByteSlice<'a> { #[cfg(feature = "alloc")] mod allocating { - use super::ByteSlice; - use crate::{referenced::RefToOwned, Bytes}; + use super::BytesRef; + use crate::{referenced::RefToOwned, BytesOwned}; - impl<'a> RefToOwned<'a> for ByteSlice<'a> { - type Owned = Bytes; + impl<'a> RefToOwned<'a> for BytesRef<'a> { + type Owned = BytesOwned; fn to_owned(&self) -> Self::Owned { - Bytes::from(*self) + BytesOwned::from(*self) } } } diff --git a/der/src/lib.rs b/der/src/lib.rs index 5431c44b8..b1d3aaf2a 100644 --- a/der/src/lib.rs +++ b/der/src/lib.rs @@ -344,7 +344,7 @@ pub mod asn1; pub mod referenced; pub(crate) mod arrayvec; -mod byte_slice; +mod bytes_ref; mod datetime; mod decode; mod encode; @@ -354,14 +354,16 @@ mod header; mod length; mod ord; mod reader; -mod str_slice; +mod str_ref; mod tag; mod writer; #[cfg(feature = "alloc")] -mod bytes; +mod bytes_owned; #[cfg(feature = "alloc")] mod document; +#[cfg(feature = "alloc")] +mod str_owned; pub use crate::{ asn1::{AnyRef, Choice, Sequence}, @@ -410,6 +412,6 @@ pub use zeroize; #[cfg(all(feature = "alloc", feature = "zeroize"))] pub use crate::document::SecretDocument; +pub(crate) use crate::{arrayvec::ArrayVec, bytes_ref::BytesRef, str_ref::StrRef}; #[cfg(feature = "alloc")] -pub(crate) use crate::bytes::Bytes; -pub(crate) use crate::{arrayvec::ArrayVec, byte_slice::ByteSlice, str_slice::StrSlice}; +pub(crate) use crate::{bytes_owned::BytesOwned, str_owned::StrOwned}; diff --git a/der/src/reader/slice.rs b/der/src/reader/slice.rs index fe7560807..e78468fed 100644 --- a/der/src/reader/slice.rs +++ b/der/src/reader/slice.rs @@ -1,12 +1,12 @@ //! Slice reader. -use crate::{ByteSlice, Decode, Error, ErrorKind, Header, Length, Reader, Result, Tag}; +use crate::{BytesRef, Decode, Error, ErrorKind, Header, Length, Reader, Result, Tag}; /// [`Reader`] which consumes an input byte slice. #[derive(Clone, Debug)] pub struct SliceReader<'a> { /// Byte slice being decoded. - bytes: ByteSlice<'a>, + bytes: BytesRef<'a>, /// Did the decoding operation fail? failed: bool, @@ -19,7 +19,7 @@ impl<'a> SliceReader<'a> { /// Create a new slice reader for the given byte slice. pub fn new(bytes: &'a [u8]) -> Result { Ok(Self { - bytes: ByteSlice::new(bytes)?, + bytes: BytesRef::new(bytes)?, failed: false, position: Length::ZERO, }) diff --git a/der/src/str_owned.rs b/der/src/str_owned.rs new file mode 100644 index 000000000..726716021 --- /dev/null +++ b/der/src/str_owned.rs @@ -0,0 +1,105 @@ +//! Common handling for types backed by `String` with enforcement of a +//! library-level length limitation i.e. `Length::max()`. + +use crate::{ + referenced::OwnedToRef, BytesRef, DecodeValue, EncodeValue, Header, Length, Reader, Result, + StrRef, Writer, +}; +use alloc::string::String; +use core::str; + +/// String newtype which respects the [`Length::max`] limit. +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct StrOwned { + /// Inner value + pub(crate) inner: String, + + /// Precomputed `Length` (avoids possible panicking conversions) + pub(crate) length: Length, +} + +impl StrOwned { + /// Create a new [`StrOwned`], ensuring that the byte representation of + /// the provided `str` value is shorter than `Length::max()`. + pub fn new(s: &str) -> Result { + Ok(Self { + inner: String::from(s), + length: Length::try_from(s.as_bytes().len())?, + }) + } + + /// Parse a [`String`] from UTF-8 encoded bytes. + pub fn from_bytes(bytes: &[u8]) -> Result { + Ok(Self { + inner: String::from_utf8(bytes.to_vec())?, + length: Length::try_from(bytes.len())?, + }) + } + + /// Borrow the inner `str` + pub fn as_str(&self) -> &str { + &self.inner + } + + /// Borrow the inner byte slice + pub fn as_bytes(&self) -> &[u8] { + self.inner.as_bytes() + } + + /// Get the [`Length`] of this [`StrOwned`] + pub fn len(&self) -> Length { + self.length + } + + /// Is this [`StrOwned`] empty? + pub fn is_empty(&self) -> bool { + self.len() == Length::ZERO + } +} + +impl AsRef for StrOwned { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl AsRef<[u8]> for StrOwned { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<'a> DecodeValue<'a> for StrOwned { + fn decode_value>(reader: &mut R, header: Header) -> Result { + Self::from_bytes(BytesRef::decode_value(reader, header)?.as_slice()) + } +} + +impl EncodeValue for StrOwned { + fn value_len(&self) -> Result { + Ok(self.length) + } + + fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> { + writer.write(self.as_ref()) + } +} + +impl From> for StrOwned { + fn from(s: StrRef<'_>) -> StrOwned { + Self { + inner: String::from(s.inner), + length: s.length, + } + } +} + +impl OwnedToRef for StrOwned { + type Borrowed<'a> = StrRef<'a>; + fn to_ref(&self) -> Self::Borrowed<'_> { + StrRef { + length: self.length, + inner: self.inner.as_ref(), + } + } +} diff --git a/der/src/str_slice.rs b/der/src/str_ref.rs similarity index 64% rename from der/src/str_slice.rs rename to der/src/str_ref.rs index 8c94528aa..ac76f1759 100644 --- a/der/src/str_slice.rs +++ b/der/src/str_ref.rs @@ -1,12 +1,12 @@ //! Common handling for types backed by `str` slices with enforcement of a //! library-level length limitation i.e. `Length::max()`. -use crate::{ByteSlice, DecodeValue, EncodeValue, Header, Length, Reader, Result, Writer}; +use crate::{BytesRef, DecodeValue, EncodeValue, Header, Length, Reader, Result, Writer}; use core::str; /// String slice newtype which respects the [`Length::max`] limit. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub struct StrSlice<'a> { +pub struct StrRef<'a> { /// Inner value pub(crate) inner: &'a str, @@ -14,8 +14,8 @@ pub struct StrSlice<'a> { pub(crate) length: Length, } -impl<'a> StrSlice<'a> { - /// Create a new [`StrSlice`], ensuring that the byte representation of +impl<'a> StrRef<'a> { + /// Create a new [`StrRef`], ensuring that the byte representation of /// the provided `str` value is shorter than `Length::max()`. pub fn new(s: &'a str) -> Result { Ok(Self { @@ -24,7 +24,7 @@ impl<'a> StrSlice<'a> { }) } - /// Parse a [`StrSlice`] from UTF-8 encoded bytes. + /// Parse a [`StrRef`] from UTF-8 encoded bytes. pub fn from_bytes(bytes: &'a [u8]) -> Result { Self::new(str::from_utf8(bytes)?) } @@ -39,36 +39,36 @@ impl<'a> StrSlice<'a> { self.inner.as_bytes() } - /// Get the [`Length`] of this [`StrSlice`] + /// Get the [`Length`] of this [`StrRef`] pub fn len(self) -> Length { self.length } - /// Is this [`StrSlice`] empty? + /// Is this [`StrRef`] empty? pub fn is_empty(self) -> bool { self.len() == Length::ZERO } } -impl AsRef for StrSlice<'_> { +impl AsRef for StrRef<'_> { fn as_ref(&self) -> &str { self.as_str() } } -impl AsRef<[u8]> for StrSlice<'_> { +impl AsRef<[u8]> for StrRef<'_> { fn as_ref(&self) -> &[u8] { self.as_bytes() } } -impl<'a> DecodeValue<'a> for StrSlice<'a> { +impl<'a> DecodeValue<'a> for StrRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { - Self::from_bytes(ByteSlice::decode_value(reader, header)?.as_slice()) + Self::from_bytes(BytesRef::decode_value(reader, header)?.as_slice()) } } -impl<'a> EncodeValue for StrSlice<'a> { +impl<'a> EncodeValue for StrRef<'a> { fn value_len(&self) -> Result { Ok(self.length) } @@ -77,3 +77,16 @@ impl<'a> EncodeValue for StrSlice<'a> { writer.write(self.as_ref()) } } + +#[cfg(feature = "alloc")] +mod allocating { + use super::StrRef; + use crate::{referenced::RefToOwned, StrOwned}; + + impl<'a> RefToOwned<'a> for StrRef<'a> { + type Owned = StrOwned; + fn to_owned(&self) -> Self::Owned { + StrOwned::from(*self) + } + } +} diff --git a/pkcs7/src/certificate_choices.rs b/pkcs7/src/certificate_choices.rs index dfc6bb7ca..f6c370a8c 100644 --- a/pkcs7/src/certificate_choices.rs +++ b/pkcs7/src/certificate_choices.rs @@ -36,7 +36,7 @@ pub struct OtherCertificateFormat<'a> { #[allow(clippy::large_enum_variant)] pub enum CertificateChoices<'a> { /// X.509 certificate - Certificate(Certificate<'a>), + Certificate(Certificate), /// PKCS #6 extended certificate (obsolete) #[deprecated] diff --git a/pkcs7/src/signer_info.rs b/pkcs7/src/signer_info.rs index 3bd2f83ad..3f71769d6 100644 --- a/pkcs7/src/signer_info.rs +++ b/pkcs7/src/signer_info.rs @@ -36,13 +36,13 @@ type UnsignedAttributes<'a> = SetOfVec; // subjectKeyIdentifier [0] SubjectKeyIdentifier } /// ``` #[derive(Clone, Debug, PartialEq, Eq, Choice, ValueOrd)] -pub enum SignerIdentifier<'a> { +pub enum SignerIdentifier { /// issuer and serial number IssuerAndSerialNumber(IssuerAndSerialNumber), /// subject key identifier #[asn1(context_specific = "0")] - SubjectKeyIdentifier(SubjectKeyIdentifier<'a>), + SubjectKeyIdentifier(SubjectKeyIdentifier), } #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] @@ -75,7 +75,7 @@ pub struct SignerInfo<'a> { pub version: CmsVersion, /// the signer identifier - pub sid: SignerIdentifier<'a>, + pub sid: SignerIdentifier, /// the message digest algorithm pub digest_algorithm: DigestAlgorithmIdentifier<'a>, diff --git a/x509-cert/Cargo.toml b/x509-cert/Cargo.toml index b169a2296..0edbc7f2e 100644 --- a/x509-cert/Cargo.toml +++ b/x509-cert/Cargo.toml @@ -19,7 +19,7 @@ arbitrary = { version = "1.2.0", features = ["derive"], optional = true } const-oid = { version = "=0.10.0-pre", features = ["db"], path = "../const-oid" } der = { version = "=0.7.0-pre", features = ["derive", "alloc", "flagset"], path = "../der" } flagset = { version = "0.4.3" } -spki = { version = "=0.7.0-pre", path = "../spki" } +spki = { version = "=0.7.0-pre", path = "../spki", features = ["alloc"] } [dev-dependencies] hex-literal = "0.3" diff --git a/x509-cert/src/anchor.rs b/x509-cert/src/anchor.rs index de38807ad..9b2f01edf 100644 --- a/x509-cert/src/anchor.rs +++ b/x509-cert/src/anchor.rs @@ -4,10 +4,11 @@ use crate::ext::pkix::{certpolicy::CertificatePolicies, NameConstraints}; use crate::{ext::Extensions, name::Name}; use crate::{Certificate, TbsCertificate}; -use der::asn1::{OctetStringRef, Utf8StringRef}; +use alloc::string::String; +use der::asn1::OctetString; use der::{Choice, Enumerated, Sequence}; use flagset::{flags, FlagSet}; -use spki::SubjectPublicKeyInfoRef; +use spki::SubjectPublicKeyInfoOwned; /// Version identifier for TrustAnchorInfo #[derive(Clone, Debug, Copy, PartialEq, Eq, Enumerated)] @@ -41,25 +42,25 @@ impl Default for Version { /// ``` #[derive(Clone, Debug, PartialEq, Eq, Sequence)] #[allow(missing_docs)] -pub struct TrustAnchorInfo<'a> { +pub struct TrustAnchorInfo { #[asn1(default = "Default::default")] pub version: Version, - pub pub_key: SubjectPublicKeyInfoRef<'a>, + pub pub_key: SubjectPublicKeyInfoOwned, - pub key_id: OctetStringRef<'a>, + pub key_id: OctetString, #[asn1(optional = "true")] - pub ta_title: Option>, + pub ta_title: Option, #[asn1(optional = "true")] - pub cert_path: Option>, + pub cert_path: Option, #[asn1(context_specific = "1", tag_mode = "EXPLICIT", optional = "true")] - pub extensions: Option>, + pub extensions: Option, #[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")] - pub ta_title_lang_tag: Option>, + pub ta_title_lang_tag: Option, } /// ```text @@ -74,20 +75,20 @@ pub struct TrustAnchorInfo<'a> { /// ``` #[derive(Clone, Debug, Eq, PartialEq, Sequence)] #[allow(missing_docs)] -pub struct CertPathControls<'a> { +pub struct CertPathControls { pub ta_name: Name, #[asn1(context_specific = "0", tag_mode = "IMPLICIT", optional = "true")] - pub certificate: Option>, + pub certificate: Option, #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")] - pub policy_set: Option>, + pub policy_set: Option, #[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")] pub policy_flags: Option, #[asn1(context_specific = "3", tag_mode = "IMPLICIT", optional = "true")] - pub name_constr: Option>, + pub name_constr: Option, #[asn1(context_specific = "4", tag_mode = "IMPLICIT", optional = "true")] pub path_len_constraint: Option, @@ -128,12 +129,12 @@ pub type CertPolicyFlags = FlagSet; #[derive(Clone, Debug, PartialEq, Eq, Choice)] #[allow(clippy::large_enum_variant)] #[allow(missing_docs)] -pub enum TrustAnchorChoice<'a> { - Certificate(Certificate<'a>), +pub enum TrustAnchorChoice { + Certificate(Certificate), #[asn1(context_specific = "1", tag_mode = "EXPLICIT", constructed = "true")] - TbsCertificate(TbsCertificate<'a>), + TbsCertificate(TbsCertificate), #[asn1(context_specific = "2", tag_mode = "EXPLICIT", constructed = "true")] - TaInfo(TrustAnchorInfo<'a>), + TaInfo(TrustAnchorInfo), } diff --git a/x509-cert/src/certificate.rs b/x509-cert/src/certificate.rs index 62a84747f..bb2a8603c 100644 --- a/x509-cert/src/certificate.rs +++ b/x509-cert/src/certificate.rs @@ -6,9 +6,9 @@ use alloc::vec::Vec; use core::cmp::Ordering; use const_oid::AssociatedOid; -use der::asn1::BitStringRef; +use der::asn1::BitString; use der::{Decode, Enumerated, Error, ErrorKind, Sequence, ValueOrd}; -use spki::{AlgorithmIdentifierRef, SubjectPublicKeyInfoRef}; +use spki::{AlgorithmIdentifierOwned, SubjectPublicKeyInfoOwned}; #[cfg(feature = "pem")] use der::pem::PemLabel; @@ -75,7 +75,7 @@ impl Default for Version { #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] #[allow(missing_docs)] -pub struct TbsCertificate<'a> { +pub struct TbsCertificate { /// The certificate version /// /// Note that this value defaults to Version 1 per the RFC. However, @@ -86,31 +86,29 @@ pub struct TbsCertificate<'a> { pub version: Version, pub serial_number: SerialNumber, - pub signature: AlgorithmIdentifierRef<'a>, + pub signature: AlgorithmIdentifierOwned, pub issuer: Name, pub validity: Validity, pub subject: Name, - pub subject_public_key_info: SubjectPublicKeyInfoRef<'a>, + pub subject_public_key_info: SubjectPublicKeyInfoOwned, #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")] - pub issuer_unique_id: Option>, + pub issuer_unique_id: Option, #[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")] - pub subject_unique_id: Option>, + pub subject_unique_id: Option, #[asn1(context_specific = "3", tag_mode = "EXPLICIT", optional = "true")] - pub extensions: Option>, + pub extensions: Option, } -impl<'a> TbsCertificate<'a> { +impl TbsCertificate { /// Decodes a single extension /// /// Returns an error if multiple of these extensions is present. Returns /// `Ok(None)` if the extension is not present. Returns a decoding error /// if decoding failed. Otherwise returns the extension. - pub fn get<'b: 'a, T: Decode<'a> + AssociatedOid>( - &'b self, - ) -> Result, Error> { + pub fn get<'a, T: Decode<'a> + AssociatedOid>(&'a self) -> Result, Error> { let mut iter = self.filter::().peekable(); match iter.next() { None => Ok(None), @@ -124,15 +122,15 @@ impl<'a> TbsCertificate<'a> { /// Filters extensions by an associated OID /// /// Returns a filtered iterator over all the extensions with the OID. - pub fn filter<'b: 'a, T: Decode<'a> + AssociatedOid>( - &'b self, - ) -> impl 'b + Iterator> { + pub fn filter<'a, T: Decode<'a> + AssociatedOid>( + &'a self, + ) -> impl 'a + Iterator> { self.extensions .as_deref() .unwrap_or(&[]) .iter() .filter(|e| e.extn_id == T::OID) - .map(|e| Ok((e.critical, T::from_der(e.extn_value)?))) + .map(|e| Ok((e.critical, T::from_der(e.extn_value.as_bytes())?))) } } @@ -150,15 +148,15 @@ impl<'a> TbsCertificate<'a> { #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] #[allow(missing_docs)] -pub struct Certificate<'a> { - pub tbs_certificate: TbsCertificate<'a>, - pub signature_algorithm: AlgorithmIdentifierRef<'a>, - pub signature: BitStringRef<'a>, +pub struct Certificate { + pub tbs_certificate: TbsCertificate, + pub signature_algorithm: AlgorithmIdentifierOwned, + pub signature: BitString, } #[cfg(feature = "pem")] #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] -impl PemLabel for Certificate<'_> { +impl PemLabel for Certificate { const PEM_LABEL: &'static str = "CERTIFICATE"; } @@ -173,4 +171,4 @@ impl PemLabel for Certificate<'_> { /// ``` /// /// [RFC 6066]: https://datatracker.ietf.org/doc/html/rfc6066#section-10.1 -pub type PkiPath<'a> = Vec>; +pub type PkiPath = Vec; diff --git a/x509-cert/src/crl.rs b/x509-cert/src/crl.rs index 3e83c57a0..a75c504cb 100644 --- a/x509-cert/src/crl.rs +++ b/x509-cert/src/crl.rs @@ -8,7 +8,7 @@ use crate::Version; use alloc::vec::Vec; -use der::asn1::BitStringRef; +use der::asn1::BitString; use der::{Sequence, ValueOrd}; use spki::AlgorithmIdentifierRef; @@ -28,7 +28,7 @@ use spki::AlgorithmIdentifierRef; pub struct CertificateList<'a> { pub tbs_cert_list: TbsCertList<'a>, pub signature_algorithm: AlgorithmIdentifierRef<'a>, - pub signature: BitStringRef<'a>, + pub signature: BitString, } /// Implicit intermediate structure from the ASN.1 definition of `TBSCertList`. @@ -47,10 +47,10 @@ pub struct CertificateList<'a> { /// [RFC 5280 Section 5.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.1 #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] #[allow(missing_docs)] -pub struct RevokedCert<'a> { +pub struct RevokedCert { pub serial_number: SerialNumber, pub revocation_date: Time, - pub crl_entry_extensions: Option>, + pub crl_entry_extensions: Option, } /// `TbsCertList` as defined in [RFC 5280 Section 5.1]. @@ -80,8 +80,8 @@ pub struct TbsCertList<'a> { pub issuer: Name, pub this_update: Time, pub next_update: Option