use super::{EncodedValue, algorithm, end, enter, number, tag, version};
use crate::{
Error, ErrorCode, Octets, Result,
signer::{SignerIdentifier, required},
};
use structured_asn1::memory::{OwnedVec, Work};
use structured_asn1::{Element, Oid, Reader, Tag, universal};
use structured_pkix::AlgorithmIdentifier;
const FIELD: &str = "envelopedData.recipientInfos";
#[derive(Debug)]
pub struct KeyIdentifier<'a> {
identifier: Octets<'a>,
date: Option<Element<'a>>,
other: Option<(Oid<'a>, Option<Element<'a>>)>,
encoding: structured_asn1::Encoding,
}
#[derive(Debug)]
pub enum Originator<'a> {
Identifier(SignerIdentifier<'a>),
Key {
algorithm: AlgorithmIdentifier<'a>,
bits: EncodedValue<'a>,
},
}
#[derive(Debug)]
pub struct RecipientKey<'a> {
pub identifier: AgreementIdentifier<'a>,
pub encrypted: Octets<'a>,
}
#[derive(Debug)]
pub enum AgreementIdentifier<'a> {
IssuerAndSerial(SignerIdentifier<'a>),
KeyIdentifier(KeyIdentifier<'a>),
}
#[derive(Debug)]
pub enum Recipient<'a> {
Transport {
version: u64,
identifier: SignerIdentifier<'a>,
algorithm: AlgorithmIdentifier<'a>,
encrypted: Octets<'a>,
},
Agreement {
originator: Originator<'a>,
ukm: Option<Octets<'a>>,
algorithm: AlgorithmIdentifier<'a>,
keys: OwnedVec<RecipientKey<'a>>,
},
Kek {
identifier: KeyIdentifier<'a>,
algorithm: AlgorithmIdentifier<'a>,
encrypted: Octets<'a>,
},
Password {
derivation: Option<AlgorithmIdentifier<'a>>,
algorithm: AlgorithmIdentifier<'a>,
encrypted: Octets<'a>,
},
Other {
kind: Oid<'a>,
value: EncodedValue<'a>,
},
}
impl<'a> Recipient<'a> {
pub(super) fn is_transport_zero(&self) -> bool {
matches!(self, Self::Transport { version: 0, .. })
}
pub(super) fn read(parent: &Reader<'a>, element: &Element<'a>) -> Result<Self> {
let mut inside = enter(parent, element, FIELD)?;
let result = match element.tag() {
t if t == Tag::constructed(universal::SEQUENCE) => {
let (version, at) = number(&mut inside, FIELD)?;
let value = required(&mut inside, FIELD)?;
let identifier = SignerIdentifier::read_as(&inside, &value, FIELD)?;
let expected = if matches!(identifier, SignerIdentifier::IssuerAndSerial { .. }) {
0
} else {
2
};
if version != expected {
return Err(Error::schema(ErrorCode::UnsupportedVersion, FIELD, at));
}
let value = required(&mut inside, FIELD)?;
let algorithm = algorithm(&inside, &value, FIELD)?;
let encrypted = octets(&mut inside)?;
Self::Transport {
version,
identifier,
algorithm,
encrypted,
}
}
t if t == Tag::context(true, 1) => Self::agreement(parent, &mut inside)?,
t if t == Tag::context(true, 2) => {
version(&mut inside, 4, FIELD)?;
let value = inside
.expect(Tag::constructed(universal::SEQUENCE))
.map_err(|e| Error::encoding(e, FIELD))?;
let identifier = KeyIdentifier::read(&inside, &value)?;
let value = required(&mut inside, FIELD)?;
let algorithm = algorithm(&inside, &value, FIELD)?;
let encrypted = octets(&mut inside)?;
Self::Kek {
identifier,
algorithm,
encrypted,
}
}
t if t == Tag::context(true, 3) => {
version(&mut inside, 0, FIELD)?;
let mut value = required(&mut inside, FIELD)?;
let derivation = if value.tag() == Tag::context(true, 0) {
let derivation =
structured_pkix::algorithm::read_implicit(&inside, &value, 0, FIELD)
.map_err(Error::pkix)?;
value = required(&mut inside, FIELD)?;
Some(derivation)
} else {
None
};
let algorithm = algorithm(&inside, &value, FIELD)?;
let encrypted = octets(&mut inside)?;
Self::Password {
derivation,
algorithm,
encrypted,
}
}
t if t == Tag::context(true, 4) => {
let kind = inside.read_oid().map_err(|e| Error::encoding(e, FIELD))?;
let value = required(&mut inside, FIELD)?;
structured_pkix::der::conforms(&inside, &value, FIELD).map_err(Error::pkix)?;
Self::Other {
kind,
value: EncodedValue::new(&inside, value),
}
}
_ => {
return Err(Error::schema(
ErrorCode::UnknownField,
FIELD,
element.span().start,
));
}
};
end(&inside, FIELD)?;
Ok(result)
}
}
impl<'a> Recipient<'a> {
fn agreement(parent: &Reader<'a>, inside: &mut Reader<'a>) -> Result<Self> {
version(inside, 3, FIELD)?;
let wrapper = inside
.expect(Tag::context(true, 0))
.map_err(|e| Error::encoding(e, FIELD))?;
let mut explicit = enter(inside, &wrapper, FIELD)?;
let value = required(&mut explicit, FIELD)?;
let originator = if value.tag() == Tag::context(true, 1) {
let mut key = enter(&explicit, &value, FIELD)?;
let value = required(&mut key, FIELD)?;
let algorithm = algorithm(&key, &value, FIELD)?;
let bits = required(&mut key, FIELD)?;
if bits.tag() != Tag::primitive(universal::BIT_STRING)
&& bits.tag() != Tag::constructed(universal::BIT_STRING)
{
return Err(Error::schema(
ErrorCode::UnexpectedTag,
FIELD,
bits.span().start,
));
}
structured_pkix::der::conforms(&key, &bits, FIELD).map_err(Error::pkix)?;
end(&key, FIELD)?;
Originator::Key {
algorithm,
bits: EncodedValue::new(&key, bits),
}
} else {
Originator::Identifier(SignerIdentifier::read_as(&explicit, &value, FIELD)?)
};
end(&explicit, FIELD)?;
let mut value = required(inside, FIELD)?;
let ukm = if value.tag() == Tag::context(true, 1) {
let mut explicit = enter(inside, &value, FIELD)?;
let ukm = octets(&mut explicit)?;
end(&explicit, FIELD)?;
value = required(inside, FIELD)?;
Some(ukm)
} else {
None
};
let algorithm = algorithm(inside, &value, FIELD)?;
let set = inside
.expect(Tag::constructed(universal::SEQUENCE))
.map_err(|e| Error::encoding(e, FIELD))?;
let mut members = enter(inside, &set, FIELD)?;
let work = parent.execution();
let mut keys = work.vector();
while let Some(value) = members
.next_element()
.map_err(|e| Error::encoding(e, FIELD))?
{
keys.try_reserve(1)
.map_err(|e| Error::resource(e, FIELD, value.span().start))?;
tag(&value, Tag::constructed(universal::SEQUENCE), FIELD)?;
let mut entry = enter(&members, &value, FIELD)?;
let value = required(&mut entry, FIELD)?;
let identifier = if value.tag() == Tag::context(true, 0) {
AgreementIdentifier::KeyIdentifier(KeyIdentifier::read(&entry, &value)?)
} else {
tag(&value, Tag::constructed(universal::SEQUENCE), FIELD)?;
AgreementIdentifier::IssuerAndSerial(SignerIdentifier::read_as(
&entry, &value, FIELD,
)?)
};
let encrypted = octets(&mut entry)?;
end(&entry, FIELD)?;
keys.try_push(RecipientKey {
identifier,
encrypted,
})
.map_err(|e| Error::resource(e, FIELD, value.span().start))?;
}
if keys.is_empty() {
return Err(Error::schema(
ErrorCode::MissingField,
FIELD,
set.span().start,
));
}
Ok(Self::Agreement {
originator,
ukm,
algorithm,
keys: keys.into_owned(),
})
}
}
impl<'a> KeyIdentifier<'a> {
#[must_use]
pub fn identifier(&self) -> &Octets<'a> {
&self.identifier
}
#[must_use]
pub fn date(&self) -> Option<EncodedValue<'a>> {
self.date
.map(|element| self.encoded(element, self.identifier.outer_depth()))
}
#[must_use]
pub fn other(&self) -> Option<(Oid<'a>, Option<EncodedValue<'a>>)> {
self.other.map(|(kind, value)| {
let depth = self.identifier.outer_depth();
debug_assert!(depth < u32::MAX);
(kind, value.map(|element| self.encoded(element, depth + 1)))
})
}
fn encoded(&self, element: Element<'a>, depth: u32) -> EncodedValue<'a> {
EncodedValue {
element,
parser: self.identifier.parser(),
encoding: self.encoding,
depth,
}
}
fn read(parent: &Reader<'a>, element: &Element<'a>) -> Result<Self> {
let mut inside = enter(parent, element, FIELD)?;
let identifier = octets(&mut inside)?;
let mut next = inside
.next_element()
.map_err(|e| Error::encoding(e, FIELD))?;
let date = if let Some(value) = next.as_ref().filter(|e| {
e.tag().number() == Some(universal::GENERALIZED_TIME)
&& e.tag().class() == structured_asn1::Class::Universal
}) {
structured_pkix::der::conforms(&inside, value, FIELD).map_err(Error::pkix)?;
let time = *value;
next = inside
.next_element()
.map_err(|e| Error::encoding(e, FIELD))?;
Some(time)
} else {
None
};
let other = if let Some(value) = next {
tag(&value, Tag::constructed(universal::SEQUENCE), FIELD)?;
let mut fields = enter(&inside, &value, FIELD)?;
let kind = fields.read_oid().map_err(|e| Error::encoding(e, FIELD))?;
let other = fields
.next_element()
.map_err(|e| Error::encoding(e, FIELD))?;
if let Some(value) = other.as_ref() {
structured_pkix::der::conforms(&fields, value, FIELD).map_err(Error::pkix)?;
}
end(&fields, FIELD)?;
Some((kind, other))
} else {
None
};
end(&inside, FIELD)?;
Ok(Self {
identifier,
date,
other,
encoding: inside.encoding(),
})
}
}
fn octets<'a>(parent: &mut Reader<'a>) -> Result<Octets<'a>> {
let value = required(parent, FIELD)?;
Octets::read(parent, &value, FIELD)
}