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() {
44            execution.charge_work(11).map_err(|reason| {
45                Error::resource(reason, "ocspResponse.extensions", extension.span().start)
46            })?;
47            if extension.kind() == oid::OCSP_NONCE {
48                nonce = Some(super::nonce::read(extension, execution)?);
49            } else if extension.is_critical() {
50                return Ok(Processed {
51                    processing: ExtensionProcessing::Unsupported {
52                        kind: extension.kind(),
53                        span: extension.span(),
54                    },
55                    nonce,
56                });
57            }
58        }
59        Ok(Processed {
60            processing: ExtensionProcessing::Understood,
61            nonce,
62        })
63    }
64}
65
66impl<'a> SingleResponse<'a> {
67    /// Process this assertion's critical demands, independently of unrelated
68    /// assertions. No optional single-extension semantics are advertised
69    /// by this core, so unknown critical demands remain unsupported facts.
70    pub fn check_extensions(&self, execution: &Memory) -> Result<ExtensionProcessing<'a>> {
71        execution.charge_work(1).map_err(|reason| {
72            Error::resource(
73                reason,
74                "ocspResponse.singleResponse.extensions",
75                self.span.start,
76            )
77        })?;
78        if let Some(extension) = self.extensions.criticals(execution).next() {
79            let extension = extension?;
80            return Ok(ExtensionProcessing::Unsupported {
81                kind: extension.kind(),
82                span: extension.span(),
83            });
84        }
85        Ok(ExtensionProcessing::Understood)
86    }
87}