image4 0.8.2

A no_std-friendly library for parsing and generation of Image4 images written in pure Rust.
Documentation
use super::iter;
#[cfg(any(feature = "alloc", test))]
use super::{Cert, CertChain};

macro_rules! def_borrowed_wrapper {
    ($(#[$m:meta])* $name:ident, $owned:ident $(,$(#[$pos_m:meta])* position)?) => {
        #[derive(Clone, Eq, Debug)]
        $(#[$m])*
        pub struct $name<'a> {
            pub(super) inner: &'a [u8],
            $($(#[$pos_m])*)?
            pub(super) position: ::der::Length,
            pub(super) length: ::der::Length,
        }

        impl<'a> $name<'a> {
            /// Returns the contents of the body as a byte slice.
            pub fn as_bytes(&self) -> &'a [u8] {
                self.inner
            }

            /// Returns the length of the body.
            pub fn len(&self) -> ::der::Length {
                self.length
            }

            /// Returns `true` if the body is empty.
            pub fn is_empty(&self) -> bool {
                self.inner.is_empty()
            }
        }

        impl ::core::cmp::PartialEq for $name<'_> {
            fn eq(&self, other: &Self) -> bool {
                self.inner == other.inner
            }
        }

        impl ::der::FixedTag for $name<'_> {
            const TAG: ::der::Tag = ::der::Tag::Sequence;
        }

        impl<'a> ::der::DecodeValue<'a> for $name<'a> {
            fn decode_value<R: ::der::Reader<'a>>(
                reader: &mut R,
                header: ::der::Header
            ) -> ::der::Result<Self> {
                debug_assert_eq!(header.tag, der::Tag::Sequence);

                $($(#[$pos_m])*)?
                let position = reader.position();
                let length = header.length;
                ::core::result::Result::Ok(Self {
                    inner: reader.read_slice(length)?,
                    $($(#[$pos_m])*)?
                    position,
                    length,
                })
            }
        }

        impl ::der::EncodeValue for $name<'_> {
            fn value_len(&self) -> ::der::Result<::der::Length> {
                ::core::result::Result::Ok(self.length)
            }

            fn encode_value(&self, encoder: &mut impl ::der::Writer) -> ::der::Result<()> {
                encoder.write(self.inner)
            }
        }

        #[cfg(any(feature = "alloc", test))]
        impl<'a> ::core::convert::From<&'a $owned> for $name<'a> {
            fn from(value: &'a $owned) -> Self {
                Self {
                    inner: &value.inner,
                    position: value.position,
                    length: value.length,
                }
            }
        }

        #[cfg(any(feature = "alloc", test))]
        impl<'a> ::der::referenced::RefToOwned<'a> for $name<'a> {
            type Owned = $owned;

            fn ref_to_owned(&self) -> Self::Owned {
                self.into()
            }
        }
    };
}

#[cfg(feature = "x509-cert")]
macro_rules! impl_borrowed_decode_body {
    ($name:ident, $decoded:ty, $decodes_as:literal) => {
        impl $name<'_> {
            #[doc = concat!("Decodes the body as ", $decodes_as, ".")]
            #[cfg(feature = "x509-cert")]
            pub fn decode_body(&self) -> ::der::Result<$decoded> {
                let mut reader = ::der::SliceReader::new(self.inner)?;

                match <$decoded as ::der::DecodeValue>::decode_value(
                    &mut reader,
                    ::der::Header {
                        tag: <Self as ::der::FixedTag>::TAG,
                        length: self.length,
                    },
                ) {
                    Ok(v) => Ok(v),
                    Err(e) => Err($crate::util::shift_error_position(e, self.position)),
                }
            }
        }
    };
}

def_borrowed_wrapper!(
    /// A reference to a byte slice that is expected to be a valid DER-encoded **body** of an X.509
    /// certificate.
    CertRef,
    Cert,
    #[cfg(any(feature = "alloc", test))]
    position
);
#[cfg(feature = "x509-cert")]
impl_borrowed_decode_body!(
    CertRef,
    x509_cert::Certificate,
    "a [`Certificate`](x509_cert::Certificate)"
);

def_borrowed_wrapper!(
    /// A reference to a byte slice that is expected to be a valid sequence of DER-encoded X.509
    /// certificates.
    ///
    /// This is used to store a chain of certificates in an Image4 manifests without actually
    /// parsing them. There are two reasons for this:
    ///
    /// 1. The library currently uses the [`x509_cert`] crate to decode the certificates and that
    /// means the original signed TBS certificates are lost when a manifest is decoded. Verifying
    /// the manifest's certificate chain isn't possible in that case.
    /// 2. Parsing the certificates requires processing time and memory. There is no reason to do
    /// this, for example, when all you want to do is to encode them back into DER and write to
    /// another file.
    CertChainRef,
    CertChain
);
#[cfg(feature = "x509-cert")]
impl_borrowed_decode_body!(
    CertChainRef,
    alloc::vec::Vec<x509_cert::Certificate>,
    "a vector of [`Certificate`](x509_cert::Certificate)s"
);

impl CertChainRef<'_> {
    /// Returns iterator over individual certificates in the chain.
    pub fn iter(&self) -> iter::CertIter<'_> {
        iter::CertIter {
            inner: self.inner,
            position: self.position,
        }
    }
}