1use std::{collections::HashMap, fmt, time::SystemTime};
4
5use crypto_bigint::BoxedUint;
6use dsa::pkcs8::EncodePublicKey as DsaEncodePublicKey;
7use hmac::{KeyInit, Mac};
8use rsa::pkcs8::DecodePublicKey as _;
9use x509_parser::{
10 prelude::{FromDer, X509Certificate},
11 public_key::PublicKey,
12 x509::SubjectPublicKeyInfo,
13};
14use zeroize::Zeroizing;
15
16use super::signature::{
17 decode_dsa_verifying_key, signature_value_matches_spki,
18 signature_value_matches_spki_with_encoding, validate_dsa_signature_spki_with_minimum,
19 validate_ec_public_key_encoding, validate_rsa_signature_spki_with_minimum,
20 verify_dsa_signature_spki_primitive, verify_dsa_signature_spki_with_minimum,
21 verify_rsa_signature_spki_primitive, verify_rsa_signature_spki_with_minimum,
22};
23use super::{
24 DsigError, KeyInfo, KeyInfoSource, KeyResolver, KeyValueInfo, SignatureAlgorithm, VerifyingKey,
25 X509ChainOptions, X509DataInfo,
26 parse::{
27 EC_P256_OID, EC_P384_OID, EC_P521_OID, ParseError, X509ChainBuildError,
28 build_x509_certificate_paths_to_selector_targets,
29 build_x509_certificate_paths_to_trusted_prefix, distinguished_names_equal,
30 parse_x509_certificate, x509_certificate_matches_any_selector,
31 x509_data_has_lookup_identifiers, x509_selector_categories_match_chain,
32 },
33 verify_ecdsa_signature_spki, verify_ecdsa_signature_spki_with_encoding,
34 x509::verify_x509_certificate_chain_with_provider_and_crls,
35};
36use super::{ResolvedVerificationKey, TrustedPublicKey, X509TrustEvidence};
37
38#[derive(Clone)]
45pub struct HmacVerificationKey {
46 secret: Zeroizing<Vec<u8>>,
47}
48
49impl fmt::Debug for HmacVerificationKey {
50 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
51 formatter
52 .debug_struct("HmacVerificationKey")
53 .finish_non_exhaustive()
54 }
55}
56
57impl HmacVerificationKey {
58 pub fn new(secret: impl Into<Vec<u8>>) -> Result<Self, KeyResolutionError> {
60 let secret = secret.into();
61 if secret.is_empty() {
62 return Err(KeyResolutionError::InvalidPublicKey);
63 }
64 Ok(Self {
65 secret: Zeroizing::new(secret),
66 })
67 }
68
69 fn validate_output(
70 &self,
71 policy: crate::policy::HmacPolicy,
72 algorithm: SignatureAlgorithm,
73 signature_value: &[u8],
74 ) -> Result<(), DsigError> {
75 if algorithm.hmac_output_bits().is_none() {
76 return Err(KeyResolutionError::AlgorithmMismatch.into());
77 }
78 policy.validate_key_bytes(self.secret.len())?;
79 policy.validate_output(algorithm, signature_value.len().saturating_mul(8))?;
80 Ok(())
81 }
82
83 fn verify_with_hmac_policy(
84 &self,
85 policy: crate::policy::HmacPolicy,
86 algorithm: SignatureAlgorithm,
87 signed_data: &[u8],
88 signature_value: &[u8],
89 ) -> Result<bool, DsigError> {
90 self.validate_output(policy, algorithm, signature_value)?;
91 macro_rules! verify_hmac {
92 ($digest:ty) => {{
93 let mut mac = hmac::Hmac::<$digest>::new_from_slice(&self.secret)
94 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
95 mac.update(signed_data);
96 let expected = mac.finalize().into_bytes();
97 subtle::ConstantTimeEq::ct_eq(&expected[..signature_value.len()], signature_value)
98 .into()
99 }};
100 }
101 Ok(match algorithm {
102 SignatureAlgorithm::HmacSha1 => verify_hmac!(sha1::Sha1),
103 SignatureAlgorithm::HmacSha224 => verify_hmac!(sha2::Sha224),
104 SignatureAlgorithm::HmacSha256 => verify_hmac!(sha2::Sha256),
105 SignatureAlgorithm::HmacSha384 => verify_hmac!(sha2::Sha384),
106 SignatureAlgorithm::HmacSha512 => verify_hmac!(sha2::Sha512),
107 _ => return Err(KeyResolutionError::AlgorithmMismatch.into()),
108 })
109 }
110}
111
112impl VerifyingKey for HmacVerificationKey {
113 fn validate_policy(&self, policy: &crate::policy::VerificationPolicy) -> Result<(), DsigError> {
114 policy
115 .hmac
116 .validate_key_bytes(self.secret.len())
117 .map_err(Into::into)
118 }
119
120 fn validate_signature_value(
121 &self,
122 algorithm: SignatureAlgorithm,
123 signature_value: &[u8],
124 ) -> Result<bool, DsigError> {
125 self.validate_output(
126 crate::policy::HmacPolicy::default(),
127 algorithm,
128 signature_value,
129 )?;
130 Ok(true)
131 }
132
133 fn validate_signature_value_with_policy(
134 &self,
135 policy: &crate::policy::VerificationPolicy,
136 algorithm: SignatureAlgorithm,
137 signature_value: &[u8],
138 ) -> Result<bool, DsigError> {
139 self.validate_output(policy.hmac, algorithm, signature_value)?;
140 Ok(true)
141 }
142
143 fn verify(
144 &self,
145 algorithm: SignatureAlgorithm,
146 signed_data: &[u8],
147 signature_value: &[u8],
148 ) -> Result<bool, DsigError> {
149 self.verify_with_hmac_policy(
150 crate::policy::HmacPolicy::default(),
151 algorithm,
152 signed_data,
153 signature_value,
154 )
155 }
156
157 fn verify_with_policy(
158 &self,
159 policy: &crate::policy::VerificationPolicy,
160 algorithm: SignatureAlgorithm,
161 signed_data: &[u8],
162 signature_value: &[u8],
163 ) -> Result<bool, DsigError> {
164 self.verify_with_hmac_policy(policy.hmac, algorithm, signed_data, signature_value)
165 }
166}
167
168pub type HmacSha1VerificationKey = HmacVerificationKey;
170
171#[derive(Debug, Clone, PartialEq, Eq)]
173pub struct VerificationKey {
174 pub algorithm: SignatureAlgorithm,
176 pub public_key_bytes: Vec<u8>,
178 pub certificate_der: Option<Vec<u8>>,
180 pub name: Option<String>,
182}
183
184impl VerifyingKey for VerificationKey {
185 fn verification_spki(&self, algorithm: SignatureAlgorithm) -> Result<Option<&[u8]>, DsigError> {
186 if algorithm != self.algorithm {
187 return Err(KeyResolutionError::AlgorithmMismatch.into());
188 }
189 Ok(Some(&self.public_key_bytes))
190 }
191 fn verify_with_context(
192 &self,
193 algorithm: SignatureAlgorithm,
194 context: &super::SignatureContext,
195 data: &[u8],
196 signature: &[u8],
197 ) -> Result<bool, DsigError> {
198 if algorithm != self.algorithm {
199 return Err(KeyResolutionError::AlgorithmMismatch.into());
200 }
201 if algorithm.eddsa_signature_len().is_some()
202 || matches!(algorithm, SignatureAlgorithm::PostQuantum(_))
203 {
204 return super::modern::verify_with_context(
205 algorithm,
206 &self.public_key_bytes,
207 context,
208 data,
209 signature,
210 )
211 .map_err(DsigError::Crypto);
212 }
213 if !context.as_bytes().is_empty() {
214 return Err(KeyResolutionError::AlgorithmMismatch.into());
215 }
216 self.verify(algorithm, data, signature)
217 }
218 fn validate_policy(&self, policy: &crate::policy::VerificationPolicy) -> Result<(), DsigError> {
219 let result = match self.algorithm {
220 SignatureAlgorithm::Ed25519
221 | SignatureAlgorithm::Ed25519Ctx
222 | SignatureAlgorithm::Ed25519Ph
223 | SignatureAlgorithm::Ed448
224 | SignatureAlgorithm::Ed448Ph
225 | SignatureAlgorithm::PostQuantum(_) => {
226 super::modern::validate_public_key(self.algorithm, &self.public_key_bytes)
227 }
228 SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256 => {
229 validate_dsa_signature_spki_with_minimum(
230 &self.public_key_bytes,
231 policy.key_trust.dsa_keys.minimum_modulus_bits,
232 )
233 }
234 SignatureAlgorithm::RsaSha1
235 | SignatureAlgorithm::RsaSha224
236 | SignatureAlgorithm::RsaSha256
237 | SignatureAlgorithm::RsaSha384
238 | SignatureAlgorithm::RsaSha512 => validate_rsa_signature_spki_with_minimum(
239 self.algorithm,
240 &self.public_key_bytes,
241 policy.key_trust.rsa_keys.minimum_modulus_bits,
242 ),
243 SignatureAlgorithm::HmacSha1
244 | SignatureAlgorithm::HmacSha224
245 | SignatureAlgorithm::HmacSha256
246 | SignatureAlgorithm::HmacSha384
247 | SignatureAlgorithm::HmacSha512
248 | SignatureAlgorithm::EcdsaSha1
249 | SignatureAlgorithm::EcdsaSha224
250 | SignatureAlgorithm::EcdsaSha256
251 | SignatureAlgorithm::EcdsaSha384
252 | SignatureAlgorithm::EcdsaSha512
253 | SignatureAlgorithm::EcdsaSha3_224
254 | SignatureAlgorithm::EcdsaSha3_256
255 | SignatureAlgorithm::EcdsaSha3_384
256 | SignatureAlgorithm::EcdsaSha3_512 => Ok(()),
257 };
258 result.map_err(DsigError::Crypto)
259 }
260
261 fn validate_signature_value(
262 &self,
263 algorithm: SignatureAlgorithm,
264 signature_value: &[u8],
265 ) -> Result<bool, DsigError> {
266 if algorithm != self.algorithm {
267 return Err(KeyResolutionError::AlgorithmMismatch.into());
268 }
269 signature_value_matches_spki(algorithm, &self.public_key_bytes, signature_value)
270 .map_err(DsigError::Crypto)
271 }
272
273 fn validate_signature_value_with_policy(
274 &self,
275 policy: &crate::policy::VerificationPolicy,
276 algorithm: SignatureAlgorithm,
277 signature_value: &[u8],
278 ) -> Result<bool, DsigError> {
279 if algorithm != self.algorithm {
280 return Err(KeyResolutionError::AlgorithmMismatch.into());
281 }
282 signature_value_matches_spki_with_encoding(
283 algorithm,
284 &self.public_key_bytes,
285 signature_value,
286 policy.ecdsa_signature_value_encoding,
287 )
288 .map_err(DsigError::Crypto)
289 }
290
291 fn verify(
292 &self,
293 algorithm: SignatureAlgorithm,
294 signed_data: &[u8],
295 signature_value: &[u8],
296 ) -> Result<bool, DsigError> {
297 if algorithm != self.algorithm {
298 return Err(KeyResolutionError::AlgorithmMismatch.into());
299 }
300 let result = match algorithm {
301 SignatureAlgorithm::Ed25519
302 | SignatureAlgorithm::Ed25519Ctx
303 | SignatureAlgorithm::Ed25519Ph
304 | SignatureAlgorithm::Ed448
305 | SignatureAlgorithm::Ed448Ph
306 | SignatureAlgorithm::PostQuantum(_) => super::modern::verify(
307 algorithm,
308 &self.public_key_bytes,
309 signed_data,
310 signature_value,
311 ),
312 SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256 => {
313 verify_dsa_signature_spki_primitive(
314 algorithm,
315 &self.public_key_bytes,
316 signed_data,
317 signature_value,
318 )
319 }
320 SignatureAlgorithm::HmacSha1
321 | SignatureAlgorithm::HmacSha224
322 | SignatureAlgorithm::HmacSha256
323 | SignatureAlgorithm::HmacSha384
324 | SignatureAlgorithm::HmacSha512 => {
325 return Err(KeyResolutionError::AlgorithmMismatch.into());
326 }
327 SignatureAlgorithm::RsaSha1
328 | SignatureAlgorithm::RsaSha224
329 | SignatureAlgorithm::RsaSha256
330 | SignatureAlgorithm::RsaSha384
331 | SignatureAlgorithm::RsaSha512 => verify_rsa_signature_spki_primitive(
332 algorithm,
333 &self.public_key_bytes,
334 signed_data,
335 signature_value,
336 ),
337 SignatureAlgorithm::EcdsaSha1
338 | SignatureAlgorithm::EcdsaSha224
339 | SignatureAlgorithm::EcdsaSha256
340 | SignatureAlgorithm::EcdsaSha384
341 | SignatureAlgorithm::EcdsaSha512
342 | SignatureAlgorithm::EcdsaSha3_224
343 | SignatureAlgorithm::EcdsaSha3_256
344 | SignatureAlgorithm::EcdsaSha3_384
345 | SignatureAlgorithm::EcdsaSha3_512 => verify_ecdsa_signature_spki(
346 algorithm,
347 &self.public_key_bytes,
348 signed_data,
349 signature_value,
350 ),
351 };
352 result.map_err(DsigError::Crypto)
353 }
354
355 fn verify_with_policy(
356 &self,
357 policy: &crate::policy::VerificationPolicy,
358 algorithm: SignatureAlgorithm,
359 signed_data: &[u8],
360 signature_value: &[u8],
361 ) -> Result<bool, DsigError> {
362 if algorithm != self.algorithm {
363 return Err(KeyResolutionError::AlgorithmMismatch.into());
364 }
365 if algorithm.ecdsa_digest().is_some() {
366 return verify_ecdsa_signature_spki_with_encoding(
367 algorithm,
368 &self.public_key_bytes,
369 signed_data,
370 signature_value,
371 policy.ecdsa_signature_value_encoding,
372 )
373 .map_err(DsigError::Crypto);
374 }
375 self.verify(algorithm, signed_data, signature_value)
376 }
377}
378
379struct PolicyBoundVerificationKey {
380 key: VerificationKey,
381 rsa_minimum_bits: usize,
382 dsa_minimum_bits: usize,
383}
384
385impl VerifyingKey for PolicyBoundVerificationKey {
386 fn verification_spki(&self, algorithm: SignatureAlgorithm) -> Result<Option<&[u8]>, DsigError> {
387 if matches!(
389 algorithm,
390 SignatureAlgorithm::RsaSha1
391 | SignatureAlgorithm::RsaSha224
392 | SignatureAlgorithm::RsaSha256
393 | SignatureAlgorithm::RsaSha384
394 | SignatureAlgorithm::RsaSha512
395 ) {
396 validate_rsa_signature_spki_with_minimum(
397 algorithm,
398 &self.key.public_key_bytes,
399 self.rsa_minimum_bits,
400 )
401 .map_err(DsigError::Crypto)?;
402 }
403 self.key.verification_spki(algorithm)
404 }
405 fn verify_with_context(
406 &self,
407 algorithm: SignatureAlgorithm,
408 context: &super::SignatureContext,
409 data: &[u8],
410 signature: &[u8],
411 ) -> Result<bool, DsigError> {
412 if context.as_bytes().is_empty() {
413 return self.verify(algorithm, data, signature);
414 }
415 self.key
416 .verify_with_context(algorithm, context, data, signature)
417 }
418 fn validate_signature_value(
419 &self,
420 algorithm: SignatureAlgorithm,
421 signature_value: &[u8],
422 ) -> Result<bool, DsigError> {
423 self.key
424 .validate_signature_value(algorithm, signature_value)
425 }
426
427 fn validate_signature_value_with_policy(
428 &self,
429 policy: &crate::policy::VerificationPolicy,
430 algorithm: SignatureAlgorithm,
431 signature_value: &[u8],
432 ) -> Result<bool, DsigError> {
433 self.key
434 .validate_signature_value_with_policy(policy, algorithm, signature_value)
435 }
436
437 fn verify(
438 &self,
439 algorithm: SignatureAlgorithm,
440 signed_data: &[u8],
441 signature_value: &[u8],
442 ) -> Result<bool, DsigError> {
443 if algorithm != self.key.algorithm {
444 return Err(KeyResolutionError::AlgorithmMismatch.into());
445 }
446 let result = match algorithm {
447 SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256 => {
448 verify_dsa_signature_spki_with_minimum(
449 algorithm,
450 &self.key.public_key_bytes,
451 signed_data,
452 signature_value,
453 self.dsa_minimum_bits,
454 )
455 }
456 SignatureAlgorithm::RsaSha1
457 | SignatureAlgorithm::RsaSha224
458 | SignatureAlgorithm::RsaSha256
459 | SignatureAlgorithm::RsaSha384
460 | SignatureAlgorithm::RsaSha512 => verify_rsa_signature_spki_with_minimum(
461 algorithm,
462 &self.key.public_key_bytes,
463 signed_data,
464 signature_value,
465 self.rsa_minimum_bits,
466 ),
467 _ => return self.key.verify(algorithm, signed_data, signature_value),
468 };
469 result.map_err(DsigError::Crypto)
470 }
471
472 fn verify_with_policy(
473 &self,
474 policy: &crate::policy::VerificationPolicy,
475 algorithm: SignatureAlgorithm,
476 signed_data: &[u8],
477 signature_value: &[u8],
478 ) -> Result<bool, DsigError> {
479 if algorithm.ecdsa_digest().is_some() {
480 return self
481 .key
482 .verify_with_policy(policy, algorithm, signed_data, signature_value);
483 }
484 self.verify(algorithm, signed_data, signature_value)
485 }
486}
487
488#[derive(Debug, thiserror::Error)]
490#[non_exhaustive]
491pub enum KeyResolutionError {
492 #[error("verification key does not match the signature algorithm")]
494 AlgorithmMismatch,
495 #[error("invalid embedded certificate DER")]
497 InvalidCertificate,
498 #[error("invalid public key DER")]
500 InvalidPublicKey,
501 #[error("X.509 lookup selectors match multiple configured certificates")]
503 AmbiguousCertificate,
504 #[error("unsupported X.509 digest algorithm: {0}")]
506 UnsupportedDigestAlgorithm(String),
507 #[error("certificate chain validation failed: {0}")]
509 Chain(#[from] super::X509ChainError),
510 #[error("system time is unavailable")]
512 SystemTime,
513}
514
515#[derive(Debug, Clone, Default, PartialEq, Eq)]
521pub struct KeyResolverConfig {
522 pub lookup_certs: Vec<Vec<u8>>,
526 pub trusted_certs: Vec<Vec<u8>>,
528 pub crls: Vec<Vec<u8>>,
530 pub named_keys: HashMap<String, VerificationKey>,
532}
533
534#[derive(Debug, Clone, Default)]
536pub struct DefaultKeyResolver {
537 config: KeyResolverConfig,
538}
539
540#[derive(Clone, Copy)]
541pub(crate) enum ResolutionScope {
542 Document,
543 Trusted,
544 DocumentPrefix(usize),
545 TrustedPrefix(usize),
546 DocumentSuffix(usize),
547 TrustedSuffix(usize),
548}
549
550pub(crate) struct SourceResolution {
553 pub(crate) key: Option<ResolvedVerificationKey<'static>>,
554 pub(crate) deferred_error: Option<KeyResolutionError>,
555}
556
557impl SourceResolution {
558 pub(crate) fn finish(self) -> Result<Option<ResolvedVerificationKey<'static>>, DsigError> {
559 if let Some(error) = self.deferred_error {
560 return Err(error.into());
561 }
562 Ok(self.key)
563 }
564}
565
566#[derive(Debug)]
574pub struct InspectedKeyCandidateBudget {
575 maximum: usize,
576 attempted: usize,
577}
578
579impl InspectedKeyCandidateBudget {
580 #[must_use]
582 pub fn new(policy: &crate::policy::VerificationPolicy) -> Self {
583 Self {
584 maximum: policy.resources.max_key_candidates,
585 attempted: 0,
586 }
587 }
588
589 pub fn charge(&mut self) -> Result<(), DsigError> {
591 self.charge_many(1)
592 }
593
594 pub(crate) fn charge_many(&mut self, count: usize) -> Result<(), DsigError> {
595 if self.attempted > self.maximum || count > self.maximum - self.attempted {
596 return Err(crate::policy::PolicyViolation::ResourceLimit {
597 resource: crate::policy::resource_name::KEY_CANDIDATES,
598 maximum: self.maximum,
599 actual: self.attempted.saturating_add(count),
600 }
601 .into());
602 }
603 debug_assert!(self.attempted <= self.maximum);
604 self.attempted += count;
605 Ok(())
606 }
607}
608
609pub(crate) fn validate_key_info_source_permissions(
610 key_info: &KeyInfo,
611 allowed: crate::policy::KeySourcePolicy,
612) -> Result<(), crate::policy::PolicyViolation> {
613 for source in &key_info.sources {
614 let disabled_reason = match source {
615 KeyInfoSource::X509Data(_) if !allowed.x509_data => {
616 Some("X509Data key sources are disabled")
617 }
618 KeyInfoSource::DerEncodedKeyValue(_) if !allowed.der_encoded_key_value => {
619 Some("DEREncodedKeyValue key sources are disabled")
620 }
621 KeyInfoSource::KeyName(_) if !allowed.key_name => {
622 Some("KeyName key sources are disabled")
623 }
624 KeyInfoSource::KeyValue(_) if !allowed.key_value => {
625 Some("KeyValue key sources are disabled")
626 }
627 KeyInfoSource::KeyInfoReference { .. } if !allowed.key_info_reference => {
628 Some("KeyInfoReference key sources are disabled")
629 }
630 KeyInfoSource::X509Data(_)
631 | KeyInfoSource::DerEncodedKeyValue(_)
632 | KeyInfoSource::KeyName(_)
633 | KeyInfoSource::KeyValue(_)
634 | KeyInfoSource::RetrievalMethod { .. }
635 | KeyInfoSource::KeyInfoReference { .. } => None,
636 };
637 if let Some(reason) = disabled_reason {
638 return Err(crate::policy::PolicyViolation::KeyTrust { reason });
639 }
640 }
641 Ok(())
642}
643
644impl DefaultKeyResolver {
645 pub fn resolve_with_candidate_budget(
649 &self,
650 key_info: Option<&KeyInfo>,
651 algorithm: SignatureAlgorithm,
652 policy: &crate::policy::VerificationPolicy,
653 provider: &dyn crate::provider::CryptoProvider,
654 candidate_budget: &mut InspectedKeyCandidateBudget,
655 ) -> Result<Option<ResolvedVerificationKey<'static>>, DsigError> {
656 candidate_budget.maximum = candidate_budget
657 .maximum
658 .min(policy.resources.max_key_candidates);
659 candidate_budget.charge_many(0)?;
660 self.resolve_with_trust(
661 key_info,
662 algorithm,
663 policy,
664 provider,
665 candidate_budget,
666 ResolutionScope::Document,
667 )
668 }
669
670 pub(crate) fn resolve_trusted_material_with_candidate_budget(
671 &self,
672 key_info: &KeyInfo,
673 algorithm: SignatureAlgorithm,
674 policy: &crate::policy::VerificationPolicy,
675 provider: &dyn crate::provider::CryptoProvider,
676 candidate_budget: &mut InspectedKeyCandidateBudget,
677 ) -> Result<Option<ResolvedVerificationKey<'static>>, DsigError> {
678 self.resolve_with_trust(
679 Some(key_info),
680 algorithm,
681 policy,
682 provider,
683 candidate_budget,
684 ResolutionScope::Trusted,
685 )
686 }
687
688 pub(crate) fn resolve_sources_with_candidate_budget(
689 &self,
690 key_info: &KeyInfo,
691 algorithm: SignatureAlgorithm,
692 policy: &crate::policy::VerificationPolicy,
693 provider: &dyn crate::provider::CryptoProvider,
694 candidate_budget: &mut InspectedKeyCandidateBudget,
695 scope: ResolutionScope,
696 ) -> Result<SourceResolution, DsigError> {
697 self.resolve_source_range(
698 Some(key_info),
699 algorithm,
700 policy,
701 provider,
702 candidate_budget,
703 scope,
704 )
705 }
706 #[must_use]
708 pub fn new(config: KeyResolverConfig) -> Self {
709 Self { config }
710 }
711
712 #[must_use]
714 pub fn config(&self) -> &KeyResolverConfig {
715 &self.config
716 }
717
718 fn check_configured_x509_material(
719 &self,
720 info: &X509DataInfo,
721 resources: &crate::policy::ResourcePolicy,
722 trust: &crate::policy::KeyTrustPolicy,
723 budget: &mut InspectedKeyCandidateBudget,
724 charge_crls: bool,
725 ) -> Result<(), DsigError> {
726 if charge_crls && trust.check_crls && trust.verify_x509_chains {
727 budget.charge_many(self.config.crls.len())?;
728 }
729 let certificates = self
730 .config
731 .trusted_certs
732 .iter()
733 .chain(&self.config.lookup_certs);
734 let crls = self
735 .config
736 .crls
737 .iter()
738 .filter(|_| trust.check_crls && trust.verify_x509_chains);
739 let mut total = 0_usize;
740 for material in info
743 .certificates
744 .iter()
745 .chain(&info.crls)
746 .chain(certificates)
747 .chain(crls)
748 {
749 if material.len() > resources.max_external_resource_bytes {
750 return Err(crate::policy::PolicyViolation::ResourceLimit {
751 resource: crate::policy::resource_name::EXTERNAL_RESOURCE_BYTES,
752 maximum: resources.max_external_resource_bytes,
753 actual: material.len(),
754 }
755 .into());
756 }
757 debug_assert!(total <= resources.max_external_resource_total_bytes);
758 if material.len() > resources.max_external_resource_total_bytes - total {
759 return Err(crate::policy::PolicyViolation::ResourceLimit {
760 resource: crate::policy::resource_name::AGGREGATE_EXTERNAL_RESOURCE_BYTES,
761 maximum: resources.max_external_resource_total_bytes,
762 actual: total.saturating_add(material.len()),
763 }
764 .into());
765 }
766 total += material.len();
767 }
768 Ok(())
769 }
770
771 fn resolve_x509(
772 &self,
773 info: &X509DataInfo,
774 algorithm: SignatureAlgorithm,
775 trust: &crate::policy::KeyTrustPolicy,
776 provider: &dyn crate::provider::CryptoProvider,
777 budget: &mut InspectedKeyCandidateBudget,
778 ) -> Result<Option<(VerificationKey, Option<X509TrustEvidence>)>, DsigError> {
779 let mut evidence = None;
780 let effective_trust;
781 let trust = if trust.verify_x509_chains && trust.verification_time.is_none() {
782 effective_trust = {
783 let mut captured = trust.clone();
784 captured.verification_time = Some(SystemTime::now());
785 captured
786 };
787 &effective_trust
788 } else {
789 trust
790 };
791 let certificate_der = if let Some(&signing_index) = info.certificate_chain.first() {
792 if trust.verify_x509_chains {
793 let path =
794 self.prepare_embedded_x509(info, signing_index, trust, provider, budget)?;
795 evidence = Some(Self::x509_trust_evidence(&path, trust)?);
796 } else {
797 budget.charge_many(info.certificates.len())?;
798 }
799 info.certificates
800 .get(signing_index)
801 .ok_or(KeyResolutionError::InvalidCertificate)?
802 .clone()
803 } else {
804 let Some(selected) = self.resolve_configured_x509(info, trust, provider, budget)?
805 else {
806 return Ok(None);
807 };
808 if trust.verify_x509_chains {
809 evidence = Some(Self::x509_trust_evidence(&selected, trust)?);
810 }
811 selected
812 .certificate_chain
813 .first()
814 .and_then(|index| selected.certificates.get(*index))
815 .ok_or(KeyResolutionError::InvalidCertificate)?
816 .clone()
817 };
818
819 let (rest, certificate) = X509Certificate::from_der(&certificate_der)
820 .map_err(|_| KeyResolutionError::InvalidCertificate)?;
821 if !rest.is_empty() {
822 return Err(KeyResolutionError::InvalidCertificate.into());
823 }
824 let public_key_bytes = certificate.public_key().raw.to_vec();
825 validate_spki_algorithm(&public_key_bytes, algorithm)?;
826 Ok(Some((
827 VerificationKey {
828 algorithm,
829 public_key_bytes,
830 certificate_der: Some(certificate_der),
831 name: None,
832 },
833 evidence,
834 )))
835 }
836
837 fn x509_trust_evidence(
838 info: &X509DataInfo,
839 trust: &crate::policy::KeyTrustPolicy,
840 ) -> Result<X509TrustEvidence, DsigError> {
841 let time = trust
842 .verification_time
843 .ok_or(KeyResolutionError::SystemTime)?;
844 X509TrustEvidence::new(
845 info.certificate_chain
846 .iter()
847 .map(|index| info.certificates[*index].as_slice()),
848 time,
849 trust.check_crls,
850 )
851 }
852
853 fn verify_x509_policy(
854 &self,
855 info: &X509DataInfo,
856 trust: &crate::policy::KeyTrustPolicy,
857 provider: &dyn crate::provider::CryptoProvider,
858 ) -> Result<(), KeyResolutionError> {
859 let options = X509ChainOptions {
860 trusted_certs: &self.config.trusted_certs,
861 verification_time: trust.verification_time.unwrap_or_else(SystemTime::now),
862 max_chain_depth: trust.max_x509_chain_depth,
863 check_crls: trust.check_crls,
864 allowed_extended_key_usages: Some(&trust.allowed_extended_key_usages),
865 rsa_keys: trust.rsa_keys,
866 dsa_keys: trust.dsa_keys,
867 certificate_signature_algorithms: trust.certificate_signature_algorithms.as_ref(),
868 };
869 verify_x509_certificate_chain_with_provider_and_crls(
870 info,
871 &options,
872 provider,
873 &self.config.crls,
874 )?;
875 Ok(())
876 }
877
878 fn prepare_embedded_x509(
879 &self,
880 info: &X509DataInfo,
881 signing_index: usize,
882 trust: &crate::policy::KeyTrustPolicy,
883 provider: &dyn crate::provider::CryptoProvider,
884 budget: &mut InspectedKeyCandidateBudget,
885 ) -> Result<X509DataInfo, DsigError> {
886 let signing_der = info
887 .certificates
888 .get(signing_index)
889 .ok_or(KeyResolutionError::InvalidCertificate)?;
890 let mut available = X509DataInfo {
891 crls: info.crls.clone(),
892 ..X509DataInfo::default()
893 };
894 let mut trusted_prefix_len = 0;
895 for certificate in &self.config.trusted_certs {
896 budget.charge()?;
897 if available
898 .certificates
899 .iter()
900 .any(|known| known == certificate)
901 {
902 continue;
903 }
904 available.parsed_certificates.push(
905 parse_x509_certificate(certificate)
906 .map_err(|_| KeyResolutionError::InvalidCertificate)?,
907 );
908 available.certificates.push(certificate.clone());
909 trusted_prefix_len += 1;
910 }
911 for certificate in self.config.lookup_certs.iter().chain(&info.certificates) {
912 budget.charge()?;
913 if available
914 .certificates
915 .iter()
916 .any(|known| known == certificate)
917 {
918 continue;
919 }
920 available.parsed_certificates.push(
921 parse_x509_certificate(certificate)
922 .map_err(|_| KeyResolutionError::InvalidCertificate)?,
923 );
924 available.certificates.push(certificate.clone());
925 }
926 let signing_index = available
927 .certificates
928 .iter()
929 .position(|certificate| certificate == signing_der)
930 .ok_or(KeyResolutionError::InvalidCertificate)?;
931 self.select_valid_x509_path(
932 &mut available,
933 signing_index,
934 trusted_prefix_len,
935 trust,
936 provider,
937 None,
938 )?;
939 Ok(available)
940 }
941
942 fn select_valid_x509_path(
943 &self,
944 available: &mut X509DataInfo,
945 signing_index: usize,
946 trusted_prefix_len: usize,
947 trust: &crate::policy::KeyTrustPolicy,
948 provider: &dyn crate::provider::CryptoProvider,
949 selectors: Option<&X509DataInfo>,
950 ) -> Result<bool, KeyResolutionError> {
951 let candidates = build_x509_certificate_paths_to_trusted_prefix(
952 available,
953 signing_index,
954 trusted_prefix_len,
955 trust.max_x509_chain_depth,
956 trust.max_x509_candidate_paths,
957 provider,
958 trust.certificate_signature_algorithms.as_ref(),
959 )
960 .map_err(|error| match error {
961 X509ChainBuildError::AmbiguousIssuer => KeyResolutionError::AmbiguousCertificate,
962 X509ChainBuildError::Policy(error) => {
963 KeyResolutionError::Chain(super::X509ChainError::Policy(error))
964 }
965 X509ChainBuildError::Provider(error) => {
966 KeyResolutionError::Chain(super::X509ChainError::Provider(error))
967 }
968 X509ChainBuildError::UnsupportedSignatureAlgorithm { oid } => {
969 KeyResolutionError::Chain(super::X509ChainError::UnsupportedSignatureAlgorithm {
970 oid,
971 })
972 }
973 _ => KeyResolutionError::InvalidCertificate,
974 })?;
975 let mut first_error = None;
976 let mut valid_path_without_selector_match = false;
977 for candidate in candidates {
978 available.certificate_chain = candidate;
979 match self.verify_x509_policy(available, trust, provider) {
980 Ok(()) => {
981 if match selectors {
982 Some(selectors) => {
983 selected_x509_path_matches_selectors(available, selectors, provider)?
984 }
985 None => true,
986 } {
987 return Ok(true);
988 }
989 valid_path_without_selector_match = true;
990 }
991 Err(error) => {
992 first_error.get_or_insert(error);
993 }
994 }
995 }
996 if valid_path_without_selector_match {
997 return Ok(false);
998 }
999 Err(first_error.unwrap_or(KeyResolutionError::Chain(
1000 super::X509ChainError::UntrustedRoot,
1001 )))
1002 }
1003
1004 fn select_x509_selector_path(
1005 &self,
1006 available: &mut X509DataInfo,
1007 signing_index: usize,
1008 matching_indices: &[usize],
1009 trust: &crate::policy::KeyTrustPolicy,
1010 provider: &dyn crate::provider::CryptoProvider,
1011 selectors: &X509DataInfo,
1012 ) -> Result<bool, KeyResolutionError> {
1013 let targets = matching_indices
1014 .iter()
1015 .copied()
1016 .filter(|index| *index != signing_index)
1017 .collect::<Vec<_>>();
1018 if targets.is_empty() {
1019 return Ok(false);
1020 }
1021 let candidates = build_x509_certificate_paths_to_selector_targets(
1022 available,
1023 signing_index,
1024 &targets,
1025 trust.max_x509_chain_depth,
1026 trust.max_x509_candidate_paths,
1027 provider,
1028 trust.certificate_signature_algorithms.as_ref(),
1029 )
1030 .map_err(|error| match error {
1031 X509ChainBuildError::AmbiguousIssuer => KeyResolutionError::AmbiguousCertificate,
1032 X509ChainBuildError::Policy(error) => {
1033 KeyResolutionError::Chain(super::X509ChainError::Policy(error))
1034 }
1035 X509ChainBuildError::Provider(error) => {
1036 KeyResolutionError::Chain(super::X509ChainError::Provider(error))
1037 }
1038 X509ChainBuildError::UnsupportedSignatureAlgorithm { oid } => {
1039 KeyResolutionError::Chain(super::X509ChainError::UnsupportedSignatureAlgorithm {
1040 oid,
1041 })
1042 }
1043 _ => KeyResolutionError::InvalidCertificate,
1044 })?;
1045 for candidate in candidates {
1046 available.certificate_chain = candidate;
1047 if selected_x509_path_matches_selectors(available, selectors, provider)? {
1048 return Ok(true);
1049 }
1050 }
1051 Ok(false)
1052 }
1053
1054 fn resolve_configured_x509(
1055 &self,
1056 info: &X509DataInfo,
1057 trust: &crate::policy::KeyTrustPolicy,
1058 provider: &dyn crate::provider::CryptoProvider,
1059 budget: &mut InspectedKeyCandidateBudget,
1060 ) -> Result<Option<X509DataInfo>, DsigError> {
1061 if !x509_data_has_lookup_identifiers(info) {
1062 return Ok(None);
1063 }
1064
1065 let mut available = X509DataInfo {
1066 subject_names: info.subject_names.clone(),
1067 issuer_serials: info.issuer_serials.clone(),
1068 skis: info.skis.clone(),
1069 crls: info.crls.clone(),
1070 digests: info.digests.clone(),
1071 ..X509DataInfo::default()
1072 };
1073 let mut matches = Vec::new();
1074 let mut trusted_prefix_len = 0usize;
1075 for (trusted, certificate_der) in self
1076 .config
1077 .trusted_certs
1078 .iter()
1079 .map(|certificate| (true, certificate))
1080 .chain(
1081 self.config
1082 .lookup_certs
1083 .iter()
1084 .map(|certificate| (false, certificate)),
1085 )
1086 {
1087 budget.charge()?;
1088 if available
1089 .certificates
1090 .iter()
1091 .any(|available_der| available_der == certificate_der)
1092 {
1093 continue;
1094 }
1095 let parsed = parse_x509_certificate(certificate_der)
1096 .map_err(|_| KeyResolutionError::InvalidCertificate)?;
1097 let is_match =
1098 x509_certificate_matches_any_selector(info, &parsed, certificate_der, provider)
1099 .map_err(map_x509_selector_error)?;
1100 if is_match {
1101 matches.push((available.certificates.len(), parsed.clone()));
1102 }
1103 available.certificates.push(certificate_der.clone());
1104 available.parsed_certificates.push(parsed);
1105 if trusted {
1106 trusted_prefix_len += 1;
1107 }
1108 }
1109
1110 let matched_chain = X509DataInfo {
1111 certificates: matches
1112 .iter()
1113 .map(|(index, _)| available.certificates[*index].clone())
1114 .collect(),
1115 parsed_certificates: matches.iter().map(|(_, parsed)| parsed.clone()).collect(),
1116 ..X509DataInfo::default()
1117 };
1118 if !x509_selector_categories_match_chain(
1119 &X509DataInfo {
1120 subject_names: info.subject_names.clone(),
1121 issuer_serials: info.issuer_serials.clone(),
1122 skis: info.skis.clone(),
1123 digests: info.digests.clone(),
1124 ..matched_chain
1125 },
1126 provider,
1127 )
1128 .map_err(map_x509_selector_error)?
1129 {
1130 return Ok(None);
1131 }
1132
1133 let signing_index = match matches.as_slice() {
1134 [] => return Ok(None),
1135 [(index, _)] => *index,
1136 _ => {
1137 let leaves = matches
1138 .iter()
1139 .filter(|(_, candidate)| {
1140 !distinguished_names_equal(&candidate.subject_dn, &candidate.issuer_dn)
1141 && !matches.iter().any(|(_, other)| {
1142 distinguished_names_equal(&other.issuer_dn, &candidate.subject_dn)
1143 })
1144 })
1145 .collect::<Vec<_>>();
1146 match leaves.as_slice() {
1147 [(index, _)] => *index,
1148 _ => return Err(KeyResolutionError::AmbiguousCertificate.into()),
1149 }
1150 }
1151 };
1152 let matching_indices = matches.iter().map(|(index, _)| *index).collect::<Vec<_>>();
1153 available.certificate_chain =
1157 if signing_index < trusted_prefix_len || !trust.verify_x509_chains {
1158 vec![signing_index]
1159 } else {
1160 if !self.select_valid_x509_path(
1161 &mut available,
1162 signing_index,
1163 trusted_prefix_len,
1164 trust,
1165 provider,
1166 Some(info),
1167 )? {
1168 return Ok(None);
1169 }
1170 available.certificate_chain.clone()
1171 };
1172 if trust.verify_x509_chains && signing_index < trusted_prefix_len {
1173 self.verify_x509_policy(&available, trust, provider)?;
1174 }
1175 if !trust.verify_x509_chains || signing_index < trusted_prefix_len {
1176 let direct_match = selected_x509_path_matches_selectors(&available, info, provider)?;
1177 if !direct_match
1178 && (signing_index < trusted_prefix_len
1179 || !self.select_x509_selector_path(
1180 &mut available,
1181 signing_index,
1182 &matching_indices,
1183 trust,
1184 provider,
1185 info,
1186 )?)
1187 {
1188 return Ok(None);
1189 }
1190 }
1191 Ok(Some(available))
1192 }
1193
1194 fn resolve_key_value(
1195 key_value: &KeyValueInfo,
1196 algorithm: SignatureAlgorithm,
1197 ) -> Result<Option<VerificationKey>, KeyResolutionError> {
1198 let public_key_bytes = match key_value {
1199 KeyValueInfo::Dsa { p, q, g, y } => {
1200 if !matches!(
1201 algorithm,
1202 SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256
1203 ) {
1204 return Err(KeyResolutionError::AlgorithmMismatch);
1205 }
1206 let (Some(p), Some(q), Some(g)) = (p.as_deref(), q.as_deref(), g.as_deref()) else {
1207 return Err(KeyResolutionError::InvalidPublicKey);
1208 };
1209 dsa_key_value_to_spki_der(p, q, g, y)?
1210 }
1211 KeyValueInfo::Rsa { modulus, exponent } => {
1212 if !matches!(
1213 algorithm,
1214 SignatureAlgorithm::RsaSha1
1215 | SignatureAlgorithm::RsaSha224
1216 | SignatureAlgorithm::RsaSha256
1217 | SignatureAlgorithm::RsaSha384
1218 | SignatureAlgorithm::RsaSha512
1219 ) {
1220 return Err(KeyResolutionError::AlgorithmMismatch);
1221 }
1222 rsa_key_value_to_spki_der(modulus, exponent)?
1223 }
1224 KeyValueInfo::Ec {
1225 curve_oid,
1226 public_key,
1227 } => {
1228 if algorithm.ecdsa_digest().is_none() {
1229 return Ok(None);
1230 }
1231 ec_key_value_to_spki_der(curve_oid, public_key)?
1232 }
1233 KeyValueInfo::InvalidEcKeyValue => return Err(KeyResolutionError::InvalidPublicKey),
1234 KeyValueInfo::Unsupported { .. } => return Ok(None),
1235 };
1236 validate_spki_algorithm(&public_key_bytes, algorithm)?;
1237
1238 Ok(Some(VerificationKey {
1239 algorithm,
1240 public_key_bytes,
1241 certificate_der: None,
1242 name: None,
1243 }))
1244 }
1245
1246 fn resolve_with_trust(
1247 &self,
1248 key_info: Option<&KeyInfo>,
1249 algorithm: SignatureAlgorithm,
1250 policy: &crate::policy::VerificationPolicy,
1251 provider: &dyn crate::provider::CryptoProvider,
1252 candidate_budget: &mut InspectedKeyCandidateBudget,
1253 scope: ResolutionScope,
1254 ) -> Result<Option<ResolvedVerificationKey<'static>>, DsigError> {
1255 self.resolve_source_range(
1256 key_info,
1257 algorithm,
1258 policy,
1259 provider,
1260 candidate_budget,
1261 scope,
1262 )?
1263 .finish()
1264 }
1265
1266 fn resolve_source_range(
1267 &self,
1268 key_info: Option<&KeyInfo>,
1269 algorithm: SignatureAlgorithm,
1270 policy: &crate::policy::VerificationPolicy,
1271 provider: &dyn crate::provider::CryptoProvider,
1272 candidate_budget: &mut InspectedKeyCandidateBudget,
1273 scope: ResolutionScope,
1274 ) -> Result<SourceResolution, DsigError> {
1275 let trust = &policy.key_trust;
1276 let resources = &policy.resources;
1277 trust.validate()?;
1278 resources.validate()?;
1279 let Some(key_info) = key_info else {
1280 return Ok(SourceResolution {
1281 key: None,
1282 deferred_error: None,
1283 });
1284 };
1285 let document_sources = matches!(
1286 scope,
1287 ResolutionScope::Document
1288 | ResolutionScope::DocumentPrefix(_)
1289 | ResolutionScope::DocumentSuffix(_)
1290 );
1291 if document_sources {
1292 validate_key_info_source_permissions(key_info, policy.key_sources)?;
1293 }
1294 let source_end = match scope {
1295 ResolutionScope::DocumentPrefix(end) | ResolutionScope::TrustedPrefix(end) => end,
1296 _ => key_info.sources.len(),
1297 };
1298 let source_start = match scope {
1299 ResolutionScope::DocumentSuffix(start) | ResolutionScope::TrustedSuffix(start) => start,
1300 _ => 0,
1301 };
1302 let mut deferred_key_value_error = None;
1303 let mut configured_material_checked = false;
1304 for source in &key_info.sources[source_start..source_end] {
1305 if !document_sources && matches!(source, KeyInfoSource::KeyName(_)) {
1306 continue;
1307 }
1308 let mut path_evidence = None;
1309 let mut caller_trusted =
1310 !document_sources || matches!(source, KeyInfoSource::KeyName(_));
1311 let resolved = match source {
1312 KeyInfoSource::X509Data(info) => {
1313 if if info.certificate_chain.is_empty() {
1314 x509_data_has_lookup_identifiers(info)
1315 } else {
1316 trust.verify_x509_chains
1317 } {
1318 self.check_configured_x509_material(
1319 info,
1320 resources,
1321 trust,
1322 candidate_budget,
1323 !configured_material_checked,
1324 )?;
1325 configured_material_checked = true;
1326 }
1327 match self.resolve_x509(info, algorithm, trust, provider, candidate_budget)? {
1328 Some((key, evidence)) => {
1329 if evidence.is_none()
1330 && !caller_trusted
1331 && trust.mode
1332 == crate::policy::VerificationTrustMode::RequireTrustedKey
1333 && let Some(der) = key.certificate_der.as_ref()
1334 {
1335 for anchor in &self.config.trusted_certs {
1338 candidate_budget.charge()?;
1339 if anchor == der {
1340 caller_trusted = true;
1341 break;
1342 }
1343 }
1344 }
1345 path_evidence = evidence;
1346 Some(key)
1347 }
1348 None => None,
1349 }
1350 }
1351 KeyInfoSource::DerEncodedKeyValue(public_key_bytes) => {
1352 candidate_budget.charge()?;
1353 validate_spki_algorithm(public_key_bytes, algorithm)?;
1354 Some(VerificationKey {
1355 algorithm,
1356 public_key_bytes: public_key_bytes.clone(),
1357 certificate_der: None,
1358 name: None,
1359 })
1360 }
1361 KeyInfoSource::KeyName(name) => {
1362 candidate_budget.charge()?;
1363 self.config
1364 .named_keys
1365 .get(name)
1366 .map(|key| {
1367 if key.algorithm != algorithm {
1368 return Err(KeyResolutionError::AlgorithmMismatch);
1369 }
1370 validate_spki_algorithm(&key.public_key_bytes, algorithm)?;
1371 Ok(key.clone())
1372 })
1373 .transpose()?
1374 }
1375 KeyInfoSource::KeyValue(key_value) => {
1376 candidate_budget.charge()?;
1377 match Self::resolve_key_value(key_value, algorithm) {
1378 Ok(resolved) => resolved,
1379 Err(error) if key_value_error_allows_fallback(key_value, &error) => {
1380 deferred_key_value_error.get_or_insert(error);
1381 None
1382 }
1383 Err(error) => return Err(error.into()),
1384 }
1385 }
1386 KeyInfoSource::RetrievalMethod { .. } => {
1387 candidate_budget.charge()?;
1388 None
1389 }
1390 KeyInfoSource::KeyInfoReference { .. } => {
1391 candidate_budget.charge()?;
1392 None
1393 }
1394 };
1395 if let Some(key) = resolved {
1396 let key = Box::new(PolicyBoundVerificationKey {
1397 key,
1398 rsa_minimum_bits: trust.rsa_keys.minimum_modulus_bits,
1399 dsa_minimum_bits: trust.dsa_keys.minimum_modulus_bits,
1400 });
1401 let key = if policy.key_trust.mode
1402 == crate::policy::VerificationTrustMode::CryptographicOnly
1403 {
1404 ResolvedVerificationKey::Candidate(key)
1405 } else if let Some(evidence) = path_evidence {
1406 ResolvedVerificationKey::Validated(TrustedPublicKey::new(
1407 key,
1408 trust.clone(),
1409 evidence,
1410 ))
1411 } else if caller_trusted {
1412 ResolvedVerificationKey::CallerTrusted(key)
1413 } else {
1414 ResolvedVerificationKey::Candidate(key)
1415 };
1416 return Ok(SourceResolution {
1417 key: Some(key),
1418 deferred_error: None,
1419 });
1420 }
1421 }
1422 Ok(SourceResolution {
1423 key: None,
1424 deferred_error: deferred_key_value_error,
1425 })
1426 }
1427}
1428
1429impl KeyResolver for DefaultKeyResolver {
1430 fn resolve_for_verification<'a>(
1431 &'a self,
1432 key_info: Option<&KeyInfo>,
1433 algorithm: SignatureAlgorithm,
1434 policy: &crate::policy::VerificationPolicy,
1435 provider: &dyn crate::provider::CryptoProvider,
1436 ) -> Result<Option<ResolvedVerificationKey<'a>>, DsigError> {
1437 let mut budget = InspectedKeyCandidateBudget::new(policy);
1438 self.resolve_with_candidate_budget(key_info, algorithm, policy, provider, &mut budget)
1439 }
1440 fn resolve<'a>(
1441 &'a self,
1442 key_info: Option<&KeyInfo>,
1443 algorithm: SignatureAlgorithm,
1444 ) -> Result<Option<Box<dyn VerifyingKey + 'a>>, DsigError> {
1445 let policy = crate::policy::VerificationPolicy::default();
1446 let mut candidate_budget = InspectedKeyCandidateBudget::new(&policy);
1447 self.resolve_with_trust(
1448 key_info,
1449 algorithm,
1450 &policy,
1451 crate::provider::default_provider(),
1452 &mut candidate_budget,
1453 ResolutionScope::Document,
1454 )
1455 .map(|key| key.map(ResolvedVerificationKey::into_key))
1456 }
1457
1458 fn resolve_with_policy<'a>(
1459 &'a self,
1460 key_info: Option<&KeyInfo>,
1461 algorithm: SignatureAlgorithm,
1462 policy: &crate::policy::VerificationPolicy,
1463 ) -> Result<Option<Box<dyn VerifyingKey + 'a>>, DsigError> {
1464 self.resolve_with_policy_and_provider(
1465 key_info,
1466 algorithm,
1467 policy,
1468 crate::provider::default_provider(),
1469 )
1470 }
1471
1472 fn resolve_with_policy_and_provider<'a>(
1473 &'a self,
1474 key_info: Option<&KeyInfo>,
1475 algorithm: SignatureAlgorithm,
1476 policy: &crate::policy::VerificationPolicy,
1477 provider: &dyn crate::provider::CryptoProvider,
1478 ) -> Result<Option<Box<dyn VerifyingKey + 'a>>, DsigError> {
1479 let mut candidate_budget = InspectedKeyCandidateBudget::new(policy);
1480 self.resolve_with_candidate_budget(
1481 key_info,
1482 algorithm,
1483 policy,
1484 provider,
1485 &mut candidate_budget,
1486 )
1487 .map(|key| key.map(ResolvedVerificationKey::into_key))
1488 }
1489
1490 fn consumes_document_key_info(&self) -> bool {
1491 true
1492 }
1493}
1494
1495fn map_x509_selector_error(error: ParseError) -> DsigError {
1496 match error {
1497 ParseError::Provider(error) => DsigError::Provider(error),
1498 ParseError::UnsupportedAlgorithm { uri } => {
1499 KeyResolutionError::UnsupportedDigestAlgorithm(uri).into()
1500 }
1501 _ => KeyResolutionError::InvalidCertificate.into(),
1502 }
1503}
1504
1505fn selected_x509_path_matches_selectors(
1506 available: &X509DataInfo,
1507 selectors: &X509DataInfo,
1508 provider: &dyn crate::provider::CryptoProvider,
1509) -> Result<bool, KeyResolutionError> {
1510 let selected = X509DataInfo {
1511 subject_names: selectors.subject_names.clone(),
1512 issuer_serials: selectors.issuer_serials.clone(),
1513 skis: selectors.skis.clone(),
1514 digests: selectors.digests.clone(),
1515 certificates: available
1516 .certificate_chain
1517 .iter()
1518 .map(|index| available.certificates[*index].clone())
1519 .collect(),
1520 parsed_certificates: available
1521 .certificate_chain
1522 .iter()
1523 .map(|index| available.parsed_certificates[*index].clone())
1524 .collect(),
1525 ..X509DataInfo::default()
1526 };
1527 x509_selector_categories_match_chain(&selected, provider).map_err(|error| match error {
1528 ParseError::Provider(error) => {
1529 KeyResolutionError::Chain(super::X509ChainError::Provider(error))
1530 }
1531 ParseError::UnsupportedAlgorithm { uri } => {
1532 KeyResolutionError::UnsupportedDigestAlgorithm(uri)
1533 }
1534 _ => KeyResolutionError::InvalidCertificate,
1535 })
1536}
1537
1538fn rsa_key_value_to_spki_der(
1539 modulus: &[u8],
1540 exponent: &[u8],
1541) -> Result<Vec<u8>, KeyResolutionError> {
1542 let (modulus, exponent) = bounded_rsa_public_components(modulus, exponent)?;
1543 let key = rsa::RsaPublicKey::new(
1544 BoxedUint::from_be_slice_vartime(modulus),
1545 BoxedUint::from_be_slice_vartime(exponent),
1546 )
1547 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1548 key.to_public_key_der()
1549 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1550 .map(|der| der.as_bytes().to_vec())
1551}
1552
1553pub(crate) fn bounded_rsa_public_components<'a>(
1554 modulus: &'a [u8],
1555 exponent: &'a [u8],
1556) -> Result<(&'a [u8], &'a [u8]), KeyResolutionError> {
1557 let modulus = &modulus[modulus
1558 .iter()
1559 .position(|byte| *byte != 0)
1560 .unwrap_or(modulus.len())..];
1561 let exponent = &exponent[exponent
1562 .iter()
1563 .position(|byte| *byte != 0)
1564 .unwrap_or(exponent.len())..];
1565 let maximum = crate::hard_limits::RSA_MODULUS_BIT_CEILING;
1566 if modulus.is_empty()
1567 || exponent.is_empty()
1568 || modulus.len() > maximum.div_ceil(8)
1569 || exponent.len() > maximum.div_ceil(8)
1570 || (modulus.len() * 8 - modulus[0].leading_zeros() as usize) > maximum
1571 {
1572 return Err(KeyResolutionError::InvalidPublicKey);
1573 }
1574 Ok((modulus, exponent))
1575}
1576
1577fn dsa_key_value_to_spki_der(
1578 p: &[u8],
1579 q: &[u8],
1580 g: &[u8],
1581 y: &[u8],
1582) -> Result<Vec<u8>, KeyResolutionError> {
1583 let trim = |bytes: &[u8]| bytes.iter().take_while(|byte| **byte == 0).count();
1586 let p = &p[trim(p)..];
1587 let q = &q[trim(q)..];
1588 let g = &g[trim(g)..];
1589 let y = &y[trim(y)..];
1590 for value in [p, q, g, y] {
1591 if value.is_empty() || value.len() > crate::hard_limits::DSA_KEY_COMPONENT_BYTE_CEILING {
1592 return Err(KeyResolutionError::InvalidPublicKey);
1593 }
1594 }
1595 let components = dsa::Components::from_components(
1596 BoxedUint::from_be_slice_vartime(p),
1597 BoxedUint::from_be_slice_vartime(q),
1598 BoxedUint::from_be_slice_vartime(g),
1599 )
1600 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1601 dsa::VerifyingKey::from_components(components, BoxedUint::from_be_slice_vartime(y))
1602 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
1603 .to_public_key_der()
1604 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1605 .map(|der| der.as_bytes().to_vec())
1606}
1607
1608fn ec_key_value_to_spki_der(
1609 curve_oid: &str,
1610 public_key: &[u8],
1611) -> Result<Vec<u8>, KeyResolutionError> {
1612 match curve_oid {
1613 EC_P256_OID => p256::PublicKey::from_sec1_bytes(public_key)
1614 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
1615 .to_public_key_der()
1616 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1617 .map(|der| der.as_bytes().to_vec()),
1618 EC_P384_OID => p384::PublicKey::from_sec1_bytes(public_key)
1619 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
1620 .to_public_key_der()
1621 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1622 .map(|der| der.as_bytes().to_vec()),
1623 EC_P521_OID => p521::PublicKey::from_sec1_bytes(public_key)
1624 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
1625 .to_public_key_der()
1626 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1627 .map(|der| der.as_bytes().to_vec()),
1628 _ => Err(KeyResolutionError::InvalidPublicKey),
1629 }
1630}
1631
1632fn key_value_error_allows_fallback(key_value: &KeyValueInfo, error: &KeyResolutionError) -> bool {
1633 matches!(
1634 key_value,
1635 KeyValueInfo::Dsa { .. } | KeyValueInfo::Ec { .. } | KeyValueInfo::InvalidEcKeyValue
1636 ) && matches!(
1637 error,
1638 KeyResolutionError::InvalidPublicKey | KeyResolutionError::AlgorithmMismatch
1639 )
1640}
1641
1642fn validate_spki_algorithm(
1643 public_key_bytes: &[u8],
1644 algorithm: SignatureAlgorithm,
1645) -> Result<(), KeyResolutionError> {
1646 if algorithm.eddsa_signature_len().is_some()
1647 || matches!(algorithm, SignatureAlgorithm::PostQuantum(_))
1648 {
1649 return super::modern::validate_public_key(algorithm, public_key_bytes)
1650 .map_err(|_| KeyResolutionError::InvalidPublicKey);
1651 }
1652 let (rest, spki) = SubjectPublicKeyInfo::from_der(public_key_bytes)
1653 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1654 if !rest.is_empty() {
1655 return Err(KeyResolutionError::InvalidPublicKey);
1656 }
1657 let parsed = spki
1658 .parsed()
1659 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1660 let curve_oid = spki
1661 .algorithm
1662 .parameters
1663 .as_ref()
1664 .and_then(|value| value.as_oid().ok())
1665 .map(|oid| oid.to_id_string());
1666 match (algorithm, parsed) {
1667 (SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256, PublicKey::DSA(_)) => {
1668 let _ = decode_dsa_verifying_key(public_key_bytes)
1669 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1670 Ok(())
1671 }
1672 (
1673 SignatureAlgorithm::RsaSha1
1674 | SignatureAlgorithm::RsaSha224
1675 | SignatureAlgorithm::RsaSha256
1676 | SignatureAlgorithm::RsaSha384
1677 | SignatureAlgorithm::RsaSha512,
1678 PublicKey::RSA(_),
1679 ) => Ok(()),
1680 (
1681 SignatureAlgorithm::EcdsaSha1
1682 | SignatureAlgorithm::EcdsaSha224
1683 | SignatureAlgorithm::EcdsaSha256
1684 | SignatureAlgorithm::EcdsaSha384
1685 | SignatureAlgorithm::EcdsaSha512
1686 | SignatureAlgorithm::EcdsaSha3_224
1687 | SignatureAlgorithm::EcdsaSha3_256
1688 | SignatureAlgorithm::EcdsaSha3_384
1689 | SignatureAlgorithm::EcdsaSha3_512,
1690 PublicKey::EC(ec),
1691 ) if matches!(
1692 curve_oid.as_deref(),
1693 Some(EC_P256_OID | EC_P384_OID | EC_P521_OID)
1694 ) =>
1695 {
1696 validate_ec_public_key_encoding(&ec, spki.subject_public_key.data.as_ref())
1697 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1698 validate_ec_point(curve_oid.as_deref(), spki.subject_public_key.data.as_ref())?;
1699 Ok(())
1700 }
1701 _ => Err(KeyResolutionError::AlgorithmMismatch),
1702 }
1703}
1704
1705pub(crate) fn supported_parsed_spki_is_rsa(
1706 spki: &SubjectPublicKeyInfo<'_>,
1707 public_key_bytes: &[u8],
1708) -> Result<bool, KeyResolutionError> {
1709 let borrowed = pkcs8::SubjectPublicKeyInfoRef::try_from(public_key_bytes)
1710 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1711 if let Some(parameter) = super::PqAlgorithm::from_oid(borrowed.algorithm.oid) {
1712 super::modern::validate_public_key(
1713 SignatureAlgorithm::PostQuantum(parameter),
1714 public_key_bytes,
1715 )
1716 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1717 return Ok(false);
1718 }
1719 let eddsa = match spki.algorithm.algorithm.to_id_string().as_str() {
1720 "1.3.101.112" => Some(SignatureAlgorithm::Ed25519),
1721 "1.3.101.113" => Some(SignatureAlgorithm::Ed448),
1722 _ => None,
1723 };
1724 if let Some(algorithm) = eddsa {
1725 super::modern::validate_public_key(algorithm, public_key_bytes)
1726 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1727 return Ok(false);
1728 }
1729 let parsed = spki
1730 .parsed()
1731 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1732 match parsed {
1733 PublicKey::RSA(key) => {
1734 bounded_rsa_public_components(key.modulus, key.exponent)?;
1735 rsa::RsaPublicKey::from_public_key_der(public_key_bytes)
1736 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1737 Ok(true)
1738 }
1739 PublicKey::DSA(_) => {
1740 let _ = decode_dsa_verifying_key(public_key_bytes)
1741 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1742 Ok(false)
1743 }
1744 PublicKey::EC(ec) => {
1745 validate_ec_public_key_encoding(&ec, spki.subject_public_key.data.as_ref())
1746 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1747 let curve_oid = spki
1748 .algorithm
1749 .parameters
1750 .as_ref()
1751 .and_then(|value| value.as_oid().ok())
1752 .map(|oid| oid.to_id_string());
1753 validate_ec_point(curve_oid.as_deref(), spki.subject_public_key.data.as_ref())?;
1754 Ok(false)
1755 }
1756 _ => Err(KeyResolutionError::AlgorithmMismatch),
1757 }
1758}
1759
1760fn validate_ec_point(curve_oid: Option<&str>, point: &[u8]) -> Result<(), KeyResolutionError> {
1761 match curve_oid {
1762 Some(EC_P256_OID) => p256::PublicKey::from_sec1_bytes(point).map(|_| ()),
1763 Some(EC_P384_OID) => p384::PublicKey::from_sec1_bytes(point).map(|_| ()),
1764 Some(EC_P521_OID) => p521::PublicKey::from_sec1_bytes(point).map(|_| ()),
1765 _ => return Err(KeyResolutionError::AlgorithmMismatch),
1766 }
1767 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1768}
1769
1770pub(crate) fn supported_key_value_is_rsa(value: &KeyValueInfo) -> Result<bool, KeyResolutionError> {
1771 let (spki, is_rsa) = match value {
1772 KeyValueInfo::Rsa { modulus, exponent } => {
1773 (rsa_key_value_to_spki_der(modulus, exponent)?, true)
1774 }
1775 KeyValueInfo::Dsa {
1776 p: Some(p),
1777 q: Some(q),
1778 g: Some(g),
1779 y,
1780 } => (dsa_key_value_to_spki_der(p, q, g, y)?, false),
1781 KeyValueInfo::Ec {
1782 curve_oid,
1783 public_key,
1784 } => (ec_key_value_to_spki_der(curve_oid, public_key)?, false),
1785 _ => return Err(KeyResolutionError::InvalidPublicKey),
1786 };
1787 let algorithm = if is_rsa {
1788 SignatureAlgorithm::RsaSha256
1789 } else if matches!(value, KeyValueInfo::Dsa { .. }) {
1790 SignatureAlgorithm::DsaSha256
1791 } else {
1792 SignatureAlgorithm::EcdsaSha256
1793 };
1794 validate_spki_algorithm(&spki, algorithm)?;
1795 Ok(is_rsa)
1796}
1797
1798#[cfg(test)]
1799mod tests {
1800 use crate::xml::dom as roxmltree;
1801 use std::sync::atomic::{AtomicUsize, Ordering};
1802
1803 use base64::{Engine, engine::general_purpose::STANDARD};
1804 use der::Decode as _;
1805 use rcgen::{
1806 CertificateRevocationListParams, Issuer, KeyIdMethod, KeyPair, KeyUsagePurpose,
1807 RevokedCertParams, SerialNumber, date_time_ymd,
1808 };
1809 use rsa::{pkcs8::DecodePublicKey, traits::PublicKeyParts};
1810
1811 use super::*;
1812
1813 #[test]
1814 fn shared_candidate_budget_cannot_relax_active_policy() {
1815 let resolver = DefaultKeyResolver::new(KeyResolverConfig::default());
1818 let info = KeyInfo {
1819 sources: vec![KeyInfoSource::KeyName("missing".into())],
1820 };
1821 let mut policy = crate::policy::VerificationPolicy::default();
1822 policy.resources.max_key_candidates = 1;
1823 let mut budget = InspectedKeyCandidateBudget::new(&policy);
1824 assert!(
1825 resolver
1826 .resolve_with_candidate_budget(
1827 Some(&info),
1828 SignatureAlgorithm::RsaSha256,
1829 &policy,
1830 crate::provider::default_provider(),
1831 &mut budget
1832 )
1833 .expect("first candidate fits the active policy")
1834 .is_none()
1835 );
1836 assert!(matches!(
1837 resolver.resolve_with_candidate_budget(
1838 Some(&info),
1839 SignatureAlgorithm::RsaSha256,
1840 &policy,
1841 crate::provider::default_provider(),
1842 &mut budget
1843 ),
1844 Err(DsigError::Policy(
1845 crate::policy::PolicyViolation::ResourceLimit {
1846 maximum: 1,
1847 actual: 2,
1848 ..
1849 }
1850 ))
1851 ));
1852 let mut spent =
1853 InspectedKeyCandidateBudget::new(&crate::policy::VerificationPolicy::default());
1854 spent
1855 .charge_many(2)
1856 .expect("initial budget admits two candidates");
1857 assert!(matches!(
1858 resolver.resolve_with_candidate_budget(
1859 None,
1860 SignatureAlgorithm::RsaSha256,
1861 &policy,
1862 crate::provider::default_provider(),
1863 &mut spent
1864 ),
1865 Err(DsigError::Policy(
1866 crate::policy::PolicyViolation::ResourceLimit {
1867 maximum: 1,
1868 actual: 2,
1869 ..
1870 }
1871 ))
1872 ));
1873 }
1874
1875 #[test]
1876 fn dsa_key_value_components_are_bounded_before_bigint_decode() {
1877 let public = dsa::VerifyingKey::from_public_key_pem(include_str!(
1880 "../../tests/fixtures/keys/dsa/dsa-2048-public.pem"
1881 ))
1882 .expect("DSA fixture");
1883 let components = public.components();
1884 let values = [
1885 components.p().to_be_bytes_trimmed_vartime().to_vec(),
1886 components.q().to_be_bytes_trimmed_vartime().to_vec(),
1887 components.g().to_be_bytes_trimmed_vartime().to_vec(),
1888 public.y().to_be_bytes_trimmed_vartime().to_vec(),
1889 ];
1890 let expected = dsa_key_value_to_spki_der(&values[0], &values[1], &values[2], &values[3])
1891 .expect("valid DSA");
1892 for index in 0..4 {
1893 let mut oversized = values.clone();
1894 oversized[index] = vec![1; crate::hard_limits::DSA_KEY_COMPONENT_BYTE_CEILING + 1];
1895 assert!(
1896 dsa_key_value_to_spki_der(
1897 &oversized[0],
1898 &oversized[1],
1899 &oversized[2],
1900 &oversized[3]
1901 )
1902 .is_err()
1903 );
1904 }
1905 let padded = values.map(|value| {
1906 let mut padded = vec![0; 1024];
1907 padded.extend(value);
1908 padded
1909 });
1910 assert_eq!(
1911 dsa_key_value_to_spki_der(&padded[0], &padded[1], &padded[2], &padded[3])
1912 .expect("zero padding preserves unsigned DSA value"),
1913 expected
1914 );
1915 }
1916
1917 #[test]
1918 fn xml_rsa_components_are_bounded_before_bigint_decode() {
1919 let oversized = vec![1_u8; crate::hard_limits::RSA_MODULUS_BIT_CEILING.div_ceil(8) + 1];
1921 assert!(matches!(
1922 rsa_key_value_to_spki_der(&oversized, &[1, 0, 1]),
1923 Err(KeyResolutionError::InvalidPublicKey)
1924 ));
1925 }
1926
1927 #[test]
1928 fn oversized_dsa_spki_parameter_is_rejected_before_bigint_decode() {
1929 let oversized = vec![1_u8; crate::hard_limits::DSA_KEY_COMPONENT_BYTE_CEILING + 1];
1932 let one = [1_u8];
1933 let params = der::Encode::to_der(&super::super::signature::BorrowedDsaPublicParameters {
1934 p: der::asn1::UintRef::new(&oversized).expect("positive P"),
1935 q: der::asn1::UintRef::new(&one).expect("positive Q"),
1936 g: der::asn1::UintRef::new(&one).expect("positive G"),
1937 })
1938 .expect("parameters encode");
1939 let y = der::Encode::to_der(&der::asn1::UintRef::new(&one).expect("positive Y"))
1940 .expect("public value encodes");
1941 let spki = rsa::pkcs8::SubjectPublicKeyInfoRef {
1942 algorithm: rsa::pkcs8::AlgorithmIdentifierRef {
1943 oid: dsa::OID,
1944 parameters: Some(der::asn1::AnyRef::from_der(¶ms).expect("parameters")),
1945 },
1946 subject_public_key: der::asn1::BitStringRef::new(0, &y).expect("bit string"),
1947 };
1948 let encoded = der::Encode::to_der(&spki).expect("SPKI encodes");
1949 assert!(matches!(
1950 decode_dsa_verifying_key(&encoded),
1951 Err(super::super::signature::SignatureVerificationError::InvalidKeyDer)
1952 ));
1953 assert!(matches!(
1956 validate_spki_algorithm(&encoded, SignatureAlgorithm::DsaSha256),
1957 Err(KeyResolutionError::InvalidPublicKey)
1958 ));
1959 }
1960
1961 struct RejectSecondSha512Provider {
1962 sha512_calls: AtomicUsize,
1963 verification_calls: AtomicUsize,
1964 reject_verification_call: Option<usize>,
1965 rejected_verification_data: Option<Vec<u8>>,
1966 }
1967
1968 impl crate::provider::CryptoProvider for RejectSecondSha512Provider {
1969 fn name(&self) -> &'static str {
1970 "reject-second-sha512"
1971 }
1972
1973 fn supports(&self, capability: crate::provider::ProviderCapability<'_>) -> bool {
1974 crate::provider::default_provider().supports(capability)
1975 }
1976
1977 fn fill_random(&self, output: &mut [u8]) -> Result<(), crate::provider::ProviderError> {
1978 crate::provider::default_provider().fill_random(output)
1979 }
1980
1981 fn derive_key(
1982 &self,
1983 parameters: &crate::provider::KdfParameters<'_>,
1984 secret: &[u8],
1985 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1986 crate::provider::default_provider().derive_key(parameters, secret)
1987 }
1988
1989 fn digest(
1990 &self,
1991 algorithm: super::super::DigestAlgorithm,
1992 data: &[u8],
1993 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1994 if algorithm == super::super::DigestAlgorithm::Sha512
1995 && self.sha512_calls.fetch_add(1, Ordering::Relaxed) > 0
1996 {
1997 return Err(crate::provider::ProviderError::Unsupported {
1998 operation: crate::provider::ProviderOperation::Digest,
1999 algorithm: Some(algorithm.uri().to_owned()),
2000 });
2001 }
2002 crate::provider::default_provider().digest(algorithm, data)
2003 }
2004
2005 fn sign(
2006 &self,
2007 key: &dyn super::super::SigningKey,
2008 algorithm: SignatureAlgorithm,
2009 data: &[u8],
2010 ) -> Result<Vec<u8>, super::super::SigningKeyError> {
2011 crate::provider::default_provider().sign(key, algorithm, data)
2012 }
2013
2014 fn verify(
2015 &self,
2016 key: &dyn VerifyingKey,
2017 algorithm: SignatureAlgorithm,
2018 data: &[u8],
2019 signature: &[u8],
2020 ) -> Result<bool, DsigError> {
2021 let call = self.verification_calls.fetch_add(1, Ordering::Relaxed);
2022 if self.reject_verification_call == Some(call)
2023 || self
2024 .rejected_verification_data
2025 .as_deref()
2026 .is_some_and(|rejected| rejected == data)
2027 {
2028 return Err(crate::provider::ProviderError::Unsupported {
2029 operation: crate::provider::ProviderOperation::Verify,
2030 algorithm: Some(algorithm.uri().to_owned()),
2031 }
2032 .into());
2033 }
2034 crate::provider::default_provider().verify(key, algorithm, data, signature)
2035 }
2036
2037 fn verify_x509_signature(
2038 &self,
2039 algorithm: crate::provider::X509SignatureAlgorithm,
2040 data: &[u8],
2041 signature: &[u8],
2042 issuer_spki_der: &[u8],
2043 ) -> Result<bool, crate::provider::ProviderError> {
2044 let call = self.verification_calls.fetch_add(1, Ordering::Relaxed);
2045 if self.reject_verification_call == Some(call)
2046 || self
2047 .rejected_verification_data
2048 .as_deref()
2049 .is_some_and(|rejected| rejected == data)
2050 {
2051 return Err(crate::provider::ProviderError::Unsupported {
2052 operation: crate::provider::ProviderOperation::VerifyCertificate,
2053 algorithm: Some(algorithm.oid().to_owned()),
2054 });
2055 }
2056 crate::provider::default_provider().verify_x509_signature(
2057 algorithm,
2058 data,
2059 signature,
2060 issuer_spki_der,
2061 )
2062 }
2063
2064 #[cfg(feature = "xmlenc")]
2065 fn encrypt_data(
2066 &self,
2067 algorithm: crate::xmlenc::DataEncryptionAlgorithm,
2068 key: &[u8],
2069 plaintext: &[u8],
2070 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2071 crate::provider::default_provider().encrypt_data(algorithm, key, plaintext)
2072 }
2073
2074 #[cfg(feature = "xmlenc")]
2075 fn decrypt_data(
2076 &self,
2077 algorithm: crate::xmlenc::DataEncryptionAlgorithm,
2078 key: &[u8],
2079 ciphertext: &[u8],
2080 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2081 crate::provider::default_provider().decrypt_data(algorithm, key, ciphertext)
2082 }
2083
2084 #[cfg(feature = "xmlenc")]
2085 fn wrap_key(
2086 &self,
2087 algorithm: crate::xmlenc::KeyWrapAlgorithm,
2088 kek: &[u8],
2089 key: &[u8],
2090 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2091 crate::provider::default_provider().wrap_key(algorithm, kek, key)
2092 }
2093
2094 #[cfg(feature = "xmlenc")]
2095 fn unwrap_key(
2096 &self,
2097 algorithm: crate::xmlenc::KeyWrapAlgorithm,
2098 kek: &[u8],
2099 wrapped: &[u8],
2100 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2101 crate::provider::default_provider().unwrap_key(algorithm, kek, wrapped)
2102 }
2103
2104 #[cfg(feature = "xmlenc")]
2105 fn transport_key(
2106 &self,
2107 key: &dyn crate::provider::KeyTransportKey,
2108 parameters: &crate::xmlenc::RsaOaepParameters,
2109 plaintext: &[u8],
2110 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2111 crate::provider::default_provider().transport_key(key, parameters, plaintext)
2112 }
2113
2114 #[cfg(feature = "xmlenc")]
2115 fn recover_key(
2116 &self,
2117 key: &dyn crate::provider::KeyRecoveryKey,
2118 parameters: &crate::xmlenc::RsaOaepParameters,
2119 ciphertext: &[u8],
2120 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2121 crate::provider::default_provider().recover_key(key, parameters, ciphertext)
2122 }
2123 }
2124
2125 fn chain_policy() -> crate::policy::KeyTrustPolicy {
2126 crate::policy::KeyTrustPolicy {
2127 verify_x509_chains: true,
2128 ..crate::policy::KeyTrustPolicy::default()
2129 }
2130 }
2131
2132 fn cryptographic_policy() -> crate::policy::VerificationPolicy {
2133 verification_policy_with_trust(crate::policy::KeyTrustPolicy {
2135 mode: crate::policy::VerificationTrustMode::CryptographicOnly,
2136 ..crate::policy::KeyTrustPolicy::default()
2137 })
2138 }
2139
2140 fn chain_policy_at(verification_time: SystemTime) -> crate::policy::KeyTrustPolicy {
2141 crate::policy::KeyTrustPolicy {
2142 verification_time: Some(verification_time),
2143 ..chain_policy()
2144 }
2145 }
2146
2147 fn verification_policy_with_trust(
2148 key_trust: crate::policy::KeyTrustPolicy,
2149 ) -> crate::policy::VerificationPolicy {
2150 crate::policy::VerificationPolicy {
2151 key_trust,
2152 ..crate::policy::VerificationPolicy::default()
2153 }
2154 }
2155
2156 const SIGNED_SAML: &str =
2157 include_str!("../../tests/fixtures/saml/response_signed_by_idp_ecdsa.xml");
2158 const SAML_PUBLIC_KEY: &str =
2159 include_str!("../../tests/fixtures/keys/ec/saml-idp-ecdsa-pubkey.pem");
2160 const RSA_PUBLIC_KEY: &str = include_str!("../../tests/fixtures/keys/rsa/rsa-2048-pubkey.pem");
2161 const RSA_4096_CERTIFICATE: &str =
2162 include_str!("../../tests/fixtures/keys/rsa/rsa-4096-cert.pem");
2163 const X509_DIGEST_SIGNATURE: &str = include_str!(
2164 "../../tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloped-x509-digest-sha512.xml"
2165 );
2166 const X509_DIGEST_SHA256_SIGNATURE: &str = include_str!(
2167 "../../tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloped-x509-digest-sha256.xml"
2168 );
2169 const RSA_KEY_VALUE_SIGNATURE: &str = include_str!(
2170 "../../tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloping-sha256-rsa-sha256.xml"
2171 );
2172 const LEGACY_RSA_KEY_VALUE_SIGNATURE: &str = include_str!(
2173 "../../tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-rsa.xml"
2174 );
2175 const EC_P256_KEY_VALUE_SIGNATURE: &str = include_str!(
2176 "../../tests/fixtures/xmldsig/xmldsig11-interop-2012/signature-enveloping-p256_sha256.xml"
2177 );
2178 const EC_P384_KEY_VALUE_SIGNATURE: &str = include_str!(
2179 "../../tests/fixtures/xmldsig/xmldsig11-interop-2012/signature-enveloping-p384_sha384.xml"
2180 );
2181
2182 fn replace_key_info(xml: &str, replacement: &str) -> String {
2183 let start = xml.find("<ds:KeyInfo>").expect("fixture has KeyInfo");
2184 let end = xml
2185 .find("</ds:KeyInfo>")
2186 .expect("fixture has closing KeyInfo")
2187 + "</ds:KeyInfo>".len();
2188 format!("{}{}{}", &xml[..start], replacement, &xml[end..])
2189 }
2190
2191 fn replace_unprefixed_key_info(xml: &str, replacement: &str) -> String {
2192 let start = xml.find("<KeyInfo>").expect("fixture has KeyInfo");
2193 let end = xml.find("</KeyInfo>").expect("fixture has closing KeyInfo") + "</KeyInfo>".len();
2194 format!("{}{}{}", &xml[..start], replacement, &xml[end..])
2195 }
2196
2197 fn rsa_key_value_parts(public_key: &rsa::RsaPublicKey) -> (String, String) {
2198 (
2199 STANDARD.encode(public_key.n().to_be_bytes_trimmed_vartime()),
2200 STANDARD.encode(public_key.e().to_be_bytes_trimmed_vartime()),
2201 )
2202 }
2203
2204 fn x509_signature_with_leaf_subject() -> String {
2205 replace_unprefixed_key_info(
2206 X509_DIGEST_SIGNATURE,
2207 "<KeyInfo><X509Data><X509SubjectName>CN=Test Key rsa-4096,O=XML Security Library (http://www.aleksey.com/xmlsec),ST=California,C=US</X509SubjectName></X509Data></KeyInfo>",
2208 )
2209 }
2210
2211 fn fixture_certificate_time() -> SystemTime {
2212 SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_800_000_000)
2214 }
2215
2216 fn public_key_der(pem_text: &str) -> Vec<u8> {
2217 let (rest, pem) = x509_parser::pem::parse_x509_pem(pem_text.as_bytes())
2218 .expect("fixture public key is PEM");
2219 assert!(rest.iter().all(|byte| byte.is_ascii_whitespace()));
2220 assert_eq!(pem.label, "PUBLIC KEY");
2221 pem.contents
2222 }
2223
2224 fn certificate_der(pem_text: &str) -> Vec<u8> {
2225 let (rest, pem) = x509_parser::pem::parse_x509_pem(pem_text.as_bytes())
2226 .expect("fixture certificate is PEM");
2227 assert!(rest.iter().all(|byte| byte.is_ascii_whitespace()));
2228 assert_eq!(pem.label, "CERTIFICATE");
2229 pem.contents
2230 }
2231
2232 fn crl_der(pem_text: &str) -> Vec<u8> {
2233 let (rest, pem) =
2234 x509_parser::pem::parse_x509_pem(pem_text.as_bytes()).expect("fixture CRL is PEM");
2235 assert!(rest.iter().all(|byte| byte.is_ascii_whitespace()));
2236 assert_eq!(pem.label, "X509 CRL");
2237 pem.contents
2238 }
2239
2240 fn generated_certificate_params(common_name: &str, is_ca: bool) -> rcgen::CertificateParams {
2241 let mut params = rcgen::CertificateParams::new(Vec::new())
2242 .expect("empty SAN list should produce valid certificate parameters");
2243 params
2244 .distinguished_name
2245 .push(rcgen::DnType::CommonName, common_name);
2246 if is_ca {
2247 params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2248 params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2249 }
2250 params
2251 }
2252
2253 fn authorized_revoked_chain() -> (X509DataInfo, Vec<u8>) {
2254 let mut root_params = generated_certificate_params("revocation root", true);
2255 root_params.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign];
2256 let root = rcgen::CertifiedIssuer::self_signed(
2257 root_params,
2258 KeyPair::generate().expect("root key generation should succeed"),
2259 )
2260 .expect("root should be self-signable");
2261
2262 let issuer_key = KeyPair::generate().expect("issuer key generation should succeed");
2263 let mut issuer_params = generated_certificate_params("revocation issuer", true);
2264 issuer_params.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign];
2265 let issuer_certificate = issuer_params
2266 .signed_by(&issuer_key, &root)
2267 .expect("root should sign issuer certificate");
2268 let issuer = Issuer::new(issuer_params, issuer_key);
2269
2270 let mut leaf_params = generated_certificate_params("revoked signer", false);
2271 leaf_params.serial_number = Some(SerialNumber::from(42_u64));
2272 leaf_params.key_usages = vec![KeyUsagePurpose::DigitalSignature];
2273 let leaf = leaf_params
2274 .signed_by(
2275 &KeyPair::generate().expect("leaf key generation should succeed"),
2276 &issuer,
2277 )
2278 .expect("issuer should sign leaf certificate");
2279 let crl = CertificateRevocationListParams {
2280 this_update: date_time_ymd(2026, 3, 15),
2281 next_update: date_time_ymd(2026, 4, 15),
2282 crl_number: SerialNumber::from(1_u64),
2283 issuing_distribution_point: None,
2284 revoked_certs: vec![RevokedCertParams {
2285 serial_number: SerialNumber::from(42_u64),
2286 revocation_time: date_time_ymd(2026, 3, 16),
2287 reason_code: None,
2288 invalidity_date: None,
2289 }],
2290 key_identifier_method: KeyIdMethod::Sha256,
2291 }
2292 .signed_by(&issuer)
2293 .expect("issuer should sign CRL");
2294 let mut info = x509_info(
2295 vec![
2296 leaf.der().to_vec(),
2297 issuer_certificate.der().to_vec(),
2298 root.der().to_vec(),
2299 ],
2300 0,
2301 );
2302 info.crls.push(crl.der().to_vec());
2303 (info, root.der().to_vec())
2304 }
2305
2306 fn x509_info(certificates: Vec<Vec<u8>>, signing_index: usize) -> X509DataInfo {
2307 let parsed_certificates = certificates
2308 .iter()
2309 .map(|certificate| {
2310 parse_x509_certificate(certificate)
2311 .expect("generated certificate should have supported metadata")
2312 })
2313 .collect();
2314 X509DataInfo {
2315 certificates,
2316 parsed_certificates,
2317 certificate_chain: vec![signing_index],
2318 ..X509DataInfo::default()
2319 }
2320 }
2321
2322 #[test]
2323 fn defaults_match_key_resolution_policy() {
2324 let config = KeyResolverConfig::default();
2326
2327 assert!(config.trusted_certs.is_empty());
2328 assert!(config.lookup_certs.is_empty());
2329 assert!(config.named_keys.is_empty());
2330 let trust = crate::policy::VerificationPolicy::default().key_trust;
2331 assert!(!trust.verify_x509_chains);
2332 assert!(!trust.check_crls);
2333 assert_eq!(trust.verification_time, None);
2334 assert_eq!(trust.max_x509_chain_depth, 9);
2335 }
2336
2337 #[test]
2338 fn verification_policy_controls_leaf_extended_key_usage() {
2339 let root = rcgen::CertifiedIssuer::self_signed(
2342 generated_certificate_params("EKU policy root", true),
2343 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2344 )
2345 .expect("root should be self-signable");
2346 let mut leaf_params = generated_certificate_params("TLS-only XML signer", false);
2347 leaf_params.key_usages = vec![rcgen::KeyUsagePurpose::DigitalSignature];
2348 leaf_params.extended_key_usages = vec![rcgen::ExtendedKeyUsagePurpose::ServerAuth];
2349 let leaf = leaf_params
2350 .signed_by(
2351 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2352 &root,
2353 )
2354 .expect("root should sign leaf certificate");
2355 let key_info = KeyInfo {
2356 sources: vec![KeyInfoSource::X509Data(x509_info(
2357 vec![leaf.der().to_vec(), root.der().to_vec()],
2358 0,
2359 ))],
2360 };
2361 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2362 trusted_certs: vec![root.der().to_vec()],
2363 ..KeyResolverConfig::default()
2364 });
2365 let mut policy = crate::policy::VerificationPolicy::default();
2366 policy.key_trust.verify_x509_chains = true;
2367
2368 let error = match resolver.resolve_with_policy(
2369 Some(&key_info),
2370 SignatureAlgorithm::EcdsaSha256,
2371 &policy,
2372 ) {
2373 Ok(_) => panic!("unapproved restricted EKU must be rejected"),
2374 Err(error) => error,
2375 };
2376 assert!(matches!(
2377 error,
2378 DsigError::KeyResolution(KeyResolutionError::Chain(
2379 super::super::X509ChainError::InvalidKeyUsage {
2380 position: 0,
2381 required: "an approved extended key usage",
2382 }
2383 ))
2384 ));
2385
2386 policy.key_trust.allowed_extended_key_usages =
2387 std::collections::HashSet::from([crate::policy::ExtendedKeyPurpose::ServerAuth]);
2388 assert!(
2389 resolver
2390 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::EcdsaSha256, &policy,)
2391 .expect("approved restricted EKU must pass path validation")
2392 .is_some()
2393 );
2394 }
2395
2396 #[test]
2397 fn operation_policy_rejects_zero_x509_resource_limits() {
2398 for trust in [
2401 crate::policy::KeyTrustPolicy {
2402 verify_x509_chains: true,
2403 max_x509_chain_depth: 0,
2404 ..crate::policy::KeyTrustPolicy::default()
2405 },
2406 crate::policy::KeyTrustPolicy {
2407 verify_x509_chains: true,
2408 max_x509_candidate_paths: 0,
2409 ..crate::policy::KeyTrustPolicy::default()
2410 },
2411 ] {
2412 let certificate = certificate_der(RSA_4096_CERTIFICATE);
2413 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2414 trusted_certs: vec![certificate],
2415 ..KeyResolverConfig::default()
2416 });
2417 let policy = crate::policy::VerificationPolicy {
2418 key_trust: trust,
2419 ..crate::policy::VerificationPolicy::default()
2420 };
2421 let error = super::super::VerifyContext::new()
2422 .policy(policy)
2423 .key_resolver(&resolver)
2424 .verify(&x509_signature_with_leaf_subject())
2425 .expect_err("zero composed X.509 limits must fail as policy errors");
2426
2427 assert!(matches!(
2428 error,
2429 DsigError::Policy(crate::policy::PolicyViolation::InvalidResourceLimit {
2430 requirement: "limit must be nonzero",
2431 actual: 0,
2432 ..
2433 })
2434 ));
2435 }
2436 }
2437
2438 #[test]
2439 fn operation_policy_rejects_crl_checking_without_chain_validation() {
2440 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2443 lookup_certs: vec![certificate_der(RSA_4096_CERTIFICATE)],
2444 ..KeyResolverConfig::default()
2445 });
2446 let policy = crate::policy::VerificationPolicy {
2447 key_trust: crate::policy::KeyTrustPolicy {
2448 check_crls: true,
2449 ..crate::policy::KeyTrustPolicy::default()
2450 },
2451 ..crate::policy::VerificationPolicy::default()
2452 };
2453 let error = super::super::VerifyContext::new()
2454 .policy(policy)
2455 .key_resolver(&resolver)
2456 .verify(&x509_signature_with_leaf_subject())
2457 .expect_err("CRL-only trust policy must fail before certificate use");
2458
2459 assert!(matches!(
2460 error,
2461 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust {
2462 reason: "CRL checking requires X.509 chain validation"
2463 })
2464 ));
2465 }
2466
2467 #[test]
2468 fn hmac_key_rejects_empty_secret_and_wrong_algorithm() {
2469 assert!(matches!(
2471 HmacSha1VerificationKey::new(Vec::new()),
2472 Err(KeyResolutionError::InvalidPublicKey)
2473 ));
2474 let key = HmacSha1VerificationKey::new(b"secret".to_vec())
2475 .expect("non-empty HMAC secret must be accepted");
2476 assert!(matches!(
2477 key.verify(SignatureAlgorithm::RsaSha256, b"data", b"signature"),
2478 Err(DsigError::KeyResolution(
2479 KeyResolutionError::AlgorithmMismatch
2480 ))
2481 ));
2482 }
2483
2484 #[test]
2485 fn hmac_key_uses_the_operation_policy_for_truncation() {
2486 let key = HmacVerificationKey::new(b"secret".to_vec())
2490 .expect("the fixture HMAC secret is non-empty");
2491 let mut mac = hmac::Hmac::<sha1::Sha1>::new_from_slice(b"secret")
2492 .expect("HMAC accepts an arbitrary non-empty secret");
2493 mac.update(b"data");
2494 let expected = mac.finalize().into_bytes();
2495
2496 let policy = crate::policy::VerificationPolicy {
2497 hmac: crate::policy::HmacPolicy {
2498 minimum_key_bits: 40,
2499 minimum_output_bits: 80,
2500 },
2501 ..crate::policy::VerificationPolicy::default()
2502 };
2503 assert!(
2504 key.verify_with_policy(
2505 &policy,
2506 SignatureAlgorithm::HmacSha1,
2507 b"data",
2508 &expected[..10],
2509 )
2510 .expect("the compatibility policy and algorithm match")
2511 );
2512 assert!(
2513 !key.verify_with_policy(&policy, SignatureAlgorithm::HmacSha1, b"data", &[0_u8; 10],)
2514 .expect("a mismatched truncated MAC must be rejected")
2515 );
2516 }
2517
2518 #[test]
2519 fn hmac_key_direct_api_rejects_attacker_selected_short_output() {
2520 let key = HmacVerificationKey::new([0x42; 16]).expect("fixed HMAC key must parse");
2523 let mut mac = hmac::Hmac::<sha2::Sha256>::new_from_slice(&[0x42; 16])
2524 .expect("HMAC accepts the fixed secret");
2525 mac.update(b"data");
2526 let expected = mac.finalize().into_bytes();
2527
2528 assert!(matches!(
2529 key.verify(SignatureAlgorithm::HmacSha256, b"data", &expected[..1]),
2530 Err(DsigError::Policy(
2531 crate::policy::PolicyViolation::HmacOutputLength {
2532 minimum: 128,
2533 maximum: 256,
2534 actual: 8,
2535 }
2536 ))
2537 ));
2538 }
2539
2540 #[test]
2541 fn hmac_key_debug_redacts_secret_material() {
2542 let secret = b"unique-debug-secret-marker";
2544 let key = HmacVerificationKey::new(secret.to_vec())
2545 .expect("the fixture HMAC secret is non-empty");
2546
2547 let debug = format!("{key:?}");
2548 assert!(
2549 !debug
2550 .contains(std::str::from_utf8(secret).expect("the debug marker is literal ASCII"))
2551 );
2552 assert!(!debug.contains(&format!("{secret:?}")));
2553 assert!(!debug.contains("output_length_bits"));
2554 }
2555
2556 #[test]
2557 fn stores_named_verification_key_metadata() {
2558 let key = VerificationKey {
2560 algorithm: SignatureAlgorithm::RsaSha256,
2561 public_key_bytes: vec![1, 2, 3],
2562 certificate_der: Some(vec![4, 5, 6]),
2563 name: Some("idp-signing".into()),
2564 };
2565 let mut config = KeyResolverConfig::default();
2566 config.named_keys.insert("idp-signing".into(), key.clone());
2567
2568 assert_eq!(config.named_keys.get("idp-signing"), Some(&key));
2569 }
2570
2571 #[test]
2572 fn resolves_embedded_certificate_end_to_end() {
2573 let resolver = DefaultKeyResolver::default();
2575 let result = super::super::VerifyContext::new()
2576 .policy(cryptographic_policy())
2577 .key_resolver(&resolver)
2578 .verify(SIGNED_SAML)
2579 .expect("embedded certificate should resolve");
2580
2581 assert_eq!(result.status, super::super::DsigStatus::Valid);
2582 assert_eq!(
2583 result.key_trust,
2584 super::super::KeyTrustEvidence::NotEstablished
2585 );
2586 }
2587
2588 #[test]
2589 fn embedded_certificate_requires_trust_but_explicit_pin_authorizes_it() {
2590 let untrusted = DefaultKeyResolver::default();
2592 let error = super::super::VerifyContext::new()
2593 .key_resolver(&untrusted)
2594 .verify(SIGNED_SAML)
2595 .expect_err("an embedded certificate is not a trust declaration");
2596 assert!(matches!(
2597 error,
2598 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust { .. })
2599 ));
2600
2601 let xml = roxmltree::Document::parse(SIGNED_SAML).expect("signed SAML fixture must parse");
2602 let certificate = xml
2603 .descendants()
2604 .find(|node| {
2605 node.has_tag_name(("http://www.w3.org/2000/09/xmldsig#", "X509Certificate"))
2606 })
2607 .expect("signed SAML must embed its certificate");
2608 let der = STANDARD
2609 .decode(
2610 certificate
2611 .text()
2612 .expect("fixture certificate must contain Base64 text")
2613 .split_whitespace()
2614 .collect::<String>(),
2615 )
2616 .expect("fixture certificate must be valid Base64");
2617 let trusted = DefaultKeyResolver::new(KeyResolverConfig {
2618 trusted_certs: vec![der],
2619 ..KeyResolverConfig::default()
2620 });
2621 let result = super::super::VerifyContext::new()
2622 .key_resolver(&trusted)
2623 .verify(SIGNED_SAML)
2624 .expect("an exact caller certificate pin authorizes the key");
2625 assert_eq!(result.status, super::super::DsigStatus::Valid);
2626 assert_eq!(
2627 result.key_trust,
2628 super::super::KeyTrustEvidence::CallerTrusted
2629 );
2630
2631 assert!(
2633 super::super::VerifyContext::new()
2634 .key_resolver(&untrusted)
2635 .verify(SIGNED_SAML)
2636 .is_err()
2637 );
2638 }
2639
2640 #[test]
2641 fn certificate_pin_inspections_share_the_candidate_budget() {
2642 let xml = roxmltree::Document::parse(SIGNED_SAML).expect("fixture must parse");
2644 let text = xml
2645 .descendants()
2646 .find(|node| {
2647 node.has_tag_name(("http://www.w3.org/2000/09/xmldsig#", "X509Certificate"))
2648 })
2649 .and_then(|node| node.text())
2650 .expect("fixture embeds a certificate");
2651 let certificate = STANDARD
2652 .decode(text.split_whitespace().collect::<String>())
2653 .expect("fixture certificate must decode");
2654 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2655 trusted_certs: vec![certificate],
2656 ..KeyResolverConfig::default()
2657 });
2658 let mut policy = crate::policy::VerificationPolicy::default();
2659 policy.resources.max_key_candidates = 1;
2660 let error = super::super::VerifyContext::new()
2661 .policy(policy)
2662 .key_resolver(&resolver)
2663 .verify(SIGNED_SAML)
2664 .expect_err("the certificate and pin are separate inspections");
2665 assert!(matches!(
2666 error,
2667 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
2668 resource: crate::policy::resource_name::KEY_CANDIDATES,
2669 maximum: 1,
2670 actual: 2,
2671 })
2672 ));
2673 }
2674
2675 #[test]
2676 fn resolves_x509_digest_from_configured_certificates() {
2677 let leaf_certificate_der = certificate_der(RSA_4096_CERTIFICATE);
2680 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2681 lookup_certs: vec![leaf_certificate_der],
2682 trusted_certs: vec![
2683 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
2684 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
2685 ],
2686 ..KeyResolverConfig::default()
2687 });
2688 for signature in [X509_DIGEST_SHA256_SIGNATURE, X509_DIGEST_SIGNATURE] {
2689 let result = super::super::VerifyContext::new()
2690 .policy(cryptographic_policy())
2691 .key_resolver(&resolver)
2692 .verify(signature)
2693 .expect("X509Digest should resolve a configured certificate");
2694
2695 assert_eq!(result.status, super::super::DsigStatus::Valid);
2696 }
2697 }
2698
2699 #[test]
2700 fn selector_resolved_certificate_obeys_chain_policy() {
2701 let leaf_certificate_der = certificate_der(RSA_4096_CERTIFICATE);
2704 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2705 lookup_certs: vec![leaf_certificate_der],
2706 trusted_certs: vec![
2707 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
2708 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
2709 ],
2710 ..KeyResolverConfig::default()
2711 });
2712 let error = super::super::VerifyContext::new()
2713 .policy(verification_policy_with_trust(chain_policy_at(
2714 SystemTime::UNIX_EPOCH,
2715 )))
2716 .key_resolver(&resolver)
2717 .verify(&x509_signature_with_leaf_subject())
2718 .expect_err("selector-resolved certificate must satisfy chain policy");
2719
2720 assert!(
2721 matches!(
2722 &error,
2723 DsigError::KeyResolution(KeyResolutionError::Chain(
2724 super::super::X509ChainError::CertificateNotValid(_)
2725 ))
2726 ),
2727 "unexpected selector policy error: {error:?}"
2728 );
2729 }
2730
2731 #[test]
2732 fn selector_resolved_configured_root_remains_a_trust_anchor() {
2733 let mut params = rcgen::CertificateParams::new(Vec::new())
2736 .expect("empty SAN list should produce valid certificate parameters");
2737 params
2738 .distinguished_name
2739 .push(rcgen::DnType::CommonName, "configured root");
2740 params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2741 let key_pair = rcgen::KeyPair::generate().expect("test key generation should succeed");
2742 let certificate = params
2743 .self_signed(&key_pair)
2744 .expect("test root should be self-signable");
2745 let certificate_der = certificate.der().to_vec();
2746 let key_info_xml = concat!(
2747 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
2748 "<X509Data><X509SubjectName>CN=configured root</X509SubjectName></X509Data>",
2749 "</KeyInfo>"
2750 );
2751 let document = roxmltree::Document::parse(key_info_xml)
2752 .expect("static selector KeyInfo should parse as XML");
2753 let key_info = super::super::parse_key_info(document.root_element())
2754 .expect("static selector KeyInfo should satisfy XMLDSig structure");
2755 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2756 trusted_certs: vec![certificate_der],
2757 ..KeyResolverConfig::default()
2758 });
2759
2760 let resolved = resolver
2761 .resolve_with_policy(
2762 Some(&key_info),
2763 SignatureAlgorithm::EcdsaSha256,
2764 &verification_policy_with_trust(chain_policy()),
2765 )
2766 .expect("configured self-signed certificate should validate as its own anchor");
2767
2768 assert!(resolved.is_some());
2769 }
2770
2771 #[test]
2772 fn selector_resolved_non_self_signed_trust_anchor_terminates_the_path() {
2773 let mut issuer_params = rcgen::CertificateParams::new(Vec::new())
2777 .expect("empty issuer SAN list should be valid");
2778 issuer_params
2779 .distinguished_name
2780 .push(rcgen::DnType::CommonName, "lookup-only issuer");
2781 issuer_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2782 issuer_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2783 let issuer = rcgen::CertifiedIssuer::self_signed(
2784 issuer_params,
2785 rcgen::KeyPair::generate().expect("issuer key generation should succeed"),
2786 )
2787 .expect("issuer certificate should be self-signable");
2788
2789 let mut anchor_params = rcgen::CertificateParams::new(Vec::new())
2790 .expect("empty anchor SAN list should be valid");
2791 anchor_params
2792 .distinguished_name
2793 .push(rcgen::DnType::CommonName, "direct trust anchor");
2794 let anchor = anchor_params
2795 .signed_by(
2796 &rcgen::KeyPair::generate().expect("anchor key generation should succeed"),
2797 &issuer,
2798 )
2799 .expect("issuer should sign the directly trusted certificate");
2800 let key_info_xml = concat!(
2801 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
2802 "<X509Data><X509SubjectName>CN=direct trust anchor</X509SubjectName></X509Data>",
2803 "</KeyInfo>"
2804 );
2805 let document = roxmltree::Document::parse(key_info_xml)
2806 .expect("static selector KeyInfo should parse as XML");
2807 let key_info = super::super::parse_key_info(document.root_element())
2808 .expect("static selector KeyInfo should satisfy XMLDSig structure");
2809 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2810 trusted_certs: vec![anchor.der().to_vec()],
2811 lookup_certs: vec![issuer.der().to_vec()],
2812 ..KeyResolverConfig::default()
2813 });
2814
2815 let resolved = resolver
2816 .resolve_with_policy(
2817 Some(&key_info),
2818 SignatureAlgorithm::EcdsaSha256,
2819 &verification_policy_with_trust(chain_policy()),
2820 )
2821 .expect("an explicitly trusted selected certificate must terminate its path");
2822
2823 assert!(resolved.is_some());
2824 }
2825
2826 #[test]
2827 fn selector_resolved_leaf_stops_at_non_self_signed_trust_anchor() {
2828 let external_issuer = rcgen::CertifiedIssuer::self_signed(
2831 generated_certificate_params("external issuer", true),
2832 rcgen::KeyPair::generate().expect("external issuer key generation should succeed"),
2833 )
2834 .expect("external issuer should be self-signable");
2835 let anchor = rcgen::CertifiedIssuer::signed_by(
2836 generated_certificate_params("non-self-signed anchor", true),
2837 rcgen::KeyPair::generate().expect("anchor key generation should succeed"),
2838 &external_issuer,
2839 )
2840 .expect("external issuer should sign the anchor");
2841 let leaf = generated_certificate_params("anchor leaf", false)
2842 .signed_by(
2843 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2844 &anchor,
2845 )
2846 .expect("anchor should sign the leaf");
2847 let leaf_metadata = parse_x509_certificate(leaf.der())
2848 .expect("generated leaf should have supported metadata");
2849 let key_info = KeyInfo {
2850 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
2851 subject_names: vec![leaf_metadata.subject_dn],
2852 ..X509DataInfo::default()
2853 })],
2854 };
2855 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2856 trusted_certs: vec![anchor.der().to_vec()],
2857 lookup_certs: vec![leaf.der().to_vec(), external_issuer.der().to_vec()],
2858 ..KeyResolverConfig::default()
2859 });
2860
2861 let resolved = resolver
2862 .resolve_with_policy(
2863 Some(&key_info),
2864 SignatureAlgorithm::EcdsaSha256,
2865 &verification_policy_with_trust(chain_policy()),
2866 )
2867 .expect("path construction must stop at the configured anchor");
2868
2869 assert!(resolved.is_some());
2870 }
2871
2872 #[test]
2873 fn selector_resolved_leaf_does_not_anchor_itself() {
2874 let certificate_der = certificate_der(RSA_4096_CERTIFICATE);
2877 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2878 lookup_certs: vec![certificate_der],
2879 ..KeyResolverConfig::default()
2880 });
2881 let error = super::super::VerifyContext::new()
2882 .policy(verification_policy_with_trust(chain_policy_at(
2883 fixture_certificate_time(),
2884 )))
2885 .key_resolver(&resolver)
2886 .verify(&x509_signature_with_leaf_subject())
2887 .expect_err("selector-resolved leaf must not trust itself");
2888
2889 assert!(matches!(
2890 error,
2891 DsigError::KeyResolution(KeyResolutionError::Chain(
2892 super::super::X509ChainError::UntrustedRoot
2893 ))
2894 ));
2895 }
2896
2897 #[test]
2898 fn selector_resolved_leaf_uses_separate_anchor() {
2899 let leaf = certificate_der(RSA_4096_CERTIFICATE);
2902 let issuer = certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem"));
2903 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2904 lookup_certs: vec![leaf],
2905 trusted_certs: vec![issuer],
2906 ..KeyResolverConfig::default()
2907 });
2908 let result = super::super::VerifyContext::new()
2909 .policy(verification_policy_with_trust(chain_policy_at(
2910 fixture_certificate_time(),
2911 )))
2912 .key_resolver(&resolver)
2913 .verify(&x509_signature_with_leaf_subject())
2914 .expect("selector-resolved leaf should chain to its configured issuer");
2915
2916 assert_eq!(result.status, super::super::DsigStatus::Valid);
2917 }
2918
2919 #[test]
2920 fn selector_resolved_leaf_uses_lookup_intermediate() {
2921 let mut root_params =
2924 rcgen::CertificateParams::new(Vec::new()).expect("empty root SAN list should be valid");
2925 root_params
2926 .distinguished_name
2927 .push(rcgen::DnType::CommonName, "lookup root");
2928 root_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2929 root_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2930 let root = rcgen::CertifiedIssuer::self_signed(
2931 root_params,
2932 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2933 )
2934 .expect("root certificate should be self-signable");
2935
2936 let mut intermediate_params = rcgen::CertificateParams::new(Vec::new())
2937 .expect("empty intermediate SAN list should be valid");
2938 intermediate_params
2939 .distinguished_name
2940 .push(rcgen::DnType::CommonName, "lookup intermediate");
2941 intermediate_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2942 intermediate_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2943 let intermediate = rcgen::CertifiedIssuer::signed_by(
2944 intermediate_params,
2945 rcgen::KeyPair::generate().expect("intermediate key generation should succeed"),
2946 &root,
2947 )
2948 .expect("root should sign the intermediate certificate");
2949
2950 let mut leaf_params =
2951 rcgen::CertificateParams::new(Vec::new()).expect("empty leaf SAN list should be valid");
2952 leaf_params
2953 .distinguished_name
2954 .push(rcgen::DnType::CommonName, "lookup leaf");
2955 let leaf = leaf_params
2956 .signed_by(
2957 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2958 &intermediate,
2959 )
2960 .expect("intermediate should sign the leaf certificate");
2961 let key_info_xml = concat!(
2962 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
2963 "<X509Data><X509SubjectName>CN=lookup leaf</X509SubjectName></X509Data>",
2964 "</KeyInfo>"
2965 );
2966 let document = roxmltree::Document::parse(key_info_xml)
2967 .expect("static selector KeyInfo should parse as XML");
2968 let key_info = super::super::parse_key_info(document.root_element())
2969 .expect("static selector KeyInfo should satisfy XMLDSig structure");
2970 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2971 lookup_certs: vec![leaf.der().to_vec(), intermediate.der().to_vec()],
2972 trusted_certs: vec![root.der().to_vec()],
2973 ..KeyResolverConfig::default()
2974 });
2975
2976 let resolved = resolver
2977 .resolve_with_policy(
2978 Some(&key_info),
2979 SignatureAlgorithm::EcdsaSha256,
2980 &verification_policy_with_trust(chain_policy()),
2981 )
2982 .expect("selector-resolved leaf should chain through the lookup intermediate");
2983
2984 assert!(resolved.is_some());
2985 }
2986
2987 #[test]
2988 fn x509_path_signatures_use_the_operation_provider() {
2989 let root = rcgen::CertifiedIssuer::self_signed(
2993 generated_certificate_params("provider root", true),
2994 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2995 )
2996 .expect("root should be self-signable");
2997 let leaf = generated_certificate_params("provider leaf", false)
2998 .signed_by(
2999 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3000 &root,
3001 )
3002 .expect("root should sign the leaf");
3003 let leaf_der = leaf.der().to_vec();
3004 let leaf_metadata =
3005 parse_x509_certificate(&leaf_der).expect("generated leaf metadata should parse");
3006 let policy = crate::policy::VerificationPolicy {
3007 key_trust: chain_policy(),
3008 ..crate::policy::VerificationPolicy::default()
3009 };
3010
3011 let cases = [
3012 (
3013 KeyInfo {
3014 sources: vec![KeyInfoSource::X509Data(x509_info(
3015 vec![leaf_der.clone()],
3016 0,
3017 ))],
3018 },
3019 Vec::new(),
3020 ),
3021 (
3022 KeyInfo {
3023 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
3024 subject_names: vec![leaf_metadata.subject_dn],
3025 ..X509DataInfo::default()
3026 })],
3027 },
3028 vec![leaf_der],
3029 ),
3030 ];
3031
3032 for (key_info, lookup_certs) in cases {
3033 let provider = RejectSecondSha512Provider {
3034 sha512_calls: AtomicUsize::new(0),
3035 verification_calls: AtomicUsize::new(0),
3036 reject_verification_call: Some(0),
3037 rejected_verification_data: None,
3038 };
3039 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3040 trusted_certs: vec![root.der().to_vec()],
3041 lookup_certs,
3042 ..KeyResolverConfig::default()
3043 });
3044 let error = match resolver.resolve_with_policy_and_provider(
3045 Some(&key_info),
3046 SignatureAlgorithm::EcdsaSha256,
3047 &policy,
3048 &provider,
3049 ) {
3050 Ok(_) => panic!("the operation provider must gate every X.509 path signature"),
3051 Err(error) => error,
3052 };
3053
3054 assert!(matches!(
3055 error,
3056 DsigError::KeyResolution(KeyResolutionError::Chain(
3057 super::super::X509ChainError::UnsupportedSignatureAlgorithm { ref oid }
3058 )) if oid == "1.2.840.10045.4.3.2"
3059 ));
3060 assert_eq!(provider.verification_calls.load(Ordering::Relaxed), 1);
3061 }
3062
3063 let provider = RejectSecondSha512Provider {
3066 sha512_calls: AtomicUsize::new(0),
3067 verification_calls: AtomicUsize::new(0),
3068 reject_verification_call: Some(1),
3069 rejected_verification_data: None,
3070 };
3071 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3072 trusted_certs: vec![root.der().to_vec()],
3073 ..KeyResolverConfig::default()
3074 });
3075 let key_info = KeyInfo {
3076 sources: vec![KeyInfoSource::X509Data(x509_info(
3077 vec![leaf.der().to_vec()],
3078 0,
3079 ))],
3080 };
3081 let error = match resolver.resolve_with_policy_and_provider(
3082 Some(&key_info),
3083 SignatureAlgorithm::EcdsaSha256,
3084 &policy,
3085 &provider,
3086 ) {
3087 Ok(_) => panic!("complete-path validation must retain the operation provider"),
3088 Err(error) => error,
3089 };
3090 assert!(matches!(
3091 error,
3092 DsigError::KeyResolution(KeyResolutionError::Chain(
3093 super::super::X509ChainError::Provider(_)
3094 ))
3095 ));
3096 assert_eq!(provider.verification_calls.load(Ordering::Relaxed), 2);
3097 }
3098
3099 #[test]
3100 fn embedded_leaf_uses_lookup_intermediate_with_duplicate_anchor() {
3101 let trusted_root = rcgen::CertifiedIssuer::self_signed(
3104 generated_certificate_params("unrelated trusted root", true),
3105 rcgen::KeyPair::generate().expect("root key generation should succeed"),
3106 )
3107 .expect("root should be self-signable");
3108 let issuer_root = rcgen::CertifiedIssuer::self_signed(
3109 generated_certificate_params("untrusted issuer root", true),
3110 rcgen::KeyPair::generate().expect("issuer root key generation should succeed"),
3111 )
3112 .expect("issuer root should be self-signable");
3113 let intermediate = rcgen::CertifiedIssuer::signed_by(
3114 generated_certificate_params("embedded intermediate", true),
3115 rcgen::KeyPair::generate().expect("intermediate key generation should succeed"),
3116 &issuer_root,
3117 )
3118 .expect("issuer root should sign the intermediate");
3119 let leaf = generated_certificate_params("embedded leaf", false)
3120 .signed_by(
3121 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3122 &intermediate,
3123 )
3124 .expect("intermediate should sign the leaf");
3125 let key_info = KeyInfo {
3126 sources: vec![KeyInfoSource::X509Data(x509_info(
3127 vec![leaf.der().to_vec()],
3128 0,
3129 ))],
3130 };
3131 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3132 lookup_certs: vec![intermediate.der().to_vec()],
3133 trusted_certs: vec![trusted_root.der().to_vec(), trusted_root.der().to_vec()],
3134 ..KeyResolverConfig::default()
3135 });
3136
3137 let policy = verification_policy_with_trust(chain_policy());
3138 let error = match resolver.resolve_with_policy(
3139 Some(&key_info),
3140 SignatureAlgorithm::EcdsaSha256,
3141 &policy,
3142 ) {
3143 Ok(_) => panic!("an untrusted lookup intermediate must not become a trust anchor"),
3144 Err(error) => error,
3145 };
3146
3147 assert!(matches!(
3148 error,
3149 DsigError::KeyResolution(KeyResolutionError::Chain(
3150 super::super::X509ChainError::UntrustedRoot
3151 ))
3152 ));
3153 }
3154
3155 #[test]
3156 fn selector_resolved_leaf_chooses_unique_valid_same_key_path() {
3157 let trusted_root = rcgen::CertifiedIssuer::self_signed(
3161 generated_certificate_params("trusted cross-sign root", true),
3162 rcgen::KeyPair::generate().expect("trusted root key generation should succeed"),
3163 )
3164 .expect("trusted root should be self-signable");
3165 let untrusted_root = rcgen::CertifiedIssuer::self_signed(
3166 generated_certificate_params("untrusted cross-sign root", true),
3167 rcgen::KeyPair::generate().expect("untrusted root key generation should succeed"),
3168 )
3169 .expect("untrusted root should be self-signable");
3170 let shared_params = generated_certificate_params("shared cross-sign issuer", true);
3171 let shared_key =
3172 rcgen::KeyPair::generate().expect("shared issuer key generation should succeed");
3173 let trusted_intermediate = shared_params
3174 .signed_by(&shared_key, &trusted_root)
3175 .expect("trusted root should cross-sign the shared issuer key");
3176 let untrusted_intermediate = shared_params
3177 .signed_by(&shared_key, &untrusted_root)
3178 .expect("untrusted root should cross-sign the shared issuer key");
3179 let shared_issuer = rcgen::Issuer::from_params(&shared_params, &shared_key);
3180 let leaf = generated_certificate_params("cross-signed leaf", false)
3181 .signed_by(
3182 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3183 &shared_issuer,
3184 )
3185 .expect("shared issuer key should sign the leaf");
3186 let leaf_metadata = parse_x509_certificate(leaf.der())
3187 .expect("generated leaf should have supported metadata");
3188 let key_info = KeyInfo {
3189 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
3190 subject_names: vec![leaf_metadata.subject_dn],
3191 ..X509DataInfo::default()
3192 })],
3193 };
3194 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3195 trusted_certs: vec![trusted_root.der().to_vec()],
3196 lookup_certs: vec![
3197 leaf.der().to_vec(),
3198 untrusted_intermediate.der().to_vec(),
3199 trusted_intermediate.der().to_vec(),
3200 untrusted_root.der().to_vec(),
3201 ],
3202 ..KeyResolverConfig::default()
3203 });
3204
3205 let resolved = resolver
3206 .resolve_with_policy(
3207 Some(&key_info),
3208 SignatureAlgorithm::EcdsaSha256,
3209 &verification_policy_with_trust(chain_policy()),
3210 )
3211 .expect("the sole path to a configured anchor should be selected");
3212
3213 assert!(resolved.is_some());
3214 }
3215
3216 #[test]
3217 fn self_issued_rollover_continues_to_same_name_trusted_signer() {
3218 let root = rcgen::CertifiedIssuer::self_signed(
3221 generated_certificate_params("rollover authority", true),
3222 rcgen::KeyPair::generate().expect("root key generation should succeed"),
3223 )
3224 .expect("root should be self-signable");
3225 let rollover_params = generated_certificate_params("rollover authority", true);
3226 let rollover_key =
3227 rcgen::KeyPair::generate().expect("rollover key generation should succeed");
3228 let rollover_certificate = rollover_params
3229 .signed_by(&rollover_key, &root)
3230 .expect("root should sign the same-name rollover certificate");
3231 let rollover_issuer = rcgen::Issuer::from_params(&rollover_params, &rollover_key);
3232 let leaf = generated_certificate_params("rollover leaf", false)
3233 .signed_by(
3234 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3235 &rollover_issuer,
3236 )
3237 .expect("rollover key should sign the leaf");
3238 let leaf_metadata =
3239 parse_x509_certificate(leaf.der()).expect("generated leaf metadata should parse");
3240 let key_info = KeyInfo {
3241 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
3242 subject_names: vec![leaf_metadata.subject_dn],
3243 ..X509DataInfo::default()
3244 })],
3245 };
3246 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3247 trusted_certs: vec![root.der().to_vec()],
3248 lookup_certs: vec![leaf.der().to_vec(), rollover_certificate.der().to_vec()],
3249 ..KeyResolverConfig::default()
3250 });
3251
3252 let resolved = resolver
3253 .resolve_with_policy(
3254 Some(&key_info),
3255 SignatureAlgorithm::EcdsaSha256,
3256 &verification_policy_with_trust(chain_policy()),
3257 )
3258 .expect("same-name rollover path must reach its configured signer");
3259
3260 assert!(resolved.is_some());
3261 }
3262
3263 #[test]
3264 fn x509_candidate_limit_counts_generated_partial_paths() {
3265 let root = rcgen::CertifiedIssuer::self_signed(
3268 generated_certificate_params("candidate root", true),
3269 rcgen::KeyPair::generate().expect("root key generation should succeed"),
3270 )
3271 .expect("root should be self-signable");
3272 let intermediate = rcgen::CertifiedIssuer::signed_by(
3273 generated_certificate_params("candidate intermediate", true),
3274 rcgen::KeyPair::generate().expect("intermediate key generation should succeed"),
3275 &root,
3276 )
3277 .expect("root should sign the intermediate");
3278 let leaf = generated_certificate_params("candidate leaf", false)
3279 .signed_by(
3280 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3281 &intermediate,
3282 )
3283 .expect("intermediate should sign the leaf");
3284 let info = x509_info(
3285 vec![
3286 root.der().to_vec(),
3287 intermediate.der().to_vec(),
3288 leaf.der().to_vec(),
3289 ],
3290 2,
3291 );
3292
3293 assert!(matches!(
3294 build_x509_certificate_paths_to_trusted_prefix(
3295 &info,
3296 2,
3297 1,
3298 9,
3299 2,
3300 crate::provider::default_provider(),
3301 None,
3302 ),
3303 Err(X509ChainBuildError::AmbiguousIssuer)
3304 ));
3305 }
3306
3307 #[test]
3308 fn selector_resolved_leaf_disambiguates_same_subject_issuers_by_signature() {
3309 let mut root_params =
3313 rcgen::CertificateParams::new(Vec::new()).expect("empty root SAN list should be valid");
3314 root_params
3315 .distinguished_name
3316 .push(rcgen::DnType::CommonName, "shared-issuer root");
3317 root_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
3318 root_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
3319 let root = rcgen::CertifiedIssuer::self_signed(
3320 root_params,
3321 rcgen::KeyPair::generate().expect("root key generation should succeed"),
3322 )
3323 .expect("root certificate should be self-signable");
3324
3325 let intermediate = |key: rcgen::KeyPair| {
3326 let mut params = rcgen::CertificateParams::new(Vec::new())
3327 .expect("empty intermediate SAN list should be valid");
3328 params
3329 .distinguished_name
3330 .push(rcgen::DnType::CommonName, "renewed intermediate");
3331 params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
3332 params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
3333 rcgen::CertifiedIssuer::signed_by(params, key, &root)
3334 .expect("root should sign the intermediate certificate")
3335 };
3336 let unrelated_intermediate = intermediate(
3337 rcgen::KeyPair::generate().expect("unrelated intermediate key generation should work"),
3338 );
3339 let signing_intermediate = intermediate(
3340 rcgen::KeyPair::generate().expect("signing intermediate key generation should work"),
3341 );
3342
3343 let mut leaf_params =
3344 rcgen::CertificateParams::new(Vec::new()).expect("empty leaf SAN list should be valid");
3345 leaf_params
3346 .distinguished_name
3347 .push(rcgen::DnType::CommonName, "same-subject leaf");
3348 let leaf = leaf_params
3349 .signed_by(
3350 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3351 &signing_intermediate,
3352 )
3353 .expect("the selected intermediate should sign the leaf certificate");
3354 let key_info_xml = concat!(
3355 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
3356 "<X509Data><X509SubjectName>CN=same-subject leaf</X509SubjectName></X509Data>",
3357 "</KeyInfo>"
3358 );
3359 let document = roxmltree::Document::parse(key_info_xml)
3360 .expect("static selector KeyInfo should parse as XML");
3361 let key_info = super::super::parse_key_info(document.root_element())
3362 .expect("static selector KeyInfo should satisfy XMLDSig structure");
3363 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3364 lookup_certs: vec![
3365 leaf.der().to_vec(),
3366 unrelated_intermediate.der().to_vec(),
3367 signing_intermediate.der().to_vec(),
3368 ],
3369 trusted_certs: vec![root.der().to_vec()],
3370 ..KeyResolverConfig::default()
3371 });
3372
3373 let resolved = resolver
3374 .resolve_with_policy(
3375 Some(&key_info),
3376 SignatureAlgorithm::EcdsaSha256,
3377 &verification_policy_with_trust(chain_policy()),
3378 )
3379 .expect("the leaf signature should select its unique same-subject issuer");
3380
3381 assert!(resolved.is_some());
3382 }
3383
3384 #[test]
3385 fn x509_path_builder_skips_policy_rejected_alternatives() {
3386 use crate::provider::X509SignatureAlgorithm;
3387 use std::collections::HashSet;
3388 let root = rcgen::CertifiedIssuer::self_signed(
3391 generated_certificate_params("policy root", true),
3392 rcgen::KeyPair::generate().expect("root key"),
3393 )
3394 .expect("root certificate");
3395 let alternate_root = rcgen::CertifiedIssuer::self_signed(
3396 generated_certificate_params("policy alternate root", true),
3397 rcgen::KeyPair::generate_for(&rcgen::PKCS_ECDSA_P384_SHA384)
3398 .expect("alternate root key"),
3399 )
3400 .expect("alternate root certificate");
3401 let shared_params = generated_certificate_params("policy shared issuer", true);
3402 let shared_key = rcgen::KeyPair::generate().expect("issuer key");
3403 let rejected = shared_params
3404 .signed_by(&shared_key, &alternate_root)
3405 .expect("cross-signed issuer");
3406 let shared = rcgen::CertifiedIssuer::signed_by(shared_params, shared_key, &root)
3407 .expect("issuer certificate");
3408 let leaf = generated_certificate_params("policy leaf", false)
3409 .signed_by(&rcgen::KeyPair::generate().expect("leaf key"), &shared)
3410 .expect("leaf certificate");
3411 let rejected = rejected.der().to_vec();
3412 let allowed = crate::policy::CertificateSignatureAlgorithms::Allowlist(HashSet::from([
3413 X509SignatureAlgorithm::Ecdsa(super::super::DigestAlgorithm::Sha256),
3414 ]));
3415 for rejected_first in [true, false] {
3416 let mut alternatives = vec![shared.der().to_vec(), rejected.clone()];
3417 if rejected_first {
3418 alternatives.reverse();
3419 }
3420 let permitted_index = if rejected_first { 3 } else { 2 };
3421 let info = x509_info(
3422 vec![
3423 root.der().to_vec(),
3424 leaf.der().to_vec(),
3425 alternatives.remove(0),
3426 alternatives.remove(0),
3427 alternate_root.der().to_vec(),
3428 ],
3429 1,
3430 );
3431 assert_eq!(
3432 build_x509_certificate_paths_to_trusted_prefix(
3433 &info,
3434 1,
3435 1,
3436 4,
3437 8,
3438 crate::provider::default_provider(),
3439 Some(&allowed),
3440 )
3441 .expect("forbidden alternative must not abort search"),
3442 vec![vec![1, permitted_index, 0]]
3443 );
3444 }
3445 let info = x509_info(
3446 vec![
3447 root.der().to_vec(),
3448 leaf.der().to_vec(),
3449 rejected,
3450 alternate_root.der().to_vec(),
3451 ],
3452 1,
3453 );
3454 assert!(matches!(
3455 build_x509_certificate_paths_to_trusted_prefix(
3456 &info,
3457 1,
3458 1,
3459 4,
3460 8,
3461 crate::provider::default_provider(),
3462 Some(&allowed),
3463 ),
3464 Err(X509ChainBuildError::Policy(_))
3465 ));
3466 }
3467
3468 #[test]
3469 fn x509_path_builder_skips_branch_local_unsupported_algorithms() {
3470 let root = rcgen::CertifiedIssuer::self_signed(
3474 generated_certificate_params("unsupported-edge root", true),
3475 rcgen::KeyPair::generate().expect("root key generation should succeed"),
3476 )
3477 .expect("root certificate should be self-signable");
3478 let signing_intermediate = rcgen::CertifiedIssuer::signed_by(
3479 generated_certificate_params("shared unsupported-edge issuer", true),
3480 rcgen::KeyPair::generate().expect("signing issuer key generation should succeed"),
3481 &root,
3482 )
3483 .expect("root should sign the intermediate certificate");
3484 let key_unsupported_intermediate = rcgen::CertifiedIssuer::signed_by(
3485 generated_certificate_params("shared unsupported-edge issuer", true),
3486 rcgen::KeyPair::generate().expect("unsupported issuer key generation should succeed"),
3487 &root,
3488 )
3489 .expect("root should sign the alternate intermediate certificate");
3490 let leaf = generated_certificate_params("unsupported-edge leaf", false)
3491 .signed_by(
3492 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3493 &signing_intermediate,
3494 )
3495 .expect("signing intermediate should sign the leaf");
3496
3497 let ordered = x509_info(
3498 vec![
3499 leaf.der().to_vec(),
3500 key_unsupported_intermediate.der().to_vec(),
3501 signing_intermediate.der().to_vec(),
3502 root.der().to_vec(),
3503 ],
3504 0,
3505 );
3506 let key_selective_provider = RejectSecondSha512Provider {
3507 sha512_calls: AtomicUsize::new(0),
3508 verification_calls: AtomicUsize::new(0),
3509 reject_verification_call: Some(0),
3510 rejected_verification_data: None,
3511 };
3512 assert_eq!(
3513 super::super::parse::build_x509_certificate_chain_from(
3514 &ordered,
3515 0,
3516 &key_selective_provider,
3517 None,
3518 )
3519 .expect("one unsupported issuer key must not suppress a usable candidate"),
3520 vec![0, 2, 3]
3521 );
3522
3523 let anchored_same_edge = x509_info(
3524 vec![
3525 root.der().to_vec(),
3526 leaf.der().to_vec(),
3527 key_unsupported_intermediate.der().to_vec(),
3528 signing_intermediate.der().to_vec(),
3529 ],
3530 1,
3531 );
3532 let first_candidate_unsupported = RejectSecondSha512Provider {
3533 sha512_calls: AtomicUsize::new(0),
3534 verification_calls: AtomicUsize::new(0),
3535 reject_verification_call: Some(0),
3536 rejected_verification_data: None,
3537 };
3538 assert_eq!(
3539 build_x509_certificate_paths_to_trusted_prefix(
3540 &anchored_same_edge,
3541 1,
3542 1,
3543 4,
3544 8,
3545 &first_candidate_unsupported,
3546 None,
3547 )
3548 .expect("a later same-DN issuer must survive an earlier provider capability miss"),
3549 vec![vec![1, 3, 0]]
3550 );
3551
3552 let mut unsupported_intermediate = signing_intermediate.der().to_vec();
3553 let ecdsa_sha256_oid = [0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02];
3554 let offsets = unsupported_intermediate
3555 .windows(ecdsa_sha256_oid.len())
3556 .enumerate()
3557 .filter_map(|(offset, window)| (window == ecdsa_sha256_oid).then_some(offset))
3558 .collect::<Vec<_>>();
3559 assert_eq!(
3560 offsets.len(),
3561 2,
3562 "certificate must repeat its signature OID"
3563 );
3564 for offset in offsets {
3565 unsupported_intermediate[offset + ecdsa_sha256_oid.len() - 1] = 0x05;
3566 }
3567
3568 let anchored = x509_info(
3569 vec![
3570 root.der().to_vec(),
3571 leaf.der().to_vec(),
3572 signing_intermediate.der().to_vec(),
3573 unsupported_intermediate,
3574 ],
3575 1,
3576 );
3577 assert_eq!(
3578 build_x509_certificate_paths_to_trusted_prefix(
3579 &anchored,
3580 1,
3581 1,
3582 4,
3583 8,
3584 crate::provider::default_provider(),
3585 None,
3586 )
3587 .expect("a branch-local provider gap must not abort path enumeration"),
3588 vec![vec![1, 2, 0]]
3589 );
3590
3591 let unsupported_only = x509_info(
3592 vec![
3593 root.der().to_vec(),
3594 leaf.der().to_vec(),
3595 anchored.certificates[3].clone(),
3596 ],
3597 1,
3598 );
3599 assert!(matches!(
3600 build_x509_certificate_paths_to_trusted_prefix(
3601 &unsupported_only,
3602 1,
3603 1,
3604 4,
3605 8,
3606 crate::provider::default_provider(),
3607 None,
3608 ),
3609 Err(X509ChainBuildError::UnsupportedSignatureAlgorithm { ref oid })
3610 if oid == "1.2.840.10045.4.3.5"
3611 ));
3612 }
3613
3614 #[test]
3615 fn selector_resolved_certificate_preserves_supplied_crls() {
3616 let selector = "<KeyInfo><X509Data><X509SubjectName>CN=Test Key rsa-2048,O=XML Security Library (http://www.aleksey.com/xmlsec),ST=California,C=US</X509SubjectName><X509CRL>CRL_PLACEHOLDER</X509CRL></X509Data></KeyInfo>";
3617 let crl = crl_der(include_str!(
3618 "../../tests/fixtures/keys/rsa/rsa-2048-cert-revoked-crl.pem"
3619 ));
3620 let (_, parsed_crl) =
3621 x509_parser::revocation_list::CertificateRevocationList::from_der(&crl)
3622 .expect("tracked CRL must parse");
3623 let crl_signed_data = parsed_crl.tbs_cert_list.as_ref().to_vec();
3624 let xml = replace_unprefixed_key_info(
3625 RSA_KEY_VALUE_SIGNATURE,
3626 &selector.replace("CRL_PLACEHOLDER", &STANDARD.encode(&crl)),
3627 );
3628 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3629 lookup_certs: vec![certificate_der(include_str!(
3630 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
3631 ))],
3632 trusted_certs: vec![
3633 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
3634 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
3635 ],
3636 ..KeyResolverConfig::default()
3637 });
3638 let policy = verification_policy_with_trust(crate::policy::KeyTrustPolicy {
3639 check_crls: true,
3640 max_x509_chain_depth: 3,
3641 ..chain_policy_at(
3642 SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_773_964_800),
3643 )
3644 });
3645
3646 let error = super::super::VerifyContext::new()
3647 .policy(policy.clone())
3648 .key_resolver(&resolver)
3649 .verify(&xml)
3650 .expect_err("selector lookup must retain and enforce the supplied CRL");
3651 assert!(matches!(
3655 error,
3656 DsigError::KeyResolution(KeyResolutionError::Chain(
3657 super::super::X509ChainError::InvalidKeyUsage {
3658 position: 1,
3659 required: "cRLSign"
3660 }
3661 ))
3662 ));
3663
3664 let provider = RejectSecondSha512Provider {
3668 sha512_calls: AtomicUsize::new(0),
3669 verification_calls: AtomicUsize::new(0),
3670 reject_verification_call: None,
3671 rejected_verification_data: Some(crl_signed_data),
3672 };
3673 let error = super::super::VerifyContext::new()
3674 .policy(policy)
3675 .key_resolver(&resolver)
3676 .provider(&provider)
3677 .verify(&xml)
3678 .expect_err("CRL authentication must retain the operation provider");
3679 assert!(matches!(
3680 error,
3681 DsigError::KeyResolution(KeyResolutionError::Chain(
3682 super::super::X509ChainError::Provider(_)
3683 ))
3684 ));
3685 }
3686
3687 #[test]
3688 fn resolver_rejects_revoked_leaf_with_authorized_crl_issuer() {
3689 let (mut info, root) = authorized_revoked_chain();
3692 let issuer = info.certificates[1].clone();
3693 info.certificates.truncate(1);
3694 info.parsed_certificates.truncate(1);
3695 let key_info = KeyInfo {
3696 sources: vec![KeyInfoSource::X509Data(info)],
3697 };
3698 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3699 lookup_certs: vec![issuer],
3700 trusted_certs: vec![root],
3701 ..KeyResolverConfig::default()
3702 });
3703 let policy = verification_policy_with_trust(crate::policy::KeyTrustPolicy {
3704 check_crls: true,
3705 max_x509_chain_depth: 3,
3706 ..chain_policy_at(
3707 SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_773_964_800),
3708 )
3709 });
3710
3711 let error = match resolver.resolve_with_policy(
3712 Some(&key_info),
3713 SignatureAlgorithm::EcdsaSha256,
3714 &policy,
3715 ) {
3716 Ok(_) => panic!("an authenticated CRL must reject its revoked leaf"),
3717 Err(error) => error,
3718 };
3719 assert!(matches!(
3720 error,
3721 DsigError::KeyResolution(KeyResolutionError::Chain(
3722 super::super::X509ChainError::Revoked(0)
3723 ))
3724 ));
3725 }
3726
3727 #[test]
3728 fn resolves_each_x509_selector_from_configured_certificates() {
3729 let selectors = [
3732 "<X509SubjectName>CN=Test Key rsa-2048,O=XML Security Library (http://www.aleksey.com/xmlsec),ST=California,C=US</X509SubjectName>",
3733 "<X509SubjectName>CN= test key rsa-2048 ,O=xml security library (HTTP://WWW.ALEKSEY.COM/XMLSEC),ST=california,C=us</X509SubjectName>",
3734 "<X509IssuerSerial><X509IssuerName>Email=xmlsec@aleksey.com,CN=Aleksey Sanin,OU=Second level CA,O=XML Security Library (http://www.aleksey.com/xmlsec),ST=California,C=US</X509IssuerName><X509SerialNumber>680572598617295163017172295025714171905498632019</X509SerialNumber></X509IssuerSerial>",
3735 "<X509SKI>bcOXN/nsVl8GatRbcKrPbzIbw0Y=</X509SKI>",
3736 ];
3737 let configured_certificate = certificate_der(include_str!(
3738 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
3739 ));
3740
3741 for selector in selectors {
3742 let key_info = format!("<KeyInfo><X509Data>{selector}</X509Data></KeyInfo>");
3743 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
3744 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3745 lookup_certs: vec![configured_certificate.clone()],
3746 ..KeyResolverConfig::default()
3747 });
3748 let result = super::super::VerifyContext::new()
3749 .policy(cryptographic_policy())
3750 .key_resolver(&resolver)
3751 .verify(&xml)
3752 .expect("X509 selector should resolve configured certificate");
3753
3754 assert_eq!(result.status, super::super::DsigStatus::Valid);
3755 }
3756 }
3757
3758 #[test]
3759 fn resolves_configured_chain_selectors_across_certificates() {
3760 let key_info = r#"<KeyInfo><X509Data><X509SubjectName>CN=Test Key rsa-2048,O=XML Security Library (http://www.aleksey.com/xmlsec),ST=California,C=US</X509SubjectName><X509SKI>0X0XrEVCio75sBcl1TxymJ2IOiU=</X509SKI></X509Data></KeyInfo>"#;
3763 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
3764 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3765 lookup_certs: vec![
3766 certificate_der(include_str!(
3767 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
3768 )),
3769 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
3770 ],
3771 ..KeyResolverConfig::default()
3772 });
3773 let result = super::super::VerifyContext::new()
3774 .policy(cryptographic_policy())
3775 .key_resolver(&resolver)
3776 .verify(&xml)
3777 .expect("selectors across one configured chain should resolve its leaf");
3778
3779 assert_eq!(result.status, super::super::DsigStatus::Valid);
3780 }
3781
3782 #[test]
3783 fn selectors_must_all_match_the_selected_certificate_path() {
3784 let signing_certificate = certificate_der(include_str!(
3787 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
3788 ));
3789 let issuer_certificate =
3790 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem"));
3791 let unrelated = generated_certificate_params("unrelated selector certificate", false)
3792 .self_signed(
3793 &rcgen::KeyPair::generate().expect("unrelated key generation should succeed"),
3794 )
3795 .expect("unrelated certificate should be self-signable")
3796 .der()
3797 .to_vec();
3798 let digest = crate::provider::default_provider()
3799 .digest(super::super::DigestAlgorithm::Sha256, &unrelated)
3800 .expect("SHA-256 selector digest must be available");
3801 let key_info_xml = format!(
3802 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:dsig11=\"http://www.w3.org/2009/xmldsig11#\"><X509Data><X509SubjectName>CN=Test Key rsa-2048,O=XML Security Library (http://www.aleksey.com/xmlsec),ST=California,C=US</X509SubjectName><dsig11:X509Digest Algorithm=\"http://www.w3.org/2001/04/xmlenc#sha256\">{}</dsig11:X509Digest></X509Data></KeyInfo>",
3803 STANDARD.encode(digest)
3804 );
3805 let document = roxmltree::Document::parse(&key_info_xml)
3806 .expect("generated selector KeyInfo must be XML");
3807 let key_info = super::super::parse_key_info(document.root_element())
3808 .expect("generated selector KeyInfo must be structurally valid");
3809 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3810 lookup_certs: vec![signing_certificate, issuer_certificate, unrelated],
3811 ..KeyResolverConfig::default()
3812 });
3813
3814 assert!(
3815 resolver
3816 .resolve(Some(&key_info), SignatureAlgorithm::RsaSha256)
3817 .expect("disjoint selector matches are a key miss")
3818 .is_none()
3819 );
3820 }
3821
3822 #[test]
3823 fn unmatched_x509_selector_does_not_resolve() {
3824 let key_info = "<KeyInfo><X509Data><X509SubjectName>CN=not-the-signer</X509SubjectName></X509Data></KeyInfo>";
3826 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
3827 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3828 lookup_certs: vec![certificate_der(include_str!(
3829 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
3830 ))],
3831 ..KeyResolverConfig::default()
3832 });
3833 let result = super::super::VerifyContext::new()
3834 .key_resolver(&resolver)
3835 .verify(&xml)
3836 .expect("an unmatched selector is a key miss, not a parser failure");
3837
3838 assert!(matches!(
3839 result.status,
3840 super::super::DsigStatus::Invalid(super::super::FailureReason::KeyNotFound)
3841 ));
3842 }
3843
3844 #[test]
3845 fn overlapping_trusted_and_lookup_certificate_preserves_trust() {
3846 let certificate = certificate_der(RSA_4096_CERTIFICATE);
3849 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3850 trusted_certs: vec![certificate.clone()],
3851 lookup_certs: vec![certificate],
3852 ..KeyResolverConfig::default()
3853 });
3854 let result = super::super::VerifyContext::new()
3855 .policy(verification_policy_with_trust(chain_policy_at(
3856 fixture_certificate_time(),
3857 )))
3858 .key_resolver(&resolver)
3859 .verify(&x509_signature_with_leaf_subject())
3860 .expect("trusted/lookup overlap must resolve as one trusted candidate");
3861
3862 assert_eq!(result.status, super::super::DsigStatus::Valid);
3863 let super::super::KeyTrustEvidence::ValidatedX509(evidence) = result.key_trust else {
3864 panic!("successful path validation must retain typed evidence");
3865 };
3866 assert_eq!(evidence.verification_time(), fixture_certificate_time());
3867 assert!(!evidence.revocation_checked());
3868 assert_eq!(evidence.certificate_fingerprints().len(), 1);
3869 assert_eq!(
3870 evidence.anchor_fingerprint(),
3871 &evidence.certificate_fingerprints()[0]
3872 );
3873
3874 let document = crate::XmlDocument::parse(x509_signature_with_leaf_subject())
3877 .expect("signed certificate selector fixture must parse");
3878 let report = super::super::VerifyContext::new()
3879 .policy(verification_policy_with_trust(chain_policy_at(
3880 fixture_certificate_time(),
3881 )))
3882 .key_resolver(&resolver)
3883 .verify_all(&document)
3884 .expect("batch verification must preserve the validated path");
3885 assert!(
3886 report
3887 .accepted(&document)
3888 .expect("current document acceptance")
3889 );
3890 assert_eq!(
3891 report.signatures()[0]
3892 .result()
3893 .as_ref()
3894 .expect("the individually processed Signature must verify")
3895 .key_trust,
3896 super::super::KeyTrustEvidence::ValidatedX509(evidence)
3897 );
3898 }
3899
3900 #[test]
3901 fn distinct_x509_selector_matches_remain_ambiguous() {
3902 let certificate = || {
3905 generated_certificate_params("ambiguous selector", false)
3906 .self_signed(
3907 &rcgen::KeyPair::generate().expect("test key generation should succeed"),
3908 )
3909 .expect("test certificate should be self-signable")
3910 .der()
3911 .to_vec()
3912 };
3913 let xml = replace_unprefixed_key_info(
3914 X509_DIGEST_SIGNATURE,
3915 "<KeyInfo><X509Data><X509SubjectName>CN=ambiguous selector</X509SubjectName></X509Data></KeyInfo>",
3916 );
3917 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3918 lookup_certs: vec![certificate(), certificate()],
3919 ..KeyResolverConfig::default()
3920 });
3921 let error = super::super::VerifyContext::new()
3922 .key_resolver(&resolver)
3923 .verify(&xml)
3924 .expect_err("distinct selector matches must fail closed");
3925
3926 assert!(matches!(
3927 error,
3928 DsigError::KeyResolution(KeyResolutionError::AmbiguousCertificate)
3929 ));
3930 }
3931
3932 #[test]
3933 fn unsupported_x509_digest_selector_fails_closed() {
3934 let key_info = "<KeyInfo xmlns:dsig11=\"http://www.w3.org/2009/xmldsig11#\"><X509Data><dsig11:X509Digest Algorithm=\"urn:unsupported\">AQ==</dsig11:X509Digest></X509Data></KeyInfo>";
3937 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
3938 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3939 lookup_certs: vec![certificate_der(include_str!(
3940 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
3941 ))],
3942 ..KeyResolverConfig::default()
3943 });
3944 let error = super::super::VerifyContext::new()
3945 .key_resolver(&resolver)
3946 .verify(&xml)
3947 .expect_err("unsupported X509Digest algorithm must fail closed");
3948
3949 assert!(matches!(
3950 error,
3951 DsigError::KeyResolution(KeyResolutionError::UnsupportedDigestAlgorithm(uri))
3952 if uri == "urn:unsupported"
3953 ));
3954 }
3955
3956 #[test]
3957 fn x509_digest_selector_uses_operation_provider() {
3958 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3961 lookup_certs: vec![certificate_der(RSA_4096_CERTIFICATE)],
3962 trusted_certs: vec![
3963 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
3964 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
3965 ],
3966 ..KeyResolverConfig::default()
3967 });
3968 let provider = RejectSecondSha512Provider {
3969 sha512_calls: AtomicUsize::new(0),
3970 verification_calls: AtomicUsize::new(0),
3971 reject_verification_call: None,
3972 rejected_verification_data: None,
3973 };
3974 let error = super::super::VerifyContext::new()
3975 .key_resolver(&resolver)
3976 .provider(&provider)
3977 .verify(X509_DIGEST_SIGNATURE)
3978 .expect_err("X509Digest selection must use the operation provider");
3979
3980 assert!(
3981 matches!(
3982 error,
3983 DsigError::Provider(crate::provider::ProviderError::Unsupported {
3984 operation: crate::provider::ProviderOperation::Digest,
3985 algorithm: Some(ref uri),
3986 }) if uri == super::super::DigestAlgorithm::Sha512.uri()
3987 ),
3988 "unexpected error: {error:?}"
3989 );
3990 }
3991
3992 #[test]
3993 fn resolves_named_key_end_to_end() {
3994 let xml = replace_key_info(
3996 SIGNED_SAML,
3997 "<ds:KeyInfo><ds:KeyName>idp-signing</ds:KeyName></ds:KeyInfo>",
3998 );
3999 let mut config = KeyResolverConfig::default();
4000 config.named_keys.insert(
4001 "idp-signing".into(),
4002 VerificationKey {
4003 algorithm: SignatureAlgorithm::EcdsaSha256,
4004 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4005 certificate_der: None,
4006 name: Some("idp-signing".into()),
4007 },
4008 );
4009 let resolver = DefaultKeyResolver::new(config);
4010 let result = super::super::VerifyContext::new()
4011 .key_resolver(&resolver)
4012 .verify(&xml)
4013 .expect("named key should resolve");
4014
4015 assert_eq!(result.status, super::super::DsigStatus::Valid);
4016 }
4017
4018 #[test]
4019 fn resolves_der_encoded_key_end_to_end() {
4020 let encoded = STANDARD.encode(public_key_der(SAML_PUBLIC_KEY));
4022 let xml = replace_key_info(
4023 SIGNED_SAML,
4024 &format!(
4025 "<ds:KeyInfo><dsig11:DEREncodedKeyValue xmlns:dsig11=\"http://www.w3.org/2009/xmldsig11#\">{encoded}</dsig11:DEREncodedKeyValue></ds:KeyInfo>"
4026 ),
4027 );
4028 let resolver = DefaultKeyResolver::default();
4029 let result = super::super::VerifyContext::new()
4030 .policy(cryptographic_policy())
4031 .key_resolver(&resolver)
4032 .verify(&xml)
4033 .expect("DER key should resolve");
4034
4035 assert_eq!(result.status, super::super::DsigStatus::Valid);
4036 }
4037
4038 #[test]
4039 fn resolves_rsa_key_value_end_to_end() {
4040 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
4042 .expect("fixture must contain an RSA public key");
4043 let (modulus, exponent) = rsa_key_value_parts(&public_key);
4044 let key_info = format!(
4045 "<KeyInfo><KeyValue><RSAKeyValue><Modulus>{}</Modulus><Exponent>{}</Exponent></RSAKeyValue></KeyValue></KeyInfo>",
4046 modulus, exponent,
4047 );
4048 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
4049 let resolver = DefaultKeyResolver::default();
4050 let result = super::super::VerifyContext::new()
4051 .policy(cryptographic_policy())
4052 .key_resolver(&resolver)
4053 .verify(&xml)
4054 .expect("RSAKeyValue should resolve");
4055
4056 assert_eq!(result.status, super::super::DsigStatus::Valid);
4057 }
4058
4059 #[test]
4060 fn rsa_key_value_rejects_legacy_weak_modulus() {
4061 let resolver = DefaultKeyResolver::default();
4064 let error = super::super::VerifyContext::new()
4065 .key_resolver(&resolver)
4066 .verify(LEGACY_RSA_KEY_VALUE_SIGNATURE)
4067 .expect_err("context policy must override permissive resolver defaults");
4068
4069 assert!(matches!(
4070 error,
4071 DsigError::Policy(crate::policy::PolicyViolation::Algorithm {
4072 operation: "verification",
4073 ..
4074 })
4075 ));
4076 }
4077
4078 #[test]
4079 fn operation_policy_rejects_disabled_embedded_key_source() {
4080 let key_info = KeyInfo {
4083 sources: vec![KeyInfoSource::KeyValue(KeyValueInfo::Rsa {
4084 modulus: vec![0x80; 256],
4085 exponent: vec![1, 0, 1],
4086 })],
4087 };
4088 let mut policy = crate::policy::VerificationPolicy::default();
4089 policy.key_sources.key_value = false;
4090
4091 let error = match DefaultKeyResolver::default().resolve_with_policy(
4092 Some(&key_info),
4093 SignatureAlgorithm::RsaSha256,
4094 &policy,
4095 ) {
4096 Ok(_) => panic!("disabled KeyValue must fail before key construction"),
4097 Err(error) => error,
4098 };
4099
4100 assert!(matches!(
4101 error,
4102 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust {
4103 reason: "KeyValue key sources are disabled"
4104 })
4105 ));
4106 }
4107
4108 #[test]
4109 fn operation_policy_preflights_every_key_info_source_before_resolution() {
4110 let mut config = KeyResolverConfig::default();
4113 config.named_keys.insert(
4114 "idp-signing".into(),
4115 VerificationKey {
4116 algorithm: SignatureAlgorithm::EcdsaSha256,
4117 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4118 certificate_der: None,
4119 name: Some("idp-signing".into()),
4120 },
4121 );
4122 let resolver = DefaultKeyResolver::new(config);
4123 let mut policy = crate::policy::VerificationPolicy::default();
4124 policy.key_sources.x509_data = false;
4125
4126 for sources in [
4127 vec![
4128 KeyInfoSource::KeyName("idp-signing".into()),
4129 KeyInfoSource::X509Data(X509DataInfo::default()),
4130 ],
4131 vec![
4132 KeyInfoSource::X509Data(X509DataInfo::default()),
4133 KeyInfoSource::KeyName("idp-signing".into()),
4134 ],
4135 ] {
4136 let error = match resolver.resolve_with_policy(
4137 Some(&KeyInfo { sources }),
4138 SignatureAlgorithm::EcdsaSha256,
4139 &policy,
4140 ) {
4141 Ok(_) => panic!("source order must not hide disabled X509Data"),
4142 Err(error) => error,
4143 };
4144
4145 assert!(matches!(
4146 error,
4147 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust {
4148 reason: "X509Data key sources are disabled"
4149 })
4150 ));
4151 }
4152 }
4153
4154 #[test]
4155 fn operation_policy_bounds_ordered_key_info_candidates() {
4156 let mut config = KeyResolverConfig::default();
4159 config.named_keys.insert(
4160 "idp-signing".into(),
4161 VerificationKey {
4162 algorithm: SignatureAlgorithm::EcdsaSha256,
4163 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4164 certificate_der: None,
4165 name: Some("idp-signing".into()),
4166 },
4167 );
4168 let resolver = DefaultKeyResolver::new(config);
4169 let key_info = KeyInfo {
4170 sources: vec![
4171 KeyInfoSource::KeyValue(KeyValueInfo::Ec {
4172 curve_oid: "1.3.132.0.35".into(),
4173 public_key: vec![4],
4174 }),
4175 KeyInfoSource::KeyName("idp-signing".into()),
4176 ],
4177 };
4178
4179 for maximum in [0, 1] {
4180 let mut policy = crate::policy::VerificationPolicy::default();
4181 policy.resources.max_key_candidates = maximum;
4182 let error = match resolver.resolve_with_policy(
4183 Some(&key_info),
4184 SignatureAlgorithm::EcdsaSha256,
4185 &policy,
4186 ) {
4187 Ok(_) => panic!("candidate ceiling {maximum} must stop resolution"),
4188 Err(error) => error,
4189 };
4190 assert!(matches!(
4191 error,
4192 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4193 resource: crate::policy::resource_name::KEY_CANDIDATES,
4194 maximum: observed,
4195 actual,
4196 }) if observed == maximum && actual == maximum + 1
4197 ));
4198 }
4199
4200 let mut policy = crate::policy::VerificationPolicy::default();
4201 policy.resources.max_key_candidates = 2;
4202 assert!(
4203 resolver
4204 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::EcdsaSha256, &policy,)
4205 .expect("two allowed attempts must reach the named key")
4206 .is_some()
4207 );
4208 }
4209
4210 #[test]
4211 fn operation_policy_bounds_configured_x509_selector_candidates() {
4212 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4216 lookup_certs: vec![
4217 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
4218 certificate_der(RSA_4096_CERTIFICATE),
4219 ],
4220 ..KeyResolverConfig::default()
4221 });
4222 let mut policy = crate::policy::VerificationPolicy::default();
4223 policy.resources.max_key_candidates = 1;
4224
4225 let error = super::super::VerifyContext::new()
4226 .policy(policy)
4227 .key_resolver(&resolver)
4228 .verify(&x509_signature_with_leaf_subject())
4229 .expect_err("the second configured certificate must exceed the candidate budget");
4230
4231 assert!(matches!(
4232 error,
4233 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4234 resource: crate::policy::resource_name::KEY_CANDIDATES,
4235 maximum: 1,
4236 actual: 2,
4237 })
4238 ));
4239 }
4240
4241 #[test]
4242 fn configured_crls_are_bounded_before_der_parsing() {
4243 let key_info = KeyInfo {
4245 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
4246 subject_names: vec!["CN=selected".into()],
4247 ..X509DataInfo::default()
4248 })],
4249 };
4250 let mut policy = crate::policy::VerificationPolicy::default();
4251 policy.key_trust.check_crls = true;
4252 policy.key_trust.verify_x509_chains = true;
4253 policy.resources.max_external_resource_bytes = 4;
4254 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4255 crls: vec![vec![0; 5]],
4256 ..KeyResolverConfig::default()
4257 });
4258 let error = resolver
4259 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::RsaSha256, &policy)
4260 .err()
4261 .expect("oversized CRL must fail before DER parsing");
4262 assert!(
4263 matches!(
4264 error,
4265 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4266 resource: crate::policy::resource_name::EXTERNAL_RESOURCE_BYTES,
4267 ..
4268 })
4269 ),
4270 "{error:?}"
4271 );
4272
4273 policy.resources.max_external_resource_bytes = 4;
4274 policy.resources.max_external_resource_total_bytes = 7;
4275 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4276 crls: vec![vec![0; 4], vec![0; 4]],
4277 ..KeyResolverConfig::default()
4278 });
4279 let error = resolver
4280 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::RsaSha256, &policy)
4281 .err()
4282 .expect("aggregate CRL bytes must fail before DER parsing");
4283 assert!(matches!(
4284 error,
4285 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4286 resource: crate::policy::resource_name::AGGREGATE_EXTERNAL_RESOURCE_BYTES,
4287 ..
4288 })
4289 ));
4290
4291 policy.resources.max_external_resource_total_bytes = 8;
4292 policy.resources.max_key_candidates = 1;
4293 let error = resolver
4294 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::RsaSha256, &policy)
4295 .err()
4296 .expect("CRL candidate count must fail before DER parsing");
4297 assert!(matches!(
4298 error,
4299 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4300 resource: crate::policy::resource_name::KEY_CANDIDATES,
4301 ..
4302 })
4303 ));
4304 }
4305
4306 #[test]
4307 fn configured_certificates_and_crls_share_external_byte_budget() {
4308 let key_info = KeyInfo {
4312 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
4313 subject_names: vec!["CN=selected".into()],
4314 ..X509DataInfo::default()
4315 })],
4316 };
4317 let mut policy = crate::policy::VerificationPolicy::default();
4318 policy.key_trust.check_crls = true;
4319 policy.key_trust.verify_x509_chains = true;
4320 policy.resources.max_external_resource_bytes = 8;
4321 policy.resources.max_external_resource_total_bytes = 12;
4322 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4323 trusted_certs: vec![vec![0; 8]],
4324 crls: vec![vec![0; 8]],
4325 ..KeyResolverConfig::default()
4326 });
4327 let error = resolver
4328 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::RsaSha256, &policy)
4329 .err()
4330 .expect("combined external material exceeds the operation limit");
4331 assert!(matches!(
4332 error,
4333 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4334 resource: crate::policy::resource_name::AGGREGATE_EXTERNAL_RESOURCE_BYTES,
4335 ..
4336 })
4337 ));
4338 }
4339
4340 #[test]
4341 fn embedded_and_configured_x509_share_one_byte_budget() {
4342 let mut info = KeyInfo {
4345 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
4346 certificates: vec![vec![0; 8]],
4347 certificate_chain: vec![0],
4348 crls: vec![vec![0; 2]],
4349 ..X509DataInfo::default()
4350 })],
4351 };
4352 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4353 crls: vec![vec![0; 8]],
4354 ..KeyResolverConfig::default()
4355 });
4356 let mut policy = crate::policy::VerificationPolicy::default();
4357 policy.key_trust.check_crls = true;
4358 policy.key_trust.verify_x509_chains = true;
4359 policy.resources.max_external_resource_total_bytes = 17;
4360 let error = resolver
4361 .resolve_with_policy(Some(&info), SignatureAlgorithm::RsaSha256, &policy)
4362 .err()
4363 .expect("combined material must be rejected");
4364 assert!(
4365 matches!(
4366 error,
4367 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4368 resource: crate::policy::resource_name::AGGREGATE_EXTERNAL_RESOURCE_BYTES,
4369 actual: 18,
4370 ..
4371 })
4372 ),
4373 "{error:?}"
4374 );
4375 policy.resources.max_external_resource_total_bytes = 18;
4376 let error = resolver
4377 .resolve_with_policy(Some(&info), SignatureAlgorithm::RsaSha256, &policy)
4378 .err()
4379 .expect("exact byte allowance reaches DER parsing");
4380 assert!(
4381 matches!(
4382 error,
4383 DsigError::KeyResolution(KeyResolutionError::InvalidCertificate)
4384 ),
4385 "{error:?}"
4386 );
4387 info.sources.insert(
4390 0,
4391 KeyInfoSource::X509Data(X509DataInfo {
4392 subject_names: vec!["CN=absent".into()],
4393 ..X509DataInfo::default()
4394 }),
4395 );
4396 policy.resources.max_external_resource_total_bytes = 17;
4397 policy.resources.max_key_candidates = 2;
4398 assert!(matches!(
4399 resolver.resolve_with_policy(Some(&info), SignatureAlgorithm::RsaSha256, &policy),
4400 Err(DsigError::Policy(
4401 crate::policy::PolicyViolation::ResourceLimit {
4402 resource: crate::policy::resource_name::AGGREGATE_EXTERNAL_RESOURCE_BYTES,
4403 actual: 18,
4404 ..
4405 }
4406 ))
4407 ));
4408 }
4409
4410 #[test]
4411 fn direct_certificate_does_not_charge_unused_configured_store() {
4412 let certificate = certificate_der(RSA_4096_CERTIFICATE);
4415 let key_info = KeyInfo {
4416 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
4417 certificates: vec![certificate],
4418 certificate_chain: vec![0],
4419 subject_names: vec!["CN=unused-selector".into()],
4420 ..X509DataInfo::default()
4421 })],
4422 };
4423 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4424 lookup_certs: vec![vec![0; 4096]],
4425 trusted_certs: vec![vec![0; 4096]],
4426 ..KeyResolverConfig::default()
4427 });
4428 let mut policy = crate::policy::VerificationPolicy::default();
4429 policy.resources.max_external_resource_bytes = 1024;
4430 policy.resources.max_external_resource_total_bytes = 1024;
4431 assert!(
4432 resolver
4433 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::RsaSha256, &policy)
4434 .expect("unused configured certificates are not charged")
4435 .is_some()
4436 );
4437 }
4438
4439 #[test]
4440 fn operation_policy_bounds_embedded_x509_certificate_candidates() {
4441 let key_info = KeyInfo {
4445 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
4446 certificates: vec![
4447 certificate_der(RSA_4096_CERTIFICATE),
4448 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
4449 ],
4450 certificate_chain: vec![0],
4451 ..X509DataInfo::default()
4452 })],
4453 };
4454 let mut policy = crate::policy::VerificationPolicy::default();
4455 policy.resources.max_key_candidates = 1;
4456
4457 let error = match DefaultKeyResolver::default().resolve_with_policy(
4458 Some(&key_info),
4459 SignatureAlgorithm::RsaSha256,
4460 &policy,
4461 ) {
4462 Ok(_) => panic!("the second embedded certificate must exceed the candidate budget"),
4463 Err(error) => error,
4464 };
4465
4466 assert!(matches!(
4467 error,
4468 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4469 resource: crate::policy::resource_name::KEY_CANDIDATES,
4470 maximum: 1,
4471 actual: 2,
4472 })
4473 ));
4474 }
4475
4476 #[test]
4477 fn operation_policy_charges_duplicate_configured_x509_candidates() {
4478 let certificate = certificate_der(RSA_4096_CERTIFICATE);
4481 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4482 lookup_certs: vec![certificate.clone(), certificate],
4483 ..KeyResolverConfig::default()
4484 });
4485 let mut policy = crate::policy::VerificationPolicy::default();
4486 policy.resources.max_key_candidates = 1;
4487
4488 let error = super::super::VerifyContext::new()
4489 .policy(policy)
4490 .key_resolver(&resolver)
4491 .verify(&x509_signature_with_leaf_subject())
4492 .expect_err("the duplicate configured entry must consume candidate work");
4493
4494 assert!(matches!(
4495 error,
4496 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4497 resource: crate::policy::resource_name::KEY_CANDIDATES,
4498 maximum: 1,
4499 actual: 2,
4500 })
4501 ));
4502 }
4503
4504 #[test]
4505 fn operation_policy_charges_duplicate_embedded_x509_candidates() {
4506 let certificate = certificate_der(RSA_4096_CERTIFICATE);
4509 let key_info = KeyInfo {
4510 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
4511 certificates: vec![certificate.clone(), certificate],
4512 certificate_chain: vec![0],
4513 ..X509DataInfo::default()
4514 })],
4515 };
4516 let mut policy = crate::policy::VerificationPolicy::default();
4517 policy.resources.max_key_candidates = 1;
4518
4519 let error = match DefaultKeyResolver::default().resolve_with_policy(
4520 Some(&key_info),
4521 SignatureAlgorithm::RsaSha256,
4522 &policy,
4523 ) {
4524 Ok(_) => panic!("the duplicate embedded entry must consume candidate work"),
4525 Err(error) => error,
4526 };
4527
4528 assert!(matches!(
4529 error,
4530 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4531 resource: crate::policy::resource_name::KEY_CANDIDATES,
4532 maximum: 1,
4533 actual: 2,
4534 })
4535 ));
4536 }
4537
4538 #[test]
4539 fn policy_aware_resolver_rejects_resources_above_hard_ceiling() {
4540 let mut policy = crate::policy::VerificationPolicy::default();
4543 policy.resources.max_key_candidates = usize::MAX;
4544
4545 let error = match DefaultKeyResolver::default().resolve_with_policy(
4546 None,
4547 SignatureAlgorithm::RsaSha256,
4548 &policy,
4549 ) {
4550 Ok(_) => panic!("invalid resource policy must fail before key resolution"),
4551 Err(error) => error,
4552 };
4553
4554 assert!(matches!(
4555 error,
4556 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4557 resource: crate::policy::resource_name::KEY_CANDIDATES,
4558 actual: usize::MAX,
4559 ..
4560 })
4561 ));
4562 }
4563
4564 #[test]
4565 fn embedded_x509_digest_selection_uses_operation_provider() {
4566 let certificate = certificate_der(RSA_4096_CERTIFICATE);
4569 let digest =
4570 super::super::compute_digest(super::super::DigestAlgorithm::Sha512, &certificate);
4571 let xml = format!(
4572 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><X509Data><X509Certificate>{}</X509Certificate><X509Digest xmlns=\"http://www.w3.org/2009/xmldsig11#\" Algorithm=\"{}\">{}</X509Digest></X509Data></KeyInfo>",
4573 STANDARD.encode(&certificate),
4574 super::super::DigestAlgorithm::Sha512.uri(),
4575 STANDARD.encode(digest),
4576 );
4577 let document = roxmltree::Document::parse(&xml).expect("generated KeyInfo must be XML");
4578 let provider = RejectSecondSha512Provider {
4579 sha512_calls: AtomicUsize::new(1),
4580 verification_calls: AtomicUsize::new(0),
4581 reject_verification_call: None,
4582 rejected_verification_data: None,
4583 };
4584
4585 let error =
4586 super::super::parse::parse_key_info_with_provider(document.root_element(), &provider)
4587 .expect_err("embedded X509Digest selection must use the operation provider");
4588
4589 assert!(
4590 matches!(
4591 error,
4592 ParseError::Provider(crate::provider::ProviderError::Unsupported {
4593 operation: crate::provider::ProviderOperation::Digest,
4594 algorithm: Some(ref uri),
4595 }) if uri == super::super::DigestAlgorithm::Sha512.uri()
4596 ),
4597 "unexpected error: {error:?}"
4598 );
4599 }
4600
4601 #[test]
4602 fn generic_key_resolution_keeps_legacy_capability_source_independent() {
4603 let certificate =
4604 include_bytes!("../../tests/fixtures/xmldsig/phaos-xmldsig-three/certs/rsa-cert.der")
4605 .to_vec();
4606 let (_, parsed_certificate) = X509Certificate::from_der(&certificate)
4607 .expect("the Phaos fixture is a DER certificate");
4608 let public_key = parsed_certificate.public_key().raw.to_vec();
4609 let rsa_public_key = rsa::RsaPublicKey::from_public_key_der(&public_key)
4610 .expect("the Phaos certificate contains an RSA public key");
4611 let certificate_metadata = parse_x509_certificate(&certificate)
4612 .expect("the Phaos fixture has supported X.509 metadata");
4613 let named_key = VerificationKey {
4614 algorithm: SignatureAlgorithm::RsaSha1,
4615 public_key_bytes: public_key.clone(),
4616 certificate_der: None,
4617 name: Some("legacy".into()),
4618 };
4619 let key_infos = [
4620 KeyInfo {
4621 sources: vec![KeyInfoSource::KeyName("legacy".into())],
4622 },
4623 KeyInfo {
4624 sources: vec![KeyInfoSource::DerEncodedKeyValue(public_key.clone())],
4625 },
4626 KeyInfo {
4627 sources: vec![KeyInfoSource::KeyValue(KeyValueInfo::Rsa {
4628 modulus: rsa_public_key.n().to_be_bytes_trimmed_vartime().to_vec(),
4629 exponent: rsa_public_key.e().to_be_bytes_trimmed_vartime().to_vec(),
4630 })],
4631 },
4632 KeyInfo {
4633 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
4634 certificates: vec![certificate],
4635 parsed_certificates: vec![certificate_metadata],
4636 certificate_chain: vec![0],
4637 ..X509DataInfo::default()
4638 })],
4639 },
4640 ];
4641 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4642 named_keys: HashMap::from([("legacy".into(), named_key.clone())]),
4643 ..KeyResolverConfig::default()
4644 });
4645 let mut policy = crate::policy::VerificationPolicy::default();
4646 policy.key_trust.rsa_keys.minimum_modulus_bits = 1024;
4647 policy
4648 .key_trust
4649 .allowed_legacy_signature_algorithms
4650 .insert(SignatureAlgorithm::RsaSha1);
4651
4652 for key_info in &key_infos {
4653 let key = resolver
4654 .resolve_with_policy(Some(key_info), SignatureAlgorithm::RsaSha1, &policy)
4655 .expect("the key source is valid")
4656 .expect("key resolution remains independent from operation policy");
4657 assert!(
4658 !key.verify(SignatureAlgorithm::RsaSha1, b"data", &[0; 128])
4659 .expect("the legacy RSA key is structurally valid")
4660 );
4661 }
4662 }
4663
4664 #[test]
4665 fn rsa_key_value_rejects_ecdsa_signature_method() {
4666 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
4668 .expect("fixture must contain an RSA public key");
4669 let (modulus, exponent) = rsa_key_value_parts(&public_key);
4670 let key_info = format!(
4671 "<ds:KeyInfo><ds:KeyValue><ds:RSAKeyValue><ds:Modulus>{}</ds:Modulus><ds:Exponent>{}</ds:Exponent></ds:RSAKeyValue></ds:KeyValue></ds:KeyInfo>",
4672 modulus, exponent,
4673 );
4674 let xml = replace_key_info(SIGNED_SAML, &key_info);
4675 let resolver = DefaultKeyResolver::default();
4676 let error = super::super::VerifyContext::new()
4677 .key_resolver(&resolver)
4678 .verify(&xml)
4679 .expect_err("RSAKeyValue must not resolve for ECDSA");
4680
4681 assert!(matches!(
4682 error,
4683 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
4684 ));
4685 }
4686
4687 #[test]
4688 fn resolves_ec_p256_key_value_end_to_end() {
4689 let resolver = DefaultKeyResolver::default();
4691 let result = super::super::VerifyContext::new()
4692 .policy(cryptographic_policy())
4693 .key_resolver(&resolver)
4694 .verify(EC_P256_KEY_VALUE_SIGNATURE)
4695 .expect("P-256 ECKeyValue should resolve");
4696
4697 assert_eq!(result.status, super::super::DsigStatus::Valid);
4698 }
4699
4700 #[test]
4701 fn resolves_ec_p384_key_value_end_to_end() {
4702 let resolver = DefaultKeyResolver::default();
4704 let result = super::super::VerifyContext::new()
4705 .policy(cryptographic_policy())
4706 .key_resolver(&resolver)
4707 .verify(EC_P384_KEY_VALUE_SIGNATURE)
4708 .expect("P-384 ECKeyValue should resolve");
4709
4710 assert_eq!(result.status, super::super::DsigStatus::Valid);
4711 }
4712
4713 #[test]
4714 fn ec_key_value_ignored_for_rsa_signature_method() {
4715 let key_info = r#"<KeyInfo xmlns:dsig11="http://www.w3.org/2009/xmldsig11#"><KeyValue><dsig11:ECKeyValue><dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/><dsig11:PublicKey>BJ/yaXNlq4FRObyJCBhb5jAz8GVzinK3bBGLjSDfjbJwNfydtgjnlS4EsDmxSRhWyJWq6GIqy5wvnaiARK04uB4=</dsig11:PublicKey></dsig11:ECKeyValue></KeyValue></KeyInfo>"#;
4717 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
4718 let resolver = DefaultKeyResolver::default();
4719 let result = super::super::VerifyContext::new()
4720 .key_resolver(&resolver)
4721 .verify(&xml)
4722 .expect("single incompatible ECKeyValue should be ignored");
4723
4724 assert_eq!(
4725 result.status,
4726 super::super::DsigStatus::Invalid(super::super::FailureReason::KeyNotFound)
4727 );
4728 }
4729
4730 #[test]
4731 fn incompatible_ec_key_value_falls_back_to_later_rsa_key_value() {
4732 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
4734 .expect("fixture must contain an RSA public key");
4735 let (modulus, exponent) = rsa_key_value_parts(&public_key);
4736 let key_info = format!(
4737 r#"<KeyInfo xmlns:dsig11="http://www.w3.org/2009/xmldsig11#"><KeyValue><dsig11:ECKeyValue><dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/><dsig11:PublicKey>BJ/yaXNlq4FRObyJCBhb5jAz8GVzinK3bBGLjSDfjbJwNfydtgjnlS4EsDmxSRhWyJWq6GIqy5wvnaiARK04uB4=</dsig11:PublicKey></dsig11:ECKeyValue></KeyValue><KeyValue><RSAKeyValue><Modulus>{}</Modulus><Exponent>{}</Exponent></RSAKeyValue></KeyValue></KeyInfo>"#,
4738 modulus, exponent,
4739 );
4740 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
4741 let resolver = DefaultKeyResolver::default();
4742 let result = super::super::VerifyContext::new()
4743 .policy(cryptographic_policy())
4744 .key_resolver(&resolver)
4745 .verify(&xml)
4746 .expect("later RSAKeyValue should resolve");
4747
4748 assert_eq!(result.status, super::super::DsigStatus::Valid);
4749 }
4750
4751 #[test]
4752 fn unsupported_ec_key_value_falls_back_to_later_key_name() {
4753 let key_info = r#"<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:dsig11="http://www.w3.org/2009/xmldsig11#"><ds:KeyValue><dsig11:ECKeyValue><dsig11:NamedCurve URI="urn:oid:1.3.132.0.35"/><dsig11:PublicKey>BA==</dsig11:PublicKey></dsig11:ECKeyValue></ds:KeyValue><ds:KeyName>idp-signing</ds:KeyName></ds:KeyInfo>"#;
4755 let xml = replace_key_info(SIGNED_SAML, key_info);
4756 let mut config = KeyResolverConfig::default();
4757 config.named_keys.insert(
4758 "idp-signing".into(),
4759 VerificationKey {
4760 algorithm: SignatureAlgorithm::EcdsaSha256,
4761 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4762 certificate_der: None,
4763 name: Some("idp-signing".into()),
4764 },
4765 );
4766 let resolver = DefaultKeyResolver::new(config);
4767 let result = super::super::VerifyContext::new()
4768 .key_resolver(&resolver)
4769 .verify(&xml)
4770 .expect("later KeyName should resolve");
4771
4772 assert_eq!(result.status, super::super::DsigStatus::Valid);
4773 }
4774
4775 #[test]
4776 fn invalid_ec_key_value_falls_back_to_later_key_name() {
4777 let key_info = r#"<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:dsig11="http://www.w3.org/2009/xmldsig11#"><ds:KeyValue><dsig11:ECKeyValue><dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/><dsig11:PublicKey>BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</dsig11:PublicKey></dsig11:ECKeyValue></ds:KeyValue><ds:KeyName>idp-signing</ds:KeyName></ds:KeyInfo>"#;
4779 let xml = replace_key_info(SIGNED_SAML, key_info);
4780 let mut config = KeyResolverConfig::default();
4781 config.named_keys.insert(
4782 "idp-signing".into(),
4783 VerificationKey {
4784 algorithm: SignatureAlgorithm::EcdsaSha256,
4785 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4786 certificate_der: None,
4787 name: Some("idp-signing".into()),
4788 },
4789 );
4790 let resolver = DefaultKeyResolver::new(config);
4791 let result = super::super::VerifyContext::new()
4792 .key_resolver(&resolver)
4793 .verify(&xml)
4794 .expect("later KeyName should resolve after invalid ECKeyValue");
4795
4796 assert_eq!(result.status, super::super::DsigStatus::Valid);
4797 }
4798
4799 #[test]
4800 fn malformed_ec_key_value_falls_back_to_later_key_name() {
4801 let key_info = r#"<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:dsig11="http://www.w3.org/2009/xmldsig11#"><ds:KeyValue><dsig11:ECKeyValue><dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/><dsig11:PublicKey>AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</dsig11:PublicKey></dsig11:ECKeyValue></ds:KeyValue><ds:KeyName>idp-signing</ds:KeyName></ds:KeyInfo>"#;
4803 let xml = replace_key_info(SIGNED_SAML, key_info);
4804 let mut config = KeyResolverConfig::default();
4805 config.named_keys.insert(
4806 "idp-signing".into(),
4807 VerificationKey {
4808 algorithm: SignatureAlgorithm::EcdsaSha256,
4809 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4810 certificate_der: None,
4811 name: Some("idp-signing".into()),
4812 },
4813 );
4814 let resolver = DefaultKeyResolver::new(config);
4815 let result = super::super::VerifyContext::new()
4816 .key_resolver(&resolver)
4817 .verify(&xml)
4818 .expect("later KeyName should resolve after malformed ECKeyValue");
4819
4820 assert_eq!(result.status, super::super::DsigStatus::Valid);
4821 }
4822
4823 #[test]
4824 fn invalid_base64_ec_key_value_falls_back_to_later_key_name() {
4825 let key_info = r#"<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:dsig11="http://www.w3.org/2009/xmldsig11#"><ds:KeyValue><dsig11:ECKeyValue><dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/><dsig11:PublicKey>not base64!</dsig11:PublicKey></dsig11:ECKeyValue></ds:KeyValue><ds:KeyName>idp-signing</ds:KeyName></ds:KeyInfo>"#;
4828 let xml = replace_key_info(SIGNED_SAML, key_info);
4829 let mut config = KeyResolverConfig::default();
4830 config.named_keys.insert(
4831 "idp-signing".into(),
4832 VerificationKey {
4833 algorithm: SignatureAlgorithm::EcdsaSha256,
4834 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4835 certificate_der: None,
4836 name: Some("idp-signing".into()),
4837 },
4838 );
4839 let resolver = DefaultKeyResolver::new(config);
4840 let result = super::super::VerifyContext::new()
4841 .key_resolver(&resolver)
4842 .verify(&xml)
4843 .expect("later KeyName should resolve after bad ECKeyValue base64");
4844
4845 assert_eq!(result.status, super::super::DsigStatus::Valid);
4846 }
4847
4848 #[test]
4849 fn missing_curve_uri_ec_key_value_falls_back_to_later_key_name() {
4850 let key_info = r#"<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:dsig11="http://www.w3.org/2009/xmldsig11#"><ds:KeyValue><dsig11:ECKeyValue><dsig11:NamedCurve/><dsig11:PublicKey>BA==</dsig11:PublicKey></dsig11:ECKeyValue></ds:KeyValue><ds:KeyName>idp-signing</ds:KeyName></ds:KeyInfo>"#;
4852 let xml = replace_key_info(SIGNED_SAML, key_info);
4853 let mut config = KeyResolverConfig::default();
4854 config.named_keys.insert(
4855 "idp-signing".into(),
4856 VerificationKey {
4857 algorithm: SignatureAlgorithm::EcdsaSha256,
4858 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4859 certificate_der: None,
4860 name: Some("idp-signing".into()),
4861 },
4862 );
4863 let resolver = DefaultKeyResolver::new(config);
4864 let result = super::super::VerifyContext::new()
4865 .key_resolver(&resolver)
4866 .verify(&xml)
4867 .expect("later KeyName should resolve after missing EC curve URI");
4868
4869 assert_eq!(result.status, super::super::DsigStatus::Valid);
4870 }
4871
4872 #[test]
4873 fn malformed_ec_key_value_children_fall_back_to_later_key_name() {
4874 let malformed_ec_key_values = [
4877 r#"<dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/>"#,
4878 r#"<dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/><dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/>"#,
4879 r#"<dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/><dsig11:PublicKey>BA==</dsig11:PublicKey><dsig11:PublicKey>BA==</dsig11:PublicKey>"#,
4880 ];
4881
4882 for malformed_children in malformed_ec_key_values {
4883 let key_info = format!(
4884 r#"<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:dsig11="http://www.w3.org/2009/xmldsig11#"><ds:KeyValue><dsig11:ECKeyValue>{malformed_children}</dsig11:ECKeyValue></ds:KeyValue><ds:KeyName>idp-signing</ds:KeyName></ds:KeyInfo>"#
4885 );
4886 let xml = replace_key_info(SIGNED_SAML, &key_info);
4887 let mut config = KeyResolverConfig::default();
4888 config.named_keys.insert(
4889 "idp-signing".into(),
4890 VerificationKey {
4891 algorithm: SignatureAlgorithm::EcdsaSha256,
4892 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4893 certificate_der: None,
4894 name: Some("idp-signing".into()),
4895 },
4896 );
4897 let resolver = DefaultKeyResolver::new(config);
4898 let result = super::super::VerifyContext::new()
4899 .key_resolver(&resolver)
4900 .verify(&xml)
4901 .expect("later KeyName should resolve after malformed EC child shape");
4902
4903 assert_eq!(result.status, super::super::DsigStatus::Valid);
4904 }
4905 }
4906
4907 #[test]
4908 fn supported_ec_curve_does_not_fall_back_to_later_key_name() {
4909 let key_info = r#"<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:dsig11="http://www.w3.org/2009/xmldsig11#"><ds:KeyValue><dsig11:ECKeyValue><dsig11:NamedCurve URI="urn:oid:1.3.132.0.34"/><dsig11:PublicKey>BO/yd/OZzDfjX4qivDY/vsUIuh6KWAxoxW5P4ukvwd+T6pVljWsX2UBJNNy5MdhTwB8e2YwB8kUbJwdsAS/XGi/fz8unFrs+lVlAgIs6s/xBYFbfUoRiAacD2SpVDe6XBA==</dsig11:PublicKey></dsig11:ECKeyValue></ds:KeyValue><ds:KeyName>idp-signing</ds:KeyName></ds:KeyInfo>"#;
4913 let xml = replace_key_info(SIGNED_SAML, key_info);
4914 let mut config = KeyResolverConfig::default();
4915 config.named_keys.insert(
4916 "idp-signing".into(),
4917 VerificationKey {
4918 algorithm: SignatureAlgorithm::EcdsaSha256,
4919 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4920 certificate_der: None,
4921 name: Some("idp-signing".into()),
4922 },
4923 );
4924 let resolver = DefaultKeyResolver::new(config);
4925 let error = super::super::VerifyContext::new()
4926 .policy(cryptographic_policy())
4927 .key_resolver(&resolver)
4928 .verify(&xml)
4929 .expect_err("a usable first key source must not fall through after verification");
4930
4931 assert!(matches!(
4932 error,
4933 DsigError::Crypto(super::super::SignatureVerificationError::InvalidSignatureFormat)
4934 ));
4935 }
4936
4937 #[test]
4938 fn lone_malformed_ec_key_value_reports_invalid_public_key() {
4939 let key_info = r#"<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:dsig11="http://www.w3.org/2009/xmldsig11#"><ds:KeyValue><dsig11:ECKeyValue><dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/><dsig11:PublicKey>AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</dsig11:PublicKey></dsig11:ECKeyValue></ds:KeyValue></ds:KeyInfo>"#;
4940 let xml = replace_key_info(SIGNED_SAML, key_info);
4941 let error = super::super::VerifyContext::new()
4942 .key_resolver(&DefaultKeyResolver::default())
4943 .verify(&xml)
4944 .expect_err("lone malformed ECKeyValue should surface typed key error");
4945
4946 assert!(matches!(
4947 error,
4948 DsigError::KeyResolution(KeyResolutionError::InvalidPublicKey)
4949 ));
4950 }
4951
4952 #[test]
4953 fn lone_supported_ec_curve_reaches_signature_verification() {
4954 let key_info = r#"<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:dsig11="http://www.w3.org/2009/xmldsig11#"><ds:KeyValue><dsig11:ECKeyValue><dsig11:NamedCurve URI="urn:oid:1.3.132.0.34"/><dsig11:PublicKey>BO/yd/OZzDfjX4qivDY/vsUIuh6KWAxoxW5P4ukvwd+T6pVljWsX2UBJNNy5MdhTwB8e2YwB8kUbJwdsAS/XGi/fz8unFrs+lVlAgIs6s/xBYFbfUoRiAacD2SpVDe6XBA==</dsig11:PublicKey></dsig11:ECKeyValue></ds:KeyValue></ds:KeyInfo>"#;
4955 let xml = replace_key_info(SIGNED_SAML, key_info);
4956 let error = super::super::VerifyContext::new()
4957 .policy(cryptographic_policy())
4958 .key_resolver(&DefaultKeyResolver::default())
4959 .verify(&xml)
4960 .expect_err("a supported EC curve must reach signature verification");
4961
4962 assert!(matches!(
4963 error,
4964 DsigError::Crypto(super::super::SignatureVerificationError::InvalidSignatureFormat)
4965 ));
4966 }
4967
4968 #[test]
4969 fn chain_verification_rejects_untrusted_embedded_certificate() {
4970 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4972 ..KeyResolverConfig::default()
4973 });
4974 let error = super::super::VerifyContext::new()
4975 .policy(verification_policy_with_trust(chain_policy()))
4976 .key_resolver(&resolver)
4977 .verify(SIGNED_SAML)
4978 .expect_err("untrusted certificate must fail chain validation");
4979
4980 assert!(matches!(
4981 error,
4982 DsigError::KeyResolution(KeyResolutionError::Chain(
4983 super::super::X509ChainError::UntrustedRoot
4984 ))
4985 ));
4986 }
4987
4988 #[test]
4989 fn named_key_algorithm_mismatch_fails_closed() {
4990 let xml = replace_key_info(
4992 SIGNED_SAML,
4993 "<ds:KeyInfo><ds:KeyName>wrong-algorithm</ds:KeyName></ds:KeyInfo>",
4994 );
4995 let mut config = KeyResolverConfig::default();
4996 config.named_keys.insert(
4997 "wrong-algorithm".into(),
4998 VerificationKey {
4999 algorithm: SignatureAlgorithm::RsaSha256,
5000 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
5001 certificate_der: None,
5002 name: Some("wrong-algorithm".into()),
5003 },
5004 );
5005 let resolver = DefaultKeyResolver::new(config);
5006 let error = super::super::VerifyContext::new()
5007 .key_resolver(&resolver)
5008 .verify(&xml)
5009 .expect_err("algorithm mismatch must fail closed");
5010
5011 assert!(matches!(
5012 error,
5013 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
5014 ));
5015 }
5016
5017 #[test]
5018 fn named_key_spki_type_mismatch_fails_during_resolution() {
5019 let xml = replace_key_info(
5021 SIGNED_SAML,
5022 "<ds:KeyInfo><ds:KeyName>mislabeled</ds:KeyName></ds:KeyInfo>",
5023 );
5024 let mut config = KeyResolverConfig::default();
5025 config.named_keys.insert(
5026 "mislabeled".into(),
5027 VerificationKey {
5028 algorithm: SignatureAlgorithm::EcdsaSha256,
5029 public_key_bytes: public_key_der(RSA_PUBLIC_KEY),
5030 certificate_der: None,
5031 name: Some("mislabeled".into()),
5032 },
5033 );
5034 let resolver = DefaultKeyResolver::new(config);
5035 let error = super::super::VerifyContext::new()
5036 .key_resolver(&resolver)
5037 .verify(&xml)
5038 .expect_err("mislabeled named key must fail during resolution");
5039
5040 assert!(matches!(
5041 error,
5042 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
5043 ));
5044 }
5045
5046 #[test]
5047 fn malformed_named_key_reports_public_key_error() {
5048 let xml = replace_key_info(
5050 SIGNED_SAML,
5051 "<ds:KeyInfo><ds:KeyName>malformed</ds:KeyName></ds:KeyInfo>",
5052 );
5053 let mut config = KeyResolverConfig::default();
5054 config.named_keys.insert(
5055 "malformed".into(),
5056 VerificationKey {
5057 algorithm: SignatureAlgorithm::EcdsaSha256,
5058 public_key_bytes: vec![1, 2, 3],
5059 certificate_der: None,
5060 name: Some("malformed".into()),
5061 },
5062 );
5063 let resolver = DefaultKeyResolver::new(config);
5064 let error = super::super::VerifyContext::new()
5065 .key_resolver(&resolver)
5066 .verify(&xml)
5067 .expect_err("malformed named key must fail during resolution");
5068
5069 assert!(matches!(
5070 error,
5071 DsigError::KeyResolution(KeyResolutionError::InvalidPublicKey)
5072 ));
5073 }
5074}