Skip to main content

structured_cms/timestamp/
imprint.rs

1//! Original `MessageImprint` fields, without a concrete digest backend.
2
3use super::record;
4use crate::{Error, ErrorCode, Octets, Result};
5use structured_asn1::memory::{OwnedVec, Work};
6use structured_asn1::{Element, Oid, Reader, Span, Tag, universal};
7use structured_pkix::AlgorithmIdentifier;
8
9#[derive(Debug, Clone, Copy)]
10pub(super) struct ImprintFields {
11    pub enclosing: &'static str,
12    pub algorithm: &'static str,
13    pub hashed: &'static str,
14}
15
16const TOKEN: ImprintFields = ImprintFields {
17    enclosing: "tstInfo.messageImprint",
18    algorithm: "tstInfo.messageImprint.hashAlgorithm",
19    hashed: "tstInfo.messageImprint.hashedMessage",
20};
21
22/// A written identifier versus uniquely bounded malformed algorithm syntax.
23#[derive(Debug)]
24pub enum HashAlgorithmReading<'a> {
25    /// Original `AlgorithmIdentifier`, with original parameter/depth provenance.
26    Identifier(AlgorithmIdentifier<'a>),
27    /// No identifier may be dispatched as if its syntax were conforming.
28    Malformed {
29        /// Whole original malformed field, never retagged or re-encoded.
30        element: Element<'a>,
31        /// Bare OID only when the shared OID decoder actually read it.
32        kind: Option<Oid<'a>>,
33    },
34}
35
36/// Borrowed algorithm/hash fields and independently accounted diagnostics.
37/// Reading is independent of algorithm support, output width and token trust.
38#[derive(Debug)]
39pub struct MessageImprint<'a> {
40    algorithm: HashAlgorithmReading<'a>,
41    hashed: Octets<'a>,
42    faults: OwnedVec<Error>,
43    span: Span,
44    fields: ImprintFields,
45}
46
47impl<'a> MessageImprint<'a> {
48    /// Reads the two original fields of RFC3161 ยง2.4.1 `MessageImprint`.
49    ///
50    /// The normative algorithm is `AlgorithmIdentifier`. Inspection retains a
51    /// uniquely bounded malformed first field and readable OCTET STRING, with
52    /// faults; a bare OID does not become a fabricated valid identifier. This
53    /// recovery is not specified by RFC3161. Missing/unreadable hash refuses.
54    /// The selected provider resolves written identifiers and their full
55    /// parameter/output semantics separately; no fixed hash registry is assumed.
56    /// <https://www.rfc-editor.org/rfc/rfc3161#section-2.4.1>
57    pub fn read(parent: &Reader<'a>, element: &Element<'a>) -> Result<Self> {
58        Self::read_fields(parent, element, TOKEN)
59    }
60
61    pub(super) fn read_fields(
62        parent: &Reader<'a>,
63        element: &Element<'a>,
64        fields: ImprintFields,
65    ) -> Result<Self> {
66        if element.tag() != Tag::constructed(universal::SEQUENCE) {
67            return Err(Error::schema(
68                ErrorCode::UnexpectedTag,
69                fields.enclosing,
70                element.span().start,
71            ));
72        }
73        let mut inside = parent
74            .enter(element)
75            .map_err(|error| Error::encoding(error, fields.enclosing))?;
76        let written = crate::signer::required(&mut inside, fields.algorithm)?;
77        let execution = parent.execution();
78        let mut faults = execution.vector();
79        let algorithm = if written.tag() == Tag::constructed(universal::SEQUENCE) {
80            match structured_pkix::algorithm::read(&inside, &written, fields.algorithm)
81                .map_err(Error::pkix)
82            {
83                Ok(identifier) => HashAlgorithmReading::Identifier(identifier),
84                Err(error) if error.is_terminal() => return Err(error),
85                Err(error) => {
86                    record(&mut faults, error)?;
87                    HashAlgorithmReading::Malformed {
88                        element: written,
89                        kind: None,
90                    }
91                }
92            }
93        } else {
94            let kind = if written.tag() == Tag::primitive(universal::OID) {
95                match inside
96                    .oid(&written)
97                    .map_err(|error| Error::encoding(error, fields.algorithm))
98                {
99                    Ok(kind) => Some(kind),
100                    Err(error) if error.is_terminal() => return Err(error),
101                    Err(error) => {
102                        record(&mut faults, error)?;
103                        None
104                    }
105                }
106            } else {
107                None
108            };
109            record(
110                &mut faults,
111                Error::schema(
112                    ErrorCode::MalformedValue,
113                    fields.algorithm,
114                    written.span().start,
115                ),
116            )?;
117            HashAlgorithmReading::Malformed {
118                element: written,
119                kind,
120            }
121        };
122        let hashed = crate::signer::required(&mut inside, fields.hashed)?;
123        let hashed = Octets::read(&inside, &hashed, fields.hashed)?;
124        if !inside.is_empty() {
125            record(
126                &mut faults,
127                Error::schema(ErrorCode::TrailingData, fields.enclosing, inside.offset()),
128            )?;
129        }
130        Ok(Self {
131            algorithm,
132            hashed,
133            faults: faults.into_owned(),
134            span: element.span(),
135            fields,
136        })
137    }
138
139    /// Original written algorithm or explicit unreadable/malformed alternative.
140    #[must_use]
141    pub fn algorithm(&self) -> &HashAlgorithmReading<'a> {
142        &self.algorithm
143    }
144    /// Original logical hash bytes, including original BER fragment spans.
145    #[must_use]
146    pub fn hashed(&self) -> &Octets<'a> {
147        &self.hashed
148    }
149    /// Original complete `MessageImprint` range.
150    #[must_use]
151    pub fn span(&self) -> Span {
152        self.span
153    }
154    /// Readable faults, which cannot be silently ignored for proof acceptance.
155    #[must_use]
156    pub fn faults(&self) -> &[Error] {
157        &self.faults
158    }
159    pub(super) fn fields(&self) -> ImprintFields {
160        self.fields
161    }
162}