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