use crate::{
certificate,
container::XADES,
properties::{self, Error, PropertyResult},
timestamp::XADES_141,
unsigned,
xml::{Access, Name, Snapshot, Xml},
};
use structured_asn1::memory::{OwnedVec, Work};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ReferenceKind {
Certificate,
Crl,
Ocsp,
Other,
}
#[derive(Clone, Copy, Debug)]
pub enum ReferenceField<N> {
Uri(N),
Integer(N),
DateTime(N),
Binary(N),
}
#[derive(Clone, Copy, Debug)]
pub enum ReferenceIdentifier<N> {
Absent,
Certificate {
issuer_serial: N,
},
Crl {
node: N,
issuer: N,
time: N,
number: Option<N>,
},
Ocsp {
node: N,
responder: ResponderIdentifier<N>,
time: N,
},
}
#[derive(Clone, Copy, Debug)]
pub enum ResponderIdentifier<N> {
Name(N),
Key(N),
}
pub struct ReferenceEntry<N> {
node: N,
kind: ReferenceKind,
digest: Option<(N, N)>,
identifier: ReferenceIdentifier<N>,
}
impl<N: Copy> ReferenceEntry<N> {
#[must_use]
pub fn node(&self) -> N {
self.node
}
#[must_use]
pub fn kind(&self) -> ReferenceKind {
self.kind
}
#[must_use]
pub fn digest(&self) -> Option<(N, N)> {
self.digest
}
#[must_use]
pub fn identifier(&self) -> ReferenceIdentifier<N> {
self.identifier
}
#[must_use]
pub fn fields(&self) -> [Option<ReferenceField<N>>; 4] {
let digest = self.digest.map(|(_, node)| ReferenceField::Binary(node));
match self.identifier {
ReferenceIdentifier::Certificate { issuer_serial } => [
digest,
Some(ReferenceField::Uri(self.node)),
Some(ReferenceField::Binary(issuer_serial)),
None,
],
ReferenceIdentifier::Crl {
node, time, number, ..
} => [
digest,
Some(ReferenceField::DateTime(time)),
Some(ReferenceField::Uri(node)),
number.map(ReferenceField::Integer),
],
ReferenceIdentifier::Ocsp {
node,
responder,
time,
} => [
match responder {
ResponderIdentifier::Key(node) => Some(ReferenceField::Binary(node)),
ResponderIdentifier::Name(_) => None,
},
Some(ReferenceField::DateTime(time)),
Some(ReferenceField::Uri(node)),
digest,
],
ReferenceIdentifier::Absent => [
digest,
if self.kind == ReferenceKind::Certificate {
Some(ReferenceField::Uri(self.node))
} else {
None
},
None,
None,
],
}
}
}
pub struct ReferenceProperty<N, D, G> {
snapshot: Snapshot<D, G>,
signature: N,
node: N,
role: unsigned::Role,
entries: OwnedVec<ReferenceEntry<N>>,
}
impl<N: Copy, D: Copy, G: Copy> ReferenceProperty<N, D, G> {
#[must_use]
pub fn snapshot(&self) -> Snapshot<D, G> {
self.snapshot
}
#[must_use]
pub fn signature(&self) -> N {
self.signature
}
#[must_use]
pub fn node(&self) -> N {
self.node
}
#[must_use]
pub fn role(&self) -> unsigned::Role {
self.role
}
#[must_use]
pub fn entries(&self) -> &[ReferenceEntry<N>] {
&self.entries
}
}
type Reading<X> = ReferenceProperty<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>;
pub(crate) fn read<X: Xml, W: Work>(
access: &Access<'_, X, W>,
signature: X::Id,
original: unsigned::Entry<X::Id>,
) -> PropertyResult<Reading<X>, X> {
let node = original.node;
let mut entries = access.execution().vector();
match original.role {
unsigned::Role::CertificateReferences | unsigned::Role::AttributeCertificateReferences => {
let mut children = access.children(node);
let list = required(&mut children, node, "CertRefs")?;
expect(access, list, XADES_141, "CertRefs")?;
finish(&mut children)?;
read_group(access, list, ReferenceKind::Certificate, &mut entries)?;
}
unsigned::Role::RevocationReferences | unsigned::Role::AttributeRevocationReferences => {
let mut prior = None;
for child in access.children(node) {
let child = child.map_err(Error::Child)?;
let (rank, kind) = if named(access, child, XADES, "CRLRefs")? {
(0, ReferenceKind::Crl)
} else if named(access, child, XADES, "OCSPRefs")? {
(1, ReferenceKind::Ocsp)
} else if named(access, child, XADES, "OtherRefs")? {
(2, ReferenceKind::Other)
} else {
return Err(Error::Unexpected { node: child });
};
if let Some(previous) = prior {
if rank == previous {
return Err(Error::Duplicate { node: child });
}
if rank < previous {
return Err(Error::Order { node: child });
}
}
prior = Some(rank);
read_group(access, child, kind, &mut entries)?;
}
if original.role == unsigned::Role::RevocationReferences && entries.is_empty() {
return Err(Error::Missing {
parent: node,
local: "CRLRefs, OCSPRefs or OtherRefs",
});
}
}
_ => return Err(Error::Unexpected { node }),
}
Ok(ReferenceProperty {
snapshot: access.snapshot(),
signature,
node,
role: original.role,
entries: entries.into_owned(),
})
}
fn read_group<X: Xml, W: Work>(
access: &Access<'_, X, W>,
parent: X::Id,
kind: ReferenceKind,
entries: &mut OwnedVec<ReferenceEntry<X::Id>, W>,
) -> PropertyResult<(), X> {
let local = match kind {
ReferenceKind::Certificate => "Cert",
ReferenceKind::Crl => "CRLRef",
ReferenceKind::Ocsp => "OCSPRef",
ReferenceKind::Other => "OtherRef",
};
let mut found = false;
for child in access.children(parent) {
let node = child.map_err(Error::Child)?;
expect(access, node, XADES, local)?;
let mut entry = ReferenceEntry {
node,
kind,
digest: None,
identifier: ReferenceIdentifier::Absent,
};
match kind {
ReferenceKind::Certificate => {
let reference = certificate::read_entry(access, node)?;
entry.digest = Some((reference.method(), reference.digest()));
if let Some(issuer) = reference.issuer_serial() {
properties::simple_content(access, issuer)?;
entry.identifier = ReferenceIdentifier::Certificate {
issuer_serial: issuer,
};
}
}
ReferenceKind::Crl => crl(access, &mut entry)?,
ReferenceKind::Ocsp => ocsp(access, &mut entry)?,
ReferenceKind::Other => {}
}
entries
.try_push(entry)
.map_err(|cause| Error::Resource { node, cause })?;
found = true;
}
if !found {
return Err(Error::Missing { parent, local });
}
Ok(())
}
fn crl<X: Xml, W: Work>(
access: &Access<'_, X, W>,
entry: &mut ReferenceEntry<X::Id>,
) -> PropertyResult<(), X> {
let mut children = access.children(entry.node);
let digest = required(&mut children, entry.node, "DigestAlgAndValue")?;
expect(access, digest, XADES, "DigestAlgAndValue")?;
let (method, value) = properties::digest_value(access, digest)?;
entry.digest = Some((method, value));
if let Some(identifier) = children.next() {
let identifier = identifier.map_err(Error::Child)?;
expect(access, identifier, XADES, "CRLIdentifier")?;
let mut fields = access.children(identifier);
let issuer = required(&mut fields, identifier, "Issuer")?;
simple(access, issuer, "Issuer")?;
let time = required(&mut fields, identifier, "IssueTime")?;
simple(access, time, "IssueTime")?;
let mut crl_number = None;
if let Some(number) = fields.next() {
let number = number.map_err(Error::Child)?;
simple(access, number, "Number")?;
crl_number = Some(number);
}
finish(&mut fields)?;
entry.identifier = ReferenceIdentifier::Crl {
node: identifier,
issuer,
time,
number: crl_number,
};
}
finish(&mut children)
}
fn ocsp<X: Xml, W: Work>(
access: &Access<'_, X, W>,
entry: &mut ReferenceEntry<X::Id>,
) -> PropertyResult<(), X> {
let mut children = access.children(entry.node);
let identifier = required(&mut children, entry.node, "OCSPIdentifier")?;
expect(access, identifier, XADES, "OCSPIdentifier")?;
let mut fields = access.children(identifier);
let responder = required(&mut fields, identifier, "ResponderID")?;
expect(access, responder, XADES, "ResponderID")?;
let mut choice = access.children(responder);
let value = required(&mut choice, responder, "ByName or ByKey")?;
let responder = if named(access, value, XADES, "ByKey")? {
ResponderIdentifier::Key(value)
} else {
expect(access, value, XADES, "ByName")?;
ResponderIdentifier::Name(value)
};
properties::simple_content(access, value)?;
finish(&mut choice)?;
let time = required(&mut fields, identifier, "ProducedAt")?;
simple(access, time, "ProducedAt")?;
finish(&mut fields)?;
entry.identifier = ReferenceIdentifier::Ocsp {
node: identifier,
responder,
time,
};
if let Some(digest) = children.next() {
let digest = digest.map_err(Error::Child)?;
expect(access, digest, XADES, "DigestAlgAndValue")?;
let (method, value) = properties::digest_value(access, digest)?;
entry.digest = Some((method, value));
}
finish(&mut children)
}
fn required<X: Xml, W: Work>(
children: &mut crate::xml::Children<'_, '_, X, W>,
parent: X::Id,
local: &'static str,
) -> PropertyResult<X::Id, X> {
children
.next()
.transpose()
.map_err(Error::Child)?
.ok_or(Error::Missing { parent, local })
}
fn finish<X: Xml, W: Work>(
children: &mut crate::xml::Children<'_, '_, X, W>,
) -> PropertyResult<(), X> {
if let Some(extra) = children.next() {
return Err(Error::Unexpected {
node: extra.map_err(Error::Child)?,
});
}
Ok(())
}
fn simple<X: Xml, W: Work>(
access: &Access<'_, X, W>,
node: X::Id,
local: &str,
) -> PropertyResult<(), X> {
expect(access, node, XADES, local)?;
properties::simple_content(access, node)
}
fn expect<X: Xml, W: Work>(
access: &Access<'_, X, W>,
node: X::Id,
namespace: &str,
local: &str,
) -> PropertyResult<(), X> {
if !named(access, node, namespace, local)? {
return Err(Error::Unexpected { node });
}
Ok(())
}
fn named<X: Xml, W: Work>(
access: &Access<'_, X, W>,
node: X::Id,
namespace: &str,
local: &str,
) -> PropertyResult<bool, X> {
access
.has_name(node, Name { namespace, local })
.map_err(Error::Access)
}