use super::{
CrlReferenceError, CrlReferenceIdentity, ReferenceDigest, ReferenceDigestError, ReferenceKind,
ReferenceProperty, ReferenceTarget, ReferenceTime, check_crl_reference,
compare_reference_target,
};
use crate::{
binary::{self, BinaryXml, Located},
certificate::Agreement,
digest::StreamingDigest,
properties::CalendarXml,
scalar::TextXml,
xml::{Access, AccessError, Xml},
};
use structured_asn1::ScopedReader;
use structured_pkix::crl::CertificateList;
pub struct CrlValueReference<'references, 'actual, 'document, N, D, G> {
references: &'references ReferenceProperty<N, D, G>,
entry: usize,
actual: &'actual CertificateList<'document>,
identity: Option<Located<CrlReferenceIdentity<N>, N, D, G>>,
digest: Option<ReferenceDigest>,
}
impl<'r, 'a, 'd, N: Copy, D: Copy, G: Copy> CrlValueReference<'r, 'a, 'd, N, D, G> {
#[must_use]
pub fn references(&self) -> &'r ReferenceProperty<N, D, G> {
self.references
}
#[must_use]
pub fn entry(&self) -> usize {
self.entry
}
#[must_use]
pub fn actual(&self) -> &'a CertificateList<'d> {
self.actual
}
#[must_use]
pub fn identity(&self) -> Option<&Located<CrlReferenceIdentity<N>, N, D, G>> {
self.identity.as_ref()
}
#[must_use]
pub fn digest(&self) -> Option<ReferenceDigest> {
self.digest
}
#[must_use]
pub fn agrees(&self) -> bool {
if self.digest != Some(ReferenceDigest::Compared(Agreement::Matches)) {
return false;
}
if let Some(identity) = &self.identity {
return identity.value.issuer_matches()
&& identity.value.issued_at() == ReferenceTime::Matches;
}
true
}
}
#[derive(Debug)]
pub enum CrlValueError<E, PE, N, D, G> {
Access(AccessError<E, N>),
Index {
index: usize,
},
Identity(CrlReferenceError<E, N>),
Digest(binary::Error<E, ReferenceDigestError<PE>, N, D, G>),
}
pub type CrlValueResult<'r, 'a, 'd, X, PE> = Result<
Option<
CrlValueReference<'r, 'a, 'd, <X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>,
>,
CrlValueError<
<X as Xml>::Error,
PE,
<X as Xml>::Id,
<X as Xml>::Document,
<X as Xml>::Generation,
>,
>;
pub fn check_crl_value_reference<'r, 'a, 'd, X, P>(
xml: &X,
references: &'r ReferenceProperty<X::Id, X::Document, X::Generation>,
index: usize,
actual: &'a CertificateList<'d>,
provider: &P,
operation: &ScopedReader<'_, '_>,
) -> CrlValueResult<'r, 'a, 'd, X, P::Error>
where
X: BinaryXml + CalendarXml + TextXml,
P: StreamingDigest<X>,
{
let work = operation.execution();
let access = Access::new(xml, references.snapshot(), &work);
access
.query(references.node(), |_, _, _| Ok(()))
.map_err(CrlValueError::Access)?;
let Some(entry) = references.entries().get(index) else {
return Err(CrlValueError::Index { index });
};
if entry.kind() != ReferenceKind::Crl {
return Ok(None);
}
let identity = check_crl_reference(xml, references, index, actual, operation)
.map_err(CrlValueError::Identity)?;
let digest = match identity.as_ref() {
Some(identity)
if matches!(
identity.value.issued_at(),
ReferenceTime::Malformed | ReferenceTime::Unsupported
) =>
{
None
}
_ => Some(
compare_reference_target(
xml,
references,
index,
ReferenceTarget::Crl(actual),
provider,
&work,
)
.map_err(CrlValueError::Digest)?,
),
};
access
.query(entry.node(), |_, _, _| Ok(()))
.map_err(CrlValueError::Access)?;
Ok(Some(CrlValueReference {
references,
entry: index,
actual,
identity,
digest,
}))
}