use super::{CheckedPath, OcspTarget, authority};
use structured_asn1::memory::{MemoryError, Work};
use structured_pkix::{
ocsp::{AuthoritySource, ResponderRevocation},
temporal::{LeapTable, Uncertainty},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ResponderFailure {
Anchor,
Signer,
EffectiveKey,
Interval,
}
#[derive(Debug)]
pub enum ResponderError {
SourceKind,
Resource(MemoryError),
Name(structured_pkix::Error),
Time(Uncertainty),
}
impl From<authority::Error> for ResponderError {
fn from(value: authority::Error) -> Self {
match value {
authority::Error::Resource(cause) => Self::Resource(cause),
authority::Error::Name(cause) => Self::Name(cause),
authority::Error::Time(cause) => Self::Time(cause),
}
}
}
impl From<authority::Failure> for ResponderFailure {
fn from(value: authority::Failure) -> Self {
match value {
authority::Failure::Anchor => Self::Anchor,
authority::Failure::Signer => Self::Signer,
authority::Failure::EffectiveKey => Self::EffectiveKey,
authority::Failure::Interval => Self::Interval,
}
}
}
pub struct ResponderPath<'receipt, 'view, 'certificate, 'document> {
target: &'receipt OcspTarget<'view, 'certificate, 'document>,
path: &'receipt CheckedPath<'document>,
revocation: ResponderRevocation,
}
impl<'receipt, 'view, 'certificate, 'document>
ResponderPath<'receipt, 'view, 'certificate, 'document>
{
#[must_use]
pub fn target(&self) -> &'receipt OcspTarget<'view, 'certificate, 'document> {
self.target
}
#[must_use]
pub fn path(&self) -> &'receipt CheckedPath<'document> {
self.path
}
#[must_use]
pub fn revocation(&self) -> ResponderRevocation {
self.revocation
}
}
pub enum ResponderBinding<'receipt, 'view, 'certificate, 'document> {
Bound(ResponderPath<'receipt, 'view, 'certificate, 'document>),
Rejected(ResponderFailure),
}
impl<'view, 'certificate, 'document> OcspTarget<'view, 'certificate, 'document> {
pub fn bind_responder_path<'receipt, W: Work>(
&'receipt self,
path: &'receipt CheckedPath<'document>,
utc: &LeapTable<'_>,
execution: &W,
) -> Result<ResponderBinding<'receipt, 'view, 'certificate, 'document>, ResponderError> {
execution.charge_work(1).map_err(ResponderError::Resource)?;
let AuthoritySource::Delegate { revocation } = self.authority() else {
return Err(ResponderError::SourceKind);
};
let evidence = self.evidence().evidence();
let signed = evidence.source().signed();
if let Some(cause) = self.path().path_authority(
path,
signed.signer(),
signed.key(),
self.evidence().evaluated_at(),
utc,
execution,
)? {
return Ok(ResponderBinding::Rejected(cause.into()));
}
Ok(ResponderBinding::Bound(ResponderPath {
target: self,
path,
revocation,
}))
}
}