1use 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 async fn check_requested_input_async<P, I>(
71 &self,
72 requested: &MessageImprint<'a>,
73 provider: &'a P,
74 parents: (&Reader<'a>, &Reader<'a>),
75 covered: &mut I,
76 ) -> Result<(ImprintAgreement, RequestAgreement), RequestedContentError<I::Error, P::Error>>
77 where
78 P: AsnDigest<'a>,
79 I: super::AsyncComputedInput<P, P::Error>,
80 {
81 let (token_parent, requested_parent) = parents;
82 preflight(self, requested, token_parent, requested_parent)
83 .map_err(RequestedContentError::Request)?;
84 let token = match resolve(self, provider, token_parent, ImprintOperand::Token)
85 .map_err(RequestedContentError::Request)?
86 {
87 Resolved::Ready(identity) => identity,
88 Resolved::Unusable(reason) => {
89 return Ok((
90 reason,
91 RequestAgreement::Unusable {
92 operand: ImprintOperand::Token,
93 reason,
94 },
95 ));
96 }
97 };
98 let agreement = compare_resolved(
99 self,
100 requested,
101 provider,
102 token_parent,
103 requested_parent,
104 &token,
105 )
106 .map_err(RequestedContentError::Request)?;
107 let content = super::computed::compute_async(self, provider, token_parent, covered, token)
108 .await
109 .map_err(RequestedContentError::Content)?;
110 Ok((content, agreement))
111 }
112 pub fn check_requested_content<P: AsnDigest<'a>, S: crate::stream::Source>(
118 &self,
119 requested: &MessageImprint<'a>,
120 provider: &'a P,
121 parents: (&Reader<'a>, &Reader<'a>),
122 covered: &mut S,
123 ) -> Result<(ImprintAgreement, RequestAgreement), RequestedContentError<S::Error, P::Error>>
124 {
125 self.check_requested_input(
126 requested,
127 provider,
128 parents,
129 &mut super::RawInput::new(covered),
130 )
131 }
132
133 pub fn check_requested_input<P, I>(
137 &self,
138 requested: &MessageImprint<'a>,
139 provider: &'a P,
140 parents: (&Reader<'a>, &Reader<'a>),
141 covered: &mut I,
142 ) -> Result<(ImprintAgreement, RequestAgreement), RequestedContentError<I::Error, P::Error>>
143 where
144 P: AsnDigest<'a>,
145 I: super::ComputedInput<P, P::Error>,
146 {
147 let (token_parent, requested_parent) = parents;
148 preflight(self, requested, token_parent, requested_parent)
149 .map_err(RequestedContentError::Request)?;
150 let token = match resolve(self, provider, token_parent, ImprintOperand::Token)
151 .map_err(RequestedContentError::Request)?
152 {
153 Resolved::Ready(identity) => identity,
154 Resolved::Unusable(reason) => {
155 return Ok((
156 reason,
157 RequestAgreement::Unusable {
158 operand: ImprintOperand::Token,
159 reason,
160 },
161 ));
162 }
163 };
164 let agreement = compare_resolved(
165 self,
166 requested,
167 provider,
168 token_parent,
169 requested_parent,
170 &token,
171 )
172 .map_err(RequestedContentError::Request)?;
173 let content = self
174 .compute_input(provider, token_parent, covered, token)
175 .map_err(RequestedContentError::Content)?;
176 Ok((content, agreement))
177 }
178 pub fn matches_request<P: AsnDigest<'a>>(
193 &self,
194 requested: &MessageImprint<'a>,
195 provider: &'a P,
196 token_parent: &Reader<'a>,
197 requested_parent: &Reader<'a>,
198 ) -> Result<RequestAgreement, RequestImprintError<P::Error>> {
199 preflight(self, requested, token_parent, requested_parent)?;
200 let token = match resolve(self, provider, token_parent, ImprintOperand::Token)? {
201 Resolved::Ready(identity) => identity,
202 Resolved::Unusable(reason) => {
203 return Ok(RequestAgreement::Unusable {
204 operand: ImprintOperand::Token,
205 reason,
206 });
207 }
208 };
209 compare_resolved(
210 self,
211 requested,
212 provider,
213 token_parent,
214 requested_parent,
215 &token,
216 )
217 }
218}
219
220fn preflight<E>(
221 token: &MessageImprint<'_>,
222 requested: &MessageImprint<'_>,
223 token_parent: &Reader<'_>,
224 requested_parent: &Reader<'_>,
225) -> Result<(), RequestImprintError<E>> {
226 for (operand, imprint, parent) in [
228 (ImprintOperand::Token, token, token_parent),
229 (ImprintOperand::Requested, requested, requested_parent),
230 ] {
231 imprint
232 .require_session(parent)
233 .map_err(|source| RequestImprintError::Processing { operand, source })?;
234 }
235 Ok(())
236}
237
238fn compare_resolved<'a, P: AsnDigest<'a>>(
239 token_imprint: &MessageImprint<'a>,
240 requested: &MessageImprint<'a>,
241 provider: &'a P,
242 token_parent: &Reader<'a>,
243 requested_parent: &Reader<'a>,
244 token: &P::Identity,
245) -> Result<RequestAgreement, RequestImprintError<P::Error>> {
246 let asked = match resolve(
247 requested,
248 provider,
249 requested_parent,
250 ImprintOperand::Requested,
251 )? {
252 Resolved::Ready(identity) => identity,
253 Resolved::Unusable(reason) => {
254 return Ok(RequestAgreement::Unusable {
255 operand: ImprintOperand::Requested,
256 reason,
257 });
258 }
259 };
260 let execution = token_parent.execution();
261 if provider
262 .compare(token, &asked, &execution)
263 .map_err(|source| RequestImprintError::Callback {
264 operand: ImprintOperand::Token,
265 span: token_imprint.span(),
266 source,
267 })?
268 != Ordering::Equal
269 {
270 return Ok(RequestAgreement::AlgorithmDiffers);
271 }
272 let matches = token_imprint
273 .hashed()
274 .same_value(
275 requested.hashed(),
276 token_parent,
277 "tstInfo.messageImprint.hashedMessage",
278 token_imprint.hashed().span().start,
279 )
280 .map_err(|source| RequestImprintError::Processing {
281 operand: ImprintOperand::Token,
282 source,
283 })?;
284 Ok(if matches {
285 RequestAgreement::Matches
286 } else {
287 RequestAgreement::HashDiffers
288 })
289}
290
291fn resolve<'a, P: AsnDigest<'a>>(
292 imprint: &MessageImprint<'a>,
293 provider: &'a P,
294 parent: &Reader<'a>,
295 operand: ImprintOperand,
296) -> Result<Resolved<P::Identity>, RequestImprintError<P::Error>> {
297 imprint
298 .resolve(provider, parent)
299 .map_err(|source| RequestImprintError::Processing { operand, source })
300}