diff options
Diffstat (limited to 'vendor/der/src/asn1/any.rs')
-rw-r--r-- | vendor/der/src/asn1/any.rs | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/vendor/der/src/asn1/any.rs b/vendor/der/src/asn1/any.rs new file mode 100644 index 000000000..cb65f2391 --- /dev/null +++ b/vendor/der/src/asn1/any.rs @@ -0,0 +1,284 @@ +//! ASN.1 `ANY` type. + +use crate::{ + asn1::*, ByteSlice, 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 alloc::vec::Vec; + +#[cfg(feature = "oid")] +use crate::asn1::ObjectIdentifier; + +/// ASN.1 `ANY`: represents any explicitly tagged ASN.1 value. +/// +/// This is a zero-copy reference type which borrows from the input data. +/// +/// Technically `ANY` hasn't been a recommended part of ASN.1 since the X.209 +/// revision from 1988. It was deprecated and replaced by Information Object +/// Classes in X.680 in 1994, and X.690 no longer refers to it whatsoever. +/// +/// Nevertheless, this crate defines an `ANY` type as it remains a familiar +/// and useful concept which is still extensively used in things like +/// PKI-related RFCs. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct AnyRef<'a> { + /// Tag representing the type of the encoded value. + tag: Tag, + + /// Inner value encoded as bytes. + value: ByteSlice<'a>, +} + +impl<'a> AnyRef<'a> { + /// [`AnyRef`] representation of the ASN.1 `NULL` type. + pub const NULL: Self = Self { + tag: Tag::Null, + value: ByteSlice::EMPTY, + }; + + /// Create a new [`AnyRef`] from the provided [`Tag`] and DER bytes. + pub fn new(tag: Tag, bytes: &'a [u8]) -> Result<Self> { + let value = ByteSlice::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 { + Self { tag, value } + } + + /// Get the raw value for this [`AnyRef`] type as a byte slice. + pub fn value(self) -> &'a [u8] { + self.value.as_slice() + } + + /// Attempt to decode this [`AnyRef`] type into the inner value. + pub fn decode_into<T>(self) -> Result<T> + where + T: DecodeValue<'a> + FixedTag, + { + self.tag.assert_eq(T::TAG)?; + let header = Header { + tag: self.tag, + length: self.value.len(), + }; + + let mut decoder = SliceReader::new(self.value())?; + let result = T::decode_value(&mut decoder, header)?; + decoder.finish(result) + } + + /// Is this value an ASN.1 `NULL` value? + pub fn is_null(self) -> bool { + self == Self::NULL + } + + /// Attempt to decode an ASN.1 `BIT STRING`. + pub fn bit_string(self) -> Result<BitStringRef<'a>> { + self.try_into() + } + + /// Attempt to decode an ASN.1 `CONTEXT-SPECIFIC` field. + pub fn context_specific<T>(self) -> Result<ContextSpecific<T>> + where + T: Decode<'a>, + { + self.try_into() + } + + /// Attempt to decode an ASN.1 `GeneralizedTime`. + pub fn generalized_time(self) -> Result<GeneralizedTime> { + self.try_into() + } + + /// Attempt to decode an ASN.1 `IA5String`. + pub fn ia5_string(self) -> Result<Ia5StringRef<'a>> { + self.try_into() + } + + /// Attempt to decode an ASN.1 `OCTET STRING`. + pub fn octet_string(self) -> Result<OctetStringRef<'a>> { + self.try_into() + } + + /// Attempt to decode an ASN.1 `OBJECT IDENTIFIER`. + #[cfg(feature = "oid")] + #[cfg_attr(docsrs, doc(cfg(feature = "oid")))] + pub fn oid(self) -> Result<ObjectIdentifier> { + self.try_into() + } + + /// Attempt to decode an ASN.1 `OPTIONAL` value. + pub fn optional<T>(self) -> Result<Option<T>> + where + T: Choice<'a> + TryFrom<Self, Error = Error>, + { + if T::can_decode(self.tag) { + T::try_from(self).map(Some) + } else { + Ok(None) + } + } + + /// Attempt to decode an ASN.1 `PrintableString`. + pub fn printable_string(self) -> Result<PrintableStringRef<'a>> { + self.try_into() + } + + /// Attempt to decode an ASN.1 `TeletexString`. + pub fn teletex_string(self) -> Result<TeletexStringRef<'a>> { + self.try_into() + } + + /// Attempt to decode an ASN.1 `VideotexString`. + pub fn videotex_string(self) -> Result<VideotexStringRef<'a>> { + self.try_into() + } + + /// Attempt to decode this value an ASN.1 `SEQUENCE`, creating a new + /// nested reader and calling the provided argument with it. + pub fn sequence<F, T>(self, f: F) -> Result<T> + where + F: FnOnce(&mut SliceReader<'a>) -> Result<T>, + { + self.tag.assert_eq(Tag::Sequence)?; + let mut reader = SliceReader::new(self.value.as_slice())?; + let result = f(&mut reader)?; + reader.finish(result) + } + + /// Attempt to decode an ASN.1 `UTCTime`. + pub fn utc_time(self) -> Result<UtcTime> { + self.try_into() + } + + /// Attempt to decode an ASN.1 `UTF8String`. + pub fn utf8_string(self) -> Result<Utf8StringRef<'a>> { + self.try_into() + } +} + +impl<'a> Choice<'a> for AnyRef<'a> { + fn can_decode(_: Tag) -> bool { + true + } +} + +impl<'a> Decode<'a> for AnyRef<'a> { + fn decode<R: Reader<'a>>(reader: &mut R) -> Result<AnyRef<'a>> { + let header = Header::decode(reader)?; + + Ok(Self { + tag: header.tag, + value: ByteSlice::decode_value(reader, header)?, + }) + } +} + +impl EncodeValue for AnyRef<'_> { + fn value_len(&self) -> Result<Length> { + Ok(self.value.len()) + } + + fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> { + writer.write(self.value()) + } +} + +impl Tagged for AnyRef<'_> { + fn tag(&self) -> Tag { + self.tag + } +} + +impl ValueOrd for AnyRef<'_> { + fn value_cmp(&self, other: &Self) -> Result<Ordering> { + self.value.der_cmp(&other.value) + } +} + +impl<'a> From<AnyRef<'a>> for ByteSlice<'a> { + fn from(any: AnyRef<'a>) -> ByteSlice<'a> { + any.value + } +} + +impl<'a> TryFrom<&'a [u8]> for AnyRef<'a> { + type Error = Error; + + fn try_from(bytes: &'a [u8]) -> Result<AnyRef<'a>> { + AnyRef::from_der(bytes) + } +} + +/// 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")))] +#[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: Vec<u8>, +} + +#[cfg(feature = "alloc")] +impl Any { + /// Create a new [`Any`] from the provided [`Tag`] and DER bytes. + pub fn new(tag: Tag, bytes: impl Into<Vec<u8>>) -> Result<Self> { + let value = bytes.into(); + + // Ensure the tag and value are a valid `AnyRef`. + AnyRef::new(tag, &value)?; + Ok(Self { tag, value }) + } +} + +#[cfg(feature = "alloc")] +impl Choice<'_> for Any { + fn can_decode(_: Tag) -> bool { + true + } +} + +#[cfg(feature = "alloc")] +impl<'a> Decode<'a> for Any { + fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self> { + let header = Header::decode(reader)?; + let value = reader.read_vec(header.length)?; + Self::new(header.tag, value) + } +} + +#[cfg(feature = "alloc")] +impl EncodeValue for Any { + fn value_len(&self) -> Result<Length> { + self.value.len().try_into() + } + + fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> { + writer.write(&self.value) + } +} + +#[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).expect("invalid ANY") + } +} + +#[cfg(feature = "alloc")] +impl Tagged for Any { + fn tag(&self) -> Tag { + self.tag + } +} |