Skip to main content

structured_cms/timestamp/
carried.rs

1//! Exact selected-certificate carriage, distinct from SID or trust matching.
2
3use super::{ImprintOperand, Request, RequestFieldError, Token};
4use crate::{Error, ErrorCode};
5use structured_asn1::{Reader, memory::Work};
6use structured_pkix::Certificate;
7
8impl Token<'_> {
9    /// Checks the parsed request's certReq against this original `SignedData`.
10    ///
11    /// RFC3161 ยง2.4.1 requires the signing certificate when TRUE, and absence
12    /// of the certificates field when FALSE (including the schema default).
13    /// A present empty field fails FALSE; a different certificate with the same
14    /// SID fails TRUE. `selected` must independently be signature/ESS-bound;
15    /// exact carriage alone establishes neither binding nor certificate trust.
16    /// <https://www.rfc-editor.org/rfc/rfc3161#section-2.4.1>
17    pub fn matches_cert_req(
18        &self,
19        requested: &Request<'_>,
20        selected: Option<&Certificate<'_>>,
21        token_parent: &Reader<'_>,
22        request_parent: &Reader<'_>,
23    ) -> Result<bool, RequestFieldError> {
24        self.signer()
25            .require_session(token_parent, "signedData.certificates")
26            .map_err(|source| RequestFieldError {
27                operand: ImprintOperand::Token,
28                source,
29            })?;
30        if !requested.same_session(request_parent) {
31            return Err(RequestFieldError {
32                operand: ImprintOperand::Requested,
33                source: Error::pkix(structured_pkix::Error::new(
34                    structured_pkix::ErrorCode::ForeignReader,
35                    "timeStampReq.certReq",
36                    requested.span().start,
37                )),
38            });
39        }
40        let work = token_parent.execution();
41        let at = self
42            .message()
43            .certificate_field()
44            .map_or(self.message().span().start, |span| span.start);
45        let failure = |reason| RequestFieldError {
46            operand: ImprintOperand::Token,
47            source: Error::resource(reason, "signedData.certificates", at),
48        };
49        work.charge_work(1).map_err(failure)?;
50        if !requested.cert_req() {
51            return Ok(self.message().certificate_field().is_none());
52        }
53        let Some(selected) = selected else {
54            return Ok(false);
55        };
56        for carried in self.message().certificates() {
57            work.charge_work(1).map_err(failure)?;
58            let original = selected.as_bytes();
59            let written = carried.as_bytes();
60            if original.len() != written.len() {
61                continue;
62            }
63            let length = u64::try_from(original.len()).map_err(|_| RequestFieldError {
64                operand: ImprintOperand::Token,
65                source: Error::schema(ErrorCode::LengthOverflow, "signedData.certificates", at),
66            })?;
67            work.charge_work(length).map_err(failure)?;
68            if original == written {
69                return Ok(true);
70            }
71        }
72        Ok(false)
73    }
74}