1use std::{collections::HashMap, fmt, time::SystemTime};
4
5use crypto_bigint::BoxedUint;
6use dsa::pkcs8::{DecodePublicKey as DsaDecodePublicKey, EncodePublicKey as DsaEncodePublicKey};
7use hmac::{KeyInit, Mac};
8use x509_parser::{
9 prelude::{FromDer, X509Certificate},
10 public_key::PublicKey,
11 x509::SubjectPublicKeyInfo,
12};
13use zeroize::Zeroizing;
14
15use super::signature::{
16 signature_value_matches_spki, signature_value_matches_spki_with_encoding,
17 validate_dsa_signature_spki_with_minimum, validate_rsa_signature_spki_with_minimum,
18 verify_dsa_signature_spki_primitive, verify_dsa_signature_spki_with_minimum,
19 verify_rsa_signature_spki_primitive, verify_rsa_signature_spki_with_minimum,
20};
21use super::{
22 DsigError, KeyInfo, KeyInfoSource, KeyResolver, KeyValueInfo, SignatureAlgorithm, VerifyingKey,
23 X509ChainOptions, X509DataInfo,
24 parse::{
25 EC_P256_OID, EC_P384_OID, EC_P521_OID, ParseError, X509ChainBuildError,
26 build_x509_certificate_paths_to_selector_targets,
27 build_x509_certificate_paths_to_trusted_prefix, distinguished_names_equal,
28 parse_x509_certificate, x509_certificate_matches_any_selector,
29 x509_data_has_lookup_identifiers, x509_selector_categories_match_chain,
30 },
31 verify_ecdsa_signature_spki, verify_ecdsa_signature_spki_with_encoding,
32 x509::verify_x509_certificate_chain_with_provider,
33};
34
35#[derive(Clone)]
42pub struct HmacVerificationKey {
43 secret: Zeroizing<Vec<u8>>,
44}
45
46impl fmt::Debug for HmacVerificationKey {
47 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
48 formatter
49 .debug_struct("HmacVerificationKey")
50 .finish_non_exhaustive()
51 }
52}
53
54impl HmacVerificationKey {
55 pub fn new(secret: impl Into<Vec<u8>>) -> Result<Self, KeyResolutionError> {
57 let secret = secret.into();
58 if secret.is_empty() {
59 return Err(KeyResolutionError::InvalidPublicKey);
60 }
61 Ok(Self {
62 secret: Zeroizing::new(secret),
63 })
64 }
65
66 fn validate_output(
67 &self,
68 policy: crate::policy::HmacPolicy,
69 algorithm: SignatureAlgorithm,
70 signature_value: &[u8],
71 ) -> Result<(), DsigError> {
72 if algorithm.hmac_output_bits().is_none() {
73 return Err(KeyResolutionError::AlgorithmMismatch.into());
74 }
75 policy.validate_key_bytes(self.secret.len())?;
76 policy.validate_output(algorithm, signature_value.len().saturating_mul(8))?;
77 Ok(())
78 }
79
80 fn verify_with_hmac_policy(
81 &self,
82 policy: crate::policy::HmacPolicy,
83 algorithm: SignatureAlgorithm,
84 signed_data: &[u8],
85 signature_value: &[u8],
86 ) -> Result<bool, DsigError> {
87 self.validate_output(policy, algorithm, signature_value)?;
88 macro_rules! verify_hmac {
89 ($digest:ty) => {{
90 let mut mac = hmac::Hmac::<$digest>::new_from_slice(&self.secret)
91 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
92 mac.update(signed_data);
93 let expected = mac.finalize().into_bytes();
94 subtle::ConstantTimeEq::ct_eq(&expected[..signature_value.len()], signature_value)
95 .into()
96 }};
97 }
98 Ok(match algorithm {
99 SignatureAlgorithm::HmacSha1 => verify_hmac!(sha1::Sha1),
100 SignatureAlgorithm::HmacSha224 => verify_hmac!(sha2::Sha224),
101 SignatureAlgorithm::HmacSha256 => verify_hmac!(sha2::Sha256),
102 SignatureAlgorithm::HmacSha384 => verify_hmac!(sha2::Sha384),
103 SignatureAlgorithm::HmacSha512 => verify_hmac!(sha2::Sha512),
104 _ => return Err(KeyResolutionError::AlgorithmMismatch.into()),
105 })
106 }
107}
108
109impl VerifyingKey for HmacVerificationKey {
110 fn validate_policy(&self, policy: &crate::policy::VerificationPolicy) -> Result<(), DsigError> {
111 policy
112 .hmac
113 .validate_key_bytes(self.secret.len())
114 .map_err(Into::into)
115 }
116
117 fn validate_signature_value(
118 &self,
119 algorithm: SignatureAlgorithm,
120 signature_value: &[u8],
121 ) -> Result<bool, DsigError> {
122 self.validate_output(
123 crate::policy::HmacPolicy::default(),
124 algorithm,
125 signature_value,
126 )?;
127 Ok(true)
128 }
129
130 fn validate_signature_value_with_policy(
131 &self,
132 policy: &crate::policy::VerificationPolicy,
133 algorithm: SignatureAlgorithm,
134 signature_value: &[u8],
135 ) -> Result<bool, DsigError> {
136 self.validate_output(policy.hmac, algorithm, signature_value)?;
137 Ok(true)
138 }
139
140 fn verify(
141 &self,
142 algorithm: SignatureAlgorithm,
143 signed_data: &[u8],
144 signature_value: &[u8],
145 ) -> Result<bool, DsigError> {
146 self.verify_with_hmac_policy(
147 crate::policy::HmacPolicy::default(),
148 algorithm,
149 signed_data,
150 signature_value,
151 )
152 }
153
154 fn verify_with_policy(
155 &self,
156 policy: &crate::policy::VerificationPolicy,
157 algorithm: SignatureAlgorithm,
158 signed_data: &[u8],
159 signature_value: &[u8],
160 ) -> Result<bool, DsigError> {
161 self.verify_with_hmac_policy(policy.hmac, algorithm, signed_data, signature_value)
162 }
163}
164
165pub type HmacSha1VerificationKey = HmacVerificationKey;
167
168#[derive(Debug, Clone, PartialEq, Eq)]
170pub struct VerificationKey {
171 pub algorithm: SignatureAlgorithm,
173 pub public_key_bytes: Vec<u8>,
175 pub certificate_der: Option<Vec<u8>>,
177 pub name: Option<String>,
179}
180
181impl VerifyingKey for VerificationKey {
182 fn validate_policy(&self, policy: &crate::policy::VerificationPolicy) -> Result<(), DsigError> {
183 let result = match self.algorithm {
184 SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256 => {
185 validate_dsa_signature_spki_with_minimum(
186 &self.public_key_bytes,
187 policy.key_trust.dsa_keys.minimum_modulus_bits,
188 )
189 }
190 SignatureAlgorithm::RsaSha1
191 | SignatureAlgorithm::RsaSha224
192 | SignatureAlgorithm::RsaSha256
193 | SignatureAlgorithm::RsaSha384
194 | SignatureAlgorithm::RsaSha512 => validate_rsa_signature_spki_with_minimum(
195 self.algorithm,
196 &self.public_key_bytes,
197 policy.key_trust.rsa_keys.minimum_modulus_bits,
198 ),
199 SignatureAlgorithm::HmacSha1
200 | SignatureAlgorithm::HmacSha224
201 | SignatureAlgorithm::HmacSha256
202 | SignatureAlgorithm::HmacSha384
203 | SignatureAlgorithm::HmacSha512
204 | SignatureAlgorithm::EcdsaSha1
205 | SignatureAlgorithm::EcdsaSha224
206 | SignatureAlgorithm::EcdsaSha256
207 | SignatureAlgorithm::EcdsaSha384
208 | SignatureAlgorithm::EcdsaSha512 => Ok(()),
209 };
210 result.map_err(DsigError::Crypto)
211 }
212
213 fn validate_signature_value(
214 &self,
215 algorithm: SignatureAlgorithm,
216 signature_value: &[u8],
217 ) -> Result<bool, DsigError> {
218 if algorithm != self.algorithm {
219 return Err(KeyResolutionError::AlgorithmMismatch.into());
220 }
221 signature_value_matches_spki(algorithm, &self.public_key_bytes, signature_value)
222 .map_err(DsigError::Crypto)
223 }
224
225 fn validate_signature_value_with_policy(
226 &self,
227 policy: &crate::policy::VerificationPolicy,
228 algorithm: SignatureAlgorithm,
229 signature_value: &[u8],
230 ) -> Result<bool, DsigError> {
231 if algorithm != self.algorithm {
232 return Err(KeyResolutionError::AlgorithmMismatch.into());
233 }
234 signature_value_matches_spki_with_encoding(
235 algorithm,
236 &self.public_key_bytes,
237 signature_value,
238 policy.ecdsa_signature_value_encoding,
239 )
240 .map_err(DsigError::Crypto)
241 }
242
243 fn verify(
244 &self,
245 algorithm: SignatureAlgorithm,
246 signed_data: &[u8],
247 signature_value: &[u8],
248 ) -> Result<bool, DsigError> {
249 if algorithm != self.algorithm {
250 return Err(KeyResolutionError::AlgorithmMismatch.into());
251 }
252 let result = match algorithm {
253 SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256 => {
254 verify_dsa_signature_spki_primitive(
255 algorithm,
256 &self.public_key_bytes,
257 signed_data,
258 signature_value,
259 )
260 }
261 SignatureAlgorithm::HmacSha1
262 | SignatureAlgorithm::HmacSha224
263 | SignatureAlgorithm::HmacSha256
264 | SignatureAlgorithm::HmacSha384
265 | SignatureAlgorithm::HmacSha512 => {
266 return Err(KeyResolutionError::AlgorithmMismatch.into());
267 }
268 SignatureAlgorithm::RsaSha1
269 | SignatureAlgorithm::RsaSha224
270 | SignatureAlgorithm::RsaSha256
271 | SignatureAlgorithm::RsaSha384
272 | SignatureAlgorithm::RsaSha512 => verify_rsa_signature_spki_primitive(
273 algorithm,
274 &self.public_key_bytes,
275 signed_data,
276 signature_value,
277 ),
278 SignatureAlgorithm::EcdsaSha1
279 | SignatureAlgorithm::EcdsaSha224
280 | SignatureAlgorithm::EcdsaSha256
281 | SignatureAlgorithm::EcdsaSha384
282 | SignatureAlgorithm::EcdsaSha512 => verify_ecdsa_signature_spki(
283 algorithm,
284 &self.public_key_bytes,
285 signed_data,
286 signature_value,
287 ),
288 };
289 result.map_err(DsigError::Crypto)
290 }
291
292 fn verify_with_policy(
293 &self,
294 policy: &crate::policy::VerificationPolicy,
295 algorithm: SignatureAlgorithm,
296 signed_data: &[u8],
297 signature_value: &[u8],
298 ) -> Result<bool, DsigError> {
299 if algorithm != self.algorithm {
300 return Err(KeyResolutionError::AlgorithmMismatch.into());
301 }
302 if matches!(
303 algorithm,
304 SignatureAlgorithm::EcdsaSha1
305 | SignatureAlgorithm::EcdsaSha224
306 | SignatureAlgorithm::EcdsaSha256
307 | SignatureAlgorithm::EcdsaSha384
308 | SignatureAlgorithm::EcdsaSha512
309 ) {
310 return verify_ecdsa_signature_spki_with_encoding(
311 algorithm,
312 &self.public_key_bytes,
313 signed_data,
314 signature_value,
315 policy.ecdsa_signature_value_encoding,
316 )
317 .map_err(DsigError::Crypto);
318 }
319 self.verify(algorithm, signed_data, signature_value)
320 }
321}
322
323struct PolicyBoundVerificationKey {
324 key: VerificationKey,
325 rsa_minimum_bits: usize,
326 dsa_minimum_bits: usize,
327}
328
329impl VerifyingKey for PolicyBoundVerificationKey {
330 fn validate_signature_value(
331 &self,
332 algorithm: SignatureAlgorithm,
333 signature_value: &[u8],
334 ) -> Result<bool, DsigError> {
335 self.key
336 .validate_signature_value(algorithm, signature_value)
337 }
338
339 fn validate_signature_value_with_policy(
340 &self,
341 policy: &crate::policy::VerificationPolicy,
342 algorithm: SignatureAlgorithm,
343 signature_value: &[u8],
344 ) -> Result<bool, DsigError> {
345 self.key
346 .validate_signature_value_with_policy(policy, algorithm, signature_value)
347 }
348
349 fn verify(
350 &self,
351 algorithm: SignatureAlgorithm,
352 signed_data: &[u8],
353 signature_value: &[u8],
354 ) -> Result<bool, DsigError> {
355 if algorithm != self.key.algorithm {
356 return Err(KeyResolutionError::AlgorithmMismatch.into());
357 }
358 let result = match algorithm {
359 SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256 => {
360 verify_dsa_signature_spki_with_minimum(
361 algorithm,
362 &self.key.public_key_bytes,
363 signed_data,
364 signature_value,
365 self.dsa_minimum_bits,
366 )
367 }
368 SignatureAlgorithm::RsaSha1
369 | SignatureAlgorithm::RsaSha224
370 | SignatureAlgorithm::RsaSha256
371 | SignatureAlgorithm::RsaSha384
372 | SignatureAlgorithm::RsaSha512 => verify_rsa_signature_spki_with_minimum(
373 algorithm,
374 &self.key.public_key_bytes,
375 signed_data,
376 signature_value,
377 self.rsa_minimum_bits,
378 ),
379 _ => return self.key.verify(algorithm, signed_data, signature_value),
380 };
381 result.map_err(DsigError::Crypto)
382 }
383
384 fn verify_with_policy(
385 &self,
386 policy: &crate::policy::VerificationPolicy,
387 algorithm: SignatureAlgorithm,
388 signed_data: &[u8],
389 signature_value: &[u8],
390 ) -> Result<bool, DsigError> {
391 if matches!(
392 algorithm,
393 SignatureAlgorithm::EcdsaSha1
394 | SignatureAlgorithm::EcdsaSha224
395 | SignatureAlgorithm::EcdsaSha256
396 | SignatureAlgorithm::EcdsaSha384
397 | SignatureAlgorithm::EcdsaSha512
398 ) {
399 return self
400 .key
401 .verify_with_policy(policy, algorithm, signed_data, signature_value);
402 }
403 self.verify(algorithm, signed_data, signature_value)
404 }
405}
406
407#[derive(Debug, thiserror::Error)]
409#[non_exhaustive]
410pub enum KeyResolutionError {
411 #[error("verification key does not match the signature algorithm")]
413 AlgorithmMismatch,
414 #[error("invalid embedded certificate DER")]
416 InvalidCertificate,
417 #[error("invalid public key DER")]
419 InvalidPublicKey,
420 #[error("X.509 lookup selectors match multiple configured certificates")]
422 AmbiguousCertificate,
423 #[error("unsupported X.509 digest algorithm: {0}")]
425 UnsupportedDigestAlgorithm(String),
426 #[error("certificate chain validation failed: {0}")]
428 Chain(#[from] super::X509ChainError),
429 #[error("system time is unavailable")]
431 SystemTime,
432}
433
434#[derive(Debug, Clone, Default, PartialEq, Eq)]
440pub struct KeyResolverConfig {
441 pub lookup_certs: Vec<Vec<u8>>,
445 pub trusted_certs: Vec<Vec<u8>>,
447 pub named_keys: HashMap<String, VerificationKey>,
449}
450
451#[derive(Debug, Clone, Default)]
453pub struct DefaultKeyResolver {
454 config: KeyResolverConfig,
455}
456
457struct InspectedKeyCandidateBudget {
463 maximum: usize,
464 attempted: usize,
465}
466
467impl InspectedKeyCandidateBudget {
468 fn new(maximum: usize) -> Self {
469 Self {
470 maximum,
471 attempted: 0,
472 }
473 }
474
475 fn charge(&mut self) -> Result<(), DsigError> {
476 self.charge_many(1)
477 }
478
479 fn charge_many(&mut self, count: usize) -> Result<(), DsigError> {
480 self.attempted = self.attempted.saturating_add(count);
481 if self.attempted > self.maximum {
482 return Err(crate::policy::PolicyViolation::ResourceLimit {
483 resource: crate::policy::resource_name::KEY_CANDIDATES,
484 maximum: self.maximum,
485 actual: self.attempted,
486 }
487 .into());
488 }
489 Ok(())
490 }
491}
492
493fn validate_key_info_source_permissions(
494 key_info: &KeyInfo,
495 allowed: crate::policy::KeySourcePolicy,
496) -> Result<(), crate::policy::PolicyViolation> {
497 for source in &key_info.sources {
498 let disabled_reason = match source {
499 KeyInfoSource::X509Data(_) if !allowed.x509_data => {
500 Some("X509Data key sources are disabled")
501 }
502 KeyInfoSource::DerEncodedKeyValue(_) if !allowed.der_encoded_key_value => {
503 Some("DEREncodedKeyValue key sources are disabled")
504 }
505 KeyInfoSource::KeyName(_) if !allowed.key_name => {
506 Some("KeyName key sources are disabled")
507 }
508 KeyInfoSource::KeyValue(_) if !allowed.key_value => {
509 Some("KeyValue key sources are disabled")
510 }
511 KeyInfoSource::KeyInfoReference { .. } if !allowed.key_info_reference => {
512 Some("KeyInfoReference key sources are disabled")
513 }
514 KeyInfoSource::X509Data(_)
515 | KeyInfoSource::DerEncodedKeyValue(_)
516 | KeyInfoSource::KeyName(_)
517 | KeyInfoSource::KeyValue(_)
518 | KeyInfoSource::RetrievalMethod { .. }
519 | KeyInfoSource::KeyInfoReference { .. } => None,
520 };
521 if let Some(reason) = disabled_reason {
522 return Err(crate::policy::PolicyViolation::KeyTrust { reason });
523 }
524 }
525 Ok(())
526}
527
528impl DefaultKeyResolver {
529 #[must_use]
531 pub fn new(config: KeyResolverConfig) -> Self {
532 Self { config }
533 }
534
535 #[must_use]
537 pub fn config(&self) -> &KeyResolverConfig {
538 &self.config
539 }
540
541 fn resolve_x509(
542 &self,
543 info: &X509DataInfo,
544 algorithm: SignatureAlgorithm,
545 trust: &crate::policy::KeyTrustPolicy,
546 provider: &dyn crate::provider::CryptoProvider,
547 budget: &mut InspectedKeyCandidateBudget,
548 ) -> Result<Option<VerificationKey>, DsigError> {
549 let certificate_der = if let Some(&signing_index) = info.certificate_chain.first() {
550 if trust.verify_x509_chains {
551 self.prepare_embedded_x509(info, signing_index, trust, provider, budget)?;
552 } else {
553 budget.charge_many(info.certificates.len())?;
554 }
555 info.certificates
556 .get(signing_index)
557 .ok_or(KeyResolutionError::InvalidCertificate)?
558 .clone()
559 } else {
560 let Some(selected) = self.resolve_configured_x509(info, trust, provider, budget)?
561 else {
562 return Ok(None);
563 };
564 selected
565 .certificate_chain
566 .first()
567 .and_then(|index| selected.certificates.get(*index))
568 .ok_or(KeyResolutionError::InvalidCertificate)?
569 .clone()
570 };
571
572 let (rest, certificate) = X509Certificate::from_der(&certificate_der)
573 .map_err(|_| KeyResolutionError::InvalidCertificate)?;
574 if !rest.is_empty() {
575 return Err(KeyResolutionError::InvalidCertificate.into());
576 }
577 let public_key_bytes = certificate.public_key().raw.to_vec();
578 validate_spki_algorithm(&public_key_bytes, algorithm)?;
579 Ok(Some(VerificationKey {
580 algorithm,
581 public_key_bytes,
582 certificate_der: Some(certificate_der),
583 name: None,
584 }))
585 }
586
587 fn verify_x509_policy(
588 &self,
589 info: &X509DataInfo,
590 trust: &crate::policy::KeyTrustPolicy,
591 provider: &dyn crate::provider::CryptoProvider,
592 ) -> Result<(), KeyResolutionError> {
593 let options = X509ChainOptions {
594 trusted_certs: &self.config.trusted_certs,
595 verification_time: trust.verification_time.unwrap_or_else(SystemTime::now),
596 max_chain_depth: trust.max_x509_chain_depth,
597 check_crls: trust.check_crls,
598 allowed_extended_key_usages: Some(&trust.allowed_extended_key_usages),
599 rsa_keys: trust.rsa_keys,
600 dsa_keys: trust.dsa_keys,
601 };
602 verify_x509_certificate_chain_with_provider(info, &options, provider)?;
603 Ok(())
604 }
605
606 fn prepare_embedded_x509(
607 &self,
608 info: &X509DataInfo,
609 signing_index: usize,
610 trust: &crate::policy::KeyTrustPolicy,
611 provider: &dyn crate::provider::CryptoProvider,
612 budget: &mut InspectedKeyCandidateBudget,
613 ) -> Result<X509DataInfo, DsigError> {
614 let signing_der = info
615 .certificates
616 .get(signing_index)
617 .ok_or(KeyResolutionError::InvalidCertificate)?;
618 let mut available = X509DataInfo {
619 crls: info.crls.clone(),
620 ..X509DataInfo::default()
621 };
622 let mut trusted_prefix_len = 0;
623 for certificate in &self.config.trusted_certs {
624 budget.charge()?;
625 if available
626 .certificates
627 .iter()
628 .any(|known| known == certificate)
629 {
630 continue;
631 }
632 available.parsed_certificates.push(
633 parse_x509_certificate(certificate)
634 .map_err(|_| KeyResolutionError::InvalidCertificate)?,
635 );
636 available.certificates.push(certificate.clone());
637 trusted_prefix_len += 1;
638 }
639 for certificate in self.config.lookup_certs.iter().chain(&info.certificates) {
640 budget.charge()?;
641 if available
642 .certificates
643 .iter()
644 .any(|known| known == certificate)
645 {
646 continue;
647 }
648 available.parsed_certificates.push(
649 parse_x509_certificate(certificate)
650 .map_err(|_| KeyResolutionError::InvalidCertificate)?,
651 );
652 available.certificates.push(certificate.clone());
653 }
654 let signing_index = available
655 .certificates
656 .iter()
657 .position(|certificate| certificate == signing_der)
658 .ok_or(KeyResolutionError::InvalidCertificate)?;
659 self.select_valid_x509_path(
660 &mut available,
661 signing_index,
662 trusted_prefix_len,
663 trust,
664 provider,
665 None,
666 )?;
667 Ok(available)
668 }
669
670 fn select_valid_x509_path(
671 &self,
672 available: &mut X509DataInfo,
673 signing_index: usize,
674 trusted_prefix_len: usize,
675 trust: &crate::policy::KeyTrustPolicy,
676 provider: &dyn crate::provider::CryptoProvider,
677 selectors: Option<&X509DataInfo>,
678 ) -> Result<bool, KeyResolutionError> {
679 let candidates = build_x509_certificate_paths_to_trusted_prefix(
680 available,
681 signing_index,
682 trusted_prefix_len,
683 trust.max_x509_chain_depth,
684 trust.max_x509_candidate_paths,
685 provider,
686 )
687 .map_err(|error| match error {
688 X509ChainBuildError::AmbiguousIssuer => KeyResolutionError::AmbiguousCertificate,
689 X509ChainBuildError::Provider(error) => {
690 KeyResolutionError::Chain(super::X509ChainError::Provider(error))
691 }
692 X509ChainBuildError::UnsupportedSignatureAlgorithm { oid } => {
693 KeyResolutionError::Chain(super::X509ChainError::UnsupportedSignatureAlgorithm {
694 oid,
695 })
696 }
697 _ => KeyResolutionError::InvalidCertificate,
698 })?;
699 let mut first_error = None;
700 let mut valid_path_without_selector_match = false;
701 for candidate in candidates {
702 available.certificate_chain = candidate;
703 match self.verify_x509_policy(available, trust, provider) {
704 Ok(()) => {
705 if match selectors {
706 Some(selectors) => {
707 selected_x509_path_matches_selectors(available, selectors, provider)?
708 }
709 None => true,
710 } {
711 return Ok(true);
712 }
713 valid_path_without_selector_match = true;
714 }
715 Err(error) => {
716 first_error.get_or_insert(error);
717 }
718 }
719 }
720 if valid_path_without_selector_match {
721 return Ok(false);
722 }
723 Err(first_error.unwrap_or(KeyResolutionError::Chain(
724 super::X509ChainError::UntrustedRoot,
725 )))
726 }
727
728 fn select_x509_selector_path(
729 &self,
730 available: &mut X509DataInfo,
731 signing_index: usize,
732 matching_indices: &[usize],
733 trust: &crate::policy::KeyTrustPolicy,
734 provider: &dyn crate::provider::CryptoProvider,
735 selectors: &X509DataInfo,
736 ) -> Result<bool, KeyResolutionError> {
737 let targets = matching_indices
738 .iter()
739 .copied()
740 .filter(|index| *index != signing_index)
741 .collect::<Vec<_>>();
742 if targets.is_empty() {
743 return Ok(false);
744 }
745 let candidates = build_x509_certificate_paths_to_selector_targets(
746 available,
747 signing_index,
748 &targets,
749 trust.max_x509_chain_depth,
750 trust.max_x509_candidate_paths,
751 provider,
752 )
753 .map_err(|error| match error {
754 X509ChainBuildError::AmbiguousIssuer => KeyResolutionError::AmbiguousCertificate,
755 X509ChainBuildError::Provider(error) => {
756 KeyResolutionError::Chain(super::X509ChainError::Provider(error))
757 }
758 X509ChainBuildError::UnsupportedSignatureAlgorithm { oid } => {
759 KeyResolutionError::Chain(super::X509ChainError::UnsupportedSignatureAlgorithm {
760 oid,
761 })
762 }
763 _ => KeyResolutionError::InvalidCertificate,
764 })?;
765 for candidate in candidates {
766 available.certificate_chain = candidate;
767 if selected_x509_path_matches_selectors(available, selectors, provider)? {
768 return Ok(true);
769 }
770 }
771 Ok(false)
772 }
773
774 fn resolve_configured_x509(
775 &self,
776 info: &X509DataInfo,
777 trust: &crate::policy::KeyTrustPolicy,
778 provider: &dyn crate::provider::CryptoProvider,
779 budget: &mut InspectedKeyCandidateBudget,
780 ) -> Result<Option<X509DataInfo>, DsigError> {
781 if !x509_data_has_lookup_identifiers(info) {
782 return Ok(None);
783 }
784
785 let mut available = X509DataInfo {
786 subject_names: info.subject_names.clone(),
787 issuer_serials: info.issuer_serials.clone(),
788 skis: info.skis.clone(),
789 crls: info.crls.clone(),
790 digests: info.digests.clone(),
791 ..X509DataInfo::default()
792 };
793 let mut matches = Vec::new();
794 let mut trusted_prefix_len = 0usize;
795 for (trusted, certificate_der) in self
796 .config
797 .trusted_certs
798 .iter()
799 .map(|certificate| (true, certificate))
800 .chain(
801 self.config
802 .lookup_certs
803 .iter()
804 .map(|certificate| (false, certificate)),
805 )
806 {
807 budget.charge()?;
808 if available
809 .certificates
810 .iter()
811 .any(|available_der| available_der == certificate_der)
812 {
813 continue;
814 }
815 let parsed = parse_x509_certificate(certificate_der)
816 .map_err(|_| KeyResolutionError::InvalidCertificate)?;
817 let is_match =
818 x509_certificate_matches_any_selector(info, &parsed, certificate_der, provider)
819 .map_err(map_x509_selector_error)?;
820 if is_match {
821 matches.push((available.certificates.len(), parsed.clone()));
822 }
823 available.certificates.push(certificate_der.clone());
824 available.parsed_certificates.push(parsed);
825 if trusted {
826 trusted_prefix_len += 1;
827 }
828 }
829
830 let matched_chain = X509DataInfo {
831 certificates: matches
832 .iter()
833 .map(|(index, _)| available.certificates[*index].clone())
834 .collect(),
835 parsed_certificates: matches.iter().map(|(_, parsed)| parsed.clone()).collect(),
836 ..X509DataInfo::default()
837 };
838 if !x509_selector_categories_match_chain(
839 &X509DataInfo {
840 subject_names: info.subject_names.clone(),
841 issuer_serials: info.issuer_serials.clone(),
842 skis: info.skis.clone(),
843 digests: info.digests.clone(),
844 ..matched_chain
845 },
846 provider,
847 )
848 .map_err(map_x509_selector_error)?
849 {
850 return Ok(None);
851 }
852
853 let signing_index = match matches.as_slice() {
854 [] => return Ok(None),
855 [(index, _)] => *index,
856 _ => {
857 let leaves = matches
858 .iter()
859 .filter(|(_, candidate)| {
860 !distinguished_names_equal(&candidate.subject_dn, &candidate.issuer_dn)
861 && !matches.iter().any(|(_, other)| {
862 distinguished_names_equal(&other.issuer_dn, &candidate.subject_dn)
863 })
864 })
865 .collect::<Vec<_>>();
866 match leaves.as_slice() {
867 [(index, _)] => *index,
868 _ => return Err(KeyResolutionError::AmbiguousCertificate.into()),
869 }
870 }
871 };
872 let matching_indices = matches.iter().map(|(index, _)| *index).collect::<Vec<_>>();
873 available.certificate_chain =
877 if signing_index < trusted_prefix_len || !trust.verify_x509_chains {
878 vec![signing_index]
879 } else {
880 if !self.select_valid_x509_path(
881 &mut available,
882 signing_index,
883 trusted_prefix_len,
884 trust,
885 provider,
886 Some(info),
887 )? {
888 return Ok(None);
889 }
890 available.certificate_chain.clone()
891 };
892 if trust.verify_x509_chains && signing_index < trusted_prefix_len {
893 self.verify_x509_policy(&available, trust, provider)?;
894 }
895 if !trust.verify_x509_chains || signing_index < trusted_prefix_len {
896 let direct_match = selected_x509_path_matches_selectors(&available, info, provider)?;
897 if !direct_match
898 && (signing_index < trusted_prefix_len
899 || !self.select_x509_selector_path(
900 &mut available,
901 signing_index,
902 &matching_indices,
903 trust,
904 provider,
905 info,
906 )?)
907 {
908 return Ok(None);
909 }
910 }
911 Ok(Some(available))
912 }
913
914 fn resolve_key_value(
915 key_value: &KeyValueInfo,
916 algorithm: SignatureAlgorithm,
917 ) -> Result<Option<VerificationKey>, KeyResolutionError> {
918 let public_key_bytes = match key_value {
919 KeyValueInfo::Dsa { p, q, g, y } => {
920 if !matches!(
921 algorithm,
922 SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256
923 ) {
924 return Err(KeyResolutionError::AlgorithmMismatch);
925 }
926 let (Some(p), Some(q), Some(g)) = (p.as_deref(), q.as_deref(), g.as_deref()) else {
927 return Err(KeyResolutionError::InvalidPublicKey);
928 };
929 dsa_key_value_to_spki_der(p, q, g, y)?
930 }
931 KeyValueInfo::Rsa { modulus, exponent } => {
932 if !matches!(
933 algorithm,
934 SignatureAlgorithm::RsaSha1
935 | SignatureAlgorithm::RsaSha224
936 | SignatureAlgorithm::RsaSha256
937 | SignatureAlgorithm::RsaSha384
938 | SignatureAlgorithm::RsaSha512
939 ) {
940 return Err(KeyResolutionError::AlgorithmMismatch);
941 }
942 rsa_key_value_to_spki_der(modulus, exponent)?
943 }
944 KeyValueInfo::Ec {
945 curve_oid,
946 public_key,
947 } => {
948 if !matches!(
949 algorithm,
950 SignatureAlgorithm::EcdsaSha1
951 | SignatureAlgorithm::EcdsaSha224
952 | SignatureAlgorithm::EcdsaSha256
953 | SignatureAlgorithm::EcdsaSha384
954 | SignatureAlgorithm::EcdsaSha512
955 ) {
956 return Ok(None);
957 }
958 ec_key_value_to_spki_der(curve_oid, public_key)?
959 }
960 KeyValueInfo::InvalidEcKeyValue => return Err(KeyResolutionError::InvalidPublicKey),
961 KeyValueInfo::Unsupported { .. } => return Ok(None),
962 };
963 validate_spki_algorithm(&public_key_bytes, algorithm)?;
964
965 Ok(Some(VerificationKey {
966 algorithm,
967 public_key_bytes,
968 certificate_der: None,
969 name: None,
970 }))
971 }
972
973 fn resolve_with_trust<'a>(
974 &'a self,
975 key_info: Option<&KeyInfo>,
976 algorithm: SignatureAlgorithm,
977 sources: crate::policy::KeySourcePolicy,
978 trust: &crate::policy::KeyTrustPolicy,
979 resources: &crate::policy::ResourcePolicy,
980 provider: &dyn crate::provider::CryptoProvider,
981 ) -> Result<Option<Box<dyn VerifyingKey + 'a>>, DsigError> {
982 trust.validate()?;
983 resources.validate()?;
984 let Some(key_info) = key_info else {
985 return Ok(None);
986 };
987 validate_key_info_source_permissions(key_info, sources)?;
988 let mut candidate_budget = InspectedKeyCandidateBudget::new(resources.max_key_candidates);
989 let mut deferred_key_value_error = None;
990 for source in &key_info.sources {
991 let resolved = match source {
992 KeyInfoSource::X509Data(info) => {
993 self.resolve_x509(info, algorithm, trust, provider, &mut candidate_budget)?
994 }
995 KeyInfoSource::DerEncodedKeyValue(public_key_bytes) => {
996 candidate_budget.charge()?;
997 validate_spki_algorithm(public_key_bytes, algorithm)?;
998 Some(VerificationKey {
999 algorithm,
1000 public_key_bytes: public_key_bytes.clone(),
1001 certificate_der: None,
1002 name: None,
1003 })
1004 }
1005 KeyInfoSource::KeyName(name) => {
1006 candidate_budget.charge()?;
1007 self.config
1008 .named_keys
1009 .get(name)
1010 .map(|key| {
1011 if key.algorithm != algorithm {
1012 return Err(KeyResolutionError::AlgorithmMismatch);
1013 }
1014 validate_spki_algorithm(&key.public_key_bytes, algorithm)?;
1015 Ok(key.clone())
1016 })
1017 .transpose()?
1018 }
1019 KeyInfoSource::KeyValue(key_value) => {
1020 candidate_budget.charge()?;
1021 match Self::resolve_key_value(key_value, algorithm) {
1022 Ok(resolved) => resolved,
1023 Err(error) if key_value_error_allows_fallback(key_value, &error) => {
1024 deferred_key_value_error.get_or_insert(error);
1025 None
1026 }
1027 Err(error) => return Err(error.into()),
1028 }
1029 }
1030 KeyInfoSource::RetrievalMethod { .. } => {
1031 candidate_budget.charge()?;
1032 None
1033 }
1034 KeyInfoSource::KeyInfoReference { .. } => {
1035 candidate_budget.charge()?;
1036 None
1037 }
1038 };
1039 if let Some(key) = resolved {
1040 return Ok(Some(Box::new(PolicyBoundVerificationKey {
1041 key,
1042 rsa_minimum_bits: trust.rsa_keys.minimum_modulus_bits,
1043 dsa_minimum_bits: trust.dsa_keys.minimum_modulus_bits,
1044 })));
1045 }
1046 }
1047 if let Some(error) = deferred_key_value_error {
1048 return Err(error.into());
1049 }
1050 Ok(None)
1051 }
1052}
1053
1054impl KeyResolver for DefaultKeyResolver {
1055 fn resolve<'a>(
1056 &'a self,
1057 key_info: Option<&KeyInfo>,
1058 algorithm: SignatureAlgorithm,
1059 ) -> Result<Option<Box<dyn VerifyingKey + 'a>>, DsigError> {
1060 let policy = crate::policy::VerificationPolicy::default();
1061 self.resolve_with_trust(
1062 key_info,
1063 algorithm,
1064 policy.key_sources,
1065 &policy.key_trust,
1066 &policy.resources,
1067 crate::provider::default_provider(),
1068 )
1069 }
1070
1071 fn resolve_with_policy<'a>(
1072 &'a self,
1073 key_info: Option<&KeyInfo>,
1074 algorithm: SignatureAlgorithm,
1075 policy: &crate::policy::VerificationPolicy,
1076 ) -> Result<Option<Box<dyn VerifyingKey + 'a>>, DsigError> {
1077 self.resolve_with_policy_and_provider(
1078 key_info,
1079 algorithm,
1080 policy,
1081 crate::provider::default_provider(),
1082 )
1083 }
1084
1085 fn resolve_with_policy_and_provider<'a>(
1086 &'a self,
1087 key_info: Option<&KeyInfo>,
1088 algorithm: SignatureAlgorithm,
1089 policy: &crate::policy::VerificationPolicy,
1090 provider: &dyn crate::provider::CryptoProvider,
1091 ) -> Result<Option<Box<dyn VerifyingKey + 'a>>, DsigError> {
1092 self.resolve_with_trust(
1093 key_info,
1094 algorithm,
1095 policy.key_sources,
1096 &policy.key_trust,
1097 &policy.resources,
1098 provider,
1099 )
1100 }
1101
1102 fn consumes_document_key_info(&self) -> bool {
1103 true
1104 }
1105}
1106
1107fn map_x509_selector_error(error: ParseError) -> DsigError {
1108 match error {
1109 ParseError::Provider(error) => DsigError::Provider(error),
1110 ParseError::UnsupportedAlgorithm { uri } => {
1111 KeyResolutionError::UnsupportedDigestAlgorithm(uri).into()
1112 }
1113 _ => KeyResolutionError::InvalidCertificate.into(),
1114 }
1115}
1116
1117fn selected_x509_path_matches_selectors(
1118 available: &X509DataInfo,
1119 selectors: &X509DataInfo,
1120 provider: &dyn crate::provider::CryptoProvider,
1121) -> Result<bool, KeyResolutionError> {
1122 let selected = X509DataInfo {
1123 subject_names: selectors.subject_names.clone(),
1124 issuer_serials: selectors.issuer_serials.clone(),
1125 skis: selectors.skis.clone(),
1126 digests: selectors.digests.clone(),
1127 certificates: available
1128 .certificate_chain
1129 .iter()
1130 .map(|index| available.certificates[*index].clone())
1131 .collect(),
1132 parsed_certificates: available
1133 .certificate_chain
1134 .iter()
1135 .map(|index| available.parsed_certificates[*index].clone())
1136 .collect(),
1137 ..X509DataInfo::default()
1138 };
1139 x509_selector_categories_match_chain(&selected, provider).map_err(|error| match error {
1140 ParseError::Provider(error) => {
1141 KeyResolutionError::Chain(super::X509ChainError::Provider(error))
1142 }
1143 ParseError::UnsupportedAlgorithm { uri } => {
1144 KeyResolutionError::UnsupportedDigestAlgorithm(uri)
1145 }
1146 _ => KeyResolutionError::InvalidCertificate,
1147 })
1148}
1149
1150fn rsa_key_value_to_spki_der(
1151 modulus: &[u8],
1152 exponent: &[u8],
1153) -> Result<Vec<u8>, KeyResolutionError> {
1154 let key = rsa::RsaPublicKey::new(
1155 BoxedUint::from_be_slice_vartime(modulus),
1156 BoxedUint::from_be_slice_vartime(exponent),
1157 )
1158 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1159 key.to_public_key_der()
1160 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1161 .map(|der| der.as_bytes().to_vec())
1162}
1163
1164fn dsa_key_value_to_spki_der(
1165 p: &[u8],
1166 q: &[u8],
1167 g: &[u8],
1168 y: &[u8],
1169) -> Result<Vec<u8>, KeyResolutionError> {
1170 let components = dsa::Components::from_components(
1171 BoxedUint::from_be_slice_vartime(p),
1172 BoxedUint::from_be_slice_vartime(q),
1173 BoxedUint::from_be_slice_vartime(g),
1174 )
1175 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1176 dsa::VerifyingKey::from_components(components, BoxedUint::from_be_slice_vartime(y))
1177 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
1178 .to_public_key_der()
1179 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1180 .map(|der| der.as_bytes().to_vec())
1181}
1182
1183fn ec_key_value_to_spki_der(
1184 curve_oid: &str,
1185 public_key: &[u8],
1186) -> Result<Vec<u8>, KeyResolutionError> {
1187 match curve_oid {
1188 EC_P256_OID => p256::PublicKey::from_sec1_bytes(public_key)
1189 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
1190 .to_public_key_der()
1191 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1192 .map(|der| der.as_bytes().to_vec()),
1193 EC_P384_OID => p384::PublicKey::from_sec1_bytes(public_key)
1194 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
1195 .to_public_key_der()
1196 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1197 .map(|der| der.as_bytes().to_vec()),
1198 EC_P521_OID => p521::PublicKey::from_sec1_bytes(public_key)
1199 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
1200 .to_public_key_der()
1201 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1202 .map(|der| der.as_bytes().to_vec()),
1203 _ => Err(KeyResolutionError::InvalidPublicKey),
1204 }
1205}
1206
1207fn key_value_error_allows_fallback(key_value: &KeyValueInfo, error: &KeyResolutionError) -> bool {
1208 matches!(
1209 key_value,
1210 KeyValueInfo::Dsa { .. } | KeyValueInfo::Ec { .. } | KeyValueInfo::InvalidEcKeyValue
1211 ) && matches!(
1212 error,
1213 KeyResolutionError::InvalidPublicKey | KeyResolutionError::AlgorithmMismatch
1214 )
1215}
1216
1217fn validate_spki_algorithm(
1218 public_key_bytes: &[u8],
1219 algorithm: SignatureAlgorithm,
1220) -> Result<(), KeyResolutionError> {
1221 let (rest, spki) = SubjectPublicKeyInfo::from_der(public_key_bytes)
1222 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1223 if !rest.is_empty() {
1224 return Err(KeyResolutionError::InvalidPublicKey);
1225 }
1226 let parsed = spki
1227 .parsed()
1228 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1229 let curve_oid = spki
1230 .algorithm
1231 .parameters
1232 .as_ref()
1233 .and_then(|value| value.as_oid().ok())
1234 .map(|oid| oid.to_id_string());
1235 match (algorithm, parsed) {
1236 (SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256, PublicKey::DSA(_)) => {
1237 let _ = dsa::VerifyingKey::from_public_key_der(public_key_bytes)
1238 .map_err(|_| KeyResolutionError::AlgorithmMismatch)?;
1239 Ok(())
1240 }
1241 (
1242 SignatureAlgorithm::RsaSha1
1243 | SignatureAlgorithm::RsaSha224
1244 | SignatureAlgorithm::RsaSha256
1245 | SignatureAlgorithm::RsaSha384
1246 | SignatureAlgorithm::RsaSha512,
1247 PublicKey::RSA(_),
1248 ) => Ok(()),
1249 (
1250 SignatureAlgorithm::EcdsaSha1
1251 | SignatureAlgorithm::EcdsaSha224
1252 | SignatureAlgorithm::EcdsaSha256
1253 | SignatureAlgorithm::EcdsaSha384
1254 | SignatureAlgorithm::EcdsaSha512,
1255 PublicKey::EC(_),
1256 ) if matches!(
1257 curve_oid.as_deref(),
1258 Some(EC_P256_OID | EC_P384_OID | EC_P521_OID)
1259 ) =>
1260 {
1261 Ok(())
1262 }
1263 _ => Err(KeyResolutionError::AlgorithmMismatch),
1264 }
1265}
1266
1267#[cfg(test)]
1268mod tests {
1269 use crate::xml::dom as roxmltree;
1270 use std::sync::atomic::{AtomicUsize, Ordering};
1271
1272 use base64::{Engine, engine::general_purpose::STANDARD};
1273 use rsa::{pkcs8::DecodePublicKey, traits::PublicKeyParts};
1274
1275 use super::*;
1276
1277 struct RejectSecondSha512Provider {
1278 sha512_calls: AtomicUsize,
1279 verification_calls: AtomicUsize,
1280 reject_verification_call: Option<usize>,
1281 rejected_verification_data: Option<Vec<u8>>,
1282 }
1283
1284 impl crate::provider::CryptoProvider for RejectSecondSha512Provider {
1285 fn name(&self) -> &'static str {
1286 "reject-second-sha512"
1287 }
1288
1289 fn supports(&self, capability: crate::provider::ProviderCapability<'_>) -> bool {
1290 crate::provider::default_provider().supports(capability)
1291 }
1292
1293 fn fill_random(&self, output: &mut [u8]) -> Result<(), crate::provider::ProviderError> {
1294 crate::provider::default_provider().fill_random(output)
1295 }
1296
1297 fn derive_key(
1298 &self,
1299 parameters: &crate::provider::KdfParameters<'_>,
1300 secret: &[u8],
1301 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1302 crate::provider::default_provider().derive_key(parameters, secret)
1303 }
1304
1305 fn digest(
1306 &self,
1307 algorithm: super::super::DigestAlgorithm,
1308 data: &[u8],
1309 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1310 if algorithm == super::super::DigestAlgorithm::Sha512
1311 && self.sha512_calls.fetch_add(1, Ordering::Relaxed) > 0
1312 {
1313 return Err(crate::provider::ProviderError::Unsupported {
1314 operation: crate::provider::ProviderOperation::Digest,
1315 algorithm: Some(algorithm.uri().to_owned()),
1316 });
1317 }
1318 crate::provider::default_provider().digest(algorithm, data)
1319 }
1320
1321 fn sign(
1322 &self,
1323 key: &dyn super::super::SigningKey,
1324 algorithm: SignatureAlgorithm,
1325 data: &[u8],
1326 ) -> Result<Vec<u8>, super::super::SigningKeyError> {
1327 crate::provider::default_provider().sign(key, algorithm, data)
1328 }
1329
1330 fn verify(
1331 &self,
1332 key: &dyn VerifyingKey,
1333 algorithm: SignatureAlgorithm,
1334 data: &[u8],
1335 signature: &[u8],
1336 ) -> Result<bool, DsigError> {
1337 let call = self.verification_calls.fetch_add(1, Ordering::Relaxed);
1338 if self.reject_verification_call == Some(call)
1339 || self
1340 .rejected_verification_data
1341 .as_deref()
1342 .is_some_and(|rejected| rejected == data)
1343 {
1344 return Err(crate::provider::ProviderError::Unsupported {
1345 operation: crate::provider::ProviderOperation::Verify,
1346 algorithm: Some(algorithm.uri().to_owned()),
1347 }
1348 .into());
1349 }
1350 crate::provider::default_provider().verify(key, algorithm, data, signature)
1351 }
1352
1353 fn verify_x509_signature(
1354 &self,
1355 algorithm: crate::provider::X509SignatureAlgorithm,
1356 data: &[u8],
1357 signature: &[u8],
1358 issuer_spki_der: &[u8],
1359 ) -> Result<bool, crate::provider::ProviderError> {
1360 let call = self.verification_calls.fetch_add(1, Ordering::Relaxed);
1361 if self.reject_verification_call == Some(call)
1362 || self
1363 .rejected_verification_data
1364 .as_deref()
1365 .is_some_and(|rejected| rejected == data)
1366 {
1367 return Err(crate::provider::ProviderError::Unsupported {
1368 operation: crate::provider::ProviderOperation::VerifyCertificate,
1369 algorithm: Some(algorithm.oid().to_owned()),
1370 });
1371 }
1372 crate::provider::default_provider().verify_x509_signature(
1373 algorithm,
1374 data,
1375 signature,
1376 issuer_spki_der,
1377 )
1378 }
1379
1380 #[cfg(feature = "xmlenc")]
1381 fn encrypt_data(
1382 &self,
1383 algorithm: crate::xmlenc::DataEncryptionAlgorithm,
1384 key: &[u8],
1385 plaintext: &[u8],
1386 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1387 crate::provider::default_provider().encrypt_data(algorithm, key, plaintext)
1388 }
1389
1390 #[cfg(feature = "xmlenc")]
1391 fn decrypt_data(
1392 &self,
1393 algorithm: crate::xmlenc::DataEncryptionAlgorithm,
1394 key: &[u8],
1395 ciphertext: &[u8],
1396 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1397 crate::provider::default_provider().decrypt_data(algorithm, key, ciphertext)
1398 }
1399
1400 #[cfg(feature = "xmlenc")]
1401 fn wrap_key(
1402 &self,
1403 algorithm: crate::xmlenc::KeyWrapAlgorithm,
1404 kek: &[u8],
1405 key: &[u8],
1406 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1407 crate::provider::default_provider().wrap_key(algorithm, kek, key)
1408 }
1409
1410 #[cfg(feature = "xmlenc")]
1411 fn unwrap_key(
1412 &self,
1413 algorithm: crate::xmlenc::KeyWrapAlgorithm,
1414 kek: &[u8],
1415 wrapped: &[u8],
1416 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1417 crate::provider::default_provider().unwrap_key(algorithm, kek, wrapped)
1418 }
1419
1420 #[cfg(feature = "xmlenc")]
1421 fn transport_key(
1422 &self,
1423 key: &dyn crate::provider::KeyTransportKey,
1424 parameters: &crate::xmlenc::RsaOaepParameters,
1425 plaintext: &[u8],
1426 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1427 crate::provider::default_provider().transport_key(key, parameters, plaintext)
1428 }
1429
1430 #[cfg(feature = "xmlenc")]
1431 fn recover_key(
1432 &self,
1433 key: &dyn crate::provider::KeyRecoveryKey,
1434 parameters: &crate::xmlenc::RsaOaepParameters,
1435 ciphertext: &[u8],
1436 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1437 crate::provider::default_provider().recover_key(key, parameters, ciphertext)
1438 }
1439 }
1440
1441 fn chain_policy() -> crate::policy::KeyTrustPolicy {
1442 crate::policy::KeyTrustPolicy {
1443 verify_x509_chains: true,
1444 ..crate::policy::KeyTrustPolicy::default()
1445 }
1446 }
1447
1448 fn chain_policy_at(verification_time: SystemTime) -> crate::policy::KeyTrustPolicy {
1449 crate::policy::KeyTrustPolicy {
1450 verification_time: Some(verification_time),
1451 ..chain_policy()
1452 }
1453 }
1454
1455 fn verification_policy_with_trust(
1456 key_trust: crate::policy::KeyTrustPolicy,
1457 ) -> crate::policy::VerificationPolicy {
1458 crate::policy::VerificationPolicy {
1459 key_trust,
1460 ..crate::policy::VerificationPolicy::default()
1461 }
1462 }
1463
1464 const SIGNED_SAML: &str =
1465 include_str!("../../tests/fixtures/saml/response_signed_by_idp_ecdsa.xml");
1466 const SAML_PUBLIC_KEY: &str =
1467 include_str!("../../tests/fixtures/keys/ec/saml-idp-ecdsa-pubkey.pem");
1468 const RSA_PUBLIC_KEY: &str = include_str!("../../tests/fixtures/keys/rsa/rsa-2048-pubkey.pem");
1469 const RSA_4096_CERTIFICATE: &str =
1470 include_str!("../../tests/fixtures/keys/rsa/rsa-4096-cert.pem");
1471 const X509_DIGEST_SIGNATURE: &str = include_str!(
1472 "../../tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloped-x509-digest-sha512.xml"
1473 );
1474 const X509_DIGEST_SHA256_SIGNATURE: &str = include_str!(
1475 "../../tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloped-x509-digest-sha256.xml"
1476 );
1477 const RSA_KEY_VALUE_SIGNATURE: &str = include_str!(
1478 "../../tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloping-sha256-rsa-sha256.xml"
1479 );
1480 const LEGACY_RSA_KEY_VALUE_SIGNATURE: &str = include_str!(
1481 "../../tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-rsa.xml"
1482 );
1483 const EC_P256_KEY_VALUE_SIGNATURE: &str = include_str!(
1484 "../../tests/fixtures/xmldsig/xmldsig11-interop-2012/signature-enveloping-p256_sha256.xml"
1485 );
1486 const EC_P384_KEY_VALUE_SIGNATURE: &str = include_str!(
1487 "../../tests/fixtures/xmldsig/xmldsig11-interop-2012/signature-enveloping-p384_sha384.xml"
1488 );
1489
1490 fn replace_key_info(xml: &str, replacement: &str) -> String {
1491 let start = xml.find("<ds:KeyInfo>").expect("fixture has KeyInfo");
1492 let end = xml
1493 .find("</ds:KeyInfo>")
1494 .expect("fixture has closing KeyInfo")
1495 + "</ds:KeyInfo>".len();
1496 format!("{}{}{}", &xml[..start], replacement, &xml[end..])
1497 }
1498
1499 fn replace_unprefixed_key_info(xml: &str, replacement: &str) -> String {
1500 let start = xml.find("<KeyInfo>").expect("fixture has KeyInfo");
1501 let end = xml.find("</KeyInfo>").expect("fixture has closing KeyInfo") + "</KeyInfo>".len();
1502 format!("{}{}{}", &xml[..start], replacement, &xml[end..])
1503 }
1504
1505 fn rsa_key_value_parts(public_key: &rsa::RsaPublicKey) -> (String, String) {
1506 (
1507 STANDARD.encode(public_key.n().to_be_bytes_trimmed_vartime()),
1508 STANDARD.encode(public_key.e().to_be_bytes_trimmed_vartime()),
1509 )
1510 }
1511
1512 fn x509_signature_with_leaf_subject() -> String {
1513 replace_unprefixed_key_info(
1514 X509_DIGEST_SIGNATURE,
1515 "<KeyInfo><X509Data><X509SubjectName>CN=Test Key rsa-4096,O=XML Security Library (http://www.aleksey.com/xmlsec),ST=California,C=US</X509SubjectName></X509Data></KeyInfo>",
1516 )
1517 }
1518
1519 fn fixture_certificate_time() -> SystemTime {
1520 SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_800_000_000)
1522 }
1523
1524 fn public_key_der(pem_text: &str) -> Vec<u8> {
1525 let (rest, pem) = x509_parser::pem::parse_x509_pem(pem_text.as_bytes())
1526 .expect("fixture public key is PEM");
1527 assert!(rest.iter().all(|byte| byte.is_ascii_whitespace()));
1528 assert_eq!(pem.label, "PUBLIC KEY");
1529 pem.contents
1530 }
1531
1532 fn certificate_der(pem_text: &str) -> Vec<u8> {
1533 let (rest, pem) = x509_parser::pem::parse_x509_pem(pem_text.as_bytes())
1534 .expect("fixture certificate is PEM");
1535 assert!(rest.iter().all(|byte| byte.is_ascii_whitespace()));
1536 assert_eq!(pem.label, "CERTIFICATE");
1537 pem.contents
1538 }
1539
1540 fn crl_der(pem_text: &str) -> Vec<u8> {
1541 let (rest, pem) =
1542 x509_parser::pem::parse_x509_pem(pem_text.as_bytes()).expect("fixture CRL is PEM");
1543 assert!(rest.iter().all(|byte| byte.is_ascii_whitespace()));
1544 assert_eq!(pem.label, "X509 CRL");
1545 pem.contents
1546 }
1547
1548 fn generated_certificate_params(common_name: &str, is_ca: bool) -> rcgen::CertificateParams {
1549 let mut params = rcgen::CertificateParams::new(Vec::new())
1550 .expect("empty SAN list should produce valid certificate parameters");
1551 params
1552 .distinguished_name
1553 .push(rcgen::DnType::CommonName, common_name);
1554 if is_ca {
1555 params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
1556 params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
1557 }
1558 params
1559 }
1560
1561 fn x509_info(certificates: Vec<Vec<u8>>, signing_index: usize) -> X509DataInfo {
1562 let parsed_certificates = certificates
1563 .iter()
1564 .map(|certificate| {
1565 parse_x509_certificate(certificate)
1566 .expect("generated certificate should have supported metadata")
1567 })
1568 .collect();
1569 X509DataInfo {
1570 certificates,
1571 parsed_certificates,
1572 certificate_chain: vec![signing_index],
1573 ..X509DataInfo::default()
1574 }
1575 }
1576
1577 #[test]
1578 fn defaults_match_key_resolution_policy() {
1579 let config = KeyResolverConfig::default();
1581
1582 assert!(config.trusted_certs.is_empty());
1583 assert!(config.lookup_certs.is_empty());
1584 assert!(config.named_keys.is_empty());
1585 let trust = crate::policy::VerificationPolicy::default().key_trust;
1586 assert!(!trust.verify_x509_chains);
1587 assert!(!trust.check_crls);
1588 assert_eq!(trust.verification_time, None);
1589 assert_eq!(trust.max_x509_chain_depth, 9);
1590 }
1591
1592 #[test]
1593 fn verification_policy_controls_leaf_extended_key_usage() {
1594 let root = rcgen::CertifiedIssuer::self_signed(
1597 generated_certificate_params("EKU policy root", true),
1598 rcgen::KeyPair::generate().expect("root key generation should succeed"),
1599 )
1600 .expect("root should be self-signable");
1601 let mut leaf_params = generated_certificate_params("TLS-only XML signer", false);
1602 leaf_params.key_usages = vec![rcgen::KeyUsagePurpose::DigitalSignature];
1603 leaf_params.extended_key_usages = vec![rcgen::ExtendedKeyUsagePurpose::ServerAuth];
1604 let leaf = leaf_params
1605 .signed_by(
1606 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
1607 &root,
1608 )
1609 .expect("root should sign leaf certificate");
1610 let key_info = KeyInfo {
1611 sources: vec![KeyInfoSource::X509Data(x509_info(
1612 vec![leaf.der().to_vec(), root.der().to_vec()],
1613 0,
1614 ))],
1615 };
1616 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
1617 trusted_certs: vec![root.der().to_vec()],
1618 ..KeyResolverConfig::default()
1619 });
1620 let mut policy = crate::policy::VerificationPolicy::default();
1621 policy.key_trust.verify_x509_chains = true;
1622
1623 let error = match resolver.resolve_with_policy(
1624 Some(&key_info),
1625 SignatureAlgorithm::EcdsaSha256,
1626 &policy,
1627 ) {
1628 Ok(_) => panic!("unapproved restricted EKU must be rejected"),
1629 Err(error) => error,
1630 };
1631 assert!(matches!(
1632 error,
1633 DsigError::KeyResolution(KeyResolutionError::Chain(
1634 super::super::X509ChainError::InvalidKeyUsage {
1635 position: 0,
1636 required: "an approved extended key usage",
1637 }
1638 ))
1639 ));
1640
1641 policy.key_trust.allowed_extended_key_usages =
1642 std::collections::HashSet::from([crate::policy::ExtendedKeyPurpose::ServerAuth]);
1643 assert!(
1644 resolver
1645 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::EcdsaSha256, &policy,)
1646 .expect("approved restricted EKU must pass path validation")
1647 .is_some()
1648 );
1649 }
1650
1651 #[test]
1652 fn operation_policy_rejects_zero_x509_resource_limits() {
1653 for trust in [
1656 crate::policy::KeyTrustPolicy {
1657 verify_x509_chains: true,
1658 max_x509_chain_depth: 0,
1659 ..crate::policy::KeyTrustPolicy::default()
1660 },
1661 crate::policy::KeyTrustPolicy {
1662 verify_x509_chains: true,
1663 max_x509_candidate_paths: 0,
1664 ..crate::policy::KeyTrustPolicy::default()
1665 },
1666 ] {
1667 let certificate = certificate_der(RSA_4096_CERTIFICATE);
1668 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
1669 trusted_certs: vec![certificate],
1670 ..KeyResolverConfig::default()
1671 });
1672 let policy = crate::policy::VerificationPolicy {
1673 key_trust: trust,
1674 ..crate::policy::VerificationPolicy::default()
1675 };
1676 let error = super::super::VerifyContext::new()
1677 .policy(policy)
1678 .key_resolver(&resolver)
1679 .verify(&x509_signature_with_leaf_subject())
1680 .expect_err("zero composed X.509 limits must fail as policy errors");
1681
1682 assert!(matches!(
1683 error,
1684 DsigError::Policy(crate::policy::PolicyViolation::InvalidResourceLimit {
1685 requirement: "limit must be nonzero",
1686 actual: 0,
1687 ..
1688 })
1689 ));
1690 }
1691 }
1692
1693 #[test]
1694 fn operation_policy_rejects_crl_checking_without_chain_validation() {
1695 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
1698 lookup_certs: vec![certificate_der(RSA_4096_CERTIFICATE)],
1699 ..KeyResolverConfig::default()
1700 });
1701 let policy = crate::policy::VerificationPolicy {
1702 key_trust: crate::policy::KeyTrustPolicy {
1703 check_crls: true,
1704 ..crate::policy::KeyTrustPolicy::default()
1705 },
1706 ..crate::policy::VerificationPolicy::default()
1707 };
1708 let error = super::super::VerifyContext::new()
1709 .policy(policy)
1710 .key_resolver(&resolver)
1711 .verify(&x509_signature_with_leaf_subject())
1712 .expect_err("CRL-only trust policy must fail before certificate use");
1713
1714 assert!(matches!(
1715 error,
1716 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust {
1717 reason: "CRL checking requires X.509 chain validation"
1718 })
1719 ));
1720 }
1721
1722 #[test]
1723 fn hmac_key_rejects_empty_secret_and_wrong_algorithm() {
1724 assert!(matches!(
1726 HmacSha1VerificationKey::new(Vec::new()),
1727 Err(KeyResolutionError::InvalidPublicKey)
1728 ));
1729 let key = HmacSha1VerificationKey::new(b"secret".to_vec())
1730 .expect("non-empty HMAC secret must be accepted");
1731 assert!(matches!(
1732 key.verify(SignatureAlgorithm::RsaSha256, b"data", b"signature"),
1733 Err(DsigError::KeyResolution(
1734 KeyResolutionError::AlgorithmMismatch
1735 ))
1736 ));
1737 }
1738
1739 #[test]
1740 fn hmac_key_uses_the_operation_policy_for_truncation() {
1741 let key = HmacVerificationKey::new(b"secret".to_vec())
1745 .expect("the fixture HMAC secret is non-empty");
1746 let mut mac = hmac::Hmac::<sha1::Sha1>::new_from_slice(b"secret")
1747 .expect("HMAC accepts an arbitrary non-empty secret");
1748 mac.update(b"data");
1749 let expected = mac.finalize().into_bytes();
1750
1751 let policy = crate::policy::VerificationPolicy {
1752 hmac: crate::policy::HmacPolicy {
1753 minimum_key_bits: 40,
1754 minimum_output_bits: 80,
1755 },
1756 ..crate::policy::VerificationPolicy::default()
1757 };
1758 assert!(
1759 key.verify_with_policy(
1760 &policy,
1761 SignatureAlgorithm::HmacSha1,
1762 b"data",
1763 &expected[..10],
1764 )
1765 .expect("the compatibility policy and algorithm match")
1766 );
1767 assert!(
1768 !key.verify_with_policy(&policy, SignatureAlgorithm::HmacSha1, b"data", &[0_u8; 10],)
1769 .expect("a mismatched truncated MAC must be rejected")
1770 );
1771 }
1772
1773 #[test]
1774 fn hmac_key_direct_api_rejects_attacker_selected_short_output() {
1775 let key = HmacVerificationKey::new([0x42; 16]).expect("fixed HMAC key must parse");
1778 let mut mac = hmac::Hmac::<sha2::Sha256>::new_from_slice(&[0x42; 16])
1779 .expect("HMAC accepts the fixed secret");
1780 mac.update(b"data");
1781 let expected = mac.finalize().into_bytes();
1782
1783 assert!(matches!(
1784 key.verify(SignatureAlgorithm::HmacSha256, b"data", &expected[..1]),
1785 Err(DsigError::Policy(
1786 crate::policy::PolicyViolation::HmacOutputLength {
1787 minimum: 128,
1788 maximum: 256,
1789 actual: 8,
1790 }
1791 ))
1792 ));
1793 }
1794
1795 #[test]
1796 fn hmac_key_debug_redacts_secret_material() {
1797 let secret = b"unique-debug-secret-marker";
1799 let key = HmacVerificationKey::new(secret.to_vec())
1800 .expect("the fixture HMAC secret is non-empty");
1801
1802 let debug = format!("{key:?}");
1803 assert!(
1804 !debug
1805 .contains(std::str::from_utf8(secret).expect("the debug marker is literal ASCII"))
1806 );
1807 assert!(!debug.contains(&format!("{secret:?}")));
1808 assert!(!debug.contains("output_length_bits"));
1809 }
1810
1811 #[test]
1812 fn stores_named_verification_key_metadata() {
1813 let key = VerificationKey {
1815 algorithm: SignatureAlgorithm::RsaSha256,
1816 public_key_bytes: vec![1, 2, 3],
1817 certificate_der: Some(vec![4, 5, 6]),
1818 name: Some("idp-signing".into()),
1819 };
1820 let mut config = KeyResolverConfig::default();
1821 config.named_keys.insert("idp-signing".into(), key.clone());
1822
1823 assert_eq!(config.named_keys.get("idp-signing"), Some(&key));
1824 }
1825
1826 #[test]
1827 fn resolves_embedded_certificate_end_to_end() {
1828 let resolver = DefaultKeyResolver::default();
1830 let result = super::super::VerifyContext::new()
1831 .key_resolver(&resolver)
1832 .verify(SIGNED_SAML)
1833 .expect("embedded certificate should resolve");
1834
1835 assert_eq!(result.status, super::super::DsigStatus::Valid);
1836 }
1837
1838 #[test]
1839 fn resolves_x509_digest_from_configured_certificates() {
1840 let leaf_certificate_der = certificate_der(RSA_4096_CERTIFICATE);
1843 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
1844 lookup_certs: vec![leaf_certificate_der],
1845 trusted_certs: vec![
1846 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
1847 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
1848 ],
1849 ..KeyResolverConfig::default()
1850 });
1851 for signature in [X509_DIGEST_SHA256_SIGNATURE, X509_DIGEST_SIGNATURE] {
1852 let result = super::super::VerifyContext::new()
1853 .key_resolver(&resolver)
1854 .verify(signature)
1855 .expect("X509Digest should resolve a configured certificate");
1856
1857 assert_eq!(result.status, super::super::DsigStatus::Valid);
1858 }
1859 }
1860
1861 #[test]
1862 fn selector_resolved_certificate_obeys_chain_policy() {
1863 let leaf_certificate_der = certificate_der(RSA_4096_CERTIFICATE);
1866 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
1867 lookup_certs: vec![leaf_certificate_der],
1868 trusted_certs: vec![
1869 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
1870 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
1871 ],
1872 ..KeyResolverConfig::default()
1873 });
1874 let error = super::super::VerifyContext::new()
1875 .policy(verification_policy_with_trust(chain_policy_at(
1876 SystemTime::UNIX_EPOCH,
1877 )))
1878 .key_resolver(&resolver)
1879 .verify(&x509_signature_with_leaf_subject())
1880 .expect_err("selector-resolved certificate must satisfy chain policy");
1881
1882 assert!(
1883 matches!(
1884 &error,
1885 DsigError::KeyResolution(KeyResolutionError::Chain(
1886 super::super::X509ChainError::CertificateNotValid(_)
1887 ))
1888 ),
1889 "unexpected selector policy error: {error:?}"
1890 );
1891 }
1892
1893 #[test]
1894 fn selector_resolved_configured_root_remains_a_trust_anchor() {
1895 let mut params = rcgen::CertificateParams::new(Vec::new())
1898 .expect("empty SAN list should produce valid certificate parameters");
1899 params
1900 .distinguished_name
1901 .push(rcgen::DnType::CommonName, "configured root");
1902 params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
1903 let key_pair = rcgen::KeyPair::generate().expect("test key generation should succeed");
1904 let certificate = params
1905 .self_signed(&key_pair)
1906 .expect("test root should be self-signable");
1907 let certificate_der = certificate.der().to_vec();
1908 let key_info_xml = concat!(
1909 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
1910 "<X509Data><X509SubjectName>CN=configured root</X509SubjectName></X509Data>",
1911 "</KeyInfo>"
1912 );
1913 let document = roxmltree::Document::parse(key_info_xml)
1914 .expect("static selector KeyInfo should parse as XML");
1915 let key_info = super::super::parse_key_info(document.root_element())
1916 .expect("static selector KeyInfo should satisfy XMLDSig structure");
1917 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
1918 trusted_certs: vec![certificate_der],
1919 ..KeyResolverConfig::default()
1920 });
1921
1922 let resolved = resolver
1923 .resolve_with_policy(
1924 Some(&key_info),
1925 SignatureAlgorithm::EcdsaSha256,
1926 &verification_policy_with_trust(chain_policy()),
1927 )
1928 .expect("configured self-signed certificate should validate as its own anchor");
1929
1930 assert!(resolved.is_some());
1931 }
1932
1933 #[test]
1934 fn selector_resolved_non_self_signed_trust_anchor_terminates_the_path() {
1935 let mut issuer_params = rcgen::CertificateParams::new(Vec::new())
1939 .expect("empty issuer SAN list should be valid");
1940 issuer_params
1941 .distinguished_name
1942 .push(rcgen::DnType::CommonName, "lookup-only issuer");
1943 issuer_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
1944 issuer_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
1945 let issuer = rcgen::CertifiedIssuer::self_signed(
1946 issuer_params,
1947 rcgen::KeyPair::generate().expect("issuer key generation should succeed"),
1948 )
1949 .expect("issuer certificate should be self-signable");
1950
1951 let mut anchor_params = rcgen::CertificateParams::new(Vec::new())
1952 .expect("empty anchor SAN list should be valid");
1953 anchor_params
1954 .distinguished_name
1955 .push(rcgen::DnType::CommonName, "direct trust anchor");
1956 let anchor = anchor_params
1957 .signed_by(
1958 &rcgen::KeyPair::generate().expect("anchor key generation should succeed"),
1959 &issuer,
1960 )
1961 .expect("issuer should sign the directly trusted certificate");
1962 let key_info_xml = concat!(
1963 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
1964 "<X509Data><X509SubjectName>CN=direct trust anchor</X509SubjectName></X509Data>",
1965 "</KeyInfo>"
1966 );
1967 let document = roxmltree::Document::parse(key_info_xml)
1968 .expect("static selector KeyInfo should parse as XML");
1969 let key_info = super::super::parse_key_info(document.root_element())
1970 .expect("static selector KeyInfo should satisfy XMLDSig structure");
1971 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
1972 trusted_certs: vec![anchor.der().to_vec()],
1973 lookup_certs: vec![issuer.der().to_vec()],
1974 ..KeyResolverConfig::default()
1975 });
1976
1977 let resolved = resolver
1978 .resolve_with_policy(
1979 Some(&key_info),
1980 SignatureAlgorithm::EcdsaSha256,
1981 &verification_policy_with_trust(chain_policy()),
1982 )
1983 .expect("an explicitly trusted selected certificate must terminate its path");
1984
1985 assert!(resolved.is_some());
1986 }
1987
1988 #[test]
1989 fn selector_resolved_leaf_stops_at_non_self_signed_trust_anchor() {
1990 let external_issuer = rcgen::CertifiedIssuer::self_signed(
1993 generated_certificate_params("external issuer", true),
1994 rcgen::KeyPair::generate().expect("external issuer key generation should succeed"),
1995 )
1996 .expect("external issuer should be self-signable");
1997 let anchor = rcgen::CertifiedIssuer::signed_by(
1998 generated_certificate_params("non-self-signed anchor", true),
1999 rcgen::KeyPair::generate().expect("anchor key generation should succeed"),
2000 &external_issuer,
2001 )
2002 .expect("external issuer should sign the anchor");
2003 let leaf = generated_certificate_params("anchor leaf", false)
2004 .signed_by(
2005 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2006 &anchor,
2007 )
2008 .expect("anchor should sign the leaf");
2009 let leaf_metadata = parse_x509_certificate(leaf.der())
2010 .expect("generated leaf should have supported metadata");
2011 let key_info = KeyInfo {
2012 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
2013 subject_names: vec![leaf_metadata.subject_dn],
2014 ..X509DataInfo::default()
2015 })],
2016 };
2017 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2018 trusted_certs: vec![anchor.der().to_vec()],
2019 lookup_certs: vec![leaf.der().to_vec(), external_issuer.der().to_vec()],
2020 ..KeyResolverConfig::default()
2021 });
2022
2023 let resolved = resolver
2024 .resolve_with_policy(
2025 Some(&key_info),
2026 SignatureAlgorithm::EcdsaSha256,
2027 &verification_policy_with_trust(chain_policy()),
2028 )
2029 .expect("path construction must stop at the configured anchor");
2030
2031 assert!(resolved.is_some());
2032 }
2033
2034 #[test]
2035 fn selector_resolved_leaf_does_not_anchor_itself() {
2036 let certificate_der = certificate_der(RSA_4096_CERTIFICATE);
2039 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2040 lookup_certs: vec![certificate_der],
2041 ..KeyResolverConfig::default()
2042 });
2043 let error = super::super::VerifyContext::new()
2044 .policy(verification_policy_with_trust(chain_policy_at(
2045 fixture_certificate_time(),
2046 )))
2047 .key_resolver(&resolver)
2048 .verify(&x509_signature_with_leaf_subject())
2049 .expect_err("selector-resolved leaf must not trust itself");
2050
2051 assert!(matches!(
2052 error,
2053 DsigError::KeyResolution(KeyResolutionError::Chain(
2054 super::super::X509ChainError::UntrustedRoot
2055 ))
2056 ));
2057 }
2058
2059 #[test]
2060 fn selector_resolved_leaf_uses_separate_anchor() {
2061 let leaf = certificate_der(RSA_4096_CERTIFICATE);
2064 let issuer = certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem"));
2065 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2066 lookup_certs: vec![leaf],
2067 trusted_certs: vec![issuer],
2068 ..KeyResolverConfig::default()
2069 });
2070 let result = super::super::VerifyContext::new()
2071 .policy(verification_policy_with_trust(chain_policy_at(
2072 fixture_certificate_time(),
2073 )))
2074 .key_resolver(&resolver)
2075 .verify(&x509_signature_with_leaf_subject())
2076 .expect("selector-resolved leaf should chain to its configured issuer");
2077
2078 assert_eq!(result.status, super::super::DsigStatus::Valid);
2079 }
2080
2081 #[test]
2082 fn selector_resolved_leaf_uses_lookup_intermediate() {
2083 let mut root_params =
2086 rcgen::CertificateParams::new(Vec::new()).expect("empty root SAN list should be valid");
2087 root_params
2088 .distinguished_name
2089 .push(rcgen::DnType::CommonName, "lookup root");
2090 root_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2091 root_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2092 let root = rcgen::CertifiedIssuer::self_signed(
2093 root_params,
2094 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2095 )
2096 .expect("root certificate should be self-signable");
2097
2098 let mut intermediate_params = rcgen::CertificateParams::new(Vec::new())
2099 .expect("empty intermediate SAN list should be valid");
2100 intermediate_params
2101 .distinguished_name
2102 .push(rcgen::DnType::CommonName, "lookup intermediate");
2103 intermediate_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2104 intermediate_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2105 let intermediate = rcgen::CertifiedIssuer::signed_by(
2106 intermediate_params,
2107 rcgen::KeyPair::generate().expect("intermediate key generation should succeed"),
2108 &root,
2109 )
2110 .expect("root should sign the intermediate certificate");
2111
2112 let mut leaf_params =
2113 rcgen::CertificateParams::new(Vec::new()).expect("empty leaf SAN list should be valid");
2114 leaf_params
2115 .distinguished_name
2116 .push(rcgen::DnType::CommonName, "lookup leaf");
2117 let leaf = leaf_params
2118 .signed_by(
2119 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2120 &intermediate,
2121 )
2122 .expect("intermediate should sign the leaf certificate");
2123 let key_info_xml = concat!(
2124 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
2125 "<X509Data><X509SubjectName>CN=lookup leaf</X509SubjectName></X509Data>",
2126 "</KeyInfo>"
2127 );
2128 let document = roxmltree::Document::parse(key_info_xml)
2129 .expect("static selector KeyInfo should parse as XML");
2130 let key_info = super::super::parse_key_info(document.root_element())
2131 .expect("static selector KeyInfo should satisfy XMLDSig structure");
2132 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2133 lookup_certs: vec![leaf.der().to_vec(), intermediate.der().to_vec()],
2134 trusted_certs: vec![root.der().to_vec()],
2135 ..KeyResolverConfig::default()
2136 });
2137
2138 let resolved = resolver
2139 .resolve_with_policy(
2140 Some(&key_info),
2141 SignatureAlgorithm::EcdsaSha256,
2142 &verification_policy_with_trust(chain_policy()),
2143 )
2144 .expect("selector-resolved leaf should chain through the lookup intermediate");
2145
2146 assert!(resolved.is_some());
2147 }
2148
2149 #[test]
2150 fn x509_path_signatures_use_the_operation_provider() {
2151 let root = rcgen::CertifiedIssuer::self_signed(
2155 generated_certificate_params("provider root", true),
2156 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2157 )
2158 .expect("root should be self-signable");
2159 let leaf = generated_certificate_params("provider leaf", false)
2160 .signed_by(
2161 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2162 &root,
2163 )
2164 .expect("root should sign the leaf");
2165 let leaf_der = leaf.der().to_vec();
2166 let leaf_metadata =
2167 parse_x509_certificate(&leaf_der).expect("generated leaf metadata should parse");
2168 let policy = crate::policy::VerificationPolicy {
2169 key_trust: chain_policy(),
2170 ..crate::policy::VerificationPolicy::default()
2171 };
2172
2173 let cases = [
2174 (
2175 KeyInfo {
2176 sources: vec![KeyInfoSource::X509Data(x509_info(
2177 vec![leaf_der.clone()],
2178 0,
2179 ))],
2180 },
2181 Vec::new(),
2182 ),
2183 (
2184 KeyInfo {
2185 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
2186 subject_names: vec![leaf_metadata.subject_dn],
2187 ..X509DataInfo::default()
2188 })],
2189 },
2190 vec![leaf_der],
2191 ),
2192 ];
2193
2194 for (key_info, lookup_certs) in cases {
2195 let provider = RejectSecondSha512Provider {
2196 sha512_calls: AtomicUsize::new(0),
2197 verification_calls: AtomicUsize::new(0),
2198 reject_verification_call: Some(0),
2199 rejected_verification_data: None,
2200 };
2201 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2202 trusted_certs: vec![root.der().to_vec()],
2203 lookup_certs,
2204 ..KeyResolverConfig::default()
2205 });
2206 let error = match resolver.resolve_with_policy_and_provider(
2207 Some(&key_info),
2208 SignatureAlgorithm::EcdsaSha256,
2209 &policy,
2210 &provider,
2211 ) {
2212 Ok(_) => panic!("the operation provider must gate every X.509 path signature"),
2213 Err(error) => error,
2214 };
2215
2216 assert!(matches!(
2217 error,
2218 DsigError::KeyResolution(KeyResolutionError::Chain(
2219 super::super::X509ChainError::UnsupportedSignatureAlgorithm { ref oid }
2220 )) if oid == "1.2.840.10045.4.3.2"
2221 ));
2222 assert_eq!(provider.verification_calls.load(Ordering::Relaxed), 1);
2223 }
2224
2225 let provider = RejectSecondSha512Provider {
2228 sha512_calls: AtomicUsize::new(0),
2229 verification_calls: AtomicUsize::new(0),
2230 reject_verification_call: Some(1),
2231 rejected_verification_data: None,
2232 };
2233 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2234 trusted_certs: vec![root.der().to_vec()],
2235 ..KeyResolverConfig::default()
2236 });
2237 let key_info = KeyInfo {
2238 sources: vec![KeyInfoSource::X509Data(x509_info(
2239 vec![leaf.der().to_vec()],
2240 0,
2241 ))],
2242 };
2243 let error = match resolver.resolve_with_policy_and_provider(
2244 Some(&key_info),
2245 SignatureAlgorithm::EcdsaSha256,
2246 &policy,
2247 &provider,
2248 ) {
2249 Ok(_) => panic!("complete-path validation must retain the operation provider"),
2250 Err(error) => error,
2251 };
2252 assert!(matches!(
2253 error,
2254 DsigError::KeyResolution(KeyResolutionError::Chain(
2255 super::super::X509ChainError::Provider(_)
2256 ))
2257 ));
2258 assert_eq!(provider.verification_calls.load(Ordering::Relaxed), 2);
2259 }
2260
2261 #[test]
2262 fn embedded_leaf_uses_lookup_intermediate_with_duplicate_anchor() {
2263 let trusted_root = rcgen::CertifiedIssuer::self_signed(
2266 generated_certificate_params("unrelated trusted root", true),
2267 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2268 )
2269 .expect("root should be self-signable");
2270 let issuer_root = rcgen::CertifiedIssuer::self_signed(
2271 generated_certificate_params("untrusted issuer root", true),
2272 rcgen::KeyPair::generate().expect("issuer root key generation should succeed"),
2273 )
2274 .expect("issuer root should be self-signable");
2275 let intermediate = rcgen::CertifiedIssuer::signed_by(
2276 generated_certificate_params("embedded intermediate", true),
2277 rcgen::KeyPair::generate().expect("intermediate key generation should succeed"),
2278 &issuer_root,
2279 )
2280 .expect("issuer root should sign the intermediate");
2281 let leaf = generated_certificate_params("embedded leaf", false)
2282 .signed_by(
2283 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2284 &intermediate,
2285 )
2286 .expect("intermediate should sign the leaf");
2287 let key_info = KeyInfo {
2288 sources: vec![KeyInfoSource::X509Data(x509_info(
2289 vec![leaf.der().to_vec()],
2290 0,
2291 ))],
2292 };
2293 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2294 lookup_certs: vec![intermediate.der().to_vec()],
2295 trusted_certs: vec![trusted_root.der().to_vec(), trusted_root.der().to_vec()],
2296 ..KeyResolverConfig::default()
2297 });
2298
2299 let policy = verification_policy_with_trust(chain_policy());
2300 let error = match resolver.resolve_with_policy(
2301 Some(&key_info),
2302 SignatureAlgorithm::EcdsaSha256,
2303 &policy,
2304 ) {
2305 Ok(_) => panic!("an untrusted lookup intermediate must not become a trust anchor"),
2306 Err(error) => error,
2307 };
2308
2309 assert!(matches!(
2310 error,
2311 DsigError::KeyResolution(KeyResolutionError::Chain(
2312 super::super::X509ChainError::UntrustedRoot
2313 ))
2314 ));
2315 }
2316
2317 #[test]
2318 fn selector_resolved_leaf_chooses_unique_valid_same_key_path() {
2319 let trusted_root = rcgen::CertifiedIssuer::self_signed(
2323 generated_certificate_params("trusted cross-sign root", true),
2324 rcgen::KeyPair::generate().expect("trusted root key generation should succeed"),
2325 )
2326 .expect("trusted root should be self-signable");
2327 let untrusted_root = rcgen::CertifiedIssuer::self_signed(
2328 generated_certificate_params("untrusted cross-sign root", true),
2329 rcgen::KeyPair::generate().expect("untrusted root key generation should succeed"),
2330 )
2331 .expect("untrusted root should be self-signable");
2332 let shared_params = generated_certificate_params("shared cross-sign issuer", true);
2333 let shared_key =
2334 rcgen::KeyPair::generate().expect("shared issuer key generation should succeed");
2335 let trusted_intermediate = shared_params
2336 .signed_by(&shared_key, &trusted_root)
2337 .expect("trusted root should cross-sign the shared issuer key");
2338 let untrusted_intermediate = shared_params
2339 .signed_by(&shared_key, &untrusted_root)
2340 .expect("untrusted root should cross-sign the shared issuer key");
2341 let shared_issuer = rcgen::Issuer::from_params(&shared_params, &shared_key);
2342 let leaf = generated_certificate_params("cross-signed leaf", false)
2343 .signed_by(
2344 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2345 &shared_issuer,
2346 )
2347 .expect("shared issuer key should sign the leaf");
2348 let leaf_metadata = parse_x509_certificate(leaf.der())
2349 .expect("generated leaf should have supported metadata");
2350 let key_info = KeyInfo {
2351 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
2352 subject_names: vec![leaf_metadata.subject_dn],
2353 ..X509DataInfo::default()
2354 })],
2355 };
2356 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2357 trusted_certs: vec![trusted_root.der().to_vec()],
2358 lookup_certs: vec![
2359 leaf.der().to_vec(),
2360 untrusted_intermediate.der().to_vec(),
2361 trusted_intermediate.der().to_vec(),
2362 untrusted_root.der().to_vec(),
2363 ],
2364 ..KeyResolverConfig::default()
2365 });
2366
2367 let resolved = resolver
2368 .resolve_with_policy(
2369 Some(&key_info),
2370 SignatureAlgorithm::EcdsaSha256,
2371 &verification_policy_with_trust(chain_policy()),
2372 )
2373 .expect("the sole path to a configured anchor should be selected");
2374
2375 assert!(resolved.is_some());
2376 }
2377
2378 #[test]
2379 fn self_issued_rollover_continues_to_same_name_trusted_signer() {
2380 let root = rcgen::CertifiedIssuer::self_signed(
2383 generated_certificate_params("rollover authority", true),
2384 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2385 )
2386 .expect("root should be self-signable");
2387 let rollover_params = generated_certificate_params("rollover authority", true);
2388 let rollover_key =
2389 rcgen::KeyPair::generate().expect("rollover key generation should succeed");
2390 let rollover_certificate = rollover_params
2391 .signed_by(&rollover_key, &root)
2392 .expect("root should sign the same-name rollover certificate");
2393 let rollover_issuer = rcgen::Issuer::from_params(&rollover_params, &rollover_key);
2394 let leaf = generated_certificate_params("rollover leaf", false)
2395 .signed_by(
2396 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2397 &rollover_issuer,
2398 )
2399 .expect("rollover key should sign the leaf");
2400 let leaf_metadata =
2401 parse_x509_certificate(leaf.der()).expect("generated leaf metadata should parse");
2402 let key_info = KeyInfo {
2403 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
2404 subject_names: vec![leaf_metadata.subject_dn],
2405 ..X509DataInfo::default()
2406 })],
2407 };
2408 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2409 trusted_certs: vec![root.der().to_vec()],
2410 lookup_certs: vec![leaf.der().to_vec(), rollover_certificate.der().to_vec()],
2411 ..KeyResolverConfig::default()
2412 });
2413
2414 let resolved = resolver
2415 .resolve_with_policy(
2416 Some(&key_info),
2417 SignatureAlgorithm::EcdsaSha256,
2418 &verification_policy_with_trust(chain_policy()),
2419 )
2420 .expect("same-name rollover path must reach its configured signer");
2421
2422 assert!(resolved.is_some());
2423 }
2424
2425 #[test]
2426 fn x509_candidate_limit_counts_generated_partial_paths() {
2427 let root = rcgen::CertifiedIssuer::self_signed(
2430 generated_certificate_params("candidate root", true),
2431 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2432 )
2433 .expect("root should be self-signable");
2434 let intermediate = rcgen::CertifiedIssuer::signed_by(
2435 generated_certificate_params("candidate intermediate", true),
2436 rcgen::KeyPair::generate().expect("intermediate key generation should succeed"),
2437 &root,
2438 )
2439 .expect("root should sign the intermediate");
2440 let leaf = generated_certificate_params("candidate leaf", false)
2441 .signed_by(
2442 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2443 &intermediate,
2444 )
2445 .expect("intermediate should sign the leaf");
2446 let info = x509_info(
2447 vec![
2448 root.der().to_vec(),
2449 intermediate.der().to_vec(),
2450 leaf.der().to_vec(),
2451 ],
2452 2,
2453 );
2454
2455 assert!(matches!(
2456 build_x509_certificate_paths_to_trusted_prefix(
2457 &info,
2458 2,
2459 1,
2460 9,
2461 2,
2462 crate::provider::default_provider(),
2463 ),
2464 Err(X509ChainBuildError::AmbiguousIssuer)
2465 ));
2466 }
2467
2468 #[test]
2469 fn selector_resolved_leaf_disambiguates_same_subject_issuers_by_signature() {
2470 let mut root_params =
2474 rcgen::CertificateParams::new(Vec::new()).expect("empty root SAN list should be valid");
2475 root_params
2476 .distinguished_name
2477 .push(rcgen::DnType::CommonName, "shared-issuer root");
2478 root_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2479 root_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2480 let root = rcgen::CertifiedIssuer::self_signed(
2481 root_params,
2482 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2483 )
2484 .expect("root certificate should be self-signable");
2485
2486 let intermediate = |key: rcgen::KeyPair| {
2487 let mut params = rcgen::CertificateParams::new(Vec::new())
2488 .expect("empty intermediate SAN list should be valid");
2489 params
2490 .distinguished_name
2491 .push(rcgen::DnType::CommonName, "renewed intermediate");
2492 params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2493 params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2494 rcgen::CertifiedIssuer::signed_by(params, key, &root)
2495 .expect("root should sign the intermediate certificate")
2496 };
2497 let unrelated_intermediate = intermediate(
2498 rcgen::KeyPair::generate().expect("unrelated intermediate key generation should work"),
2499 );
2500 let signing_intermediate = intermediate(
2501 rcgen::KeyPair::generate().expect("signing intermediate key generation should work"),
2502 );
2503
2504 let mut leaf_params =
2505 rcgen::CertificateParams::new(Vec::new()).expect("empty leaf SAN list should be valid");
2506 leaf_params
2507 .distinguished_name
2508 .push(rcgen::DnType::CommonName, "same-subject leaf");
2509 let leaf = leaf_params
2510 .signed_by(
2511 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2512 &signing_intermediate,
2513 )
2514 .expect("the selected intermediate should sign the leaf certificate");
2515 let key_info_xml = concat!(
2516 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
2517 "<X509Data><X509SubjectName>CN=same-subject leaf</X509SubjectName></X509Data>",
2518 "</KeyInfo>"
2519 );
2520 let document = roxmltree::Document::parse(key_info_xml)
2521 .expect("static selector KeyInfo should parse as XML");
2522 let key_info = super::super::parse_key_info(document.root_element())
2523 .expect("static selector KeyInfo should satisfy XMLDSig structure");
2524 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2525 lookup_certs: vec![
2526 leaf.der().to_vec(),
2527 unrelated_intermediate.der().to_vec(),
2528 signing_intermediate.der().to_vec(),
2529 ],
2530 trusted_certs: vec![root.der().to_vec()],
2531 ..KeyResolverConfig::default()
2532 });
2533
2534 let resolved = resolver
2535 .resolve_with_policy(
2536 Some(&key_info),
2537 SignatureAlgorithm::EcdsaSha256,
2538 &verification_policy_with_trust(chain_policy()),
2539 )
2540 .expect("the leaf signature should select its unique same-subject issuer");
2541
2542 assert!(resolved.is_some());
2543 }
2544
2545 #[test]
2546 fn x509_path_builder_skips_branch_local_unsupported_algorithms() {
2547 let root = rcgen::CertifiedIssuer::self_signed(
2551 generated_certificate_params("unsupported-edge root", true),
2552 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2553 )
2554 .expect("root certificate should be self-signable");
2555 let signing_intermediate = rcgen::CertifiedIssuer::signed_by(
2556 generated_certificate_params("shared unsupported-edge issuer", true),
2557 rcgen::KeyPair::generate().expect("signing issuer key generation should succeed"),
2558 &root,
2559 )
2560 .expect("root should sign the intermediate certificate");
2561 let key_unsupported_intermediate = rcgen::CertifiedIssuer::signed_by(
2562 generated_certificate_params("shared unsupported-edge issuer", true),
2563 rcgen::KeyPair::generate().expect("unsupported issuer key generation should succeed"),
2564 &root,
2565 )
2566 .expect("root should sign the alternate intermediate certificate");
2567 let leaf = generated_certificate_params("unsupported-edge leaf", false)
2568 .signed_by(
2569 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2570 &signing_intermediate,
2571 )
2572 .expect("signing intermediate should sign the leaf");
2573
2574 let ordered = x509_info(
2575 vec![
2576 leaf.der().to_vec(),
2577 key_unsupported_intermediate.der().to_vec(),
2578 signing_intermediate.der().to_vec(),
2579 root.der().to_vec(),
2580 ],
2581 0,
2582 );
2583 let key_selective_provider = RejectSecondSha512Provider {
2584 sha512_calls: AtomicUsize::new(0),
2585 verification_calls: AtomicUsize::new(0),
2586 reject_verification_call: Some(0),
2587 rejected_verification_data: None,
2588 };
2589 assert_eq!(
2590 super::super::parse::build_x509_certificate_chain_from(
2591 &ordered,
2592 0,
2593 &key_selective_provider,
2594 )
2595 .expect("one unsupported issuer key must not suppress a usable candidate"),
2596 vec![0, 2, 3]
2597 );
2598
2599 let anchored_same_edge = x509_info(
2600 vec![
2601 root.der().to_vec(),
2602 leaf.der().to_vec(),
2603 key_unsupported_intermediate.der().to_vec(),
2604 signing_intermediate.der().to_vec(),
2605 ],
2606 1,
2607 );
2608 let first_candidate_unsupported = RejectSecondSha512Provider {
2609 sha512_calls: AtomicUsize::new(0),
2610 verification_calls: AtomicUsize::new(0),
2611 reject_verification_call: Some(0),
2612 rejected_verification_data: None,
2613 };
2614 assert_eq!(
2615 build_x509_certificate_paths_to_trusted_prefix(
2616 &anchored_same_edge,
2617 1,
2618 1,
2619 4,
2620 8,
2621 &first_candidate_unsupported,
2622 )
2623 .expect("a later same-DN issuer must survive an earlier provider capability miss"),
2624 vec![vec![1, 3, 0]]
2625 );
2626
2627 let mut unsupported_intermediate = signing_intermediate.der().to_vec();
2628 let ecdsa_sha256_oid = [0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02];
2629 let offsets = unsupported_intermediate
2630 .windows(ecdsa_sha256_oid.len())
2631 .enumerate()
2632 .filter_map(|(offset, window)| (window == ecdsa_sha256_oid).then_some(offset))
2633 .collect::<Vec<_>>();
2634 assert_eq!(
2635 offsets.len(),
2636 2,
2637 "certificate must repeat its signature OID"
2638 );
2639 for offset in offsets {
2640 unsupported_intermediate[offset + ecdsa_sha256_oid.len() - 1] = 0x05;
2641 }
2642
2643 let anchored = x509_info(
2644 vec![
2645 root.der().to_vec(),
2646 leaf.der().to_vec(),
2647 signing_intermediate.der().to_vec(),
2648 unsupported_intermediate,
2649 ],
2650 1,
2651 );
2652 assert_eq!(
2653 build_x509_certificate_paths_to_trusted_prefix(
2654 &anchored,
2655 1,
2656 1,
2657 4,
2658 8,
2659 crate::provider::default_provider(),
2660 )
2661 .expect("a branch-local provider gap must not abort path enumeration"),
2662 vec![vec![1, 2, 0]]
2663 );
2664
2665 let unsupported_only = x509_info(
2666 vec![
2667 root.der().to_vec(),
2668 leaf.der().to_vec(),
2669 anchored.certificates[3].clone(),
2670 ],
2671 1,
2672 );
2673 assert!(matches!(
2674 build_x509_certificate_paths_to_trusted_prefix(
2675 &unsupported_only,
2676 1,
2677 1,
2678 4,
2679 8,
2680 crate::provider::default_provider(),
2681 ),
2682 Err(X509ChainBuildError::UnsupportedSignatureAlgorithm { ref oid })
2683 if oid == "1.2.840.10045.4.3.5"
2684 ));
2685 }
2686
2687 #[test]
2688 fn selector_resolved_certificate_preserves_supplied_crls() {
2689 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>";
2690 let crl = crl_der(include_str!(
2691 "../../tests/fixtures/keys/rsa/rsa-2048-cert-revoked-crl.pem"
2692 ));
2693 let (_, parsed_crl) =
2694 x509_parser::revocation_list::CertificateRevocationList::from_der(&crl)
2695 .expect("tracked CRL must parse");
2696 let crl_signed_data = parsed_crl.tbs_cert_list.as_ref().to_vec();
2697 let xml = replace_unprefixed_key_info(
2698 RSA_KEY_VALUE_SIGNATURE,
2699 &selector.replace("CRL_PLACEHOLDER", &STANDARD.encode(&crl)),
2700 );
2701 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2702 lookup_certs: vec![certificate_der(include_str!(
2703 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
2704 ))],
2705 trusted_certs: vec![
2706 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
2707 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
2708 ],
2709 ..KeyResolverConfig::default()
2710 });
2711 let policy = verification_policy_with_trust(crate::policy::KeyTrustPolicy {
2712 check_crls: true,
2713 max_x509_chain_depth: 3,
2714 ..chain_policy_at(
2715 SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_773_964_800),
2716 )
2717 });
2718
2719 let error = super::super::VerifyContext::new()
2720 .policy(policy.clone())
2721 .key_resolver(&resolver)
2722 .verify(&xml)
2723 .expect_err("selector lookup must retain and enforce the supplied CRL");
2724 assert!(matches!(
2725 error,
2726 DsigError::KeyResolution(KeyResolutionError::Chain(
2727 super::super::X509ChainError::Revoked(0)
2728 ))
2729 ));
2730
2731 let provider = RejectSecondSha512Provider {
2735 sha512_calls: AtomicUsize::new(0),
2736 verification_calls: AtomicUsize::new(0),
2737 reject_verification_call: None,
2738 rejected_verification_data: Some(crl_signed_data),
2739 };
2740 let error = super::super::VerifyContext::new()
2741 .policy(policy)
2742 .key_resolver(&resolver)
2743 .provider(&provider)
2744 .verify(&xml)
2745 .expect_err("CRL authentication must retain the operation provider");
2746 assert!(matches!(
2747 error,
2748 DsigError::KeyResolution(KeyResolutionError::Chain(
2749 super::super::X509ChainError::Provider(_)
2750 ))
2751 ));
2752 }
2753
2754 #[test]
2755 fn resolves_each_x509_selector_from_configured_certificates() {
2756 let selectors = [
2759 "<X509SubjectName>CN=Test Key rsa-2048,O=XML Security Library (http://www.aleksey.com/xmlsec),ST=California,C=US</X509SubjectName>",
2760 "<X509SubjectName>CN= test key rsa-2048 ,O=xml security library (HTTP://WWW.ALEKSEY.COM/XMLSEC),ST=california,C=us</X509SubjectName>",
2761 "<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>",
2762 "<X509SKI>bcOXN/nsVl8GatRbcKrPbzIbw0Y=</X509SKI>",
2763 ];
2764 let configured_certificate = certificate_der(include_str!(
2765 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
2766 ));
2767
2768 for selector in selectors {
2769 let key_info = format!("<KeyInfo><X509Data>{selector}</X509Data></KeyInfo>");
2770 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
2771 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2772 lookup_certs: vec![configured_certificate.clone()],
2773 ..KeyResolverConfig::default()
2774 });
2775 let result = super::super::VerifyContext::new()
2776 .key_resolver(&resolver)
2777 .verify(&xml)
2778 .expect("X509 selector should resolve configured certificate");
2779
2780 assert_eq!(result.status, super::super::DsigStatus::Valid);
2781 }
2782 }
2783
2784 #[test]
2785 fn resolves_configured_chain_selectors_across_certificates() {
2786 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>"#;
2789 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
2790 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2791 lookup_certs: vec![
2792 certificate_der(include_str!(
2793 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
2794 )),
2795 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
2796 ],
2797 ..KeyResolverConfig::default()
2798 });
2799 let result = super::super::VerifyContext::new()
2800 .key_resolver(&resolver)
2801 .verify(&xml)
2802 .expect("selectors across one configured chain should resolve its leaf");
2803
2804 assert_eq!(result.status, super::super::DsigStatus::Valid);
2805 }
2806
2807 #[test]
2808 fn selectors_must_all_match_the_selected_certificate_path() {
2809 let signing_certificate = certificate_der(include_str!(
2812 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
2813 ));
2814 let issuer_certificate =
2815 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem"));
2816 let unrelated = generated_certificate_params("unrelated selector certificate", false)
2817 .self_signed(
2818 &rcgen::KeyPair::generate().expect("unrelated key generation should succeed"),
2819 )
2820 .expect("unrelated certificate should be self-signable")
2821 .der()
2822 .to_vec();
2823 let digest = crate::provider::default_provider()
2824 .digest(super::super::DigestAlgorithm::Sha256, &unrelated)
2825 .expect("SHA-256 selector digest must be available");
2826 let key_info_xml = format!(
2827 "<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>",
2828 STANDARD.encode(digest)
2829 );
2830 let document = roxmltree::Document::parse(&key_info_xml)
2831 .expect("generated selector KeyInfo must be XML");
2832 let key_info = super::super::parse_key_info(document.root_element())
2833 .expect("generated selector KeyInfo must be structurally valid");
2834 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2835 lookup_certs: vec![signing_certificate, issuer_certificate, unrelated],
2836 ..KeyResolverConfig::default()
2837 });
2838
2839 assert!(
2840 resolver
2841 .resolve(Some(&key_info), SignatureAlgorithm::RsaSha256)
2842 .expect("disjoint selector matches are a key miss")
2843 .is_none()
2844 );
2845 }
2846
2847 #[test]
2848 fn unmatched_x509_selector_does_not_resolve() {
2849 let key_info = "<KeyInfo><X509Data><X509SubjectName>CN=not-the-signer</X509SubjectName></X509Data></KeyInfo>";
2851 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
2852 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2853 lookup_certs: vec![certificate_der(include_str!(
2854 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
2855 ))],
2856 ..KeyResolverConfig::default()
2857 });
2858 let result = super::super::VerifyContext::new()
2859 .key_resolver(&resolver)
2860 .verify(&xml)
2861 .expect("an unmatched selector is a key miss, not a parser failure");
2862
2863 assert!(matches!(
2864 result.status,
2865 super::super::DsigStatus::Invalid(super::super::FailureReason::KeyNotFound)
2866 ));
2867 }
2868
2869 #[test]
2870 fn overlapping_trusted_and_lookup_certificate_preserves_trust() {
2871 let certificate = certificate_der(RSA_4096_CERTIFICATE);
2874 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2875 trusted_certs: vec![certificate.clone()],
2876 lookup_certs: vec![certificate],
2877 ..KeyResolverConfig::default()
2878 });
2879 let result = super::super::VerifyContext::new()
2880 .policy(verification_policy_with_trust(chain_policy_at(
2881 fixture_certificate_time(),
2882 )))
2883 .key_resolver(&resolver)
2884 .verify(&x509_signature_with_leaf_subject())
2885 .expect("trusted/lookup overlap must resolve as one trusted candidate");
2886
2887 assert_eq!(result.status, super::super::DsigStatus::Valid);
2888 }
2889
2890 #[test]
2891 fn distinct_x509_selector_matches_remain_ambiguous() {
2892 let certificate = || {
2895 generated_certificate_params("ambiguous selector", false)
2896 .self_signed(
2897 &rcgen::KeyPair::generate().expect("test key generation should succeed"),
2898 )
2899 .expect("test certificate should be self-signable")
2900 .der()
2901 .to_vec()
2902 };
2903 let xml = replace_unprefixed_key_info(
2904 X509_DIGEST_SIGNATURE,
2905 "<KeyInfo><X509Data><X509SubjectName>CN=ambiguous selector</X509SubjectName></X509Data></KeyInfo>",
2906 );
2907 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2908 lookup_certs: vec![certificate(), certificate()],
2909 ..KeyResolverConfig::default()
2910 });
2911 let error = super::super::VerifyContext::new()
2912 .key_resolver(&resolver)
2913 .verify(&xml)
2914 .expect_err("distinct selector matches must fail closed");
2915
2916 assert!(matches!(
2917 error,
2918 DsigError::KeyResolution(KeyResolutionError::AmbiguousCertificate)
2919 ));
2920 }
2921
2922 #[test]
2923 fn unsupported_x509_digest_selector_fails_closed() {
2924 let key_info = "<KeyInfo xmlns:dsig11=\"http://www.w3.org/2009/xmldsig11#\"><X509Data><dsig11:X509Digest Algorithm=\"urn:unsupported\">AQ==</dsig11:X509Digest></X509Data></KeyInfo>";
2927 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
2928 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2929 lookup_certs: vec![certificate_der(include_str!(
2930 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
2931 ))],
2932 ..KeyResolverConfig::default()
2933 });
2934 let error = super::super::VerifyContext::new()
2935 .key_resolver(&resolver)
2936 .verify(&xml)
2937 .expect_err("unsupported X509Digest algorithm must fail closed");
2938
2939 assert!(matches!(
2940 error,
2941 DsigError::KeyResolution(KeyResolutionError::UnsupportedDigestAlgorithm(uri))
2942 if uri == "urn:unsupported"
2943 ));
2944 }
2945
2946 #[test]
2947 fn x509_digest_selector_uses_operation_provider() {
2948 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2951 lookup_certs: vec![certificate_der(RSA_4096_CERTIFICATE)],
2952 trusted_certs: vec![
2953 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
2954 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
2955 ],
2956 ..KeyResolverConfig::default()
2957 });
2958 let provider = RejectSecondSha512Provider {
2959 sha512_calls: AtomicUsize::new(0),
2960 verification_calls: AtomicUsize::new(0),
2961 reject_verification_call: None,
2962 rejected_verification_data: None,
2963 };
2964 let error = super::super::VerifyContext::new()
2965 .key_resolver(&resolver)
2966 .provider(&provider)
2967 .verify(X509_DIGEST_SIGNATURE)
2968 .expect_err("X509Digest selection must use the operation provider");
2969
2970 assert!(
2971 matches!(
2972 error,
2973 DsigError::Provider(crate::provider::ProviderError::Unsupported {
2974 operation: crate::provider::ProviderOperation::Digest,
2975 algorithm: Some(ref uri),
2976 }) if uri == super::super::DigestAlgorithm::Sha512.uri()
2977 ),
2978 "unexpected error: {error:?}"
2979 );
2980 }
2981
2982 #[test]
2983 fn resolves_named_key_end_to_end() {
2984 let xml = replace_key_info(
2986 SIGNED_SAML,
2987 "<ds:KeyInfo><ds:KeyName>idp-signing</ds:KeyName></ds:KeyInfo>",
2988 );
2989 let mut config = KeyResolverConfig::default();
2990 config.named_keys.insert(
2991 "idp-signing".into(),
2992 VerificationKey {
2993 algorithm: SignatureAlgorithm::EcdsaSha256,
2994 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
2995 certificate_der: None,
2996 name: Some("idp-signing".into()),
2997 },
2998 );
2999 let resolver = DefaultKeyResolver::new(config);
3000 let result = super::super::VerifyContext::new()
3001 .key_resolver(&resolver)
3002 .verify(&xml)
3003 .expect("named key should resolve");
3004
3005 assert_eq!(result.status, super::super::DsigStatus::Valid);
3006 }
3007
3008 #[test]
3009 fn resolves_der_encoded_key_end_to_end() {
3010 let encoded = STANDARD.encode(public_key_der(SAML_PUBLIC_KEY));
3012 let xml = replace_key_info(
3013 SIGNED_SAML,
3014 &format!(
3015 "<ds:KeyInfo><dsig11:DEREncodedKeyValue xmlns:dsig11=\"http://www.w3.org/2009/xmldsig11#\">{encoded}</dsig11:DEREncodedKeyValue></ds:KeyInfo>"
3016 ),
3017 );
3018 let resolver = DefaultKeyResolver::default();
3019 let result = super::super::VerifyContext::new()
3020 .key_resolver(&resolver)
3021 .verify(&xml)
3022 .expect("DER key should resolve");
3023
3024 assert_eq!(result.status, super::super::DsigStatus::Valid);
3025 }
3026
3027 #[test]
3028 fn resolves_rsa_key_value_end_to_end() {
3029 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
3031 .expect("fixture must contain an RSA public key");
3032 let (modulus, exponent) = rsa_key_value_parts(&public_key);
3033 let key_info = format!(
3034 "<KeyInfo><KeyValue><RSAKeyValue><Modulus>{}</Modulus><Exponent>{}</Exponent></RSAKeyValue></KeyValue></KeyInfo>",
3035 modulus, exponent,
3036 );
3037 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
3038 let resolver = DefaultKeyResolver::default();
3039 let result = super::super::VerifyContext::new()
3040 .key_resolver(&resolver)
3041 .verify(&xml)
3042 .expect("RSAKeyValue should resolve");
3043
3044 assert_eq!(result.status, super::super::DsigStatus::Valid);
3045 }
3046
3047 #[test]
3048 fn rsa_key_value_rejects_legacy_weak_modulus() {
3049 let resolver = DefaultKeyResolver::default();
3052 let error = super::super::VerifyContext::new()
3053 .key_resolver(&resolver)
3054 .verify(LEGACY_RSA_KEY_VALUE_SIGNATURE)
3055 .expect_err("context policy must override permissive resolver defaults");
3056
3057 assert!(matches!(
3058 error,
3059 DsigError::Policy(crate::policy::PolicyViolation::Algorithm {
3060 operation: "verification",
3061 ..
3062 })
3063 ));
3064 }
3065
3066 #[test]
3067 fn operation_policy_rejects_disabled_embedded_key_source() {
3068 let key_info = KeyInfo {
3071 sources: vec![KeyInfoSource::KeyValue(KeyValueInfo::Rsa {
3072 modulus: vec![0x80; 256],
3073 exponent: vec![1, 0, 1],
3074 })],
3075 };
3076 let mut policy = crate::policy::VerificationPolicy::default();
3077 policy.key_sources.key_value = false;
3078
3079 let error = match DefaultKeyResolver::default().resolve_with_policy(
3080 Some(&key_info),
3081 SignatureAlgorithm::RsaSha256,
3082 &policy,
3083 ) {
3084 Ok(_) => panic!("disabled KeyValue must fail before key construction"),
3085 Err(error) => error,
3086 };
3087
3088 assert!(matches!(
3089 error,
3090 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust {
3091 reason: "KeyValue key sources are disabled"
3092 })
3093 ));
3094 }
3095
3096 #[test]
3097 fn operation_policy_preflights_every_key_info_source_before_resolution() {
3098 let mut config = KeyResolverConfig::default();
3101 config.named_keys.insert(
3102 "idp-signing".into(),
3103 VerificationKey {
3104 algorithm: SignatureAlgorithm::EcdsaSha256,
3105 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3106 certificate_der: None,
3107 name: Some("idp-signing".into()),
3108 },
3109 );
3110 let resolver = DefaultKeyResolver::new(config);
3111 let mut policy = crate::policy::VerificationPolicy::default();
3112 policy.key_sources.x509_data = false;
3113
3114 for sources in [
3115 vec![
3116 KeyInfoSource::KeyName("idp-signing".into()),
3117 KeyInfoSource::X509Data(X509DataInfo::default()),
3118 ],
3119 vec![
3120 KeyInfoSource::X509Data(X509DataInfo::default()),
3121 KeyInfoSource::KeyName("idp-signing".into()),
3122 ],
3123 ] {
3124 let error = match resolver.resolve_with_policy(
3125 Some(&KeyInfo { sources }),
3126 SignatureAlgorithm::EcdsaSha256,
3127 &policy,
3128 ) {
3129 Ok(_) => panic!("source order must not hide disabled X509Data"),
3130 Err(error) => error,
3131 };
3132
3133 assert!(matches!(
3134 error,
3135 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust {
3136 reason: "X509Data key sources are disabled"
3137 })
3138 ));
3139 }
3140 }
3141
3142 #[test]
3143 fn operation_policy_bounds_ordered_key_info_candidates() {
3144 let mut config = KeyResolverConfig::default();
3147 config.named_keys.insert(
3148 "idp-signing".into(),
3149 VerificationKey {
3150 algorithm: SignatureAlgorithm::EcdsaSha256,
3151 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3152 certificate_der: None,
3153 name: Some("idp-signing".into()),
3154 },
3155 );
3156 let resolver = DefaultKeyResolver::new(config);
3157 let key_info = KeyInfo {
3158 sources: vec![
3159 KeyInfoSource::KeyValue(KeyValueInfo::Ec {
3160 curve_oid: "1.3.132.0.35".into(),
3161 public_key: vec![4],
3162 }),
3163 KeyInfoSource::KeyName("idp-signing".into()),
3164 ],
3165 };
3166
3167 for maximum in [0, 1] {
3168 let mut policy = crate::policy::VerificationPolicy::default();
3169 policy.resources.max_key_candidates = maximum;
3170 let error = match resolver.resolve_with_policy(
3171 Some(&key_info),
3172 SignatureAlgorithm::EcdsaSha256,
3173 &policy,
3174 ) {
3175 Ok(_) => panic!("candidate ceiling {maximum} must stop resolution"),
3176 Err(error) => error,
3177 };
3178 assert!(matches!(
3179 error,
3180 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
3181 resource: crate::policy::resource_name::KEY_CANDIDATES,
3182 maximum: observed,
3183 actual,
3184 }) if observed == maximum && actual == maximum + 1
3185 ));
3186 }
3187
3188 let mut policy = crate::policy::VerificationPolicy::default();
3189 policy.resources.max_key_candidates = 2;
3190 assert!(
3191 resolver
3192 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::EcdsaSha256, &policy,)
3193 .expect("two allowed attempts must reach the named key")
3194 .is_some()
3195 );
3196 }
3197
3198 #[test]
3199 fn operation_policy_bounds_configured_x509_selector_candidates() {
3200 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3204 lookup_certs: vec![
3205 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
3206 certificate_der(RSA_4096_CERTIFICATE),
3207 ],
3208 ..KeyResolverConfig::default()
3209 });
3210 let mut policy = crate::policy::VerificationPolicy::default();
3211 policy.resources.max_key_candidates = 1;
3212
3213 let error = super::super::VerifyContext::new()
3214 .policy(policy)
3215 .key_resolver(&resolver)
3216 .verify(&x509_signature_with_leaf_subject())
3217 .expect_err("the second configured certificate must exceed the candidate budget");
3218
3219 assert!(matches!(
3220 error,
3221 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
3222 resource: crate::policy::resource_name::KEY_CANDIDATES,
3223 maximum: 1,
3224 actual: 2,
3225 })
3226 ));
3227 }
3228
3229 #[test]
3230 fn operation_policy_bounds_embedded_x509_certificate_candidates() {
3231 let key_info = KeyInfo {
3235 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
3236 certificates: vec![
3237 certificate_der(RSA_4096_CERTIFICATE),
3238 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
3239 ],
3240 certificate_chain: vec![0],
3241 ..X509DataInfo::default()
3242 })],
3243 };
3244 let mut policy = crate::policy::VerificationPolicy::default();
3245 policy.resources.max_key_candidates = 1;
3246
3247 let error = match DefaultKeyResolver::default().resolve_with_policy(
3248 Some(&key_info),
3249 SignatureAlgorithm::RsaSha256,
3250 &policy,
3251 ) {
3252 Ok(_) => panic!("the second embedded certificate must exceed the candidate budget"),
3253 Err(error) => error,
3254 };
3255
3256 assert!(matches!(
3257 error,
3258 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
3259 resource: crate::policy::resource_name::KEY_CANDIDATES,
3260 maximum: 1,
3261 actual: 2,
3262 })
3263 ));
3264 }
3265
3266 #[test]
3267 fn operation_policy_charges_duplicate_configured_x509_candidates() {
3268 let certificate = certificate_der(RSA_4096_CERTIFICATE);
3271 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3272 lookup_certs: vec![certificate.clone(), certificate],
3273 ..KeyResolverConfig::default()
3274 });
3275 let mut policy = crate::policy::VerificationPolicy::default();
3276 policy.resources.max_key_candidates = 1;
3277
3278 let error = super::super::VerifyContext::new()
3279 .policy(policy)
3280 .key_resolver(&resolver)
3281 .verify(&x509_signature_with_leaf_subject())
3282 .expect_err("the duplicate configured entry must consume candidate work");
3283
3284 assert!(matches!(
3285 error,
3286 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
3287 resource: crate::policy::resource_name::KEY_CANDIDATES,
3288 maximum: 1,
3289 actual: 2,
3290 })
3291 ));
3292 }
3293
3294 #[test]
3295 fn operation_policy_charges_duplicate_embedded_x509_candidates() {
3296 let certificate = certificate_der(RSA_4096_CERTIFICATE);
3299 let key_info = KeyInfo {
3300 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
3301 certificates: vec![certificate.clone(), certificate],
3302 certificate_chain: vec![0],
3303 ..X509DataInfo::default()
3304 })],
3305 };
3306 let mut policy = crate::policy::VerificationPolicy::default();
3307 policy.resources.max_key_candidates = 1;
3308
3309 let error = match DefaultKeyResolver::default().resolve_with_policy(
3310 Some(&key_info),
3311 SignatureAlgorithm::RsaSha256,
3312 &policy,
3313 ) {
3314 Ok(_) => panic!("the duplicate embedded entry must consume candidate work"),
3315 Err(error) => error,
3316 };
3317
3318 assert!(matches!(
3319 error,
3320 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
3321 resource: crate::policy::resource_name::KEY_CANDIDATES,
3322 maximum: 1,
3323 actual: 2,
3324 })
3325 ));
3326 }
3327
3328 #[test]
3329 fn policy_aware_resolver_rejects_resources_above_hard_ceiling() {
3330 let mut policy = crate::policy::VerificationPolicy::default();
3333 policy.resources.max_key_candidates = usize::MAX;
3334
3335 let error = match DefaultKeyResolver::default().resolve_with_policy(
3336 None,
3337 SignatureAlgorithm::RsaSha256,
3338 &policy,
3339 ) {
3340 Ok(_) => panic!("invalid resource policy must fail before key resolution"),
3341 Err(error) => error,
3342 };
3343
3344 assert!(matches!(
3345 error,
3346 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
3347 resource: crate::policy::resource_name::KEY_CANDIDATES,
3348 actual: usize::MAX,
3349 ..
3350 })
3351 ));
3352 }
3353
3354 #[test]
3355 fn embedded_x509_digest_selection_uses_operation_provider() {
3356 let certificate = certificate_der(RSA_4096_CERTIFICATE);
3359 let digest =
3360 super::super::compute_digest(super::super::DigestAlgorithm::Sha512, &certificate);
3361 let xml = format!(
3362 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><X509Data><X509Certificate>{}</X509Certificate><X509Digest xmlns=\"http://www.w3.org/2009/xmldsig11#\" Algorithm=\"{}\">{}</X509Digest></X509Data></KeyInfo>",
3363 STANDARD.encode(&certificate),
3364 super::super::DigestAlgorithm::Sha512.uri(),
3365 STANDARD.encode(digest),
3366 );
3367 let document = roxmltree::Document::parse(&xml).expect("generated KeyInfo must be XML");
3368 let provider = RejectSecondSha512Provider {
3369 sha512_calls: AtomicUsize::new(1),
3370 verification_calls: AtomicUsize::new(0),
3371 reject_verification_call: None,
3372 rejected_verification_data: None,
3373 };
3374
3375 let error =
3376 super::super::parse::parse_key_info_with_provider(document.root_element(), &provider)
3377 .expect_err("embedded X509Digest selection must use the operation provider");
3378
3379 assert!(
3380 matches!(
3381 error,
3382 ParseError::Provider(crate::provider::ProviderError::Unsupported {
3383 operation: crate::provider::ProviderOperation::Digest,
3384 algorithm: Some(ref uri),
3385 }) if uri == super::super::DigestAlgorithm::Sha512.uri()
3386 ),
3387 "unexpected error: {error:?}"
3388 );
3389 }
3390
3391 #[test]
3392 fn generic_key_resolution_keeps_legacy_capability_source_independent() {
3393 let certificate =
3394 include_bytes!("../../tests/fixtures/xmldsig/phaos-xmldsig-three/certs/rsa-cert.der")
3395 .to_vec();
3396 let (_, parsed_certificate) = X509Certificate::from_der(&certificate)
3397 .expect("the Phaos fixture is a DER certificate");
3398 let public_key = parsed_certificate.public_key().raw.to_vec();
3399 let rsa_public_key = rsa::RsaPublicKey::from_public_key_der(&public_key)
3400 .expect("the Phaos certificate contains an RSA public key");
3401 let certificate_metadata = parse_x509_certificate(&certificate)
3402 .expect("the Phaos fixture has supported X.509 metadata");
3403 let named_key = VerificationKey {
3404 algorithm: SignatureAlgorithm::RsaSha1,
3405 public_key_bytes: public_key.clone(),
3406 certificate_der: None,
3407 name: Some("legacy".into()),
3408 };
3409 let key_infos = [
3410 KeyInfo {
3411 sources: vec![KeyInfoSource::KeyName("legacy".into())],
3412 },
3413 KeyInfo {
3414 sources: vec![KeyInfoSource::DerEncodedKeyValue(public_key.clone())],
3415 },
3416 KeyInfo {
3417 sources: vec![KeyInfoSource::KeyValue(KeyValueInfo::Rsa {
3418 modulus: rsa_public_key.n().to_be_bytes_trimmed_vartime().to_vec(),
3419 exponent: rsa_public_key.e().to_be_bytes_trimmed_vartime().to_vec(),
3420 })],
3421 },
3422 KeyInfo {
3423 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
3424 certificates: vec![certificate],
3425 parsed_certificates: vec![certificate_metadata],
3426 certificate_chain: vec![0],
3427 ..X509DataInfo::default()
3428 })],
3429 },
3430 ];
3431 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3432 named_keys: HashMap::from([("legacy".into(), named_key.clone())]),
3433 ..KeyResolverConfig::default()
3434 });
3435 let mut policy = crate::policy::VerificationPolicy::default();
3436 policy.key_trust.rsa_keys.minimum_modulus_bits = 1024;
3437 policy
3438 .key_trust
3439 .allowed_legacy_signature_algorithms
3440 .insert(SignatureAlgorithm::RsaSha1);
3441
3442 for key_info in &key_infos {
3443 let key = resolver
3444 .resolve_with_policy(Some(key_info), SignatureAlgorithm::RsaSha1, &policy)
3445 .expect("the key source is valid")
3446 .expect("key resolution remains independent from operation policy");
3447 assert!(
3448 !key.verify(SignatureAlgorithm::RsaSha1, b"data", &[0; 128])
3449 .expect("the legacy RSA key is structurally valid")
3450 );
3451 }
3452 }
3453
3454 #[test]
3455 fn rsa_key_value_rejects_ecdsa_signature_method() {
3456 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
3458 .expect("fixture must contain an RSA public key");
3459 let (modulus, exponent) = rsa_key_value_parts(&public_key);
3460 let key_info = format!(
3461 "<ds:KeyInfo><ds:KeyValue><ds:RSAKeyValue><ds:Modulus>{}</ds:Modulus><ds:Exponent>{}</ds:Exponent></ds:RSAKeyValue></ds:KeyValue></ds:KeyInfo>",
3462 modulus, exponent,
3463 );
3464 let xml = replace_key_info(SIGNED_SAML, &key_info);
3465 let resolver = DefaultKeyResolver::default();
3466 let error = super::super::VerifyContext::new()
3467 .key_resolver(&resolver)
3468 .verify(&xml)
3469 .expect_err("RSAKeyValue must not resolve for ECDSA");
3470
3471 assert!(matches!(
3472 error,
3473 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
3474 ));
3475 }
3476
3477 #[test]
3478 fn resolves_ec_p256_key_value_end_to_end() {
3479 let resolver = DefaultKeyResolver::default();
3481 let result = super::super::VerifyContext::new()
3482 .key_resolver(&resolver)
3483 .verify(EC_P256_KEY_VALUE_SIGNATURE)
3484 .expect("P-256 ECKeyValue should resolve");
3485
3486 assert_eq!(result.status, super::super::DsigStatus::Valid);
3487 }
3488
3489 #[test]
3490 fn resolves_ec_p384_key_value_end_to_end() {
3491 let resolver = DefaultKeyResolver::default();
3493 let result = super::super::VerifyContext::new()
3494 .key_resolver(&resolver)
3495 .verify(EC_P384_KEY_VALUE_SIGNATURE)
3496 .expect("P-384 ECKeyValue should resolve");
3497
3498 assert_eq!(result.status, super::super::DsigStatus::Valid);
3499 }
3500
3501 #[test]
3502 fn ec_key_value_ignored_for_rsa_signature_method() {
3503 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>"#;
3505 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
3506 let resolver = DefaultKeyResolver::default();
3507 let result = super::super::VerifyContext::new()
3508 .key_resolver(&resolver)
3509 .verify(&xml)
3510 .expect("single incompatible ECKeyValue should be ignored");
3511
3512 assert_eq!(
3513 result.status,
3514 super::super::DsigStatus::Invalid(super::super::FailureReason::KeyNotFound)
3515 );
3516 }
3517
3518 #[test]
3519 fn incompatible_ec_key_value_falls_back_to_later_rsa_key_value() {
3520 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
3522 .expect("fixture must contain an RSA public key");
3523 let (modulus, exponent) = rsa_key_value_parts(&public_key);
3524 let key_info = format!(
3525 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>"#,
3526 modulus, exponent,
3527 );
3528 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
3529 let resolver = DefaultKeyResolver::default();
3530 let result = super::super::VerifyContext::new()
3531 .key_resolver(&resolver)
3532 .verify(&xml)
3533 .expect("later RSAKeyValue should resolve");
3534
3535 assert_eq!(result.status, super::super::DsigStatus::Valid);
3536 }
3537
3538 #[test]
3539 fn unsupported_ec_key_value_falls_back_to_later_key_name() {
3540 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>"#;
3542 let xml = replace_key_info(SIGNED_SAML, key_info);
3543 let mut config = KeyResolverConfig::default();
3544 config.named_keys.insert(
3545 "idp-signing".into(),
3546 VerificationKey {
3547 algorithm: SignatureAlgorithm::EcdsaSha256,
3548 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3549 certificate_der: None,
3550 name: Some("idp-signing".into()),
3551 },
3552 );
3553 let resolver = DefaultKeyResolver::new(config);
3554 let result = super::super::VerifyContext::new()
3555 .key_resolver(&resolver)
3556 .verify(&xml)
3557 .expect("later KeyName should resolve");
3558
3559 assert_eq!(result.status, super::super::DsigStatus::Valid);
3560 }
3561
3562 #[test]
3563 fn invalid_ec_key_value_falls_back_to_later_key_name() {
3564 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>"#;
3566 let xml = replace_key_info(SIGNED_SAML, key_info);
3567 let mut config = KeyResolverConfig::default();
3568 config.named_keys.insert(
3569 "idp-signing".into(),
3570 VerificationKey {
3571 algorithm: SignatureAlgorithm::EcdsaSha256,
3572 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3573 certificate_der: None,
3574 name: Some("idp-signing".into()),
3575 },
3576 );
3577 let resolver = DefaultKeyResolver::new(config);
3578 let result = super::super::VerifyContext::new()
3579 .key_resolver(&resolver)
3580 .verify(&xml)
3581 .expect("later KeyName should resolve after invalid ECKeyValue");
3582
3583 assert_eq!(result.status, super::super::DsigStatus::Valid);
3584 }
3585
3586 #[test]
3587 fn malformed_ec_key_value_falls_back_to_later_key_name() {
3588 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>"#;
3590 let xml = replace_key_info(SIGNED_SAML, key_info);
3591 let mut config = KeyResolverConfig::default();
3592 config.named_keys.insert(
3593 "idp-signing".into(),
3594 VerificationKey {
3595 algorithm: SignatureAlgorithm::EcdsaSha256,
3596 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3597 certificate_der: None,
3598 name: Some("idp-signing".into()),
3599 },
3600 );
3601 let resolver = DefaultKeyResolver::new(config);
3602 let result = super::super::VerifyContext::new()
3603 .key_resolver(&resolver)
3604 .verify(&xml)
3605 .expect("later KeyName should resolve after malformed ECKeyValue");
3606
3607 assert_eq!(result.status, super::super::DsigStatus::Valid);
3608 }
3609
3610 #[test]
3611 fn invalid_base64_ec_key_value_falls_back_to_later_key_name() {
3612 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>"#;
3615 let xml = replace_key_info(SIGNED_SAML, key_info);
3616 let mut config = KeyResolverConfig::default();
3617 config.named_keys.insert(
3618 "idp-signing".into(),
3619 VerificationKey {
3620 algorithm: SignatureAlgorithm::EcdsaSha256,
3621 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3622 certificate_der: None,
3623 name: Some("idp-signing".into()),
3624 },
3625 );
3626 let resolver = DefaultKeyResolver::new(config);
3627 let result = super::super::VerifyContext::new()
3628 .key_resolver(&resolver)
3629 .verify(&xml)
3630 .expect("later KeyName should resolve after bad ECKeyValue base64");
3631
3632 assert_eq!(result.status, super::super::DsigStatus::Valid);
3633 }
3634
3635 #[test]
3636 fn missing_curve_uri_ec_key_value_falls_back_to_later_key_name() {
3637 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>"#;
3639 let xml = replace_key_info(SIGNED_SAML, key_info);
3640 let mut config = KeyResolverConfig::default();
3641 config.named_keys.insert(
3642 "idp-signing".into(),
3643 VerificationKey {
3644 algorithm: SignatureAlgorithm::EcdsaSha256,
3645 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3646 certificate_der: None,
3647 name: Some("idp-signing".into()),
3648 },
3649 );
3650 let resolver = DefaultKeyResolver::new(config);
3651 let result = super::super::VerifyContext::new()
3652 .key_resolver(&resolver)
3653 .verify(&xml)
3654 .expect("later KeyName should resolve after missing EC curve URI");
3655
3656 assert_eq!(result.status, super::super::DsigStatus::Valid);
3657 }
3658
3659 #[test]
3660 fn malformed_ec_key_value_children_fall_back_to_later_key_name() {
3661 let malformed_ec_key_values = [
3664 r#"<dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/>"#,
3665 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"/>"#,
3666 r#"<dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/><dsig11:PublicKey>BA==</dsig11:PublicKey><dsig11:PublicKey>BA==</dsig11:PublicKey>"#,
3667 ];
3668
3669 for malformed_children in malformed_ec_key_values {
3670 let key_info = format!(
3671 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>"#
3672 );
3673 let xml = replace_key_info(SIGNED_SAML, &key_info);
3674 let mut config = KeyResolverConfig::default();
3675 config.named_keys.insert(
3676 "idp-signing".into(),
3677 VerificationKey {
3678 algorithm: SignatureAlgorithm::EcdsaSha256,
3679 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3680 certificate_der: None,
3681 name: Some("idp-signing".into()),
3682 },
3683 );
3684 let resolver = DefaultKeyResolver::new(config);
3685 let result = super::super::VerifyContext::new()
3686 .key_resolver(&resolver)
3687 .verify(&xml)
3688 .expect("later KeyName should resolve after malformed EC child shape");
3689
3690 assert_eq!(result.status, super::super::DsigStatus::Valid);
3691 }
3692 }
3693
3694 #[test]
3695 fn supported_ec_curve_does_not_fall_back_to_later_key_name() {
3696 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>"#;
3700 let xml = replace_key_info(SIGNED_SAML, key_info);
3701 let mut config = KeyResolverConfig::default();
3702 config.named_keys.insert(
3703 "idp-signing".into(),
3704 VerificationKey {
3705 algorithm: SignatureAlgorithm::EcdsaSha256,
3706 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3707 certificate_der: None,
3708 name: Some("idp-signing".into()),
3709 },
3710 );
3711 let resolver = DefaultKeyResolver::new(config);
3712 let error = super::super::VerifyContext::new()
3713 .key_resolver(&resolver)
3714 .verify(&xml)
3715 .expect_err("a usable first key source must not fall through after verification");
3716
3717 assert!(matches!(
3718 error,
3719 DsigError::Crypto(super::super::SignatureVerificationError::InvalidSignatureFormat)
3720 ));
3721 }
3722
3723 #[test]
3724 fn lone_malformed_ec_key_value_reports_invalid_public_key() {
3725 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>"#;
3726 let xml = replace_key_info(SIGNED_SAML, key_info);
3727 let error = super::super::VerifyContext::new()
3728 .key_resolver(&DefaultKeyResolver::default())
3729 .verify(&xml)
3730 .expect_err("lone malformed ECKeyValue should surface typed key error");
3731
3732 assert!(matches!(
3733 error,
3734 DsigError::KeyResolution(KeyResolutionError::InvalidPublicKey)
3735 ));
3736 }
3737
3738 #[test]
3739 fn lone_supported_ec_curve_reaches_signature_verification() {
3740 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>"#;
3741 let xml = replace_key_info(SIGNED_SAML, key_info);
3742 let error = super::super::VerifyContext::new()
3743 .key_resolver(&DefaultKeyResolver::default())
3744 .verify(&xml)
3745 .expect_err("a supported EC curve must reach signature verification");
3746
3747 assert!(matches!(
3748 error,
3749 DsigError::Crypto(super::super::SignatureVerificationError::InvalidSignatureFormat)
3750 ));
3751 }
3752
3753 #[test]
3754 fn chain_verification_rejects_untrusted_embedded_certificate() {
3755 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3757 ..KeyResolverConfig::default()
3758 });
3759 let error = super::super::VerifyContext::new()
3760 .policy(verification_policy_with_trust(chain_policy()))
3761 .key_resolver(&resolver)
3762 .verify(SIGNED_SAML)
3763 .expect_err("untrusted certificate must fail chain validation");
3764
3765 assert!(matches!(
3766 error,
3767 DsigError::KeyResolution(KeyResolutionError::Chain(
3768 super::super::X509ChainError::UntrustedRoot
3769 ))
3770 ));
3771 }
3772
3773 #[test]
3774 fn named_key_algorithm_mismatch_fails_closed() {
3775 let xml = replace_key_info(
3777 SIGNED_SAML,
3778 "<ds:KeyInfo><ds:KeyName>wrong-algorithm</ds:KeyName></ds:KeyInfo>",
3779 );
3780 let mut config = KeyResolverConfig::default();
3781 config.named_keys.insert(
3782 "wrong-algorithm".into(),
3783 VerificationKey {
3784 algorithm: SignatureAlgorithm::RsaSha256,
3785 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3786 certificate_der: None,
3787 name: Some("wrong-algorithm".into()),
3788 },
3789 );
3790 let resolver = DefaultKeyResolver::new(config);
3791 let error = super::super::VerifyContext::new()
3792 .key_resolver(&resolver)
3793 .verify(&xml)
3794 .expect_err("algorithm mismatch must fail closed");
3795
3796 assert!(matches!(
3797 error,
3798 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
3799 ));
3800 }
3801
3802 #[test]
3803 fn named_key_spki_type_mismatch_fails_during_resolution() {
3804 let xml = replace_key_info(
3806 SIGNED_SAML,
3807 "<ds:KeyInfo><ds:KeyName>mislabeled</ds:KeyName></ds:KeyInfo>",
3808 );
3809 let mut config = KeyResolverConfig::default();
3810 config.named_keys.insert(
3811 "mislabeled".into(),
3812 VerificationKey {
3813 algorithm: SignatureAlgorithm::EcdsaSha256,
3814 public_key_bytes: public_key_der(RSA_PUBLIC_KEY),
3815 certificate_der: None,
3816 name: Some("mislabeled".into()),
3817 },
3818 );
3819 let resolver = DefaultKeyResolver::new(config);
3820 let error = super::super::VerifyContext::new()
3821 .key_resolver(&resolver)
3822 .verify(&xml)
3823 .expect_err("mislabeled named key must fail during resolution");
3824
3825 assert!(matches!(
3826 error,
3827 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
3828 ));
3829 }
3830
3831 #[test]
3832 fn malformed_named_key_reports_public_key_error() {
3833 let xml = replace_key_info(
3835 SIGNED_SAML,
3836 "<ds:KeyInfo><ds:KeyName>malformed</ds:KeyName></ds:KeyInfo>",
3837 );
3838 let mut config = KeyResolverConfig::default();
3839 config.named_keys.insert(
3840 "malformed".into(),
3841 VerificationKey {
3842 algorithm: SignatureAlgorithm::EcdsaSha256,
3843 public_key_bytes: vec![1, 2, 3],
3844 certificate_der: None,
3845 name: Some("malformed".into()),
3846 },
3847 );
3848 let resolver = DefaultKeyResolver::new(config);
3849 let error = super::super::VerifyContext::new()
3850 .key_resolver(&resolver)
3851 .verify(&xml)
3852 .expect_err("malformed named key must fail during resolution");
3853
3854 assert!(matches!(
3855 error,
3856 DsigError::KeyResolution(KeyResolutionError::InvalidPublicKey)
3857 ));
3858 }
3859}