1use crate::binding::{self, Binding, Protection, Scope};
4use crate::provider::{DigestAlgorithm, Resolution, SignatureMode, SignatureProvider};
5use crate::signer::SignerInfo;
6use crate::{Error, ErrorCode};
7use core::cmp::Ordering;
8use structured_asn1::Reader;
9use structured_asn1::memory::Work;
10use structured_pkix::path::WorkingKey;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum Part {
15 Digest,
17 Signature,
19 ProtectedDigest,
21 ProtectedSignature,
23 DigestComparison,
25 SignatureComparison,
27}
28
29#[derive(Debug)]
31pub enum PrepareError<E> {
32 Processing(Error),
34 Callback {
36 part: Part,
38 source: E,
40 },
41}
42
43pub enum Preparation<'a, P: SignatureProvider<'a>> {
45 Ready(ResolvedSigner<'a, P>),
47 Unsupported(Part),
49 Malformed(Error),
51}
52
53#[derive(Debug)]
56pub enum ResolvedBinding<'a> {
57 Direct,
59 Attributes {
61 digest: &'a [u8],
63 digest_span: structured_asn1::Span,
65 },
66}
67
68pub struct ResolvedSigner<'a, P: SignatureProvider<'a>> {
70 provider: &'a P,
71 signer: &'a SignerInfo<'a>,
72 key: WorkingKey<'a>,
73 binding: ResolvedBinding<'a>,
74 digest: P::Identity,
75 signature: SignatureMode<P::SignatureIdentity>,
76}
77
78impl<'a, P: SignatureProvider<'a>> ResolvedSigner<'a, P> {
79 pub(crate) fn into_parts(self) -> ResolvedParts<'a, P> {
80 ResolvedParts {
81 signer: self.signer,
82 key: self.key,
83 binding: self.binding,
84 digest: self.digest,
85 signature: self.signature,
86 }
87 }
88 #[must_use]
90 pub fn provider(&self) -> &'a P {
91 self.provider
92 }
93 #[must_use]
95 pub fn signer(&self) -> &'a SignerInfo<'a> {
96 self.signer
97 }
98 #[must_use]
100 pub fn key(&self) -> WorkingKey<'a> {
101 self.key
102 }
103 #[must_use]
105 pub fn binding(&self) -> &ResolvedBinding<'a> {
106 &self.binding
107 }
108 #[must_use]
110 pub fn digest(&self) -> &P::Identity {
111 &self.digest
112 }
113 #[must_use]
115 pub fn signature(&self) -> &SignatureMode<P::SignatureIdentity> {
116 &self.signature
117 }
118
119 pub fn same_signer_value(
128 &self,
129 other: &Self,
130 parent: &Reader<'_>,
131 ) -> Result<bool, PrepareError<P::Error>> {
132 if !core::ptr::eq(self.provider, other.provider) {
133 return Err(PrepareError::Processing(Error::schema(
134 ErrorCode::ProviderMismatch,
135 "signedData.signerInfos",
136 other.signer.span().start,
137 )));
138 }
139 if !self
140 .signer
141 .same_fields(other.signer, parent)
142 .map_err(PrepareError::Processing)?
143 {
144 return Ok(false);
145 }
146 let execution = parent.execution();
147 let digest = self
148 .provider
149 .compare_digest(&self.digest, &other.digest, &execution)
150 .map_err(|source| PrepareError::Callback {
151 part: Part::DigestComparison,
152 source,
153 })?;
154 if digest != Ordering::Equal {
155 return Ok(false);
156 }
157 let ((SignatureMode::Raw(left), SignatureMode::Raw(right))
158 | (SignatureMode::Prehashed(left), SignatureMode::Prehashed(right))) =
159 (&self.signature, &other.signature)
160 else {
161 return Ok(false);
162 };
163 self.provider
164 .compare_signature(left, right, &execution)
165 .map(|order| order == Ordering::Equal)
166 .map_err(|source| PrepareError::Callback {
167 part: Part::SignatureComparison,
168 source,
169 })
170 }
171}
172
173pub(crate) struct ResolvedParts<'a, P: SignatureProvider<'a>> {
174 pub signer: &'a SignerInfo<'a>,
175 pub key: WorkingKey<'a>,
176 pub binding: ResolvedBinding<'a>,
177 pub digest: P::Identity,
178 pub signature: SignatureMode<P::SignatureIdentity>,
179}
180
181pub fn resolve<'a, P: SignatureProvider<'a>>(
192 provider: &'a P,
193 signer: &'a SignerInfo<'a>,
194 key: WorkingKey<'a>,
195 parent: &Reader<'a>,
196 scope: Scope<'a>,
197) -> Result<Preparation<'a, P>, PrepareError<P::Error>> {
198 crate::provider::require_instance(provider, "signerInfo", signer.span().start)
199 .map_err(PrepareError::Processing)?;
200 let binding = match binding::inspect(signer, parent, scope) {
201 Ok(binding) => binding,
202 Err(error) if error.is_terminal() => return Err(PrepareError::Processing(error)),
203 Err(error) => return Ok(Preparation::Malformed(error)),
204 };
205 let identifier = signer.digest_algorithm();
206 let digest = match provider
207 .resolve_digest(
208 DigestAlgorithm::Written(identifier),
209 identifier.encoding(),
210 parent,
211 )
212 .map_err(|source| PrepareError::Callback {
213 part: Part::Digest,
214 source,
215 })? {
216 Resolution::Supported(digest) => digest,
217 Resolution::Unsupported => return Ok(Preparation::Unsupported(Part::Digest)),
218 Resolution::Malformed => {
219 return Ok(Preparation::Malformed(Error::schema(
220 ErrorCode::AlgorithmSyntax,
221 "signerInfo.digestAlgorithm",
222 identifier.offset(),
223 )));
224 }
225 };
226 if let Binding::Attributes {
227 digest: expected,
228 digest_span,
229 ..
230 } = &binding
231 && let Some(width) = provider.digest_width(&digest)
232 && expected.len() != width
233 {
234 return Ok(Preparation::Malformed(Error::schema(
235 ErrorCode::DigestWidth,
236 "signerInfo.signedAttrs.messageDigest",
237 digest_span.start,
238 )));
239 }
240 let identifier = signer.signature_algorithm();
241 let signature = match provider
242 .resolve_signature(identifier, &digest, key, identifier.encoding(), parent)
243 .map_err(|source| PrepareError::Callback {
244 part: Part::Signature,
245 source,
246 })? {
247 Resolution::Supported(signature) => signature,
248 Resolution::Unsupported => return Ok(Preparation::Unsupported(Part::Signature)),
249 Resolution::Malformed => {
250 return Ok(Preparation::Malformed(Error::schema(
251 ErrorCode::AlgorithmSyntax,
252 "signerInfo.signatureAlgorithm",
253 identifier.offset(),
254 )));
255 }
256 };
257 if let Binding::Attributes {
258 protection: Some(protection),
259 ..
260 } = &binding
261 {
262 match protected(provider, *protection, &digest, &signature, key, parent)? {
263 ProtectionStatus::Matching => {}
264 ProtectionStatus::Unsupported(part) => return Ok(Preparation::Unsupported(part)),
265 ProtectionStatus::Malformed(error) => return Ok(Preparation::Malformed(error)),
266 }
267 }
268 let binding = match binding {
269 Binding::Direct => ResolvedBinding::Direct,
270 Binding::Attributes {
271 digest,
272 digest_span,
273 ..
274 } => ResolvedBinding::Attributes {
275 digest,
276 digest_span,
277 },
278 };
279 Ok(Preparation::Ready(ResolvedSigner {
280 provider,
281 signer,
282 key,
283 binding,
284 digest,
285 signature,
286 }))
287}
288
289enum ProtectionStatus {
290 Matching,
291 Unsupported(Part),
292 Malformed(Error),
293}
294
295fn protected<'a, P: SignatureProvider<'a>>(
296 provider: &'a P,
297 protection: Protection<'a>,
298 digest: &P::Identity,
299 signature: &SignatureMode<P::SignatureIdentity>,
300 key: WorkingKey<'a>,
301 parent: &Reader<'a>,
302) -> Result<ProtectionStatus, PrepareError<P::Error>> {
303 const FIELD: &str = "signerInfo.signedAttrs.cmsAlgorithmProtection";
304 let identifier = protection.digest();
305 let protected_digest = match provider
306 .resolve_digest(
307 DigestAlgorithm::Written(identifier),
308 identifier.encoding(),
309 parent,
310 )
311 .map_err(|source| PrepareError::Callback {
312 part: Part::ProtectedDigest,
313 source,
314 })? {
315 Resolution::Supported(digest) => digest,
316 Resolution::Unsupported => return Ok(ProtectionStatus::Unsupported(Part::ProtectedDigest)),
317 Resolution::Malformed => {
318 return Ok(ProtectionStatus::Malformed(Error::schema(
319 ErrorCode::AlgorithmSyntax,
320 FIELD,
321 identifier.offset(),
322 )));
323 }
324 };
325 if provider
326 .compare_digest(digest, &protected_digest, &parent.execution())
327 .map_err(|source| PrepareError::Callback {
328 part: Part::DigestComparison,
329 source,
330 })?
331 != Ordering::Equal
332 {
333 return Ok(ProtectionStatus::Malformed(Error::schema(
334 ErrorCode::AlgorithmProtection,
335 FIELD,
336 identifier.offset(),
337 )));
338 }
339 let identifier = protection.signature();
340 let protected_signature = match provider
341 .resolve_signature(
342 identifier,
343 &protected_digest,
344 key,
345 identifier.encoding(),
346 parent,
347 )
348 .map_err(|source| PrepareError::Callback {
349 part: Part::ProtectedSignature,
350 source,
351 })? {
352 Resolution::Supported(signature) => signature,
353 Resolution::Unsupported => {
354 return Ok(ProtectionStatus::Unsupported(Part::ProtectedSignature));
355 }
356 Resolution::Malformed => {
357 return Ok(ProtectionStatus::Malformed(Error::schema(
358 ErrorCode::AlgorithmSyntax,
359 FIELD,
360 identifier.offset(),
361 )));
362 }
363 };
364 parent.execution().charge_work(1).map_err(|reason| {
365 PrepareError::Processing(Error::resource(reason, FIELD, identifier.offset()))
366 })?;
367 let same = match (signature, &protected_signature) {
368 (SignatureMode::Raw(left), SignatureMode::Raw(right))
369 | (SignatureMode::Prehashed(left), SignatureMode::Prehashed(right)) => {
370 provider
371 .compare_signature(left, right, &parent.execution())
372 .map_err(|source| PrepareError::Callback {
373 part: Part::SignatureComparison,
374 source,
375 })?
376 == Ordering::Equal
377 }
378 _ => false,
379 };
380 if !same {
381 return Ok(ProtectionStatus::Malformed(Error::schema(
382 ErrorCode::AlgorithmProtection,
383 FIELD,
384 identifier.offset(),
385 )));
386 }
387 Ok(ProtectionStatus::Matching)
388}