Skip to main content

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}