316 lines
8.8 KiB
Rust
316 lines
8.8 KiB
Rust
//! ASN.1 `ANY` type.
|
|
|
|
#![cfg_attr(feature = "arbitrary", allow(clippy::integer_arithmetic))]
|
|
|
|
use crate::{
|
|
BytesRef, Choice, Decode, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind, Header, Length,
|
|
Reader, Result, SliceReader, Tag, Tagged, ValueOrd, Writer,
|
|
};
|
|
use core::cmp::Ordering;
|
|
|
|
#[cfg(feature = "alloc")]
|
|
use crate::SliceWriter;
|
|
|
|
/// ASN.1 `ANY`: represents any explicitly tagged ASN.1 value.
|
|
///
|
|
/// This is a zero-copy reference type which borrows from the input data.
|
|
///
|
|
/// Technically `ANY` hasn't been a recommended part of ASN.1 since the X.209
|
|
/// revision from 1988. It was deprecated and replaced by Information Object
|
|
/// Classes in X.680 in 1994, and X.690 no longer refers to it whatsoever.
|
|
///
|
|
/// Nevertheless, this crate defines an `ANY` type as it remains a familiar
|
|
/// and useful concept which is still extensively used in things like
|
|
/// PKI-related RFCs.
|
|
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
|
pub struct AnyRef<'a> {
|
|
/// Tag representing the type of the encoded value.
|
|
tag: Tag,
|
|
|
|
/// Inner value encoded as bytes.
|
|
value: BytesRef<'a>,
|
|
}
|
|
|
|
impl<'a> AnyRef<'a> {
|
|
/// [`AnyRef`] representation of the ASN.1 `NULL` type.
|
|
pub const NULL: Self = Self {
|
|
tag: Tag::Null,
|
|
value: BytesRef::EMPTY,
|
|
};
|
|
|
|
/// Create a new [`AnyRef`] from the provided [`Tag`] and DER bytes.
|
|
pub fn new(tag: Tag, bytes: &'a [u8]) -> Result<Self> {
|
|
let value = BytesRef::new(bytes).map_err(|_| ErrorKind::Length { tag })?;
|
|
Ok(Self { tag, value })
|
|
}
|
|
|
|
/// Infallible creation of an [`AnyRef`] from a [`BytesRef`].
|
|
pub(crate) fn from_tag_and_value(tag: Tag, value: BytesRef<'a>) -> Self {
|
|
Self { tag, value }
|
|
}
|
|
|
|
/// Get the raw value for this [`AnyRef`] type as a byte slice.
|
|
pub fn value(self) -> &'a [u8] {
|
|
self.value.as_slice()
|
|
}
|
|
|
|
/// Attempt to decode this [`AnyRef`] type into the inner value.
|
|
pub fn decode_as<T>(self) -> Result<T>
|
|
where
|
|
T: Choice<'a> + DecodeValue<'a>,
|
|
{
|
|
if !T::can_decode(self.tag) {
|
|
return Err(self.tag.unexpected_error(None));
|
|
}
|
|
|
|
let header = Header {
|
|
tag: self.tag,
|
|
length: self.value.len(),
|
|
};
|
|
|
|
let mut decoder = SliceReader::new(self.value())?;
|
|
let result = T::decode_value(&mut decoder, header)?;
|
|
decoder.finish(result)
|
|
}
|
|
|
|
/// Is this value an ASN.1 `NULL` value?
|
|
pub fn is_null(self) -> bool {
|
|
self == Self::NULL
|
|
}
|
|
|
|
/// Attempt to decode this value an ASN.1 `SEQUENCE`, creating a new
|
|
/// nested reader and calling the provided argument with it.
|
|
pub fn sequence<F, T>(self, f: F) -> Result<T>
|
|
where
|
|
F: FnOnce(&mut SliceReader<'a>) -> Result<T>,
|
|
{
|
|
self.tag.assert_eq(Tag::Sequence)?;
|
|
let mut reader = SliceReader::new(self.value.as_slice())?;
|
|
let result = f(&mut reader)?;
|
|
reader.finish(result)
|
|
}
|
|
}
|
|
|
|
impl<'a> Choice<'a> for AnyRef<'a> {
|
|
fn can_decode(_: Tag) -> bool {
|
|
true
|
|
}
|
|
}
|
|
|
|
impl<'a> Decode<'a> for AnyRef<'a> {
|
|
fn decode<R: Reader<'a>>(reader: &mut R) -> Result<AnyRef<'a>> {
|
|
let header = Header::decode(reader)?;
|
|
Self::decode_value(reader, header)
|
|
}
|
|
}
|
|
|
|
impl<'a> DecodeValue<'a> for AnyRef<'a> {
|
|
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
|
|
Ok(Self {
|
|
tag: header.tag,
|
|
value: BytesRef::decode_value(reader, header)?,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl EncodeValue for AnyRef<'_> {
|
|
fn value_len(&self) -> Result<Length> {
|
|
Ok(self.value.len())
|
|
}
|
|
|
|
fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
|
|
writer.write(self.value())
|
|
}
|
|
}
|
|
|
|
impl Tagged for AnyRef<'_> {
|
|
fn tag(&self) -> Tag {
|
|
self.tag
|
|
}
|
|
}
|
|
|
|
impl ValueOrd for AnyRef<'_> {
|
|
fn value_cmp(&self, other: &Self) -> Result<Ordering> {
|
|
self.value.der_cmp(&other.value)
|
|
}
|
|
}
|
|
|
|
impl<'a> From<AnyRef<'a>> for BytesRef<'a> {
|
|
fn from(any: AnyRef<'a>) -> BytesRef<'a> {
|
|
any.value
|
|
}
|
|
}
|
|
|
|
impl<'a> TryFrom<&'a [u8]> for AnyRef<'a> {
|
|
type Error = Error;
|
|
|
|
fn try_from(bytes: &'a [u8]) -> Result<AnyRef<'a>> {
|
|
AnyRef::from_der(bytes)
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "alloc")]
|
|
pub use self::allocating::Any;
|
|
|
|
#[cfg(feature = "alloc")]
|
|
mod allocating {
|
|
use super::*;
|
|
use crate::{referenced::*, BytesOwned};
|
|
use alloc::boxed::Box;
|
|
|
|
/// ASN.1 `ANY`: represents any explicitly tagged ASN.1 value.
|
|
///
|
|
/// This type provides the same functionality as [`AnyRef`] but owns the
|
|
/// backing data.
|
|
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
|
pub struct Any {
|
|
/// Tag representing the type of the encoded value.
|
|
tag: Tag,
|
|
|
|
/// Inner value encoded as bytes.
|
|
value: BytesOwned,
|
|
}
|
|
|
|
impl Any {
|
|
/// Create a new [`Any`] from the provided [`Tag`] and DER bytes.
|
|
pub fn new(tag: Tag, bytes: impl Into<Box<[u8]>>) -> Result<Self> {
|
|
let value = BytesOwned::new(bytes)?;
|
|
|
|
// Ensure the tag and value are a valid `AnyRef`.
|
|
AnyRef::new(tag, value.as_slice())?;
|
|
Ok(Self { tag, value })
|
|
}
|
|
|
|
/// Allow access to value
|
|
pub fn value(&self) -> &[u8] {
|
|
self.value.as_slice()
|
|
}
|
|
|
|
/// Attempt to decode this [`Any`] type into the inner value.
|
|
pub fn decode_as<'a, T>(&'a self) -> Result<T>
|
|
where
|
|
T: Choice<'a> + DecodeValue<'a>,
|
|
{
|
|
AnyRef::from(self).decode_as()
|
|
}
|
|
|
|
/// Encode the provided type as an [`Any`] value.
|
|
pub fn encode_from<T>(msg: &T) -> Result<Self>
|
|
where
|
|
T: Tagged + EncodeValue,
|
|
{
|
|
let encoded_len = usize::try_from(msg.value_len()?)?;
|
|
let mut buf = vec![0u8; encoded_len];
|
|
let mut writer = SliceWriter::new(&mut buf);
|
|
msg.encode_value(&mut writer)?;
|
|
writer.finish()?;
|
|
Any::new(msg.tag(), buf)
|
|
}
|
|
|
|
/// Attempt to decode this value an ASN.1 `SEQUENCE`, creating a new
|
|
/// nested reader and calling the provided argument with it.
|
|
pub fn sequence<'a, F, T>(&'a self, f: F) -> Result<T>
|
|
where
|
|
F: FnOnce(&mut SliceReader<'a>) -> Result<T>,
|
|
{
|
|
AnyRef::from(self).sequence(f)
|
|
}
|
|
|
|
/// [`Any`] representation of the ASN.1 `NULL` type.
|
|
pub fn null() -> Self {
|
|
Self {
|
|
tag: Tag::Null,
|
|
value: BytesOwned::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Choice<'_> for Any {
|
|
fn can_decode(_: Tag) -> bool {
|
|
true
|
|
}
|
|
}
|
|
|
|
impl<'a> Decode<'a> for Any {
|
|
fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self> {
|
|
let header = Header::decode(reader)?;
|
|
Self::decode_value(reader, header)
|
|
}
|
|
}
|
|
|
|
impl<'a> DecodeValue<'a> for Any {
|
|
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
|
|
let value = reader.read_vec(header.length)?;
|
|
Self::new(header.tag, value)
|
|
}
|
|
}
|
|
|
|
impl EncodeValue for Any {
|
|
fn value_len(&self) -> Result<Length> {
|
|
Ok(self.value.len())
|
|
}
|
|
|
|
fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
|
|
writer.write(self.value.as_slice())
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a Any> for AnyRef<'a> {
|
|
fn from(any: &'a Any) -> AnyRef<'a> {
|
|
// Ensured to parse successfully in constructor
|
|
AnyRef::new(any.tag, any.value.as_slice()).expect("invalid ANY")
|
|
}
|
|
}
|
|
|
|
impl Tagged for Any {
|
|
fn tag(&self) -> Tag {
|
|
self.tag
|
|
}
|
|
}
|
|
|
|
impl ValueOrd for Any {
|
|
fn value_cmp(&self, other: &Self) -> Result<Ordering> {
|
|
self.value.der_cmp(&other.value)
|
|
}
|
|
}
|
|
|
|
impl<'a, T> From<T> for Any
|
|
where
|
|
T: Into<AnyRef<'a>>,
|
|
{
|
|
fn from(input: T) -> Any {
|
|
let anyref: AnyRef<'a> = input.into();
|
|
Self {
|
|
tag: anyref.tag(),
|
|
value: BytesOwned::from(anyref.value),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> RefToOwned<'a> for AnyRef<'a> {
|
|
type Owned = Any;
|
|
fn ref_to_owned(&self) -> Self::Owned {
|
|
Any {
|
|
tag: self.tag(),
|
|
value: BytesOwned::from(self.value),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl OwnedToRef for Any {
|
|
type Borrowed<'a> = AnyRef<'a>;
|
|
fn owned_to_ref(&self) -> Self::Borrowed<'_> {
|
|
self.into()
|
|
}
|
|
}
|
|
|
|
impl Any {
|
|
/// Is this value an ASN.1 `NULL` value?
|
|
pub fn is_null(&self) -> bool {
|
|
self.owned_to_ref() == AnyRef::NULL
|
|
}
|
|
}
|
|
}
|