structured_cms/signed/revocation.rs
1//! First-read CMS revocation choices shared by enclosing signature formats.
2
3use super::OtherRevocationInfo;
4use structured_asn1::{Element, Oid, Reader, Tag, universal};
5use structured_pkix::{crl::CertificateList, ocsp::BasicResponse};
6
7/// Actual parsed CMS choice, without authentication or freshness claims.
8pub enum Reading<'a> {
9 /// Whole original `CertificateList`, including complete/delta distinction.
10 Crl(CertificateList<'a>),
11 /// Basic body from the successful whole RFC5940 `OCSPResponse` choice.
12 Ocsp(BasicResponse<'a>),
13 /// Original open or unsupported inner response syntax. The caller retains
14 /// the original complete choice; this is never a fabricated basic body.
15 Open {
16 /// Actual parsed other-revocation format identifier.
17 format: Oid<'a>,
18 },
19}
20
21/// Original schema/encoding versus certificate/status refusal.
22#[derive(Debug)]
23pub enum Error {
24 /// Original CMS other-format syntax or successful-response constraint.
25 Cms(crate::Error),
26 /// Original CRL/basic-response syntax or resource/producing-reader failure.
27 Pkix(structured_pkix::Error),
28}
29impl Error {
30 /// Resource and caller/source failures cannot become document findings.
31 #[must_use]
32 pub fn is_terminal(&self) -> bool {
33 match self {
34 Self::Cms(cause) => cause.is_terminal(),
35 Self::Pkix(cause) => {
36 cause.is_resource() || cause.code() == structured_pkix::ErrorCode::ForeignReader
37 }
38 }
39 }
40}
41
42/// Reads an original root/TSA/PoE choice through the SAME CRL and RFC5940
43/// kernels. No new Parser, default budget, encoded wrapper or crypto is used.
44/// `parent` must be the original located reader under the active operation,
45/// such as the one returned by `SignedData::revocation_reader_in`.
46pub fn read<'a>(parent: &Reader<'a>, element: &Element<'a>) -> Result<Reading<'a>, Error> {
47 if element.tag() == Tag::constructed(universal::SEQUENCE) {
48 return CertificateList::read_element(parent, element)
49 .map(Reading::Crl)
50 .map_err(Error::Pkix);
51 }
52 let other = OtherRevocationInfo::read(parent, element).map_err(Error::Cms)?;
53 let format = other.kind();
54 let Some(response) = other.ocsp().map_err(Error::Cms)? else {
55 return Ok(Reading::Open { format });
56 };
57 let Some(value) = response.basic_in(parent).map_err(Error::Pkix)? else {
58 return Ok(Reading::Open { format });
59 };
60 Ok(Reading::Ocsp(value))
61}