use super::{CheckedPath, CrlCoverage, CrlReadingTarget, OcspTarget, ResponderPath};
use structured_asn1::memory::{MemoryError, Work};
use structured_pkix::temporal::Reading;
pub enum MemberStatus<'view, 'certificate, 'document> {
Crl(&'view CrlCoverage<'view, 'certificate, 'document>),
CrlReading(&'view CrlReadingTarget<'view, 'certificate, 'document>),
Ocsp(&'view OcspTarget<'view, 'certificate, 'document>),
ResponderNoCheck(&'view ResponderPath<'view, 'view, 'certificate, 'document>),
}
impl<'view, 'document> MemberStatus<'view, '_, 'document> {
fn identity(&self) -> (&'view CheckedPath<'document>, usize, Reading) {
match self {
Self::Crl(value) => (
value.path(),
value.member(),
value.coverage().evaluated_at(),
),
Self::CrlReading(value) => {
(value.path(), value.member(), value.reading().evaluated_at())
}
Self::Ocsp(value) => (
value.path(),
value.member(),
value.evidence().evaluated_at(),
),
Self::ResponderNoCheck(value) => (
value.path(),
value.path().members().len() - 1,
value.target().evidence().evaluated_at(),
),
}
}
}
pub struct PathStatuses<'view, 'certificate, 'document> {
path: &'view CheckedPath<'document>,
at: Reading,
entries: &'view [MemberStatus<'view, 'certificate, 'document>],
}
impl<'view, 'certificate, 'document> PathStatuses<'view, 'certificate, 'document> {
#[must_use]
pub fn path(&self) -> &'view CheckedPath<'document> {
self.path
}
#[must_use]
pub fn evaluated_at(&self) -> Reading {
self.at
}
#[must_use]
pub fn entries(&self) -> &'view [MemberStatus<'view, 'certificate, 'document>] {
self.entries
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StatusCensusError {
Count,
Member {
index: usize,
},
Time {
index: usize,
},
Exemption {
index: usize,
},
Resource(MemoryError),
}
impl<'document> CheckedPath<'document> {
pub fn status_census<'view, 'certificate, W: Work>(
&'view self,
at: Reading,
entries: &'view [MemberStatus<'view, 'certificate, 'document>],
execution: &W,
) -> Result<PathStatuses<'view, 'certificate, 'document>, StatusCensusError> {
execution
.charge_work(1)
.map_err(StatusCensusError::Resource)?;
if self.members().len() != entries.len() {
return Err(StatusCensusError::Count);
}
for (index, entry) in entries.iter().enumerate() {
execution
.charge_work(1)
.map_err(StatusCensusError::Resource)?;
if let MemberStatus::ResponderNoCheck(value) = entry
&& value.revocation() != structured_pkix::ocsp::ResponderRevocation::NoCheck
{
return Err(StatusCensusError::Exemption { index });
}
let (path, member, evaluated_at) = entry.identity();
if !core::ptr::eq(self, path) || member != index {
return Err(StatusCensusError::Member { index });
}
if evaluated_at != at {
return Err(StatusCensusError::Time { index });
}
}
Ok(PathStatuses {
path: self,
at,
entries,
})
}
}