diff options
Diffstat (limited to 'rust/vendor/asn1-rs/src/traits.rs')
-rw-r--r-- | rust/vendor/asn1-rs/src/traits.rs | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/rust/vendor/asn1-rs/src/traits.rs b/rust/vendor/asn1-rs/src/traits.rs new file mode 100644 index 0000000..eea4cb9 --- /dev/null +++ b/rust/vendor/asn1-rs/src/traits.rs @@ -0,0 +1,348 @@ +use crate::error::*; +use crate::{Any, Class, Explicit, Implicit, Tag, TaggedParser}; +use core::convert::{TryFrom, TryInto}; +#[cfg(feature = "std")] +use std::io::Write; + +/// Phantom type representing a BER parser +#[doc(hidden)] +#[derive(Debug)] +pub enum BerParser {} + +/// Phantom type representing a DER parser +#[doc(hidden)] +#[derive(Debug)] +pub enum DerParser {} + +#[doc(hidden)] +pub trait ASN1Parser {} + +impl ASN1Parser for BerParser {} +impl ASN1Parser for DerParser {} + +pub trait Tagged { + const TAG: Tag; +} + +impl<T> Tagged for &'_ T +where + T: Tagged, +{ + const TAG: Tag = T::TAG; +} + +pub trait DynTagged { + fn tag(&self) -> Tag; +} + +impl<T> DynTagged for T +where + T: Tagged, +{ + fn tag(&self) -> Tag { + T::TAG + } +} + +/// Base trait for BER object parsers +/// +/// Library authors should usually not directly implement this trait, but should prefer implementing the +/// [`TryFrom<Any>`] trait, +/// which offers greater flexibility and provides an equivalent `FromBer` implementation for free. +/// +/// # Examples +/// +/// ``` +/// use asn1_rs::{Any, Result, Tag}; +/// use std::convert::TryFrom; +/// +/// // The type to be decoded +/// #[derive(Clone, Copy, Debug, PartialEq, Eq)] +/// pub struct MyType(pub u32); +/// +/// impl<'a> TryFrom<Any<'a>> for MyType { +/// type Error = asn1_rs::Error; +/// +/// fn try_from(any: Any<'a>) -> Result<MyType> { +/// any.tag().assert_eq(Tag::Integer)?; +/// // for this fictive example, the type contains the number of characters +/// let n = any.data.len() as u32; +/// Ok(MyType(n)) +/// } +/// } +/// +/// // The above code provides a `FromBer` implementation for free. +/// +/// // Example of parsing code: +/// use asn1_rs::FromBer; +/// +/// let input = &[2, 1, 2]; +/// // Objects can be parsed using `from_ber`, which returns the remaining bytes +/// // and the parsed object: +/// let (rem, my_type) = MyType::from_ber(input).expect("parsing failed"); +/// ``` +pub trait FromBer<'a, E = Error>: Sized { + /// Attempt to parse input bytes into a BER object + fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, E>; +} + +impl<'a, T, E> FromBer<'a, E> for T +where + T: TryFrom<Any<'a>, Error = E>, + E: From<Error>, +{ + fn from_ber(bytes: &'a [u8]) -> ParseResult<T, E> { + let (i, any) = Any::from_ber(bytes).map_err(nom::Err::convert)?; + let result = any.try_into().map_err(nom::Err::Error)?; + Ok((i, result)) + } +} + +/// Base trait for DER object parsers +/// +/// Library authors should usually not directly implement this trait, but should prefer implementing the +/// [`TryFrom<Any>`] + [`CheckDerConstraints`] traits, +/// which offers greater flexibility and provides an equivalent `FromDer` implementation for free +/// (in fact, it provides both [`FromBer`] and `FromDer`). +/// +/// Note: if you already implemented [`TryFrom<Any>`] and [`CheckDerConstraints`], +/// you can get a free [`FromDer`] implementation by implementing the +/// [`DerAutoDerive`] trait. This is not automatic, so it is also possible to manually +/// implement [`FromDer`] if preferred. +/// +/// # Examples +/// +/// ``` +/// use asn1_rs::{Any, CheckDerConstraints, DerAutoDerive, Result, Tag}; +/// use std::convert::TryFrom; +/// +/// // The type to be decoded +/// #[derive(Clone, Copy, Debug, PartialEq, Eq)] +/// pub struct MyType(pub u32); +/// +/// impl<'a> TryFrom<Any<'a>> for MyType { +/// type Error = asn1_rs::Error; +/// +/// fn try_from(any: Any<'a>) -> Result<MyType> { +/// any.tag().assert_eq(Tag::Integer)?; +/// // for this fictive example, the type contains the number of characters +/// let n = any.data.len() as u32; +/// Ok(MyType(n)) +/// } +/// } +/// +/// impl CheckDerConstraints for MyType { +/// fn check_constraints(any: &Any) -> Result<()> { +/// any.header.assert_primitive()?; +/// Ok(()) +/// } +/// } +/// +/// impl DerAutoDerive for MyType {} +/// +/// // The above code provides a `FromDer` implementation for free. +/// +/// // Example of parsing code: +/// use asn1_rs::FromDer; +/// +/// let input = &[2, 1, 2]; +/// // Objects can be parsed using `from_der`, which returns the remaining bytes +/// // and the parsed object: +/// let (rem, my_type) = MyType::from_der(input).expect("parsing failed"); +/// ``` +pub trait FromDer<'a, E = Error>: Sized { + /// Attempt to parse input bytes into a DER object (enforcing constraints) + fn from_der(bytes: &'a [u8]) -> ParseResult<Self, E>; +} + +/// Trait to automatically derive `FromDer` +/// +/// This trait is only a marker to control if a DER parser should be automatically derived. It is +/// empty. +/// +/// This trait is used in combination with others: +/// after implementing [`TryFrom<Any>`] and [`CheckDerConstraints`] for a type, +/// a free [`FromDer`] implementation is provided by implementing the +/// [`DerAutoDerive`] trait. This is the most common case. +/// +/// However, this is not automatic so it is also possible to manually +/// implement [`FromDer`] if preferred. +/// Manual implementation is generally only needed for generic containers (for ex. `Vec<T>`), +/// because the default implementation adds a constraint on `T` to implement also `TryFrom<Any>` +/// and `CheckDerConstraints`. This is problematic when `T` only provides `FromDer`, and can be +/// solved by providing a manual implementation of [`FromDer`]. +pub trait DerAutoDerive {} + +impl<'a, T, E> FromDer<'a, E> for T +where + T: TryFrom<Any<'a>, Error = E>, + T: CheckDerConstraints, + T: DerAutoDerive, + E: From<Error>, +{ + fn from_der(bytes: &'a [u8]) -> ParseResult<T, E> { + // Note: Any::from_der checks than length is definite + let (i, any) = Any::from_der(bytes).map_err(nom::Err::convert)?; + <T as CheckDerConstraints>::check_constraints(&any) + .map_err(|e| nom::Err::Error(e.into()))?; + let result = any.try_into().map_err(nom::Err::Error)?; + Ok((i, result)) + } +} + +/// Verification of DER constraints +pub trait CheckDerConstraints { + fn check_constraints(any: &Any) -> Result<()>; +} + +/// Common trait for all objects that can be encoded using the DER representation +/// +/// # Examples +/// +/// Objects from this crate can be encoded as DER: +/// +/// ``` +/// use asn1_rs::{Integer, ToDer}; +/// +/// let int = Integer::from(4u32); +/// let mut writer = Vec::new(); +/// let sz = int.write_der(&mut writer).expect("serialization failed"); +/// +/// assert_eq!(&writer, &[0x02, 0x01, 0x04]); +/// # assert_eq!(sz, 3); +/// ``` +/// +/// Many of the primitive types can also directly be encoded as DER: +/// +/// ``` +/// use asn1_rs::ToDer; +/// +/// let mut writer = Vec::new(); +/// let sz = 4.write_der(&mut writer).expect("serialization failed"); +/// +/// assert_eq!(&writer, &[0x02, 0x01, 0x04]); +/// # assert_eq!(sz, 3); +/// ``` +#[cfg(feature = "std")] +pub trait ToDer +where + Self: DynTagged, +{ + /// Get the length of the object (including the header), when encoded + /// + // Since we are using DER, length cannot be Indefinite, so we can use `usize`. + // XXX can this function fail? + fn to_der_len(&self) -> Result<usize>; + + /// Write the DER encoded representation to a newly allocated `Vec<u8>`. + fn to_der_vec(&self) -> SerializeResult<Vec<u8>> { + let mut v = Vec::new(); + let _ = self.write_der(&mut v)?; + Ok(v) + } + + /// Similar to using `to_vec`, but uses provided values without changes. + /// This can generate an invalid encoding for a DER object. + fn to_der_vec_raw(&self) -> SerializeResult<Vec<u8>> { + let mut v = Vec::new(); + let _ = self.write_der_raw(&mut v)?; + Ok(v) + } + + /// Attempt to write the DER encoded representation (header and content) into this writer. + /// + /// # Examples + /// + /// ``` + /// use asn1_rs::{Integer, ToDer}; + /// + /// let int = Integer::from(4u32); + /// let mut writer = Vec::new(); + /// let sz = int.write_der(&mut writer).expect("serialization failed"); + /// + /// assert_eq!(&writer, &[0x02, 0x01, 0x04]); + /// # assert_eq!(sz, 3); + /// ``` + fn write_der(&self, writer: &mut dyn Write) -> SerializeResult<usize> { + let sz = self.write_der_header(writer)?; + let sz = sz + self.write_der_content(writer)?; + Ok(sz) + } + + /// Attempt to write the DER header to this writer. + fn write_der_header(&self, writer: &mut dyn Write) -> SerializeResult<usize>; + + /// Attempt to write the DER content (all except header) to this writer. + fn write_der_content(&self, writer: &mut dyn Write) -> SerializeResult<usize>; + + /// Similar to using `to_der`, but uses provided values without changes. + /// This can generate an invalid encoding for a DER object. + fn write_der_raw(&self, writer: &mut dyn Write) -> SerializeResult<usize> { + self.write_der(writer) + } +} + +#[cfg(feature = "std")] +impl<'a, T> ToDer for &'a T +where + T: ToDer, + &'a T: DynTagged, +{ + fn to_der_len(&self) -> Result<usize> { + (*self).to_der_len() + } + + fn write_der_header(&self, writer: &mut dyn Write) -> SerializeResult<usize> { + (*self).write_der_header(writer) + } + + fn write_der_content(&self, writer: &mut dyn Write) -> SerializeResult<usize> { + (*self).write_der_content(writer) + } +} + +/// Helper trait for creating tagged EXPLICIT values +/// +/// # Examples +/// +/// ``` +/// use asn1_rs::{AsTaggedExplicit, Class, Error, TaggedParser}; +/// +/// // create a `[1] EXPLICIT INTEGER` value +/// let tagged: TaggedParser<_, _, Error> = 4u32.explicit(Class::ContextSpecific, 1); +/// ``` +pub trait AsTaggedExplicit<'a, E = Error>: Sized { + fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E> { + TaggedParser::new_explicit(class, tag, self) + } +} + +impl<'a, T, E> AsTaggedExplicit<'a, E> for T where T: Sized + 'a {} + +/// Helper trait for creating tagged IMPLICIT values +/// +/// # Examples +/// +/// ``` +/// use asn1_rs::{AsTaggedImplicit, Class, Error, TaggedParser}; +/// +/// // create a `[1] IMPLICIT INTEGER` value, not constructed +/// let tagged: TaggedParser<_, _, Error> = 4u32.implicit(Class::ContextSpecific, false, 1); +/// ``` +pub trait AsTaggedImplicit<'a, E = Error>: Sized { + fn implicit( + self, + class: Class, + constructed: bool, + tag: u32, + ) -> TaggedParser<'a, Implicit, Self, E> { + TaggedParser::new_implicit(class, constructed, tag, self) + } +} + +impl<'a, T, E> AsTaggedImplicit<'a, E> for T where T: Sized + 'a {} + +pub trait ToStatic { + type Owned: 'static; + fn to_static(&self) -> Self::Owned; +} |