use super::{BasicResponse, SingleResponse, retention};
use crate::temporal::Reading;
use crate::{Error, Result, oid};
use structured_asn1::memory::Work;
use structured_asn1::{Oid, Span};
#[derive(Debug, Clone, Copy)]
pub enum ExtensionProcessing<'a> {
Understood,
Unsupported {
kind: Oid<'a>,
span: Span,
},
}
pub(super) struct Processed<'a> {
pub(super) processing: ExtensionProcessing<'a>,
pub(super) nonce: Option<&'a [u8]>,
pub(super) extended_revoke: bool,
}
pub(super) struct ProcessedSingle<'a> {
pub(super) processing: ExtensionProcessing<'a>,
pub(super) archive_cutoff: Option<Reading>,
}
impl<'a> BasicResponse<'a> {
pub fn check_extensions<W: Work>(&self, execution: &W) -> Result<ExtensionProcessing<'a>> {
self.process_extensions(execution)
.map(|facts| facts.processing)
}
pub(super) fn process_extensions<W: Work>(&self, execution: &W) -> Result<Processed<'a>> {
execution.charge_work(1).map_err(|reason| {
Error::resource(reason, "ocspResponse.extensions", self.span.start)
})?;
let mut nonce = None;
let mut extended_revoke = false;
for extension in self.extensions.iter(execution) {
let extension = extension?;
execution.charge_work(10).map_err(|reason| {
Error::resource(reason, "ocspResponse.extensions", extension.span().start)
})?;
if extension.kind() == oid::OCSP_NONCE {
nonce = Some(super::nonce::read(extension, execution)?);
} else if extension.kind() == oid::OCSP_EXTENDED_REVOKE {
retention::extended_revoke(extension, execution)?;
extended_revoke = true;
} else if extension.is_critical() {
return Ok(Processed {
processing: ExtensionProcessing::Unsupported {
kind: extension.kind(),
span: extension.span(),
},
nonce,
extended_revoke,
});
}
}
Ok(Processed {
processing: ExtensionProcessing::Understood,
nonce,
extended_revoke,
})
}
}
impl<'a> SingleResponse<'a> {
pub fn check_extensions<W: Work>(&self, execution: &W) -> Result<ExtensionProcessing<'a>> {
self.process_extensions(execution)
.map(|facts| facts.processing)
}
pub(super) fn process_extensions<W: Work>(&self, execution: &W) -> Result<ProcessedSingle<'a>> {
const FIELD: &str = "ocspResponse.singleResponse.extensions";
execution
.charge_work(1)
.map_err(|reason| Error::resource(reason, FIELD, self.span.start))?;
let mut archive_cutoff = None;
for extension in self.extensions.iter(execution) {
let extension = extension?;
execution
.charge_work(10)
.map_err(|reason| Error::resource(reason, FIELD, extension.span().start))?;
if extension.kind() == oid::OCSP_ARCHIVE_CUTOFF {
archive_cutoff = Some(retention::archive_cutoff(extension, execution)?);
} else if extension.kind() == oid::OCSP_EXTENDED_REVOKE {
return Err(retention::misplaced(extension));
} else if extension.is_critical() {
return Ok(ProcessedSingle {
processing: ExtensionProcessing::Unsupported {
kind: extension.kind(),
span: extension.span(),
},
archive_cutoff,
});
}
}
Ok(ProcessedSingle {
processing: ExtensionProcessing::Understood,
archive_cutoff,
})
}
}