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 rcgen::{
1274 CertificateRevocationListParams, Issuer, KeyIdMethod, KeyPair, KeyUsagePurpose,
1275 RevokedCertParams, SerialNumber, date_time_ymd,
1276 };
1277 use rsa::{pkcs8::DecodePublicKey, traits::PublicKeyParts};
1278
1279 use super::*;
1280
1281 struct RejectSecondSha512Provider {
1282 sha512_calls: AtomicUsize,
1283 verification_calls: AtomicUsize,
1284 reject_verification_call: Option<usize>,
1285 rejected_verification_data: Option<Vec<u8>>,
1286 }
1287
1288 impl crate::provider::CryptoProvider for RejectSecondSha512Provider {
1289 fn name(&self) -> &'static str {
1290 "reject-second-sha512"
1291 }
1292
1293 fn supports(&self, capability: crate::provider::ProviderCapability<'_>) -> bool {
1294 crate::provider::default_provider().supports(capability)
1295 }
1296
1297 fn fill_random(&self, output: &mut [u8]) -> Result<(), crate::provider::ProviderError> {
1298 crate::provider::default_provider().fill_random(output)
1299 }
1300
1301 fn derive_key(
1302 &self,
1303 parameters: &crate::provider::KdfParameters<'_>,
1304 secret: &[u8],
1305 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1306 crate::provider::default_provider().derive_key(parameters, secret)
1307 }
1308
1309 fn digest(
1310 &self,
1311 algorithm: super::super::DigestAlgorithm,
1312 data: &[u8],
1313 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1314 if algorithm == super::super::DigestAlgorithm::Sha512
1315 && self.sha512_calls.fetch_add(1, Ordering::Relaxed) > 0
1316 {
1317 return Err(crate::provider::ProviderError::Unsupported {
1318 operation: crate::provider::ProviderOperation::Digest,
1319 algorithm: Some(algorithm.uri().to_owned()),
1320 });
1321 }
1322 crate::provider::default_provider().digest(algorithm, data)
1323 }
1324
1325 fn sign(
1326 &self,
1327 key: &dyn super::super::SigningKey,
1328 algorithm: SignatureAlgorithm,
1329 data: &[u8],
1330 ) -> Result<Vec<u8>, super::super::SigningKeyError> {
1331 crate::provider::default_provider().sign(key, algorithm, data)
1332 }
1333
1334 fn verify(
1335 &self,
1336 key: &dyn VerifyingKey,
1337 algorithm: SignatureAlgorithm,
1338 data: &[u8],
1339 signature: &[u8],
1340 ) -> Result<bool, DsigError> {
1341 let call = self.verification_calls.fetch_add(1, Ordering::Relaxed);
1342 if self.reject_verification_call == Some(call)
1343 || self
1344 .rejected_verification_data
1345 .as_deref()
1346 .is_some_and(|rejected| rejected == data)
1347 {
1348 return Err(crate::provider::ProviderError::Unsupported {
1349 operation: crate::provider::ProviderOperation::Verify,
1350 algorithm: Some(algorithm.uri().to_owned()),
1351 }
1352 .into());
1353 }
1354 crate::provider::default_provider().verify(key, algorithm, data, signature)
1355 }
1356
1357 fn verify_x509_signature(
1358 &self,
1359 algorithm: crate::provider::X509SignatureAlgorithm,
1360 data: &[u8],
1361 signature: &[u8],
1362 issuer_spki_der: &[u8],
1363 ) -> Result<bool, crate::provider::ProviderError> {
1364 let call = self.verification_calls.fetch_add(1, Ordering::Relaxed);
1365 if self.reject_verification_call == Some(call)
1366 || self
1367 .rejected_verification_data
1368 .as_deref()
1369 .is_some_and(|rejected| rejected == data)
1370 {
1371 return Err(crate::provider::ProviderError::Unsupported {
1372 operation: crate::provider::ProviderOperation::VerifyCertificate,
1373 algorithm: Some(algorithm.oid().to_owned()),
1374 });
1375 }
1376 crate::provider::default_provider().verify_x509_signature(
1377 algorithm,
1378 data,
1379 signature,
1380 issuer_spki_der,
1381 )
1382 }
1383
1384 #[cfg(feature = "xmlenc")]
1385 fn encrypt_data(
1386 &self,
1387 algorithm: crate::xmlenc::DataEncryptionAlgorithm,
1388 key: &[u8],
1389 plaintext: &[u8],
1390 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1391 crate::provider::default_provider().encrypt_data(algorithm, key, plaintext)
1392 }
1393
1394 #[cfg(feature = "xmlenc")]
1395 fn decrypt_data(
1396 &self,
1397 algorithm: crate::xmlenc::DataEncryptionAlgorithm,
1398 key: &[u8],
1399 ciphertext: &[u8],
1400 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1401 crate::provider::default_provider().decrypt_data(algorithm, key, ciphertext)
1402 }
1403
1404 #[cfg(feature = "xmlenc")]
1405 fn wrap_key(
1406 &self,
1407 algorithm: crate::xmlenc::KeyWrapAlgorithm,
1408 kek: &[u8],
1409 key: &[u8],
1410 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1411 crate::provider::default_provider().wrap_key(algorithm, kek, key)
1412 }
1413
1414 #[cfg(feature = "xmlenc")]
1415 fn unwrap_key(
1416 &self,
1417 algorithm: crate::xmlenc::KeyWrapAlgorithm,
1418 kek: &[u8],
1419 wrapped: &[u8],
1420 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1421 crate::provider::default_provider().unwrap_key(algorithm, kek, wrapped)
1422 }
1423
1424 #[cfg(feature = "xmlenc")]
1425 fn transport_key(
1426 &self,
1427 key: &dyn crate::provider::KeyTransportKey,
1428 parameters: &crate::xmlenc::RsaOaepParameters,
1429 plaintext: &[u8],
1430 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1431 crate::provider::default_provider().transport_key(key, parameters, plaintext)
1432 }
1433
1434 #[cfg(feature = "xmlenc")]
1435 fn recover_key(
1436 &self,
1437 key: &dyn crate::provider::KeyRecoveryKey,
1438 parameters: &crate::xmlenc::RsaOaepParameters,
1439 ciphertext: &[u8],
1440 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1441 crate::provider::default_provider().recover_key(key, parameters, ciphertext)
1442 }
1443 }
1444
1445 fn chain_policy() -> crate::policy::KeyTrustPolicy {
1446 crate::policy::KeyTrustPolicy {
1447 verify_x509_chains: true,
1448 ..crate::policy::KeyTrustPolicy::default()
1449 }
1450 }
1451
1452 fn chain_policy_at(verification_time: SystemTime) -> crate::policy::KeyTrustPolicy {
1453 crate::policy::KeyTrustPolicy {
1454 verification_time: Some(verification_time),
1455 ..chain_policy()
1456 }
1457 }
1458
1459 fn verification_policy_with_trust(
1460 key_trust: crate::policy::KeyTrustPolicy,
1461 ) -> crate::policy::VerificationPolicy {
1462 crate::policy::VerificationPolicy {
1463 key_trust,
1464 ..crate::policy::VerificationPolicy::default()
1465 }
1466 }
1467
1468 const SIGNED_SAML: &str =
1469 include_str!("../../tests/fixtures/saml/response_signed_by_idp_ecdsa.xml");
1470 const SAML_PUBLIC_KEY: &str =
1471 include_str!("../../tests/fixtures/keys/ec/saml-idp-ecdsa-pubkey.pem");
1472 const RSA_PUBLIC_KEY: &str = include_str!("../../tests/fixtures/keys/rsa/rsa-2048-pubkey.pem");
1473 const RSA_4096_CERTIFICATE: &str =
1474 include_str!("../../tests/fixtures/keys/rsa/rsa-4096-cert.pem");
1475 const X509_DIGEST_SIGNATURE: &str = include_str!(
1476 "../../tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloped-x509-digest-sha512.xml"
1477 );
1478 const X509_DIGEST_SHA256_SIGNATURE: &str = include_str!(
1479 "../../tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloped-x509-digest-sha256.xml"
1480 );
1481 const RSA_KEY_VALUE_SIGNATURE: &str = include_str!(
1482 "../../tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloping-sha256-rsa-sha256.xml"
1483 );
1484 const LEGACY_RSA_KEY_VALUE_SIGNATURE: &str = include_str!(
1485 "../../tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-rsa.xml"
1486 );
1487 const EC_P256_KEY_VALUE_SIGNATURE: &str = include_str!(
1488 "../../tests/fixtures/xmldsig/xmldsig11-interop-2012/signature-enveloping-p256_sha256.xml"
1489 );
1490 const EC_P384_KEY_VALUE_SIGNATURE: &str = include_str!(
1491 "../../tests/fixtures/xmldsig/xmldsig11-interop-2012/signature-enveloping-p384_sha384.xml"
1492 );
1493
1494 fn replace_key_info(xml: &str, replacement: &str) -> String {
1495 let start = xml.find("<ds:KeyInfo>").expect("fixture has KeyInfo");
1496 let end = xml
1497 .find("</ds:KeyInfo>")
1498 .expect("fixture has closing KeyInfo")
1499 + "</ds:KeyInfo>".len();
1500 format!("{}{}{}", &xml[..start], replacement, &xml[end..])
1501 }
1502
1503 fn replace_unprefixed_key_info(xml: &str, replacement: &str) -> String {
1504 let start = xml.find("<KeyInfo>").expect("fixture has KeyInfo");
1505 let end = xml.find("</KeyInfo>").expect("fixture has closing KeyInfo") + "</KeyInfo>".len();
1506 format!("{}{}{}", &xml[..start], replacement, &xml[end..])
1507 }
1508
1509 fn rsa_key_value_parts(public_key: &rsa::RsaPublicKey) -> (String, String) {
1510 (
1511 STANDARD.encode(public_key.n().to_be_bytes_trimmed_vartime()),
1512 STANDARD.encode(public_key.e().to_be_bytes_trimmed_vartime()),
1513 )
1514 }
1515
1516 fn x509_signature_with_leaf_subject() -> String {
1517 replace_unprefixed_key_info(
1518 X509_DIGEST_SIGNATURE,
1519 "<KeyInfo><X509Data><X509SubjectName>CN=Test Key rsa-4096,O=XML Security Library (http://www.aleksey.com/xmlsec),ST=California,C=US</X509SubjectName></X509Data></KeyInfo>",
1520 )
1521 }
1522
1523 fn fixture_certificate_time() -> SystemTime {
1524 SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_800_000_000)
1526 }
1527
1528 fn public_key_der(pem_text: &str) -> Vec<u8> {
1529 let (rest, pem) = x509_parser::pem::parse_x509_pem(pem_text.as_bytes())
1530 .expect("fixture public key is PEM");
1531 assert!(rest.iter().all(|byte| byte.is_ascii_whitespace()));
1532 assert_eq!(pem.label, "PUBLIC KEY");
1533 pem.contents
1534 }
1535
1536 fn certificate_der(pem_text: &str) -> Vec<u8> {
1537 let (rest, pem) = x509_parser::pem::parse_x509_pem(pem_text.as_bytes())
1538 .expect("fixture certificate is PEM");
1539 assert!(rest.iter().all(|byte| byte.is_ascii_whitespace()));
1540 assert_eq!(pem.label, "CERTIFICATE");
1541 pem.contents
1542 }
1543
1544 fn crl_der(pem_text: &str) -> Vec<u8> {
1545 let (rest, pem) =
1546 x509_parser::pem::parse_x509_pem(pem_text.as_bytes()).expect("fixture CRL is PEM");
1547 assert!(rest.iter().all(|byte| byte.is_ascii_whitespace()));
1548 assert_eq!(pem.label, "X509 CRL");
1549 pem.contents
1550 }
1551
1552 fn generated_certificate_params(common_name: &str, is_ca: bool) -> rcgen::CertificateParams {
1553 let mut params = rcgen::CertificateParams::new(Vec::new())
1554 .expect("empty SAN list should produce valid certificate parameters");
1555 params
1556 .distinguished_name
1557 .push(rcgen::DnType::CommonName, common_name);
1558 if is_ca {
1559 params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
1560 params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
1561 }
1562 params
1563 }
1564
1565 fn authorized_revoked_chain() -> (X509DataInfo, Vec<u8>) {
1566 let mut root_params = generated_certificate_params("revocation root", true);
1567 root_params.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign];
1568 let root = rcgen::CertifiedIssuer::self_signed(
1569 root_params,
1570 KeyPair::generate().expect("root key generation should succeed"),
1571 )
1572 .expect("root should be self-signable");
1573
1574 let issuer_key = KeyPair::generate().expect("issuer key generation should succeed");
1575 let mut issuer_params = generated_certificate_params("revocation issuer", true);
1576 issuer_params.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign];
1577 let issuer_certificate = issuer_params
1578 .signed_by(&issuer_key, &root)
1579 .expect("root should sign issuer certificate");
1580 let issuer = Issuer::new(issuer_params, issuer_key);
1581
1582 let mut leaf_params = generated_certificate_params("revoked signer", false);
1583 leaf_params.serial_number = Some(SerialNumber::from(42_u64));
1584 leaf_params.key_usages = vec![KeyUsagePurpose::DigitalSignature];
1585 let leaf = leaf_params
1586 .signed_by(
1587 &KeyPair::generate().expect("leaf key generation should succeed"),
1588 &issuer,
1589 )
1590 .expect("issuer should sign leaf certificate");
1591 let crl = CertificateRevocationListParams {
1592 this_update: date_time_ymd(2026, 3, 15),
1593 next_update: date_time_ymd(2026, 4, 15),
1594 crl_number: SerialNumber::from(1_u64),
1595 issuing_distribution_point: None,
1596 revoked_certs: vec![RevokedCertParams {
1597 serial_number: SerialNumber::from(42_u64),
1598 revocation_time: date_time_ymd(2026, 3, 16),
1599 reason_code: None,
1600 invalidity_date: None,
1601 }],
1602 key_identifier_method: KeyIdMethod::Sha256,
1603 }
1604 .signed_by(&issuer)
1605 .expect("issuer should sign CRL");
1606 let mut info = x509_info(
1607 vec![
1608 leaf.der().to_vec(),
1609 issuer_certificate.der().to_vec(),
1610 root.der().to_vec(),
1611 ],
1612 0,
1613 );
1614 info.crls.push(crl.der().to_vec());
1615 (info, root.der().to_vec())
1616 }
1617
1618 fn x509_info(certificates: Vec<Vec<u8>>, signing_index: usize) -> X509DataInfo {
1619 let parsed_certificates = certificates
1620 .iter()
1621 .map(|certificate| {
1622 parse_x509_certificate(certificate)
1623 .expect("generated certificate should have supported metadata")
1624 })
1625 .collect();
1626 X509DataInfo {
1627 certificates,
1628 parsed_certificates,
1629 certificate_chain: vec![signing_index],
1630 ..X509DataInfo::default()
1631 }
1632 }
1633
1634 #[test]
1635 fn defaults_match_key_resolution_policy() {
1636 let config = KeyResolverConfig::default();
1638
1639 assert!(config.trusted_certs.is_empty());
1640 assert!(config.lookup_certs.is_empty());
1641 assert!(config.named_keys.is_empty());
1642 let trust = crate::policy::VerificationPolicy::default().key_trust;
1643 assert!(!trust.verify_x509_chains);
1644 assert!(!trust.check_crls);
1645 assert_eq!(trust.verification_time, None);
1646 assert_eq!(trust.max_x509_chain_depth, 9);
1647 }
1648
1649 #[test]
1650 fn verification_policy_controls_leaf_extended_key_usage() {
1651 let root = rcgen::CertifiedIssuer::self_signed(
1654 generated_certificate_params("EKU policy root", true),
1655 rcgen::KeyPair::generate().expect("root key generation should succeed"),
1656 )
1657 .expect("root should be self-signable");
1658 let mut leaf_params = generated_certificate_params("TLS-only XML signer", false);
1659 leaf_params.key_usages = vec![rcgen::KeyUsagePurpose::DigitalSignature];
1660 leaf_params.extended_key_usages = vec![rcgen::ExtendedKeyUsagePurpose::ServerAuth];
1661 let leaf = leaf_params
1662 .signed_by(
1663 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
1664 &root,
1665 )
1666 .expect("root should sign leaf certificate");
1667 let key_info = KeyInfo {
1668 sources: vec![KeyInfoSource::X509Data(x509_info(
1669 vec![leaf.der().to_vec(), root.der().to_vec()],
1670 0,
1671 ))],
1672 };
1673 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
1674 trusted_certs: vec![root.der().to_vec()],
1675 ..KeyResolverConfig::default()
1676 });
1677 let mut policy = crate::policy::VerificationPolicy::default();
1678 policy.key_trust.verify_x509_chains = true;
1679
1680 let error = match resolver.resolve_with_policy(
1681 Some(&key_info),
1682 SignatureAlgorithm::EcdsaSha256,
1683 &policy,
1684 ) {
1685 Ok(_) => panic!("unapproved restricted EKU must be rejected"),
1686 Err(error) => error,
1687 };
1688 assert!(matches!(
1689 error,
1690 DsigError::KeyResolution(KeyResolutionError::Chain(
1691 super::super::X509ChainError::InvalidKeyUsage {
1692 position: 0,
1693 required: "an approved extended key usage",
1694 }
1695 ))
1696 ));
1697
1698 policy.key_trust.allowed_extended_key_usages =
1699 std::collections::HashSet::from([crate::policy::ExtendedKeyPurpose::ServerAuth]);
1700 assert!(
1701 resolver
1702 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::EcdsaSha256, &policy,)
1703 .expect("approved restricted EKU must pass path validation")
1704 .is_some()
1705 );
1706 }
1707
1708 #[test]
1709 fn operation_policy_rejects_zero_x509_resource_limits() {
1710 for trust in [
1713 crate::policy::KeyTrustPolicy {
1714 verify_x509_chains: true,
1715 max_x509_chain_depth: 0,
1716 ..crate::policy::KeyTrustPolicy::default()
1717 },
1718 crate::policy::KeyTrustPolicy {
1719 verify_x509_chains: true,
1720 max_x509_candidate_paths: 0,
1721 ..crate::policy::KeyTrustPolicy::default()
1722 },
1723 ] {
1724 let certificate = certificate_der(RSA_4096_CERTIFICATE);
1725 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
1726 trusted_certs: vec![certificate],
1727 ..KeyResolverConfig::default()
1728 });
1729 let policy = crate::policy::VerificationPolicy {
1730 key_trust: trust,
1731 ..crate::policy::VerificationPolicy::default()
1732 };
1733 let error = super::super::VerifyContext::new()
1734 .policy(policy)
1735 .key_resolver(&resolver)
1736 .verify(&x509_signature_with_leaf_subject())
1737 .expect_err("zero composed X.509 limits must fail as policy errors");
1738
1739 assert!(matches!(
1740 error,
1741 DsigError::Policy(crate::policy::PolicyViolation::InvalidResourceLimit {
1742 requirement: "limit must be nonzero",
1743 actual: 0,
1744 ..
1745 })
1746 ));
1747 }
1748 }
1749
1750 #[test]
1751 fn operation_policy_rejects_crl_checking_without_chain_validation() {
1752 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
1755 lookup_certs: vec![certificate_der(RSA_4096_CERTIFICATE)],
1756 ..KeyResolverConfig::default()
1757 });
1758 let policy = crate::policy::VerificationPolicy {
1759 key_trust: crate::policy::KeyTrustPolicy {
1760 check_crls: true,
1761 ..crate::policy::KeyTrustPolicy::default()
1762 },
1763 ..crate::policy::VerificationPolicy::default()
1764 };
1765 let error = super::super::VerifyContext::new()
1766 .policy(policy)
1767 .key_resolver(&resolver)
1768 .verify(&x509_signature_with_leaf_subject())
1769 .expect_err("CRL-only trust policy must fail before certificate use");
1770
1771 assert!(matches!(
1772 error,
1773 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust {
1774 reason: "CRL checking requires X.509 chain validation"
1775 })
1776 ));
1777 }
1778
1779 #[test]
1780 fn hmac_key_rejects_empty_secret_and_wrong_algorithm() {
1781 assert!(matches!(
1783 HmacSha1VerificationKey::new(Vec::new()),
1784 Err(KeyResolutionError::InvalidPublicKey)
1785 ));
1786 let key = HmacSha1VerificationKey::new(b"secret".to_vec())
1787 .expect("non-empty HMAC secret must be accepted");
1788 assert!(matches!(
1789 key.verify(SignatureAlgorithm::RsaSha256, b"data", b"signature"),
1790 Err(DsigError::KeyResolution(
1791 KeyResolutionError::AlgorithmMismatch
1792 ))
1793 ));
1794 }
1795
1796 #[test]
1797 fn hmac_key_uses_the_operation_policy_for_truncation() {
1798 let key = HmacVerificationKey::new(b"secret".to_vec())
1802 .expect("the fixture HMAC secret is non-empty");
1803 let mut mac = hmac::Hmac::<sha1::Sha1>::new_from_slice(b"secret")
1804 .expect("HMAC accepts an arbitrary non-empty secret");
1805 mac.update(b"data");
1806 let expected = mac.finalize().into_bytes();
1807
1808 let policy = crate::policy::VerificationPolicy {
1809 hmac: crate::policy::HmacPolicy {
1810 minimum_key_bits: 40,
1811 minimum_output_bits: 80,
1812 },
1813 ..crate::policy::VerificationPolicy::default()
1814 };
1815 assert!(
1816 key.verify_with_policy(
1817 &policy,
1818 SignatureAlgorithm::HmacSha1,
1819 b"data",
1820 &expected[..10],
1821 )
1822 .expect("the compatibility policy and algorithm match")
1823 );
1824 assert!(
1825 !key.verify_with_policy(&policy, SignatureAlgorithm::HmacSha1, b"data", &[0_u8; 10],)
1826 .expect("a mismatched truncated MAC must be rejected")
1827 );
1828 }
1829
1830 #[test]
1831 fn hmac_key_direct_api_rejects_attacker_selected_short_output() {
1832 let key = HmacVerificationKey::new([0x42; 16]).expect("fixed HMAC key must parse");
1835 let mut mac = hmac::Hmac::<sha2::Sha256>::new_from_slice(&[0x42; 16])
1836 .expect("HMAC accepts the fixed secret");
1837 mac.update(b"data");
1838 let expected = mac.finalize().into_bytes();
1839
1840 assert!(matches!(
1841 key.verify(SignatureAlgorithm::HmacSha256, b"data", &expected[..1]),
1842 Err(DsigError::Policy(
1843 crate::policy::PolicyViolation::HmacOutputLength {
1844 minimum: 128,
1845 maximum: 256,
1846 actual: 8,
1847 }
1848 ))
1849 ));
1850 }
1851
1852 #[test]
1853 fn hmac_key_debug_redacts_secret_material() {
1854 let secret = b"unique-debug-secret-marker";
1856 let key = HmacVerificationKey::new(secret.to_vec())
1857 .expect("the fixture HMAC secret is non-empty");
1858
1859 let debug = format!("{key:?}");
1860 assert!(
1861 !debug
1862 .contains(std::str::from_utf8(secret).expect("the debug marker is literal ASCII"))
1863 );
1864 assert!(!debug.contains(&format!("{secret:?}")));
1865 assert!(!debug.contains("output_length_bits"));
1866 }
1867
1868 #[test]
1869 fn stores_named_verification_key_metadata() {
1870 let key = VerificationKey {
1872 algorithm: SignatureAlgorithm::RsaSha256,
1873 public_key_bytes: vec![1, 2, 3],
1874 certificate_der: Some(vec![4, 5, 6]),
1875 name: Some("idp-signing".into()),
1876 };
1877 let mut config = KeyResolverConfig::default();
1878 config.named_keys.insert("idp-signing".into(), key.clone());
1879
1880 assert_eq!(config.named_keys.get("idp-signing"), Some(&key));
1881 }
1882
1883 #[test]
1884 fn resolves_embedded_certificate_end_to_end() {
1885 let resolver = DefaultKeyResolver::default();
1887 let result = super::super::VerifyContext::new()
1888 .key_resolver(&resolver)
1889 .verify(SIGNED_SAML)
1890 .expect("embedded certificate should resolve");
1891
1892 assert_eq!(result.status, super::super::DsigStatus::Valid);
1893 }
1894
1895 #[test]
1896 fn resolves_x509_digest_from_configured_certificates() {
1897 let leaf_certificate_der = certificate_der(RSA_4096_CERTIFICATE);
1900 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
1901 lookup_certs: vec![leaf_certificate_der],
1902 trusted_certs: vec![
1903 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
1904 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
1905 ],
1906 ..KeyResolverConfig::default()
1907 });
1908 for signature in [X509_DIGEST_SHA256_SIGNATURE, X509_DIGEST_SIGNATURE] {
1909 let result = super::super::VerifyContext::new()
1910 .key_resolver(&resolver)
1911 .verify(signature)
1912 .expect("X509Digest should resolve a configured certificate");
1913
1914 assert_eq!(result.status, super::super::DsigStatus::Valid);
1915 }
1916 }
1917
1918 #[test]
1919 fn selector_resolved_certificate_obeys_chain_policy() {
1920 let leaf_certificate_der = certificate_der(RSA_4096_CERTIFICATE);
1923 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
1924 lookup_certs: vec![leaf_certificate_der],
1925 trusted_certs: vec![
1926 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
1927 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
1928 ],
1929 ..KeyResolverConfig::default()
1930 });
1931 let error = super::super::VerifyContext::new()
1932 .policy(verification_policy_with_trust(chain_policy_at(
1933 SystemTime::UNIX_EPOCH,
1934 )))
1935 .key_resolver(&resolver)
1936 .verify(&x509_signature_with_leaf_subject())
1937 .expect_err("selector-resolved certificate must satisfy chain policy");
1938
1939 assert!(
1940 matches!(
1941 &error,
1942 DsigError::KeyResolution(KeyResolutionError::Chain(
1943 super::super::X509ChainError::CertificateNotValid(_)
1944 ))
1945 ),
1946 "unexpected selector policy error: {error:?}"
1947 );
1948 }
1949
1950 #[test]
1951 fn selector_resolved_configured_root_remains_a_trust_anchor() {
1952 let mut params = rcgen::CertificateParams::new(Vec::new())
1955 .expect("empty SAN list should produce valid certificate parameters");
1956 params
1957 .distinguished_name
1958 .push(rcgen::DnType::CommonName, "configured root");
1959 params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
1960 let key_pair = rcgen::KeyPair::generate().expect("test key generation should succeed");
1961 let certificate = params
1962 .self_signed(&key_pair)
1963 .expect("test root should be self-signable");
1964 let certificate_der = certificate.der().to_vec();
1965 let key_info_xml = concat!(
1966 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
1967 "<X509Data><X509SubjectName>CN=configured root</X509SubjectName></X509Data>",
1968 "</KeyInfo>"
1969 );
1970 let document = roxmltree::Document::parse(key_info_xml)
1971 .expect("static selector KeyInfo should parse as XML");
1972 let key_info = super::super::parse_key_info(document.root_element())
1973 .expect("static selector KeyInfo should satisfy XMLDSig structure");
1974 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
1975 trusted_certs: vec![certificate_der],
1976 ..KeyResolverConfig::default()
1977 });
1978
1979 let resolved = resolver
1980 .resolve_with_policy(
1981 Some(&key_info),
1982 SignatureAlgorithm::EcdsaSha256,
1983 &verification_policy_with_trust(chain_policy()),
1984 )
1985 .expect("configured self-signed certificate should validate as its own anchor");
1986
1987 assert!(resolved.is_some());
1988 }
1989
1990 #[test]
1991 fn selector_resolved_non_self_signed_trust_anchor_terminates_the_path() {
1992 let mut issuer_params = rcgen::CertificateParams::new(Vec::new())
1996 .expect("empty issuer SAN list should be valid");
1997 issuer_params
1998 .distinguished_name
1999 .push(rcgen::DnType::CommonName, "lookup-only issuer");
2000 issuer_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2001 issuer_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2002 let issuer = rcgen::CertifiedIssuer::self_signed(
2003 issuer_params,
2004 rcgen::KeyPair::generate().expect("issuer key generation should succeed"),
2005 )
2006 .expect("issuer certificate should be self-signable");
2007
2008 let mut anchor_params = rcgen::CertificateParams::new(Vec::new())
2009 .expect("empty anchor SAN list should be valid");
2010 anchor_params
2011 .distinguished_name
2012 .push(rcgen::DnType::CommonName, "direct trust anchor");
2013 let anchor = anchor_params
2014 .signed_by(
2015 &rcgen::KeyPair::generate().expect("anchor key generation should succeed"),
2016 &issuer,
2017 )
2018 .expect("issuer should sign the directly trusted certificate");
2019 let key_info_xml = concat!(
2020 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
2021 "<X509Data><X509SubjectName>CN=direct trust anchor</X509SubjectName></X509Data>",
2022 "</KeyInfo>"
2023 );
2024 let document = roxmltree::Document::parse(key_info_xml)
2025 .expect("static selector KeyInfo should parse as XML");
2026 let key_info = super::super::parse_key_info(document.root_element())
2027 .expect("static selector KeyInfo should satisfy XMLDSig structure");
2028 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2029 trusted_certs: vec![anchor.der().to_vec()],
2030 lookup_certs: vec![issuer.der().to_vec()],
2031 ..KeyResolverConfig::default()
2032 });
2033
2034 let resolved = resolver
2035 .resolve_with_policy(
2036 Some(&key_info),
2037 SignatureAlgorithm::EcdsaSha256,
2038 &verification_policy_with_trust(chain_policy()),
2039 )
2040 .expect("an explicitly trusted selected certificate must terminate its path");
2041
2042 assert!(resolved.is_some());
2043 }
2044
2045 #[test]
2046 fn selector_resolved_leaf_stops_at_non_self_signed_trust_anchor() {
2047 let external_issuer = rcgen::CertifiedIssuer::self_signed(
2050 generated_certificate_params("external issuer", true),
2051 rcgen::KeyPair::generate().expect("external issuer key generation should succeed"),
2052 )
2053 .expect("external issuer should be self-signable");
2054 let anchor = rcgen::CertifiedIssuer::signed_by(
2055 generated_certificate_params("non-self-signed anchor", true),
2056 rcgen::KeyPair::generate().expect("anchor key generation should succeed"),
2057 &external_issuer,
2058 )
2059 .expect("external issuer should sign the anchor");
2060 let leaf = generated_certificate_params("anchor leaf", false)
2061 .signed_by(
2062 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2063 &anchor,
2064 )
2065 .expect("anchor should sign the leaf");
2066 let leaf_metadata = parse_x509_certificate(leaf.der())
2067 .expect("generated leaf should have supported metadata");
2068 let key_info = KeyInfo {
2069 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
2070 subject_names: vec![leaf_metadata.subject_dn],
2071 ..X509DataInfo::default()
2072 })],
2073 };
2074 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2075 trusted_certs: vec![anchor.der().to_vec()],
2076 lookup_certs: vec![leaf.der().to_vec(), external_issuer.der().to_vec()],
2077 ..KeyResolverConfig::default()
2078 });
2079
2080 let resolved = resolver
2081 .resolve_with_policy(
2082 Some(&key_info),
2083 SignatureAlgorithm::EcdsaSha256,
2084 &verification_policy_with_trust(chain_policy()),
2085 )
2086 .expect("path construction must stop at the configured anchor");
2087
2088 assert!(resolved.is_some());
2089 }
2090
2091 #[test]
2092 fn selector_resolved_leaf_does_not_anchor_itself() {
2093 let certificate_der = certificate_der(RSA_4096_CERTIFICATE);
2096 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2097 lookup_certs: vec![certificate_der],
2098 ..KeyResolverConfig::default()
2099 });
2100 let error = super::super::VerifyContext::new()
2101 .policy(verification_policy_with_trust(chain_policy_at(
2102 fixture_certificate_time(),
2103 )))
2104 .key_resolver(&resolver)
2105 .verify(&x509_signature_with_leaf_subject())
2106 .expect_err("selector-resolved leaf must not trust itself");
2107
2108 assert!(matches!(
2109 error,
2110 DsigError::KeyResolution(KeyResolutionError::Chain(
2111 super::super::X509ChainError::UntrustedRoot
2112 ))
2113 ));
2114 }
2115
2116 #[test]
2117 fn selector_resolved_leaf_uses_separate_anchor() {
2118 let leaf = certificate_der(RSA_4096_CERTIFICATE);
2121 let issuer = certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem"));
2122 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2123 lookup_certs: vec![leaf],
2124 trusted_certs: vec![issuer],
2125 ..KeyResolverConfig::default()
2126 });
2127 let result = super::super::VerifyContext::new()
2128 .policy(verification_policy_with_trust(chain_policy_at(
2129 fixture_certificate_time(),
2130 )))
2131 .key_resolver(&resolver)
2132 .verify(&x509_signature_with_leaf_subject())
2133 .expect("selector-resolved leaf should chain to its configured issuer");
2134
2135 assert_eq!(result.status, super::super::DsigStatus::Valid);
2136 }
2137
2138 #[test]
2139 fn selector_resolved_leaf_uses_lookup_intermediate() {
2140 let mut root_params =
2143 rcgen::CertificateParams::new(Vec::new()).expect("empty root SAN list should be valid");
2144 root_params
2145 .distinguished_name
2146 .push(rcgen::DnType::CommonName, "lookup root");
2147 root_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2148 root_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2149 let root = rcgen::CertifiedIssuer::self_signed(
2150 root_params,
2151 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2152 )
2153 .expect("root certificate should be self-signable");
2154
2155 let mut intermediate_params = rcgen::CertificateParams::new(Vec::new())
2156 .expect("empty intermediate SAN list should be valid");
2157 intermediate_params
2158 .distinguished_name
2159 .push(rcgen::DnType::CommonName, "lookup intermediate");
2160 intermediate_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2161 intermediate_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2162 let intermediate = rcgen::CertifiedIssuer::signed_by(
2163 intermediate_params,
2164 rcgen::KeyPair::generate().expect("intermediate key generation should succeed"),
2165 &root,
2166 )
2167 .expect("root should sign the intermediate certificate");
2168
2169 let mut leaf_params =
2170 rcgen::CertificateParams::new(Vec::new()).expect("empty leaf SAN list should be valid");
2171 leaf_params
2172 .distinguished_name
2173 .push(rcgen::DnType::CommonName, "lookup leaf");
2174 let leaf = leaf_params
2175 .signed_by(
2176 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2177 &intermediate,
2178 )
2179 .expect("intermediate should sign the leaf certificate");
2180 let key_info_xml = concat!(
2181 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
2182 "<X509Data><X509SubjectName>CN=lookup leaf</X509SubjectName></X509Data>",
2183 "</KeyInfo>"
2184 );
2185 let document = roxmltree::Document::parse(key_info_xml)
2186 .expect("static selector KeyInfo should parse as XML");
2187 let key_info = super::super::parse_key_info(document.root_element())
2188 .expect("static selector KeyInfo should satisfy XMLDSig structure");
2189 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2190 lookup_certs: vec![leaf.der().to_vec(), intermediate.der().to_vec()],
2191 trusted_certs: vec![root.der().to_vec()],
2192 ..KeyResolverConfig::default()
2193 });
2194
2195 let resolved = resolver
2196 .resolve_with_policy(
2197 Some(&key_info),
2198 SignatureAlgorithm::EcdsaSha256,
2199 &verification_policy_with_trust(chain_policy()),
2200 )
2201 .expect("selector-resolved leaf should chain through the lookup intermediate");
2202
2203 assert!(resolved.is_some());
2204 }
2205
2206 #[test]
2207 fn x509_path_signatures_use_the_operation_provider() {
2208 let root = rcgen::CertifiedIssuer::self_signed(
2212 generated_certificate_params("provider root", true),
2213 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2214 )
2215 .expect("root should be self-signable");
2216 let leaf = generated_certificate_params("provider leaf", false)
2217 .signed_by(
2218 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2219 &root,
2220 )
2221 .expect("root should sign the leaf");
2222 let leaf_der = leaf.der().to_vec();
2223 let leaf_metadata =
2224 parse_x509_certificate(&leaf_der).expect("generated leaf metadata should parse");
2225 let policy = crate::policy::VerificationPolicy {
2226 key_trust: chain_policy(),
2227 ..crate::policy::VerificationPolicy::default()
2228 };
2229
2230 let cases = [
2231 (
2232 KeyInfo {
2233 sources: vec![KeyInfoSource::X509Data(x509_info(
2234 vec![leaf_der.clone()],
2235 0,
2236 ))],
2237 },
2238 Vec::new(),
2239 ),
2240 (
2241 KeyInfo {
2242 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
2243 subject_names: vec![leaf_metadata.subject_dn],
2244 ..X509DataInfo::default()
2245 })],
2246 },
2247 vec![leaf_der],
2248 ),
2249 ];
2250
2251 for (key_info, lookup_certs) in cases {
2252 let provider = RejectSecondSha512Provider {
2253 sha512_calls: AtomicUsize::new(0),
2254 verification_calls: AtomicUsize::new(0),
2255 reject_verification_call: Some(0),
2256 rejected_verification_data: None,
2257 };
2258 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2259 trusted_certs: vec![root.der().to_vec()],
2260 lookup_certs,
2261 ..KeyResolverConfig::default()
2262 });
2263 let error = match resolver.resolve_with_policy_and_provider(
2264 Some(&key_info),
2265 SignatureAlgorithm::EcdsaSha256,
2266 &policy,
2267 &provider,
2268 ) {
2269 Ok(_) => panic!("the operation provider must gate every X.509 path signature"),
2270 Err(error) => error,
2271 };
2272
2273 assert!(matches!(
2274 error,
2275 DsigError::KeyResolution(KeyResolutionError::Chain(
2276 super::super::X509ChainError::UnsupportedSignatureAlgorithm { ref oid }
2277 )) if oid == "1.2.840.10045.4.3.2"
2278 ));
2279 assert_eq!(provider.verification_calls.load(Ordering::Relaxed), 1);
2280 }
2281
2282 let provider = RejectSecondSha512Provider {
2285 sha512_calls: AtomicUsize::new(0),
2286 verification_calls: AtomicUsize::new(0),
2287 reject_verification_call: Some(1),
2288 rejected_verification_data: None,
2289 };
2290 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2291 trusted_certs: vec![root.der().to_vec()],
2292 ..KeyResolverConfig::default()
2293 });
2294 let key_info = KeyInfo {
2295 sources: vec![KeyInfoSource::X509Data(x509_info(
2296 vec![leaf.der().to_vec()],
2297 0,
2298 ))],
2299 };
2300 let error = match resolver.resolve_with_policy_and_provider(
2301 Some(&key_info),
2302 SignatureAlgorithm::EcdsaSha256,
2303 &policy,
2304 &provider,
2305 ) {
2306 Ok(_) => panic!("complete-path validation must retain the operation provider"),
2307 Err(error) => error,
2308 };
2309 assert!(matches!(
2310 error,
2311 DsigError::KeyResolution(KeyResolutionError::Chain(
2312 super::super::X509ChainError::Provider(_)
2313 ))
2314 ));
2315 assert_eq!(provider.verification_calls.load(Ordering::Relaxed), 2);
2316 }
2317
2318 #[test]
2319 fn embedded_leaf_uses_lookup_intermediate_with_duplicate_anchor() {
2320 let trusted_root = rcgen::CertifiedIssuer::self_signed(
2323 generated_certificate_params("unrelated trusted root", true),
2324 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2325 )
2326 .expect("root should be self-signable");
2327 let issuer_root = rcgen::CertifiedIssuer::self_signed(
2328 generated_certificate_params("untrusted issuer root", true),
2329 rcgen::KeyPair::generate().expect("issuer root key generation should succeed"),
2330 )
2331 .expect("issuer root should be self-signable");
2332 let intermediate = rcgen::CertifiedIssuer::signed_by(
2333 generated_certificate_params("embedded intermediate", true),
2334 rcgen::KeyPair::generate().expect("intermediate key generation should succeed"),
2335 &issuer_root,
2336 )
2337 .expect("issuer root should sign the intermediate");
2338 let leaf = generated_certificate_params("embedded leaf", false)
2339 .signed_by(
2340 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2341 &intermediate,
2342 )
2343 .expect("intermediate should sign the leaf");
2344 let key_info = KeyInfo {
2345 sources: vec![KeyInfoSource::X509Data(x509_info(
2346 vec![leaf.der().to_vec()],
2347 0,
2348 ))],
2349 };
2350 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2351 lookup_certs: vec![intermediate.der().to_vec()],
2352 trusted_certs: vec![trusted_root.der().to_vec(), trusted_root.der().to_vec()],
2353 ..KeyResolverConfig::default()
2354 });
2355
2356 let policy = verification_policy_with_trust(chain_policy());
2357 let error = match resolver.resolve_with_policy(
2358 Some(&key_info),
2359 SignatureAlgorithm::EcdsaSha256,
2360 &policy,
2361 ) {
2362 Ok(_) => panic!("an untrusted lookup intermediate must not become a trust anchor"),
2363 Err(error) => error,
2364 };
2365
2366 assert!(matches!(
2367 error,
2368 DsigError::KeyResolution(KeyResolutionError::Chain(
2369 super::super::X509ChainError::UntrustedRoot
2370 ))
2371 ));
2372 }
2373
2374 #[test]
2375 fn selector_resolved_leaf_chooses_unique_valid_same_key_path() {
2376 let trusted_root = rcgen::CertifiedIssuer::self_signed(
2380 generated_certificate_params("trusted cross-sign root", true),
2381 rcgen::KeyPair::generate().expect("trusted root key generation should succeed"),
2382 )
2383 .expect("trusted root should be self-signable");
2384 let untrusted_root = rcgen::CertifiedIssuer::self_signed(
2385 generated_certificate_params("untrusted cross-sign root", true),
2386 rcgen::KeyPair::generate().expect("untrusted root key generation should succeed"),
2387 )
2388 .expect("untrusted root should be self-signable");
2389 let shared_params = generated_certificate_params("shared cross-sign issuer", true);
2390 let shared_key =
2391 rcgen::KeyPair::generate().expect("shared issuer key generation should succeed");
2392 let trusted_intermediate = shared_params
2393 .signed_by(&shared_key, &trusted_root)
2394 .expect("trusted root should cross-sign the shared issuer key");
2395 let untrusted_intermediate = shared_params
2396 .signed_by(&shared_key, &untrusted_root)
2397 .expect("untrusted root should cross-sign the shared issuer key");
2398 let shared_issuer = rcgen::Issuer::from_params(&shared_params, &shared_key);
2399 let leaf = generated_certificate_params("cross-signed leaf", false)
2400 .signed_by(
2401 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2402 &shared_issuer,
2403 )
2404 .expect("shared issuer key should sign the leaf");
2405 let leaf_metadata = parse_x509_certificate(leaf.der())
2406 .expect("generated leaf should have supported metadata");
2407 let key_info = KeyInfo {
2408 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
2409 subject_names: vec![leaf_metadata.subject_dn],
2410 ..X509DataInfo::default()
2411 })],
2412 };
2413 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2414 trusted_certs: vec![trusted_root.der().to_vec()],
2415 lookup_certs: vec![
2416 leaf.der().to_vec(),
2417 untrusted_intermediate.der().to_vec(),
2418 trusted_intermediate.der().to_vec(),
2419 untrusted_root.der().to_vec(),
2420 ],
2421 ..KeyResolverConfig::default()
2422 });
2423
2424 let resolved = resolver
2425 .resolve_with_policy(
2426 Some(&key_info),
2427 SignatureAlgorithm::EcdsaSha256,
2428 &verification_policy_with_trust(chain_policy()),
2429 )
2430 .expect("the sole path to a configured anchor should be selected");
2431
2432 assert!(resolved.is_some());
2433 }
2434
2435 #[test]
2436 fn self_issued_rollover_continues_to_same_name_trusted_signer() {
2437 let root = rcgen::CertifiedIssuer::self_signed(
2440 generated_certificate_params("rollover authority", true),
2441 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2442 )
2443 .expect("root should be self-signable");
2444 let rollover_params = generated_certificate_params("rollover authority", true);
2445 let rollover_key =
2446 rcgen::KeyPair::generate().expect("rollover key generation should succeed");
2447 let rollover_certificate = rollover_params
2448 .signed_by(&rollover_key, &root)
2449 .expect("root should sign the same-name rollover certificate");
2450 let rollover_issuer = rcgen::Issuer::from_params(&rollover_params, &rollover_key);
2451 let leaf = generated_certificate_params("rollover leaf", false)
2452 .signed_by(
2453 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2454 &rollover_issuer,
2455 )
2456 .expect("rollover key should sign the leaf");
2457 let leaf_metadata =
2458 parse_x509_certificate(leaf.der()).expect("generated leaf metadata should parse");
2459 let key_info = KeyInfo {
2460 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
2461 subject_names: vec![leaf_metadata.subject_dn],
2462 ..X509DataInfo::default()
2463 })],
2464 };
2465 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2466 trusted_certs: vec![root.der().to_vec()],
2467 lookup_certs: vec![leaf.der().to_vec(), rollover_certificate.der().to_vec()],
2468 ..KeyResolverConfig::default()
2469 });
2470
2471 let resolved = resolver
2472 .resolve_with_policy(
2473 Some(&key_info),
2474 SignatureAlgorithm::EcdsaSha256,
2475 &verification_policy_with_trust(chain_policy()),
2476 )
2477 .expect("same-name rollover path must reach its configured signer");
2478
2479 assert!(resolved.is_some());
2480 }
2481
2482 #[test]
2483 fn x509_candidate_limit_counts_generated_partial_paths() {
2484 let root = rcgen::CertifiedIssuer::self_signed(
2487 generated_certificate_params("candidate root", true),
2488 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2489 )
2490 .expect("root should be self-signable");
2491 let intermediate = rcgen::CertifiedIssuer::signed_by(
2492 generated_certificate_params("candidate intermediate", true),
2493 rcgen::KeyPair::generate().expect("intermediate key generation should succeed"),
2494 &root,
2495 )
2496 .expect("root should sign the intermediate");
2497 let leaf = generated_certificate_params("candidate leaf", false)
2498 .signed_by(
2499 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2500 &intermediate,
2501 )
2502 .expect("intermediate should sign the leaf");
2503 let info = x509_info(
2504 vec![
2505 root.der().to_vec(),
2506 intermediate.der().to_vec(),
2507 leaf.der().to_vec(),
2508 ],
2509 2,
2510 );
2511
2512 assert!(matches!(
2513 build_x509_certificate_paths_to_trusted_prefix(
2514 &info,
2515 2,
2516 1,
2517 9,
2518 2,
2519 crate::provider::default_provider(),
2520 ),
2521 Err(X509ChainBuildError::AmbiguousIssuer)
2522 ));
2523 }
2524
2525 #[test]
2526 fn selector_resolved_leaf_disambiguates_same_subject_issuers_by_signature() {
2527 let mut root_params =
2531 rcgen::CertificateParams::new(Vec::new()).expect("empty root SAN list should be valid");
2532 root_params
2533 .distinguished_name
2534 .push(rcgen::DnType::CommonName, "shared-issuer root");
2535 root_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2536 root_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2537 let root = rcgen::CertifiedIssuer::self_signed(
2538 root_params,
2539 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2540 )
2541 .expect("root certificate should be self-signable");
2542
2543 let intermediate = |key: rcgen::KeyPair| {
2544 let mut params = rcgen::CertificateParams::new(Vec::new())
2545 .expect("empty intermediate SAN list should be valid");
2546 params
2547 .distinguished_name
2548 .push(rcgen::DnType::CommonName, "renewed intermediate");
2549 params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2550 params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2551 rcgen::CertifiedIssuer::signed_by(params, key, &root)
2552 .expect("root should sign the intermediate certificate")
2553 };
2554 let unrelated_intermediate = intermediate(
2555 rcgen::KeyPair::generate().expect("unrelated intermediate key generation should work"),
2556 );
2557 let signing_intermediate = intermediate(
2558 rcgen::KeyPair::generate().expect("signing intermediate key generation should work"),
2559 );
2560
2561 let mut leaf_params =
2562 rcgen::CertificateParams::new(Vec::new()).expect("empty leaf SAN list should be valid");
2563 leaf_params
2564 .distinguished_name
2565 .push(rcgen::DnType::CommonName, "same-subject leaf");
2566 let leaf = leaf_params
2567 .signed_by(
2568 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2569 &signing_intermediate,
2570 )
2571 .expect("the selected intermediate should sign the leaf certificate");
2572 let key_info_xml = concat!(
2573 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
2574 "<X509Data><X509SubjectName>CN=same-subject leaf</X509SubjectName></X509Data>",
2575 "</KeyInfo>"
2576 );
2577 let document = roxmltree::Document::parse(key_info_xml)
2578 .expect("static selector KeyInfo should parse as XML");
2579 let key_info = super::super::parse_key_info(document.root_element())
2580 .expect("static selector KeyInfo should satisfy XMLDSig structure");
2581 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2582 lookup_certs: vec![
2583 leaf.der().to_vec(),
2584 unrelated_intermediate.der().to_vec(),
2585 signing_intermediate.der().to_vec(),
2586 ],
2587 trusted_certs: vec![root.der().to_vec()],
2588 ..KeyResolverConfig::default()
2589 });
2590
2591 let resolved = resolver
2592 .resolve_with_policy(
2593 Some(&key_info),
2594 SignatureAlgorithm::EcdsaSha256,
2595 &verification_policy_with_trust(chain_policy()),
2596 )
2597 .expect("the leaf signature should select its unique same-subject issuer");
2598
2599 assert!(resolved.is_some());
2600 }
2601
2602 #[test]
2603 fn x509_path_builder_skips_branch_local_unsupported_algorithms() {
2604 let root = rcgen::CertifiedIssuer::self_signed(
2608 generated_certificate_params("unsupported-edge root", true),
2609 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2610 )
2611 .expect("root certificate should be self-signable");
2612 let signing_intermediate = rcgen::CertifiedIssuer::signed_by(
2613 generated_certificate_params("shared unsupported-edge issuer", true),
2614 rcgen::KeyPair::generate().expect("signing issuer key generation should succeed"),
2615 &root,
2616 )
2617 .expect("root should sign the intermediate certificate");
2618 let key_unsupported_intermediate = rcgen::CertifiedIssuer::signed_by(
2619 generated_certificate_params("shared unsupported-edge issuer", true),
2620 rcgen::KeyPair::generate().expect("unsupported issuer key generation should succeed"),
2621 &root,
2622 )
2623 .expect("root should sign the alternate intermediate certificate");
2624 let leaf = generated_certificate_params("unsupported-edge leaf", false)
2625 .signed_by(
2626 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2627 &signing_intermediate,
2628 )
2629 .expect("signing intermediate should sign the leaf");
2630
2631 let ordered = x509_info(
2632 vec![
2633 leaf.der().to_vec(),
2634 key_unsupported_intermediate.der().to_vec(),
2635 signing_intermediate.der().to_vec(),
2636 root.der().to_vec(),
2637 ],
2638 0,
2639 );
2640 let key_selective_provider = RejectSecondSha512Provider {
2641 sha512_calls: AtomicUsize::new(0),
2642 verification_calls: AtomicUsize::new(0),
2643 reject_verification_call: Some(0),
2644 rejected_verification_data: None,
2645 };
2646 assert_eq!(
2647 super::super::parse::build_x509_certificate_chain_from(
2648 &ordered,
2649 0,
2650 &key_selective_provider,
2651 )
2652 .expect("one unsupported issuer key must not suppress a usable candidate"),
2653 vec![0, 2, 3]
2654 );
2655
2656 let anchored_same_edge = x509_info(
2657 vec![
2658 root.der().to_vec(),
2659 leaf.der().to_vec(),
2660 key_unsupported_intermediate.der().to_vec(),
2661 signing_intermediate.der().to_vec(),
2662 ],
2663 1,
2664 );
2665 let first_candidate_unsupported = RejectSecondSha512Provider {
2666 sha512_calls: AtomicUsize::new(0),
2667 verification_calls: AtomicUsize::new(0),
2668 reject_verification_call: Some(0),
2669 rejected_verification_data: None,
2670 };
2671 assert_eq!(
2672 build_x509_certificate_paths_to_trusted_prefix(
2673 &anchored_same_edge,
2674 1,
2675 1,
2676 4,
2677 8,
2678 &first_candidate_unsupported,
2679 )
2680 .expect("a later same-DN issuer must survive an earlier provider capability miss"),
2681 vec![vec![1, 3, 0]]
2682 );
2683
2684 let mut unsupported_intermediate = signing_intermediate.der().to_vec();
2685 let ecdsa_sha256_oid = [0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02];
2686 let offsets = unsupported_intermediate
2687 .windows(ecdsa_sha256_oid.len())
2688 .enumerate()
2689 .filter_map(|(offset, window)| (window == ecdsa_sha256_oid).then_some(offset))
2690 .collect::<Vec<_>>();
2691 assert_eq!(
2692 offsets.len(),
2693 2,
2694 "certificate must repeat its signature OID"
2695 );
2696 for offset in offsets {
2697 unsupported_intermediate[offset + ecdsa_sha256_oid.len() - 1] = 0x05;
2698 }
2699
2700 let anchored = x509_info(
2701 vec![
2702 root.der().to_vec(),
2703 leaf.der().to_vec(),
2704 signing_intermediate.der().to_vec(),
2705 unsupported_intermediate,
2706 ],
2707 1,
2708 );
2709 assert_eq!(
2710 build_x509_certificate_paths_to_trusted_prefix(
2711 &anchored,
2712 1,
2713 1,
2714 4,
2715 8,
2716 crate::provider::default_provider(),
2717 )
2718 .expect("a branch-local provider gap must not abort path enumeration"),
2719 vec![vec![1, 2, 0]]
2720 );
2721
2722 let unsupported_only = x509_info(
2723 vec![
2724 root.der().to_vec(),
2725 leaf.der().to_vec(),
2726 anchored.certificates[3].clone(),
2727 ],
2728 1,
2729 );
2730 assert!(matches!(
2731 build_x509_certificate_paths_to_trusted_prefix(
2732 &unsupported_only,
2733 1,
2734 1,
2735 4,
2736 8,
2737 crate::provider::default_provider(),
2738 ),
2739 Err(X509ChainBuildError::UnsupportedSignatureAlgorithm { ref oid })
2740 if oid == "1.2.840.10045.4.3.5"
2741 ));
2742 }
2743
2744 #[test]
2745 fn selector_resolved_certificate_preserves_supplied_crls() {
2746 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>";
2747 let crl = crl_der(include_str!(
2748 "../../tests/fixtures/keys/rsa/rsa-2048-cert-revoked-crl.pem"
2749 ));
2750 let (_, parsed_crl) =
2751 x509_parser::revocation_list::CertificateRevocationList::from_der(&crl)
2752 .expect("tracked CRL must parse");
2753 let crl_signed_data = parsed_crl.tbs_cert_list.as_ref().to_vec();
2754 let xml = replace_unprefixed_key_info(
2755 RSA_KEY_VALUE_SIGNATURE,
2756 &selector.replace("CRL_PLACEHOLDER", &STANDARD.encode(&crl)),
2757 );
2758 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2759 lookup_certs: vec![certificate_der(include_str!(
2760 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
2761 ))],
2762 trusted_certs: vec![
2763 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
2764 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
2765 ],
2766 ..KeyResolverConfig::default()
2767 });
2768 let policy = verification_policy_with_trust(crate::policy::KeyTrustPolicy {
2769 check_crls: true,
2770 max_x509_chain_depth: 3,
2771 ..chain_policy_at(
2772 SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_773_964_800),
2773 )
2774 });
2775
2776 let error = super::super::VerifyContext::new()
2777 .policy(policy.clone())
2778 .key_resolver(&resolver)
2779 .verify(&xml)
2780 .expect_err("selector lookup must retain and enforce the supplied CRL");
2781 assert!(matches!(
2785 error,
2786 DsigError::KeyResolution(KeyResolutionError::Chain(
2787 super::super::X509ChainError::InvalidKeyUsage {
2788 position: 1,
2789 required: "cRLSign"
2790 }
2791 ))
2792 ));
2793
2794 let provider = RejectSecondSha512Provider {
2798 sha512_calls: AtomicUsize::new(0),
2799 verification_calls: AtomicUsize::new(0),
2800 reject_verification_call: None,
2801 rejected_verification_data: Some(crl_signed_data),
2802 };
2803 let error = super::super::VerifyContext::new()
2804 .policy(policy)
2805 .key_resolver(&resolver)
2806 .provider(&provider)
2807 .verify(&xml)
2808 .expect_err("CRL authentication must retain the operation provider");
2809 assert!(matches!(
2810 error,
2811 DsigError::KeyResolution(KeyResolutionError::Chain(
2812 super::super::X509ChainError::Provider(_)
2813 ))
2814 ));
2815 }
2816
2817 #[test]
2818 fn resolver_rejects_revoked_leaf_with_authorized_crl_issuer() {
2819 let (mut info, root) = authorized_revoked_chain();
2822 let issuer = info.certificates[1].clone();
2823 info.certificates.truncate(1);
2824 info.parsed_certificates.truncate(1);
2825 let key_info = KeyInfo {
2826 sources: vec![KeyInfoSource::X509Data(info)],
2827 };
2828 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2829 lookup_certs: vec![issuer],
2830 trusted_certs: vec![root],
2831 ..KeyResolverConfig::default()
2832 });
2833 let policy = verification_policy_with_trust(crate::policy::KeyTrustPolicy {
2834 check_crls: true,
2835 max_x509_chain_depth: 3,
2836 ..chain_policy_at(
2837 SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_773_964_800),
2838 )
2839 });
2840
2841 let error = match resolver.resolve_with_policy(
2842 Some(&key_info),
2843 SignatureAlgorithm::EcdsaSha256,
2844 &policy,
2845 ) {
2846 Ok(_) => panic!("an authenticated CRL must reject its revoked leaf"),
2847 Err(error) => error,
2848 };
2849 assert!(matches!(
2850 error,
2851 DsigError::KeyResolution(KeyResolutionError::Chain(
2852 super::super::X509ChainError::Revoked(0)
2853 ))
2854 ));
2855 }
2856
2857 #[test]
2858 fn resolves_each_x509_selector_from_configured_certificates() {
2859 let selectors = [
2862 "<X509SubjectName>CN=Test Key rsa-2048,O=XML Security Library (http://www.aleksey.com/xmlsec),ST=California,C=US</X509SubjectName>",
2863 "<X509SubjectName>CN= test key rsa-2048 ,O=xml security library (HTTP://WWW.ALEKSEY.COM/XMLSEC),ST=california,C=us</X509SubjectName>",
2864 "<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>",
2865 "<X509SKI>bcOXN/nsVl8GatRbcKrPbzIbw0Y=</X509SKI>",
2866 ];
2867 let configured_certificate = certificate_der(include_str!(
2868 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
2869 ));
2870
2871 for selector in selectors {
2872 let key_info = format!("<KeyInfo><X509Data>{selector}</X509Data></KeyInfo>");
2873 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
2874 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2875 lookup_certs: vec![configured_certificate.clone()],
2876 ..KeyResolverConfig::default()
2877 });
2878 let result = super::super::VerifyContext::new()
2879 .key_resolver(&resolver)
2880 .verify(&xml)
2881 .expect("X509 selector should resolve configured certificate");
2882
2883 assert_eq!(result.status, super::super::DsigStatus::Valid);
2884 }
2885 }
2886
2887 #[test]
2888 fn resolves_configured_chain_selectors_across_certificates() {
2889 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>"#;
2892 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
2893 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2894 lookup_certs: vec![
2895 certificate_der(include_str!(
2896 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
2897 )),
2898 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
2899 ],
2900 ..KeyResolverConfig::default()
2901 });
2902 let result = super::super::VerifyContext::new()
2903 .key_resolver(&resolver)
2904 .verify(&xml)
2905 .expect("selectors across one configured chain should resolve its leaf");
2906
2907 assert_eq!(result.status, super::super::DsigStatus::Valid);
2908 }
2909
2910 #[test]
2911 fn selectors_must_all_match_the_selected_certificate_path() {
2912 let signing_certificate = certificate_der(include_str!(
2915 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
2916 ));
2917 let issuer_certificate =
2918 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem"));
2919 let unrelated = generated_certificate_params("unrelated selector certificate", false)
2920 .self_signed(
2921 &rcgen::KeyPair::generate().expect("unrelated key generation should succeed"),
2922 )
2923 .expect("unrelated certificate should be self-signable")
2924 .der()
2925 .to_vec();
2926 let digest = crate::provider::default_provider()
2927 .digest(super::super::DigestAlgorithm::Sha256, &unrelated)
2928 .expect("SHA-256 selector digest must be available");
2929 let key_info_xml = format!(
2930 "<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>",
2931 STANDARD.encode(digest)
2932 );
2933 let document = roxmltree::Document::parse(&key_info_xml)
2934 .expect("generated selector KeyInfo must be XML");
2935 let key_info = super::super::parse_key_info(document.root_element())
2936 .expect("generated selector KeyInfo must be structurally valid");
2937 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2938 lookup_certs: vec![signing_certificate, issuer_certificate, unrelated],
2939 ..KeyResolverConfig::default()
2940 });
2941
2942 assert!(
2943 resolver
2944 .resolve(Some(&key_info), SignatureAlgorithm::RsaSha256)
2945 .expect("disjoint selector matches are a key miss")
2946 .is_none()
2947 );
2948 }
2949
2950 #[test]
2951 fn unmatched_x509_selector_does_not_resolve() {
2952 let key_info = "<KeyInfo><X509Data><X509SubjectName>CN=not-the-signer</X509SubjectName></X509Data></KeyInfo>";
2954 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
2955 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2956 lookup_certs: vec![certificate_der(include_str!(
2957 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
2958 ))],
2959 ..KeyResolverConfig::default()
2960 });
2961 let result = super::super::VerifyContext::new()
2962 .key_resolver(&resolver)
2963 .verify(&xml)
2964 .expect("an unmatched selector is a key miss, not a parser failure");
2965
2966 assert!(matches!(
2967 result.status,
2968 super::super::DsigStatus::Invalid(super::super::FailureReason::KeyNotFound)
2969 ));
2970 }
2971
2972 #[test]
2973 fn overlapping_trusted_and_lookup_certificate_preserves_trust() {
2974 let certificate = certificate_der(RSA_4096_CERTIFICATE);
2977 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2978 trusted_certs: vec![certificate.clone()],
2979 lookup_certs: vec![certificate],
2980 ..KeyResolverConfig::default()
2981 });
2982 let result = super::super::VerifyContext::new()
2983 .policy(verification_policy_with_trust(chain_policy_at(
2984 fixture_certificate_time(),
2985 )))
2986 .key_resolver(&resolver)
2987 .verify(&x509_signature_with_leaf_subject())
2988 .expect("trusted/lookup overlap must resolve as one trusted candidate");
2989
2990 assert_eq!(result.status, super::super::DsigStatus::Valid);
2991 }
2992
2993 #[test]
2994 fn distinct_x509_selector_matches_remain_ambiguous() {
2995 let certificate = || {
2998 generated_certificate_params("ambiguous selector", false)
2999 .self_signed(
3000 &rcgen::KeyPair::generate().expect("test key generation should succeed"),
3001 )
3002 .expect("test certificate should be self-signable")
3003 .der()
3004 .to_vec()
3005 };
3006 let xml = replace_unprefixed_key_info(
3007 X509_DIGEST_SIGNATURE,
3008 "<KeyInfo><X509Data><X509SubjectName>CN=ambiguous selector</X509SubjectName></X509Data></KeyInfo>",
3009 );
3010 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3011 lookup_certs: vec![certificate(), certificate()],
3012 ..KeyResolverConfig::default()
3013 });
3014 let error = super::super::VerifyContext::new()
3015 .key_resolver(&resolver)
3016 .verify(&xml)
3017 .expect_err("distinct selector matches must fail closed");
3018
3019 assert!(matches!(
3020 error,
3021 DsigError::KeyResolution(KeyResolutionError::AmbiguousCertificate)
3022 ));
3023 }
3024
3025 #[test]
3026 fn unsupported_x509_digest_selector_fails_closed() {
3027 let key_info = "<KeyInfo xmlns:dsig11=\"http://www.w3.org/2009/xmldsig11#\"><X509Data><dsig11:X509Digest Algorithm=\"urn:unsupported\">AQ==</dsig11:X509Digest></X509Data></KeyInfo>";
3030 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
3031 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3032 lookup_certs: vec![certificate_der(include_str!(
3033 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
3034 ))],
3035 ..KeyResolverConfig::default()
3036 });
3037 let error = super::super::VerifyContext::new()
3038 .key_resolver(&resolver)
3039 .verify(&xml)
3040 .expect_err("unsupported X509Digest algorithm must fail closed");
3041
3042 assert!(matches!(
3043 error,
3044 DsigError::KeyResolution(KeyResolutionError::UnsupportedDigestAlgorithm(uri))
3045 if uri == "urn:unsupported"
3046 ));
3047 }
3048
3049 #[test]
3050 fn x509_digest_selector_uses_operation_provider() {
3051 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3054 lookup_certs: vec![certificate_der(RSA_4096_CERTIFICATE)],
3055 trusted_certs: vec![
3056 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
3057 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
3058 ],
3059 ..KeyResolverConfig::default()
3060 });
3061 let provider = RejectSecondSha512Provider {
3062 sha512_calls: AtomicUsize::new(0),
3063 verification_calls: AtomicUsize::new(0),
3064 reject_verification_call: None,
3065 rejected_verification_data: None,
3066 };
3067 let error = super::super::VerifyContext::new()
3068 .key_resolver(&resolver)
3069 .provider(&provider)
3070 .verify(X509_DIGEST_SIGNATURE)
3071 .expect_err("X509Digest selection must use the operation provider");
3072
3073 assert!(
3074 matches!(
3075 error,
3076 DsigError::Provider(crate::provider::ProviderError::Unsupported {
3077 operation: crate::provider::ProviderOperation::Digest,
3078 algorithm: Some(ref uri),
3079 }) if uri == super::super::DigestAlgorithm::Sha512.uri()
3080 ),
3081 "unexpected error: {error:?}"
3082 );
3083 }
3084
3085 #[test]
3086 fn resolves_named_key_end_to_end() {
3087 let xml = replace_key_info(
3089 SIGNED_SAML,
3090 "<ds:KeyInfo><ds:KeyName>idp-signing</ds:KeyName></ds:KeyInfo>",
3091 );
3092 let mut config = KeyResolverConfig::default();
3093 config.named_keys.insert(
3094 "idp-signing".into(),
3095 VerificationKey {
3096 algorithm: SignatureAlgorithm::EcdsaSha256,
3097 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3098 certificate_der: None,
3099 name: Some("idp-signing".into()),
3100 },
3101 );
3102 let resolver = DefaultKeyResolver::new(config);
3103 let result = super::super::VerifyContext::new()
3104 .key_resolver(&resolver)
3105 .verify(&xml)
3106 .expect("named key should resolve");
3107
3108 assert_eq!(result.status, super::super::DsigStatus::Valid);
3109 }
3110
3111 #[test]
3112 fn resolves_der_encoded_key_end_to_end() {
3113 let encoded = STANDARD.encode(public_key_der(SAML_PUBLIC_KEY));
3115 let xml = replace_key_info(
3116 SIGNED_SAML,
3117 &format!(
3118 "<ds:KeyInfo><dsig11:DEREncodedKeyValue xmlns:dsig11=\"http://www.w3.org/2009/xmldsig11#\">{encoded}</dsig11:DEREncodedKeyValue></ds:KeyInfo>"
3119 ),
3120 );
3121 let resolver = DefaultKeyResolver::default();
3122 let result = super::super::VerifyContext::new()
3123 .key_resolver(&resolver)
3124 .verify(&xml)
3125 .expect("DER key should resolve");
3126
3127 assert_eq!(result.status, super::super::DsigStatus::Valid);
3128 }
3129
3130 #[test]
3131 fn resolves_rsa_key_value_end_to_end() {
3132 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
3134 .expect("fixture must contain an RSA public key");
3135 let (modulus, exponent) = rsa_key_value_parts(&public_key);
3136 let key_info = format!(
3137 "<KeyInfo><KeyValue><RSAKeyValue><Modulus>{}</Modulus><Exponent>{}</Exponent></RSAKeyValue></KeyValue></KeyInfo>",
3138 modulus, exponent,
3139 );
3140 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
3141 let resolver = DefaultKeyResolver::default();
3142 let result = super::super::VerifyContext::new()
3143 .key_resolver(&resolver)
3144 .verify(&xml)
3145 .expect("RSAKeyValue should resolve");
3146
3147 assert_eq!(result.status, super::super::DsigStatus::Valid);
3148 }
3149
3150 #[test]
3151 fn rsa_key_value_rejects_legacy_weak_modulus() {
3152 let resolver = DefaultKeyResolver::default();
3155 let error = super::super::VerifyContext::new()
3156 .key_resolver(&resolver)
3157 .verify(LEGACY_RSA_KEY_VALUE_SIGNATURE)
3158 .expect_err("context policy must override permissive resolver defaults");
3159
3160 assert!(matches!(
3161 error,
3162 DsigError::Policy(crate::policy::PolicyViolation::Algorithm {
3163 operation: "verification",
3164 ..
3165 })
3166 ));
3167 }
3168
3169 #[test]
3170 fn operation_policy_rejects_disabled_embedded_key_source() {
3171 let key_info = KeyInfo {
3174 sources: vec![KeyInfoSource::KeyValue(KeyValueInfo::Rsa {
3175 modulus: vec![0x80; 256],
3176 exponent: vec![1, 0, 1],
3177 })],
3178 };
3179 let mut policy = crate::policy::VerificationPolicy::default();
3180 policy.key_sources.key_value = false;
3181
3182 let error = match DefaultKeyResolver::default().resolve_with_policy(
3183 Some(&key_info),
3184 SignatureAlgorithm::RsaSha256,
3185 &policy,
3186 ) {
3187 Ok(_) => panic!("disabled KeyValue must fail before key construction"),
3188 Err(error) => error,
3189 };
3190
3191 assert!(matches!(
3192 error,
3193 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust {
3194 reason: "KeyValue key sources are disabled"
3195 })
3196 ));
3197 }
3198
3199 #[test]
3200 fn operation_policy_preflights_every_key_info_source_before_resolution() {
3201 let mut config = KeyResolverConfig::default();
3204 config.named_keys.insert(
3205 "idp-signing".into(),
3206 VerificationKey {
3207 algorithm: SignatureAlgorithm::EcdsaSha256,
3208 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3209 certificate_der: None,
3210 name: Some("idp-signing".into()),
3211 },
3212 );
3213 let resolver = DefaultKeyResolver::new(config);
3214 let mut policy = crate::policy::VerificationPolicy::default();
3215 policy.key_sources.x509_data = false;
3216
3217 for sources in [
3218 vec![
3219 KeyInfoSource::KeyName("idp-signing".into()),
3220 KeyInfoSource::X509Data(X509DataInfo::default()),
3221 ],
3222 vec![
3223 KeyInfoSource::X509Data(X509DataInfo::default()),
3224 KeyInfoSource::KeyName("idp-signing".into()),
3225 ],
3226 ] {
3227 let error = match resolver.resolve_with_policy(
3228 Some(&KeyInfo { sources }),
3229 SignatureAlgorithm::EcdsaSha256,
3230 &policy,
3231 ) {
3232 Ok(_) => panic!("source order must not hide disabled X509Data"),
3233 Err(error) => error,
3234 };
3235
3236 assert!(matches!(
3237 error,
3238 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust {
3239 reason: "X509Data key sources are disabled"
3240 })
3241 ));
3242 }
3243 }
3244
3245 #[test]
3246 fn operation_policy_bounds_ordered_key_info_candidates() {
3247 let mut config = KeyResolverConfig::default();
3250 config.named_keys.insert(
3251 "idp-signing".into(),
3252 VerificationKey {
3253 algorithm: SignatureAlgorithm::EcdsaSha256,
3254 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3255 certificate_der: None,
3256 name: Some("idp-signing".into()),
3257 },
3258 );
3259 let resolver = DefaultKeyResolver::new(config);
3260 let key_info = KeyInfo {
3261 sources: vec![
3262 KeyInfoSource::KeyValue(KeyValueInfo::Ec {
3263 curve_oid: "1.3.132.0.35".into(),
3264 public_key: vec![4],
3265 }),
3266 KeyInfoSource::KeyName("idp-signing".into()),
3267 ],
3268 };
3269
3270 for maximum in [0, 1] {
3271 let mut policy = crate::policy::VerificationPolicy::default();
3272 policy.resources.max_key_candidates = maximum;
3273 let error = match resolver.resolve_with_policy(
3274 Some(&key_info),
3275 SignatureAlgorithm::EcdsaSha256,
3276 &policy,
3277 ) {
3278 Ok(_) => panic!("candidate ceiling {maximum} must stop resolution"),
3279 Err(error) => error,
3280 };
3281 assert!(matches!(
3282 error,
3283 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
3284 resource: crate::policy::resource_name::KEY_CANDIDATES,
3285 maximum: observed,
3286 actual,
3287 }) if observed == maximum && actual == maximum + 1
3288 ));
3289 }
3290
3291 let mut policy = crate::policy::VerificationPolicy::default();
3292 policy.resources.max_key_candidates = 2;
3293 assert!(
3294 resolver
3295 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::EcdsaSha256, &policy,)
3296 .expect("two allowed attempts must reach the named key")
3297 .is_some()
3298 );
3299 }
3300
3301 #[test]
3302 fn operation_policy_bounds_configured_x509_selector_candidates() {
3303 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3307 lookup_certs: vec![
3308 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
3309 certificate_der(RSA_4096_CERTIFICATE),
3310 ],
3311 ..KeyResolverConfig::default()
3312 });
3313 let mut policy = crate::policy::VerificationPolicy::default();
3314 policy.resources.max_key_candidates = 1;
3315
3316 let error = super::super::VerifyContext::new()
3317 .policy(policy)
3318 .key_resolver(&resolver)
3319 .verify(&x509_signature_with_leaf_subject())
3320 .expect_err("the second configured certificate must exceed the candidate budget");
3321
3322 assert!(matches!(
3323 error,
3324 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
3325 resource: crate::policy::resource_name::KEY_CANDIDATES,
3326 maximum: 1,
3327 actual: 2,
3328 })
3329 ));
3330 }
3331
3332 #[test]
3333 fn operation_policy_bounds_embedded_x509_certificate_candidates() {
3334 let key_info = KeyInfo {
3338 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
3339 certificates: vec![
3340 certificate_der(RSA_4096_CERTIFICATE),
3341 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
3342 ],
3343 certificate_chain: vec![0],
3344 ..X509DataInfo::default()
3345 })],
3346 };
3347 let mut policy = crate::policy::VerificationPolicy::default();
3348 policy.resources.max_key_candidates = 1;
3349
3350 let error = match DefaultKeyResolver::default().resolve_with_policy(
3351 Some(&key_info),
3352 SignatureAlgorithm::RsaSha256,
3353 &policy,
3354 ) {
3355 Ok(_) => panic!("the second embedded certificate must exceed the candidate budget"),
3356 Err(error) => error,
3357 };
3358
3359 assert!(matches!(
3360 error,
3361 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
3362 resource: crate::policy::resource_name::KEY_CANDIDATES,
3363 maximum: 1,
3364 actual: 2,
3365 })
3366 ));
3367 }
3368
3369 #[test]
3370 fn operation_policy_charges_duplicate_configured_x509_candidates() {
3371 let certificate = certificate_der(RSA_4096_CERTIFICATE);
3374 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3375 lookup_certs: vec![certificate.clone(), certificate],
3376 ..KeyResolverConfig::default()
3377 });
3378 let mut policy = crate::policy::VerificationPolicy::default();
3379 policy.resources.max_key_candidates = 1;
3380
3381 let error = super::super::VerifyContext::new()
3382 .policy(policy)
3383 .key_resolver(&resolver)
3384 .verify(&x509_signature_with_leaf_subject())
3385 .expect_err("the duplicate configured entry must consume candidate work");
3386
3387 assert!(matches!(
3388 error,
3389 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
3390 resource: crate::policy::resource_name::KEY_CANDIDATES,
3391 maximum: 1,
3392 actual: 2,
3393 })
3394 ));
3395 }
3396
3397 #[test]
3398 fn operation_policy_charges_duplicate_embedded_x509_candidates() {
3399 let certificate = certificate_der(RSA_4096_CERTIFICATE);
3402 let key_info = KeyInfo {
3403 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
3404 certificates: vec![certificate.clone(), certificate],
3405 certificate_chain: vec![0],
3406 ..X509DataInfo::default()
3407 })],
3408 };
3409 let mut policy = crate::policy::VerificationPolicy::default();
3410 policy.resources.max_key_candidates = 1;
3411
3412 let error = match DefaultKeyResolver::default().resolve_with_policy(
3413 Some(&key_info),
3414 SignatureAlgorithm::RsaSha256,
3415 &policy,
3416 ) {
3417 Ok(_) => panic!("the duplicate embedded entry must consume candidate work"),
3418 Err(error) => error,
3419 };
3420
3421 assert!(matches!(
3422 error,
3423 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
3424 resource: crate::policy::resource_name::KEY_CANDIDATES,
3425 maximum: 1,
3426 actual: 2,
3427 })
3428 ));
3429 }
3430
3431 #[test]
3432 fn policy_aware_resolver_rejects_resources_above_hard_ceiling() {
3433 let mut policy = crate::policy::VerificationPolicy::default();
3436 policy.resources.max_key_candidates = usize::MAX;
3437
3438 let error = match DefaultKeyResolver::default().resolve_with_policy(
3439 None,
3440 SignatureAlgorithm::RsaSha256,
3441 &policy,
3442 ) {
3443 Ok(_) => panic!("invalid resource policy must fail before key resolution"),
3444 Err(error) => error,
3445 };
3446
3447 assert!(matches!(
3448 error,
3449 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
3450 resource: crate::policy::resource_name::KEY_CANDIDATES,
3451 actual: usize::MAX,
3452 ..
3453 })
3454 ));
3455 }
3456
3457 #[test]
3458 fn embedded_x509_digest_selection_uses_operation_provider() {
3459 let certificate = certificate_der(RSA_4096_CERTIFICATE);
3462 let digest =
3463 super::super::compute_digest(super::super::DigestAlgorithm::Sha512, &certificate);
3464 let xml = format!(
3465 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><X509Data><X509Certificate>{}</X509Certificate><X509Digest xmlns=\"http://www.w3.org/2009/xmldsig11#\" Algorithm=\"{}\">{}</X509Digest></X509Data></KeyInfo>",
3466 STANDARD.encode(&certificate),
3467 super::super::DigestAlgorithm::Sha512.uri(),
3468 STANDARD.encode(digest),
3469 );
3470 let document = roxmltree::Document::parse(&xml).expect("generated KeyInfo must be XML");
3471 let provider = RejectSecondSha512Provider {
3472 sha512_calls: AtomicUsize::new(1),
3473 verification_calls: AtomicUsize::new(0),
3474 reject_verification_call: None,
3475 rejected_verification_data: None,
3476 };
3477
3478 let error =
3479 super::super::parse::parse_key_info_with_provider(document.root_element(), &provider)
3480 .expect_err("embedded X509Digest selection must use the operation provider");
3481
3482 assert!(
3483 matches!(
3484 error,
3485 ParseError::Provider(crate::provider::ProviderError::Unsupported {
3486 operation: crate::provider::ProviderOperation::Digest,
3487 algorithm: Some(ref uri),
3488 }) if uri == super::super::DigestAlgorithm::Sha512.uri()
3489 ),
3490 "unexpected error: {error:?}"
3491 );
3492 }
3493
3494 #[test]
3495 fn generic_key_resolution_keeps_legacy_capability_source_independent() {
3496 let certificate =
3497 include_bytes!("../../tests/fixtures/xmldsig/phaos-xmldsig-three/certs/rsa-cert.der")
3498 .to_vec();
3499 let (_, parsed_certificate) = X509Certificate::from_der(&certificate)
3500 .expect("the Phaos fixture is a DER certificate");
3501 let public_key = parsed_certificate.public_key().raw.to_vec();
3502 let rsa_public_key = rsa::RsaPublicKey::from_public_key_der(&public_key)
3503 .expect("the Phaos certificate contains an RSA public key");
3504 let certificate_metadata = parse_x509_certificate(&certificate)
3505 .expect("the Phaos fixture has supported X.509 metadata");
3506 let named_key = VerificationKey {
3507 algorithm: SignatureAlgorithm::RsaSha1,
3508 public_key_bytes: public_key.clone(),
3509 certificate_der: None,
3510 name: Some("legacy".into()),
3511 };
3512 let key_infos = [
3513 KeyInfo {
3514 sources: vec![KeyInfoSource::KeyName("legacy".into())],
3515 },
3516 KeyInfo {
3517 sources: vec![KeyInfoSource::DerEncodedKeyValue(public_key.clone())],
3518 },
3519 KeyInfo {
3520 sources: vec![KeyInfoSource::KeyValue(KeyValueInfo::Rsa {
3521 modulus: rsa_public_key.n().to_be_bytes_trimmed_vartime().to_vec(),
3522 exponent: rsa_public_key.e().to_be_bytes_trimmed_vartime().to_vec(),
3523 })],
3524 },
3525 KeyInfo {
3526 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
3527 certificates: vec![certificate],
3528 parsed_certificates: vec![certificate_metadata],
3529 certificate_chain: vec![0],
3530 ..X509DataInfo::default()
3531 })],
3532 },
3533 ];
3534 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3535 named_keys: HashMap::from([("legacy".into(), named_key.clone())]),
3536 ..KeyResolverConfig::default()
3537 });
3538 let mut policy = crate::policy::VerificationPolicy::default();
3539 policy.key_trust.rsa_keys.minimum_modulus_bits = 1024;
3540 policy
3541 .key_trust
3542 .allowed_legacy_signature_algorithms
3543 .insert(SignatureAlgorithm::RsaSha1);
3544
3545 for key_info in &key_infos {
3546 let key = resolver
3547 .resolve_with_policy(Some(key_info), SignatureAlgorithm::RsaSha1, &policy)
3548 .expect("the key source is valid")
3549 .expect("key resolution remains independent from operation policy");
3550 assert!(
3551 !key.verify(SignatureAlgorithm::RsaSha1, b"data", &[0; 128])
3552 .expect("the legacy RSA key is structurally valid")
3553 );
3554 }
3555 }
3556
3557 #[test]
3558 fn rsa_key_value_rejects_ecdsa_signature_method() {
3559 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
3561 .expect("fixture must contain an RSA public key");
3562 let (modulus, exponent) = rsa_key_value_parts(&public_key);
3563 let key_info = format!(
3564 "<ds:KeyInfo><ds:KeyValue><ds:RSAKeyValue><ds:Modulus>{}</ds:Modulus><ds:Exponent>{}</ds:Exponent></ds:RSAKeyValue></ds:KeyValue></ds:KeyInfo>",
3565 modulus, exponent,
3566 );
3567 let xml = replace_key_info(SIGNED_SAML, &key_info);
3568 let resolver = DefaultKeyResolver::default();
3569 let error = super::super::VerifyContext::new()
3570 .key_resolver(&resolver)
3571 .verify(&xml)
3572 .expect_err("RSAKeyValue must not resolve for ECDSA");
3573
3574 assert!(matches!(
3575 error,
3576 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
3577 ));
3578 }
3579
3580 #[test]
3581 fn resolves_ec_p256_key_value_end_to_end() {
3582 let resolver = DefaultKeyResolver::default();
3584 let result = super::super::VerifyContext::new()
3585 .key_resolver(&resolver)
3586 .verify(EC_P256_KEY_VALUE_SIGNATURE)
3587 .expect("P-256 ECKeyValue should resolve");
3588
3589 assert_eq!(result.status, super::super::DsigStatus::Valid);
3590 }
3591
3592 #[test]
3593 fn resolves_ec_p384_key_value_end_to_end() {
3594 let resolver = DefaultKeyResolver::default();
3596 let result = super::super::VerifyContext::new()
3597 .key_resolver(&resolver)
3598 .verify(EC_P384_KEY_VALUE_SIGNATURE)
3599 .expect("P-384 ECKeyValue should resolve");
3600
3601 assert_eq!(result.status, super::super::DsigStatus::Valid);
3602 }
3603
3604 #[test]
3605 fn ec_key_value_ignored_for_rsa_signature_method() {
3606 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>"#;
3608 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
3609 let resolver = DefaultKeyResolver::default();
3610 let result = super::super::VerifyContext::new()
3611 .key_resolver(&resolver)
3612 .verify(&xml)
3613 .expect("single incompatible ECKeyValue should be ignored");
3614
3615 assert_eq!(
3616 result.status,
3617 super::super::DsigStatus::Invalid(super::super::FailureReason::KeyNotFound)
3618 );
3619 }
3620
3621 #[test]
3622 fn incompatible_ec_key_value_falls_back_to_later_rsa_key_value() {
3623 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
3625 .expect("fixture must contain an RSA public key");
3626 let (modulus, exponent) = rsa_key_value_parts(&public_key);
3627 let key_info = format!(
3628 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>"#,
3629 modulus, exponent,
3630 );
3631 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
3632 let resolver = DefaultKeyResolver::default();
3633 let result = super::super::VerifyContext::new()
3634 .key_resolver(&resolver)
3635 .verify(&xml)
3636 .expect("later RSAKeyValue should resolve");
3637
3638 assert_eq!(result.status, super::super::DsigStatus::Valid);
3639 }
3640
3641 #[test]
3642 fn unsupported_ec_key_value_falls_back_to_later_key_name() {
3643 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>"#;
3645 let xml = replace_key_info(SIGNED_SAML, key_info);
3646 let mut config = KeyResolverConfig::default();
3647 config.named_keys.insert(
3648 "idp-signing".into(),
3649 VerificationKey {
3650 algorithm: SignatureAlgorithm::EcdsaSha256,
3651 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3652 certificate_der: None,
3653 name: Some("idp-signing".into()),
3654 },
3655 );
3656 let resolver = DefaultKeyResolver::new(config);
3657 let result = super::super::VerifyContext::new()
3658 .key_resolver(&resolver)
3659 .verify(&xml)
3660 .expect("later KeyName should resolve");
3661
3662 assert_eq!(result.status, super::super::DsigStatus::Valid);
3663 }
3664
3665 #[test]
3666 fn invalid_ec_key_value_falls_back_to_later_key_name() {
3667 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>"#;
3669 let xml = replace_key_info(SIGNED_SAML, key_info);
3670 let mut config = KeyResolverConfig::default();
3671 config.named_keys.insert(
3672 "idp-signing".into(),
3673 VerificationKey {
3674 algorithm: SignatureAlgorithm::EcdsaSha256,
3675 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3676 certificate_der: None,
3677 name: Some("idp-signing".into()),
3678 },
3679 );
3680 let resolver = DefaultKeyResolver::new(config);
3681 let result = super::super::VerifyContext::new()
3682 .key_resolver(&resolver)
3683 .verify(&xml)
3684 .expect("later KeyName should resolve after invalid ECKeyValue");
3685
3686 assert_eq!(result.status, super::super::DsigStatus::Valid);
3687 }
3688
3689 #[test]
3690 fn malformed_ec_key_value_falls_back_to_later_key_name() {
3691 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>"#;
3693 let xml = replace_key_info(SIGNED_SAML, key_info);
3694 let mut config = KeyResolverConfig::default();
3695 config.named_keys.insert(
3696 "idp-signing".into(),
3697 VerificationKey {
3698 algorithm: SignatureAlgorithm::EcdsaSha256,
3699 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3700 certificate_der: None,
3701 name: Some("idp-signing".into()),
3702 },
3703 );
3704 let resolver = DefaultKeyResolver::new(config);
3705 let result = super::super::VerifyContext::new()
3706 .key_resolver(&resolver)
3707 .verify(&xml)
3708 .expect("later KeyName should resolve after malformed ECKeyValue");
3709
3710 assert_eq!(result.status, super::super::DsigStatus::Valid);
3711 }
3712
3713 #[test]
3714 fn invalid_base64_ec_key_value_falls_back_to_later_key_name() {
3715 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>"#;
3718 let xml = replace_key_info(SIGNED_SAML, key_info);
3719 let mut config = KeyResolverConfig::default();
3720 config.named_keys.insert(
3721 "idp-signing".into(),
3722 VerificationKey {
3723 algorithm: SignatureAlgorithm::EcdsaSha256,
3724 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3725 certificate_der: None,
3726 name: Some("idp-signing".into()),
3727 },
3728 );
3729 let resolver = DefaultKeyResolver::new(config);
3730 let result = super::super::VerifyContext::new()
3731 .key_resolver(&resolver)
3732 .verify(&xml)
3733 .expect("later KeyName should resolve after bad ECKeyValue base64");
3734
3735 assert_eq!(result.status, super::super::DsigStatus::Valid);
3736 }
3737
3738 #[test]
3739 fn missing_curve_uri_ec_key_value_falls_back_to_later_key_name() {
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/><dsig11:PublicKey>BA==</dsig11:PublicKey></dsig11:ECKeyValue></ds:KeyValue><ds:KeyName>idp-signing</ds:KeyName></ds:KeyInfo>"#;
3742 let xml = replace_key_info(SIGNED_SAML, key_info);
3743 let mut config = KeyResolverConfig::default();
3744 config.named_keys.insert(
3745 "idp-signing".into(),
3746 VerificationKey {
3747 algorithm: SignatureAlgorithm::EcdsaSha256,
3748 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3749 certificate_der: None,
3750 name: Some("idp-signing".into()),
3751 },
3752 );
3753 let resolver = DefaultKeyResolver::new(config);
3754 let result = super::super::VerifyContext::new()
3755 .key_resolver(&resolver)
3756 .verify(&xml)
3757 .expect("later KeyName should resolve after missing EC curve URI");
3758
3759 assert_eq!(result.status, super::super::DsigStatus::Valid);
3760 }
3761
3762 #[test]
3763 fn malformed_ec_key_value_children_fall_back_to_later_key_name() {
3764 let malformed_ec_key_values = [
3767 r#"<dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/>"#,
3768 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"/>"#,
3769 r#"<dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/><dsig11:PublicKey>BA==</dsig11:PublicKey><dsig11:PublicKey>BA==</dsig11:PublicKey>"#,
3770 ];
3771
3772 for malformed_children in malformed_ec_key_values {
3773 let key_info = format!(
3774 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>"#
3775 );
3776 let xml = replace_key_info(SIGNED_SAML, &key_info);
3777 let mut config = KeyResolverConfig::default();
3778 config.named_keys.insert(
3779 "idp-signing".into(),
3780 VerificationKey {
3781 algorithm: SignatureAlgorithm::EcdsaSha256,
3782 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3783 certificate_der: None,
3784 name: Some("idp-signing".into()),
3785 },
3786 );
3787 let resolver = DefaultKeyResolver::new(config);
3788 let result = super::super::VerifyContext::new()
3789 .key_resolver(&resolver)
3790 .verify(&xml)
3791 .expect("later KeyName should resolve after malformed EC child shape");
3792
3793 assert_eq!(result.status, super::super::DsigStatus::Valid);
3794 }
3795 }
3796
3797 #[test]
3798 fn supported_ec_curve_does_not_fall_back_to_later_key_name() {
3799 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>"#;
3803 let xml = replace_key_info(SIGNED_SAML, key_info);
3804 let mut config = KeyResolverConfig::default();
3805 config.named_keys.insert(
3806 "idp-signing".into(),
3807 VerificationKey {
3808 algorithm: SignatureAlgorithm::EcdsaSha256,
3809 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3810 certificate_der: None,
3811 name: Some("idp-signing".into()),
3812 },
3813 );
3814 let resolver = DefaultKeyResolver::new(config);
3815 let error = super::super::VerifyContext::new()
3816 .key_resolver(&resolver)
3817 .verify(&xml)
3818 .expect_err("a usable first key source must not fall through after verification");
3819
3820 assert!(matches!(
3821 error,
3822 DsigError::Crypto(super::super::SignatureVerificationError::InvalidSignatureFormat)
3823 ));
3824 }
3825
3826 #[test]
3827 fn lone_malformed_ec_key_value_reports_invalid_public_key() {
3828 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>"#;
3829 let xml = replace_key_info(SIGNED_SAML, key_info);
3830 let error = super::super::VerifyContext::new()
3831 .key_resolver(&DefaultKeyResolver::default())
3832 .verify(&xml)
3833 .expect_err("lone malformed ECKeyValue should surface typed key error");
3834
3835 assert!(matches!(
3836 error,
3837 DsigError::KeyResolution(KeyResolutionError::InvalidPublicKey)
3838 ));
3839 }
3840
3841 #[test]
3842 fn lone_supported_ec_curve_reaches_signature_verification() {
3843 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>"#;
3844 let xml = replace_key_info(SIGNED_SAML, key_info);
3845 let error = super::super::VerifyContext::new()
3846 .key_resolver(&DefaultKeyResolver::default())
3847 .verify(&xml)
3848 .expect_err("a supported EC curve must reach signature verification");
3849
3850 assert!(matches!(
3851 error,
3852 DsigError::Crypto(super::super::SignatureVerificationError::InvalidSignatureFormat)
3853 ));
3854 }
3855
3856 #[test]
3857 fn chain_verification_rejects_untrusted_embedded_certificate() {
3858 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3860 ..KeyResolverConfig::default()
3861 });
3862 let error = super::super::VerifyContext::new()
3863 .policy(verification_policy_with_trust(chain_policy()))
3864 .key_resolver(&resolver)
3865 .verify(SIGNED_SAML)
3866 .expect_err("untrusted certificate must fail chain validation");
3867
3868 assert!(matches!(
3869 error,
3870 DsigError::KeyResolution(KeyResolutionError::Chain(
3871 super::super::X509ChainError::UntrustedRoot
3872 ))
3873 ));
3874 }
3875
3876 #[test]
3877 fn named_key_algorithm_mismatch_fails_closed() {
3878 let xml = replace_key_info(
3880 SIGNED_SAML,
3881 "<ds:KeyInfo><ds:KeyName>wrong-algorithm</ds:KeyName></ds:KeyInfo>",
3882 );
3883 let mut config = KeyResolverConfig::default();
3884 config.named_keys.insert(
3885 "wrong-algorithm".into(),
3886 VerificationKey {
3887 algorithm: SignatureAlgorithm::RsaSha256,
3888 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
3889 certificate_der: None,
3890 name: Some("wrong-algorithm".into()),
3891 },
3892 );
3893 let resolver = DefaultKeyResolver::new(config);
3894 let error = super::super::VerifyContext::new()
3895 .key_resolver(&resolver)
3896 .verify(&xml)
3897 .expect_err("algorithm mismatch must fail closed");
3898
3899 assert!(matches!(
3900 error,
3901 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
3902 ));
3903 }
3904
3905 #[test]
3906 fn named_key_spki_type_mismatch_fails_during_resolution() {
3907 let xml = replace_key_info(
3909 SIGNED_SAML,
3910 "<ds:KeyInfo><ds:KeyName>mislabeled</ds:KeyName></ds:KeyInfo>",
3911 );
3912 let mut config = KeyResolverConfig::default();
3913 config.named_keys.insert(
3914 "mislabeled".into(),
3915 VerificationKey {
3916 algorithm: SignatureAlgorithm::EcdsaSha256,
3917 public_key_bytes: public_key_der(RSA_PUBLIC_KEY),
3918 certificate_der: None,
3919 name: Some("mislabeled".into()),
3920 },
3921 );
3922 let resolver = DefaultKeyResolver::new(config);
3923 let error = super::super::VerifyContext::new()
3924 .key_resolver(&resolver)
3925 .verify(&xml)
3926 .expect_err("mislabeled named key must fail during resolution");
3927
3928 assert!(matches!(
3929 error,
3930 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
3931 ));
3932 }
3933
3934 #[test]
3935 fn malformed_named_key_reports_public_key_error() {
3936 let xml = replace_key_info(
3938 SIGNED_SAML,
3939 "<ds:KeyInfo><ds:KeyName>malformed</ds:KeyName></ds:KeyInfo>",
3940 );
3941 let mut config = KeyResolverConfig::default();
3942 config.named_keys.insert(
3943 "malformed".into(),
3944 VerificationKey {
3945 algorithm: SignatureAlgorithm::EcdsaSha256,
3946 public_key_bytes: vec![1, 2, 3],
3947 certificate_der: None,
3948 name: Some("malformed".into()),
3949 },
3950 );
3951 let resolver = DefaultKeyResolver::new(config);
3952 let error = super::super::VerifyContext::new()
3953 .key_resolver(&resolver)
3954 .verify(&xml)
3955 .expect_err("malformed named key must fail during resolution");
3956
3957 assert!(matches!(
3958 error,
3959 DsigError::KeyResolution(KeyResolutionError::InvalidPublicKey)
3960 ));
3961 }
3962}