structured_cms/timestamp/
requested.rs1use super::imprint_check::Resolved;
4use super::{ImprintAgreement, MessageImprint};
5use crate::Error;
6use core::cmp::Ordering;
7use structured_asn1::{Reader, Span};
8use structured_pkix::algorithm::digest::AsnDigest;
9
10#[derive(Debug)]
12pub enum RequestedContentError<SE, PE> {
13 Request(RequestImprintError<PE>),
15 Content(super::ImprintError<SE, PE>),
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum ImprintOperand {
22 Token,
24 Requested,
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum RequestAgreement {
31 Matches,
33 AlgorithmDiffers,
35 HashDiffers,
37 Unusable {
39 operand: ImprintOperand,
41 reason: ImprintAgreement,
43 },
44}
45
46#[derive(Debug)]
48pub enum RequestImprintError<E> {
49 Processing {
51 operand: ImprintOperand,
53 source: Error,
55 },
56 Callback {
58 operand: ImprintOperand,
60 span: Span,
62 source: E,
64 },
65}
66
67impl<'a> MessageImprint<'a> {
68 pub fn check_requested_content<P: AsnDigest<'a>, S: crate::stream::Source>(
74 &self,
75 requested: &MessageImprint<'a>,
76 provider: &'a P,
77 parents: (&Reader<'a>, &Reader<'a>),
78 covered: &mut S,
79 ) -> Result<(ImprintAgreement, RequestAgreement), RequestedContentError<S::Error, P::Error>>
80 {
81 self.check_requested_input(
82 requested,
83 provider,
84 parents,
85 &mut super::RawInput::new(covered),
86 )
87 }
88
89 pub fn check_requested_input<P, I>(
93 &self,
94 requested: &MessageImprint<'a>,
95 provider: &'a P,
96 parents: (&Reader<'a>, &Reader<'a>),
97 covered: &mut I,
98 ) -> Result<(ImprintAgreement, RequestAgreement), RequestedContentError<I::Error, P::Error>>
99 where
100 P: AsnDigest<'a>,
101 I: super::ComputedInput<P, P::Error>,
102 {
103 let (token_parent, requested_parent) = parents;
104 preflight(self, requested, token_parent, requested_parent)
105 .map_err(RequestedContentError::Request)?;
106 let token = match resolve(self, provider, token_parent, ImprintOperand::Token)
107 .map_err(RequestedContentError::Request)?
108 {
109 Resolved::Ready(identity) => identity,
110 Resolved::Unusable(reason) => {
111 return Ok((
112 reason,
113 RequestAgreement::Unusable {
114 operand: ImprintOperand::Token,
115 reason,
116 },
117 ));
118 }
119 };
120 let agreement = compare_resolved(
121 self,
122 requested,
123 provider,
124 token_parent,
125 requested_parent,
126 &token,
127 )
128 .map_err(RequestedContentError::Request)?;
129 let content = self
130 .compute_input(provider, token_parent, covered, token)
131 .map_err(RequestedContentError::Content)?;
132 Ok((content, agreement))
133 }
134 pub fn matches_request<P: AsnDigest<'a>>(
149 &self,
150 requested: &MessageImprint<'a>,
151 provider: &'a P,
152 token_parent: &Reader<'a>,
153 requested_parent: &Reader<'a>,
154 ) -> Result<RequestAgreement, RequestImprintError<P::Error>> {
155 preflight(self, requested, token_parent, requested_parent)?;
156 let token = match resolve(self, provider, token_parent, ImprintOperand::Token)? {
157 Resolved::Ready(identity) => identity,
158 Resolved::Unusable(reason) => {
159 return Ok(RequestAgreement::Unusable {
160 operand: ImprintOperand::Token,
161 reason,
162 });
163 }
164 };
165 compare_resolved(
166 self,
167 requested,
168 provider,
169 token_parent,
170 requested_parent,
171 &token,
172 )
173 }
174}
175
176fn preflight<E>(
177 token: &MessageImprint<'_>,
178 requested: &MessageImprint<'_>,
179 token_parent: &Reader<'_>,
180 requested_parent: &Reader<'_>,
181) -> Result<(), RequestImprintError<E>> {
182 for (operand, imprint, parent) in [
184 (ImprintOperand::Token, token, token_parent),
185 (ImprintOperand::Requested, requested, requested_parent),
186 ] {
187 imprint
188 .require_session(parent)
189 .map_err(|source| RequestImprintError::Processing { operand, source })?;
190 }
191 Ok(())
192}
193
194fn compare_resolved<'a, P: AsnDigest<'a>>(
195 token_imprint: &MessageImprint<'a>,
196 requested: &MessageImprint<'a>,
197 provider: &'a P,
198 token_parent: &Reader<'a>,
199 requested_parent: &Reader<'a>,
200 token: &P::Identity,
201) -> Result<RequestAgreement, RequestImprintError<P::Error>> {
202 let asked = match resolve(
203 requested,
204 provider,
205 requested_parent,
206 ImprintOperand::Requested,
207 )? {
208 Resolved::Ready(identity) => identity,
209 Resolved::Unusable(reason) => {
210 return Ok(RequestAgreement::Unusable {
211 operand: ImprintOperand::Requested,
212 reason,
213 });
214 }
215 };
216 let execution = token_parent.execution();
217 if provider
218 .compare(token, &asked, &execution)
219 .map_err(|source| RequestImprintError::Callback {
220 operand: ImprintOperand::Token,
221 span: token_imprint.span(),
222 source,
223 })?
224 != Ordering::Equal
225 {
226 return Ok(RequestAgreement::AlgorithmDiffers);
227 }
228 let matches = token_imprint
229 .hashed()
230 .same_value(
231 requested.hashed(),
232 token_parent,
233 "tstInfo.messageImprint.hashedMessage",
234 token_imprint.hashed().span().start,
235 )
236 .map_err(|source| RequestImprintError::Processing {
237 operand: ImprintOperand::Token,
238 source,
239 })?;
240 Ok(if matches {
241 RequestAgreement::Matches
242 } else {
243 RequestAgreement::HashDiffers
244 })
245}
246
247fn resolve<'a, P: AsnDigest<'a>>(
248 imprint: &MessageImprint<'a>,
249 provider: &'a P,
250 parent: &Reader<'a>,
251 operand: ImprintOperand,
252) -> Result<Resolved<P::Identity>, RequestImprintError<P::Error>> {
253 imprint
254 .resolve(provider, parent)
255 .map_err(|source| RequestImprintError::Processing { operand, source })
256}