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