use super::CertChainRef;
use crate::{property::DictRef, util};
use der::{
asn1::{Ia5StringRef, OctetStringRef},
DecodeValue, Encode, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Writer,
};
#[cfg(any(feature = "alloc", test))]
use {
super::{AnyManifest, Manifest, UnsignedManifest},
crate::{property::Value, Tag},
alloc::collections::BTreeMap,
der::referenced::{OwnedToRef, RefToOwned},
};
#[cfg(feature = "signature")]
use {
super::{CertChain, SigningError},
signature::{SignatureEncoding, Signer},
};
fn decode_version<'a, R: Reader<'a>>(decoder: &mut R) -> der::Result<u32> {
let position = decoder.position();
let version = decoder.decode::<u32>()?;
if version != 0 {
return Err(ErrorKind::Value {
tag: der::Tag::Integer,
}
.at(position));
}
Ok(version)
}
#[derive(Clone, Debug)]
#[cfg_attr(test, derive(Eq, PartialEq))]
pub struct ManifestRef<'a> {
pub(super) tbs: UnsignedManifestRef<'a>,
pub(super) signature: OctetStringRef<'a>,
pub(super) cert_chain: CertChainRef<'a>,
}
impl<'a> ManifestRef<'a> {
pub fn decode_after_magic<R: Reader<'a>>(decoder: &mut R) -> der::Result<Self> {
let tbs = UnsignedManifestRef::decode_after_magic(decoder)?;
Self::decode_tail(decoder, tbs)
}
fn decode_tail<R: Reader<'a>>(
decoder: &mut R,
tbs: UnsignedManifestRef<'a>,
) -> der::Result<Self> {
Ok(ManifestRef {
tbs,
signature: decoder.decode()?,
cert_chain: decoder.decode()?,
})
}
pub fn version(&self) -> u32 {
self.tbs.version
}
pub fn body(&self) -> &DictRef<'a> {
&self.tbs.body
}
#[cfg(any(feature = "alloc", test))]
pub fn decode_body(&self) -> der::Result<BTreeMap<Tag, Value>> {
self.tbs.decode_body()
}
pub fn signature(&self) -> &[u8] {
self.signature.as_bytes()
}
pub fn cert_chain(&self) -> &CertChainRef<'a> {
&self.cert_chain
}
pub fn set_cert_chain(&mut self, cert_chain: CertChainRef<'a>) {
self.cert_chain = cert_chain;
}
#[cfg(feature = "signature")]
pub fn resign<K, S>(
&self,
key: &K,
cert_chain: impl Into<CertChain>,
) -> Result<Manifest, SigningError>
where
K: Signer<S>,
S: SignatureEncoding,
{
self.tbs.sign(key, cert_chain)
}
}
impl FixedTag for ManifestRef<'_> {
const TAG: der::Tag = der::Tag::Sequence;
}
impl<'a> DecodeValue<'a> for ManifestRef<'a> {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
debug_assert_eq!(header.tag, der::Tag::Sequence);
reader.read_nested(header.length, |reader| {
util::decode_and_check_magic(reader, b"IM4M")?;
ManifestRef::decode_after_magic(reader)
})
}
}
impl EncodeValue for ManifestRef<'_> {
fn value_len(&self) -> der::Result<Length> {
let tbs_len = self.tbs.value_len()?;
let signature_len = self.signature.encoded_len()?;
let cert_chain_len = self.cert_chain.encoded_len()?;
tbs_len + signature_len + cert_chain_len
}
fn encode_value(&self, encoder: &mut impl Writer) -> der::Result<()> {
self.tbs.encode_value(encoder)?;
self.signature.encode(encoder)?;
self.cert_chain.encode(encoder)
}
}
#[cfg(any(feature = "alloc", test))]
impl<'a> From<&'a Manifest> for ManifestRef<'a> {
fn from(value: &'a Manifest) -> Self {
Self {
tbs: value.tbs.owned_to_ref(),
signature: value.signature.owned_to_ref(),
cert_chain: value.cert_chain.owned_to_ref(),
}
}
}
#[cfg(any(feature = "alloc", test))]
impl<'a> RefToOwned<'a> for ManifestRef<'a> {
type Owned = Manifest;
fn ref_to_owned(&self) -> Self::Owned {
self.into()
}
}
impl<'a> AsRef<UnsignedManifestRef<'a>> for ManifestRef<'a> {
fn as_ref(&self) -> &UnsignedManifestRef<'a> {
&self.tbs
}
}
#[derive(Clone, Debug)]
#[cfg_attr(test, derive(Eq, PartialEq))]
pub struct UnsignedManifestRef<'a> {
pub(super) version: u32,
pub(super) body: DictRef<'a>,
}
impl<'a> UnsignedManifestRef<'a> {
pub fn new(body: DictRef<'a>) -> Self {
Self { version: 0, body }
}
pub fn decode_after_magic<R: Reader<'a>>(decoder: &mut R) -> der::Result<Self> {
Ok(UnsignedManifestRef {
version: decode_version(decoder)?,
body: decoder.decode()?,
})
}
pub fn version(&self) -> u32 {
self.version
}
pub fn body(&self) -> &DictRef<'a> {
&self.body
}
#[cfg(any(feature = "alloc", test))]
pub fn decode_body(&self) -> der::Result<BTreeMap<Tag, Value>> {
self.body.decode_owned()
}
#[cfg(feature = "signature")]
pub fn sign<K: Signer<S>, S: SignatureEncoding>(
&self,
key: &K,
cert_chain: impl Into<CertChain>,
) -> Result<Manifest, SigningError> {
self.ref_to_owned().sign(key, cert_chain)
}
}
impl FixedTag for UnsignedManifestRef<'_> {
const TAG: der::Tag = der::Tag::Sequence;
}
impl<'a> DecodeValue<'a> for UnsignedManifestRef<'a> {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
debug_assert_eq!(header.tag, der::Tag::Sequence);
reader.read_nested(header.length, |reader| {
util::decode_and_check_magic(reader, b"IM4M")?;
UnsignedManifestRef::decode_after_magic(reader)
})
}
}
impl EncodeValue for UnsignedManifestRef<'_> {
fn value_len(&self) -> der::Result<Length> {
let magic = Ia5StringRef::new(b"IM4M")?;
let magic_len = magic.encoded_len()?;
let version_len = self.version.encoded_len()?;
let body_len = self.body.encoded_len()?;
magic_len + version_len + body_len
}
fn encode_value(&self, encoder: &mut impl Writer) -> der::Result<()> {
let magic = Ia5StringRef::new(b"IM4M")?;
magic.encode(encoder)?;
self.version.encode(encoder)?;
self.body.encode(encoder)
}
}
impl<'a> From<ManifestRef<'a>> for UnsignedManifestRef<'a> {
fn from(value: ManifestRef<'a>) -> Self {
value.tbs
}
}
#[cfg(any(feature = "alloc", test))]
impl<'a> From<&'a Manifest> for UnsignedManifestRef<'a> {
fn from(value: &'a Manifest) -> Self {
(&value.tbs).into()
}
}
#[cfg(any(feature = "alloc", test))]
impl<'a> From<&'a UnsignedManifest> for UnsignedManifestRef<'a> {
fn from(value: &'a UnsignedManifest) -> Self {
Self {
version: value.version,
body: value.body.owned_to_ref(),
}
}
}
#[cfg(any(feature = "alloc", test))]
impl<'a> RefToOwned<'a> for UnsignedManifestRef<'a> {
type Owned = UnsignedManifest;
fn ref_to_owned(&self) -> Self::Owned {
self.into()
}
}
#[derive(Clone, Debug)]
#[cfg_attr(test, derive(Eq, PartialEq))]
pub enum AnyManifestRef<'a> {
Signed(ManifestRef<'a>),
Unsigned(UnsignedManifestRef<'a>),
}
impl<'a> AnyManifestRef<'a> {
pub fn decode_after_magic<R: Reader<'a>>(decoder: &mut R) -> der::Result<Self> {
let tbs = UnsignedManifestRef::decode_after_magic(decoder)?;
if decoder.is_finished() {
Ok(Self::Unsigned(tbs))
} else {
ManifestRef::decode_tail(decoder, tbs).map(Self::Signed)
}
}
pub fn version(&self) -> u32 {
match self {
AnyManifestRef::Signed(m) => m.version(),
AnyManifestRef::Unsigned(m) => m.version(),
}
}
#[cfg(any(feature = "alloc", test))]
pub fn decode_body(&self) -> der::Result<BTreeMap<Tag, Value>> {
match self {
AnyManifestRef::Signed(m) => m.decode_body(),
AnyManifestRef::Unsigned(m) => m.decode_body(),
}
}
}
impl FixedTag for AnyManifestRef<'_> {
const TAG: der::Tag = der::Tag::Sequence;
}
impl<'a> DecodeValue<'a> for AnyManifestRef<'a> {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
debug_assert_eq!(header.tag, der::Tag::Sequence);
reader.read_nested(header.length, |reader| {
util::decode_and_check_magic(reader, b"IM4M")?;
Self::decode_after_magic(reader)
})
}
}
impl EncodeValue for AnyManifestRef<'_> {
fn value_len(&self) -> der::Result<Length> {
match self {
AnyManifestRef::Signed(m) => m.value_len(),
AnyManifestRef::Unsigned(m) => m.value_len(),
}
}
fn encode_value(&self, encoder: &mut impl Writer) -> der::Result<()> {
match self {
AnyManifestRef::Signed(m) => m.encode_value(encoder),
AnyManifestRef::Unsigned(m) => m.encode_value(encoder),
}
}
}
impl<'a> From<ManifestRef<'a>> for AnyManifestRef<'a> {
fn from(value: ManifestRef<'a>) -> Self {
Self::Signed(value)
}
}
impl<'a> From<UnsignedManifestRef<'a>> for AnyManifestRef<'a> {
fn from(value: UnsignedManifestRef<'a>) -> Self {
Self::Unsigned(value)
}
}
impl<'a> AsRef<UnsignedManifestRef<'a>> for AnyManifestRef<'a> {
fn as_ref(&self) -> &UnsignedManifestRef<'a> {
match self {
AnyManifestRef::Signed(m) => &m.tbs,
AnyManifestRef::Unsigned(m) => m,
}
}
}
#[cfg(any(feature = "alloc", test))]
impl<'a> From<&'a AnyManifest> for AnyManifestRef<'a> {
fn from(value: &'a AnyManifest) -> Self {
match value {
AnyManifest::Signed(m) => Self::Signed(m.into()),
AnyManifest::Unsigned(m) => Self::Unsigned(m.into()),
}
}
}
#[cfg(any(feature = "alloc", test))]
impl<'a> RefToOwned<'a> for AnyManifestRef<'a> {
type Owned = AnyManifest;
fn ref_to_owned(&self) -> Self::Owned {
self.into()
}
}