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