structured_cms/timestamp/
imprint_check.rs1use super::{HashAlgorithmReading, MessageImprint};
4use crate::Error;
5use crate::digest::{DigestBatch, DigestError, PassError};
6use crate::provider::{DigestAlgorithm, DigestProvider, Resolution};
7use crate::stream::Source;
8use structured_asn1::Reader;
9use structured_asn1::memory::Work;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum ImprintAgreement {
14 Matches,
16 Differs,
18 MalformedImprint,
20 MalformedAlgorithm,
22 MalformedHash,
24 Unsupported,
26}
27
28#[derive(Debug)]
30pub enum ImprintError<SE, PE> {
31 Processing(Error),
33 Callback(PE),
35 Digest(DigestError<PE>),
37 Comparison(crate::binding::BindError<PE>),
39 Pass(PassError<SE, PE>),
41 LostRequest,
43}
44
45pub(super) enum Resolved<I> {
46 Ready(I),
47 Unusable(ImprintAgreement),
48}
49
50pub(super) enum ResolveError<E> {
51 Processing(Error),
52 Callback(E),
53}
54
55impl<'a> MessageImprint<'a> {
56 pub fn check_content<P: DigestProvider<'a>, S: Source>(
66 &self,
67 provider: &'a P,
68 parent: &Reader<'a>,
69 source: &mut S,
70 ) -> Result<ImprintAgreement, ImprintError<S::Error, P::Error>> {
71 let resolved = self
72 .resolve(provider, parent)
73 .map_err(|error| match error {
74 ResolveError::Processing(error) => ImprintError::Processing(error),
75 ResolveError::Callback(error) => ImprintError::Callback(error),
76 })?;
77 match resolved {
78 Resolved::Ready(identity) => self.compute(provider, parent, source, identity),
79 Resolved::Unusable(answer) => Ok(answer),
80 }
81 }
82
83 pub(super) fn require_session(&self, parent: &Reader<'_>) -> crate::Result<()> {
84 if !core::ptr::eq(self.hashed().parser(), parent.parser()) {
85 return Err(Error::pkix(structured_pkix::Error::new(
86 structured_pkix::ErrorCode::ForeignReader,
87 self.fields().enclosing,
88 self.span().start,
89 )));
90 }
91 Ok(())
92 }
93
94 pub(super) fn resolve<P: DigestProvider<'a>>(
95 &self,
96 provider: &'a P,
97 parent: &Reader<'a>,
98 ) -> Result<Resolved<P::Identity>, ResolveError<P::Error>> {
99 crate::provider::require_instance(provider, self.fields().enclosing, self.span().start)
100 .map_err(ResolveError::Processing)?;
101 self.require_session(parent)
102 .map_err(ResolveError::Processing)?;
103 if !self.faults().is_empty() {
104 return Ok(Resolved::Unusable(ImprintAgreement::MalformedImprint));
105 }
106 let HashAlgorithmReading::Identifier(identifier) = self.algorithm() else {
107 return Ok(Resolved::Unusable(ImprintAgreement::MalformedImprint));
108 };
109 let identity = match provider
110 .resolve_digest(
111 DigestAlgorithm::Written(*identifier),
112 parent.encoding(),
113 parent,
114 )
115 .map_err(ResolveError::Callback)?
116 {
117 Resolution::Supported(identity) => identity,
118 Resolution::Malformed => {
119 return Ok(Resolved::Unusable(ImprintAgreement::MalformedAlgorithm));
120 }
121 Resolution::Unsupported => {
122 return Ok(Resolved::Unusable(ImprintAgreement::Unsupported));
123 }
124 };
125 if let Some(width) = provider.digest_width(&identity)
126 && self.hashed().len() != width
127 {
128 return Ok(Resolved::Unusable(ImprintAgreement::MalformedHash));
129 }
130 Ok(Resolved::Ready(identity))
131 }
132
133 pub(super) fn compute<P: DigestProvider<'a>, S: Source>(
134 &self,
135 provider: &'a P,
136 parent: &Reader<'a>,
137 source: &mut S,
138 identity: P::Identity,
139 ) -> Result<ImprintAgreement, ImprintError<S::Error, P::Error>> {
140 let field = self.fields().hashed;
141 let at = self.hashed().span().start;
142 let joined;
143 let expected = if let Some(bytes) = self.hashed().as_one() {
145 bytes
146 } else {
147 joined = self
148 .hashed()
149 .copy_in(parent, field, at)
150 .map_err(ImprintError::Processing)?;
151 &*joined
152 };
153 let execution = parent.execution();
154 let mut identities = execution.vector();
155 identities
156 .try_push(identity)
157 .map_err(|reason| ImprintError::Processing(Error::resource(reason, field, at)))?;
158 let batch = DigestBatch::prepare(provider, identities.into_owned(), &execution, field, at)
159 .map_err(ImprintError::Digest)?;
160 let memo = batch.run(source, &execution).map_err(ImprintError::Pass)?;
161 let output = memo
162 .for_request(0, &execution)
163 .map_err(ImprintError::Digest)?
164 .ok_or(ImprintError::LostRequest)?;
165 let matches = crate::binding::matches_digest(
166 provider,
167 output.prehash(),
168 expected,
169 &execution,
170 field,
171 self.hashed().span(),
172 )
173 .map_err(ImprintError::Comparison)?;
174 Ok(match matches {
175 crate::binding::DigestBinding::Matches => ImprintAgreement::Matches,
176 crate::binding::DigestBinding::Differs => ImprintAgreement::Differs,
177 crate::binding::DigestBinding::Malformed(_) => ImprintAgreement::MalformedHash,
178 })
179 }
180}