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 signer
201 .require_session(parent, "signerInfo")
202 .map_err(PrepareError::Processing)?;
203 let identifiers = match algorithms(signer) {
207 Ok(identifiers) => identifiers,
208 Err(error) => return Ok(Preparation::Malformed(error)),
209 };
210 let binding = match binding::inspect(signer, parent, scope) {
211 Ok(binding) => binding,
212 Err(error) if error.is_terminal() => return Err(PrepareError::Processing(error)),
213 Err(error) => return Ok(Preparation::Malformed(error)),
214 };
215 let identifier = identifiers.0;
216 let digest = match provider
217 .resolve_digest(
218 DigestAlgorithm::Written(identifier),
219 identifier.encoding(),
220 parent,
221 )
222 .map_err(|source| PrepareError::Callback {
223 part: Part::Digest,
224 source,
225 })? {
226 Resolution::Supported(digest) => digest,
227 Resolution::Unsupported => return Ok(Preparation::Unsupported(Part::Digest)),
228 Resolution::Malformed => {
229 return Ok(Preparation::Malformed(Error::schema(
230 ErrorCode::AlgorithmSyntax,
231 "signerInfo.digestAlgorithm",
232 identifier.offset(),
233 )));
234 }
235 };
236 if let Binding::Attributes {
237 digest: expected,
238 digest_span,
239 ..
240 } = &binding
241 && let Some(width) = provider.digest_width(&digest)
242 && expected.len() != width
243 {
244 return Ok(Preparation::Malformed(Error::schema(
245 ErrorCode::DigestWidth,
246 "signerInfo.signedAttrs.messageDigest",
247 digest_span.start,
248 )));
249 }
250 let identifier = identifiers.1;
251 let signature = match provider
252 .resolve_signature(identifier, &digest, key, identifier.encoding(), parent)
253 .map_err(|source| PrepareError::Callback {
254 part: Part::Signature,
255 source,
256 })? {
257 Resolution::Supported(signature) => signature,
258 Resolution::Unsupported => return Ok(Preparation::Unsupported(Part::Signature)),
259 Resolution::Malformed => {
260 return Ok(Preparation::Malformed(Error::schema(
261 ErrorCode::AlgorithmSyntax,
262 "signerInfo.signatureAlgorithm",
263 identifier.offset(),
264 )));
265 }
266 };
267 if let Binding::Attributes {
268 protection: Some(protection),
269 ..
270 } = &binding
271 {
272 match protected(provider, *protection, &digest, &signature, key, parent)? {
273 ProtectionStatus::Matching => {}
274 ProtectionStatus::Unsupported(part) => return Ok(Preparation::Unsupported(part)),
275 ProtectionStatus::Malformed(error) => return Ok(Preparation::Malformed(error)),
276 }
277 }
278 let binding = match binding {
279 Binding::Direct => ResolvedBinding::Direct,
280 Binding::Attributes {
281 digest,
282 digest_span,
283 ..
284 } => ResolvedBinding::Attributes {
285 digest,
286 digest_span,
287 },
288 };
289 Ok(Preparation::Ready(ResolvedSigner {
290 provider,
291 signer,
292 key,
293 binding,
294 digest,
295 signature,
296 }))
297}
298
299enum ProtectionStatus {
300 Matching,
301 Unsupported(Part),
302 Malformed(Error),
303}
304
305fn algorithms<'a>(
306 signer: &SignerInfo<'a>,
307) -> Result<
308 (
309 structured_pkix::AlgorithmIdentifier<'a>,
310 structured_pkix::AlgorithmIdentifier<'a>,
311 ),
312 Error,
313> {
314 let digest = signer
315 .digest_algorithm()
316 .require_identifier()
317 .map_err(Error::pkix)?;
318 let signature = signer
319 .signature_algorithm()
320 .require_identifier()
321 .map_err(Error::pkix)?;
322 Ok((digest, signature))
323}
324
325fn protected<'a, P: SignatureProvider<'a>>(
326 provider: &'a P,
327 protection: Protection<'a>,
328 digest: &P::Identity,
329 signature: &SignatureMode<P::SignatureIdentity>,
330 key: WorkingKey<'a>,
331 parent: &Reader<'a>,
332) -> Result<ProtectionStatus, PrepareError<P::Error>> {
333 const FIELD: &str = "signerInfo.signedAttrs.cmsAlgorithmProtection";
334 let identifier = protection.digest();
335 let protected_digest = match provider
336 .resolve_digest(
337 DigestAlgorithm::Written(identifier),
338 identifier.encoding(),
339 parent,
340 )
341 .map_err(|source| PrepareError::Callback {
342 part: Part::ProtectedDigest,
343 source,
344 })? {
345 Resolution::Supported(digest) => digest,
346 Resolution::Unsupported => return Ok(ProtectionStatus::Unsupported(Part::ProtectedDigest)),
347 Resolution::Malformed => {
348 return Ok(ProtectionStatus::Malformed(Error::schema(
349 ErrorCode::AlgorithmSyntax,
350 FIELD,
351 identifier.offset(),
352 )));
353 }
354 };
355 if provider
356 .compare_digest(digest, &protected_digest, &parent.execution())
357 .map_err(|source| PrepareError::Callback {
358 part: Part::DigestComparison,
359 source,
360 })?
361 != Ordering::Equal
362 {
363 return Ok(ProtectionStatus::Malformed(Error::schema(
364 ErrorCode::AlgorithmProtection,
365 FIELD,
366 identifier.offset(),
367 )));
368 }
369 let identifier = protection.signature();
370 let protected_signature = match provider
371 .resolve_signature(
372 identifier,
373 &protected_digest,
374 key,
375 identifier.encoding(),
376 parent,
377 )
378 .map_err(|source| PrepareError::Callback {
379 part: Part::ProtectedSignature,
380 source,
381 })? {
382 Resolution::Supported(signature) => signature,
383 Resolution::Unsupported => {
384 return Ok(ProtectionStatus::Unsupported(Part::ProtectedSignature));
385 }
386 Resolution::Malformed => {
387 return Ok(ProtectionStatus::Malformed(Error::schema(
388 ErrorCode::AlgorithmSyntax,
389 FIELD,
390 identifier.offset(),
391 )));
392 }
393 };
394 parent.execution().charge_work(1).map_err(|reason| {
395 PrepareError::Processing(Error::resource(reason, FIELD, identifier.offset()))
396 })?;
397 let same = match (signature, &protected_signature) {
398 (SignatureMode::Raw(left), SignatureMode::Raw(right))
399 | (SignatureMode::Prehashed(left), SignatureMode::Prehashed(right)) => {
400 provider
401 .compare_signature(left, right, &parent.execution())
402 .map_err(|source| PrepareError::Callback {
403 part: Part::SignatureComparison,
404 source,
405 })?
406 == Ordering::Equal
407 }
408 _ => false,
409 };
410 if !same {
411 return Ok(ProtectionStatus::Malformed(Error::schema(
412 ErrorCode::AlgorithmProtection,
413 FIELD,
414 identifier.offset(),
415 )));
416 }
417 Ok(ProtectionStatus::Matching)
418}