Skip to main content

structured_pkix/ocsp/
extensions.rs

1//! Critical demands have response-wide or selected-assertion scope.
2
3use super::{BasicResponse, SingleResponse};
4use crate::{Error, Result, oid};
5use structured_asn1::memory::Memory;
6use structured_asn1::{Oid, Span};
7
8/// Supported extension processing, separate from application acceptance.
9#[derive(Debug, Clone, Copy)]
10pub enum ExtensionProcessing<'a> {
11    /// All critical demands in this scope were understood. Unsupported optional
12    /// noncritical extensions remain available in the original model.
13    Understood,
14    /// A critical demand is unsupported, with its original identifier/location.
15    Unsupported {
16        /// Original extension identifier.
17        kind: Oid<'a>,
18        /// Original extension location.
19        span: Span,
20    },
21}
22
23pub(super) struct Processed<'a> {
24    pub(super) processing: ExtensionProcessing<'a>,
25    pub(super) nonce: Option<&'a [u8]>,
26}
27
28impl<'a> BasicResponse<'a> {
29    /// Process response-wide critical demands before using any assertion.
30    /// RFC6960 ยง4.4 makes optional extension support explicit. This core
31    /// supports nonce; other optional noncritical values remain opaque.
32    /// <https://www.rfc-editor.org/rfc/rfc6960#section-4.4>
33    pub fn check_extensions(&self, execution: &Memory) -> Result<ExtensionProcessing<'a>> {
34        self.process_extensions(execution)
35            .map(|facts| facts.processing)
36    }
37
38    pub(super) fn process_extensions(&self, execution: &Memory) -> Result<Processed<'a>> {
39        execution.charge_work(1).map_err(|reason| {
40            Error::resource(reason, "ocspResponse.extensions", self.span.start)
41        })?;
42        let mut nonce = None;
43        for extension in self.extensions.iter(execution) {
44            let extension = extension?;
45            // The common iterator already admitted the metadata step.
46            execution.charge_work(10).map_err(|reason| {
47                Error::resource(reason, "ocspResponse.extensions", extension.span().start)
48            })?;
49            if extension.kind() == oid::OCSP_NONCE {
50                nonce = Some(super::nonce::read(extension, execution)?);
51            } else if extension.is_critical() {
52                return Ok(Processed {
53                    processing: ExtensionProcessing::Unsupported {
54                        kind: extension.kind(),
55                        span: extension.span(),
56                    },
57                    nonce,
58                });
59            }
60        }
61        Ok(Processed {
62            processing: ExtensionProcessing::Understood,
63            nonce,
64        })
65    }
66}
67
68impl<'a> SingleResponse<'a> {
69    /// Process this assertion's critical demands, independently of unrelated
70    /// assertions. No optional single-extension semantics are advertised
71    /// by this core, so unknown critical demands remain unsupported facts.
72    pub fn check_extensions(&self, execution: &Memory) -> Result<ExtensionProcessing<'a>> {
73        execution.charge_work(1).map_err(|reason| {
74            Error::resource(
75                reason,
76                "ocspResponse.singleResponse.extensions",
77                self.span.start,
78            )
79        })?;
80        if let Some(extension) = self.extensions.criticals(execution).next() {
81            let extension = extension?;
82            return Ok(ExtensionProcessing::Unsupported {
83                kind: extension.kind(),
84                span: extension.span(),
85            });
86        }
87        Ok(ExtensionProcessing::Understood)
88    }
89}