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