Skip to main content

structured_cms/timestamp/
request.rs

1//! Original RFC3161 request fields; no requester identity or server policy.
2
3use super::{HashAlgorithmReading, MessageImprint};
4use crate::{Error, ErrorCode, Result};
5use structured_asn1::{Element, Integer, Oid, Parser, Reader, Span, Tag, universal};
6use structured_pkix::Extensions;
7
8/// A syntactically conforming original `TimeStampReq`.
9///
10/// Algorithm support/width, extension recognition, replay history and trust
11/// are separate decisions. Unlike token inspection, request syntax faults are
12/// refused, not silently repaired or passed to the selected provider.
13#[derive(Debug)]
14pub struct Request<'a> {
15    imprint: MessageImprint<'a>,
16    policy: Option<Oid<'a>>,
17    nonce: Option<Integer<'a>>,
18    cert_req: bool,
19    extensions: Option<Extensions<'a>>,
20    span: Span,
21    parser: &'a Parser,
22}
23
24impl<'a> Request<'a> {
25    /// Reads the original SEQUENCE with inherited depth/current execution.
26    /// BER is allowed by the producing reader; the caller selects encoding.
27    /// RFC3161 §2.4.1 defines version 1 and the ordered optional fields.
28    /// <https://www.rfc-editor.org/rfc/rfc3161.html#section-2.4.1>
29    pub fn read(parent: &Reader<'a>, element: &Element<'a>) -> Result<Self> {
30        const FIELD: &str = "timeStampReq";
31        if element.tag() != Tag::constructed(universal::SEQUENCE) {
32            return Err(Error::schema(
33                ErrorCode::UnexpectedTag,
34                FIELD,
35                element.span().start,
36            ));
37        }
38        let mut inside = parent
39            .enter(element)
40            .map_err(|source| Error::encoding(source, FIELD))?;
41        let version = crate::signer::required(&mut inside, "timeStampReq.version")?;
42        if version.tag() != Tag::primitive(universal::INTEGER) {
43            return Err(Error::schema(
44                ErrorCode::UnexpectedTag,
45                "timeStampReq.version",
46                version.span().start,
47            ));
48        }
49        let number = inside
50            .integer(&version)
51            .map_err(|source| Error::encoding(source, "timeStampReq.version"))?;
52        if number.as_u64() != Some(1) {
53            return Err(Error::schema(
54                ErrorCode::UnsupportedVersion,
55                "timeStampReq.version",
56                version.span().start,
57            ));
58        }
59        let imprint = crate::signer::required(&mut inside, "timeStampReq.messageImprint")?;
60        let imprint = MessageImprint::read_fields(
61            &inside,
62            &imprint,
63            super::imprint::ImprintFields {
64                enclosing: "timeStampReq.messageImprint",
65                algorithm: "timeStampReq.messageImprint.hashAlgorithm",
66                hashed: "timeStampReq.messageImprint.hashedMessage",
67            },
68        )?;
69        if !imprint.faults().is_empty()
70            || !matches!(imprint.algorithm(), HashAlgorithmReading::Identifier(_))
71        {
72            return Err(Error::schema(
73                ErrorCode::MalformedValue,
74                "timeStampReq.messageImprint",
75                imprint.span().start,
76            ));
77        }
78        let mut output = Self {
79            imprint,
80            policy: None,
81            nonce: None,
82            cert_req: false,
83            extensions: None,
84            span: element.span(),
85            parser: parent.parser(),
86        };
87        let mut previous = 0;
88        while let Some(element) = inside
89            .next_element()
90            .map_err(|source| Error::encoding(source, FIELD))?
91        {
92            let ordinal = match element.tag() {
93                tag if tag == Tag::primitive(universal::OID) => 1,
94                tag if tag == Tag::primitive(universal::INTEGER) => 2,
95                tag if tag == Tag::primitive(universal::BOOLEAN) => 3,
96                tag if tag == Tag::context(true, 0) => 4,
97                _ => {
98                    return Err(Error::schema(
99                        ErrorCode::UnknownField,
100                        FIELD,
101                        element.span().start,
102                    ));
103                }
104            };
105            if ordinal <= previous {
106                return Err(Error::schema(
107                    if ordinal == previous {
108                        ErrorCode::DuplicateField
109                    } else {
110                        ErrorCode::FieldOrder
111                    },
112                    FIELD,
113                    element.span().start,
114                ));
115            }
116            previous = ordinal;
117            output.read_optional(&inside, &element, ordinal)?;
118        }
119        Ok(output)
120    }
121
122    fn read_optional(
123        &mut self,
124        inside: &Reader<'a>,
125        element: &Element<'a>,
126        ordinal: u8,
127    ) -> Result<()> {
128        match ordinal {
129            1 => {
130                self.policy = Some(
131                    inside
132                        .oid(element)
133                        .map_err(|source| Error::encoding(source, "timeStampReq.reqPolicy"))?,
134                );
135            }
136            2 => {
137                self.nonce = Some(
138                    inside
139                        .integer(element)
140                        .map_err(|source| Error::encoding(source, "timeStampReq.nonce"))?,
141                );
142            }
143            3 => {
144                self.cert_req = inside
145                    .boolean(element)
146                    .map_err(|source| Error::encoding(source, "timeStampReq.certReq"))?;
147                // X.690 §11.5 omits DEFAULT components in DER. BER's explicit
148                // FALSE remains the same request value, not a repaired token.
149                if !self.cert_req && inside.encoding() == structured_asn1::Encoding::Der {
150                    return Err(Error::schema(
151                        ErrorCode::DefaultWritten,
152                        "timeStampReq.certReq",
153                        element.span().start,
154                    ));
155                }
156            }
157            4 => {
158                self.extensions = Some(
159                    Extensions::read_implicit(inside, element, 0, "timeStampReq.extensions")
160                        .map_err(Error::pkix)?,
161                );
162            }
163            _ => unreachable!("ordinal comes from the four schema tags above"),
164        }
165        Ok(())
166    }
167
168    /// Full original requested imprint, including original parameter provenance.
169    #[must_use]
170    pub fn imprint(&self) -> &MessageImprint<'a> {
171        &self.imprint
172    }
173    /// Requested policy, absent when none was specified.
174    #[must_use]
175    pub fn policy(&self) -> Option<Oid<'a>> {
176        self.policy
177    }
178    /// Original minimal INTEGER view; no nonce bytes are fabricated.
179    #[must_use]
180    pub fn nonce(&self) -> Option<Integer<'a>> {
181        self.nonce
182    }
183    /// RFC3161 schema default is false when the field is absent.
184    #[must_use]
185    pub fn cert_req(&self) -> bool {
186        self.cert_req
187    }
188    /// All request extensions require server recognition, not only critical ones.
189    #[must_use]
190    pub fn extensions(&self) -> Option<&Extensions<'a>> {
191        self.extensions.as_ref()
192    }
193    /// Whole original request span, in its producing source coordinates.
194    #[must_use]
195    pub fn span(&self) -> Span {
196        self.span
197    }
198    /// Original session identity, independent of shared account identity.
199    #[must_use]
200    pub fn same_session(&self, parent: &Reader<'_>) -> bool {
201        core::ptr::eq(self.parser, parent.parser())
202    }
203}