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