1use std::{collections::HashMap, fmt, time::SystemTime};
4
5use crypto_bigint::BoxedUint;
6use dsa::pkcs8::EncodePublicKey as DsaEncodePublicKey;
7use hmac::{KeyInit, Mac};
8use rsa::pkcs8::DecodePublicKey as _;
9use x509_parser::{
10 prelude::{FromDer, X509Certificate},
11 public_key::PublicKey,
12 x509::SubjectPublicKeyInfo,
13};
14use zeroize::Zeroizing;
15
16use super::signature::{
17 decode_dsa_verifying_key, signature_value_matches_spki,
18 signature_value_matches_spki_with_encoding, validate_dsa_signature_spki_with_minimum,
19 validate_ec_public_key_encoding, validate_rsa_signature_spki_with_minimum,
20 verify_dsa_signature_spki_primitive, verify_dsa_signature_spki_with_minimum,
21 verify_rsa_signature_spki_primitive, verify_rsa_signature_spki_with_minimum,
22};
23use super::{
24 DsigError, KeyInfo, KeyInfoSource, KeyResolver, KeyValueInfo, SignatureAlgorithm, VerifyingKey,
25 X509ChainOptions, X509DataInfo,
26 parse::{
27 EC_P256_OID, EC_P384_OID, EC_P521_OID, ParseError, X509ChainBuildError,
28 build_x509_certificate_paths_to_selector_targets,
29 build_x509_certificate_paths_to_trusted_prefix, distinguished_names_equal,
30 parse_x509_certificate, x509_certificate_matches_any_selector,
31 x509_data_has_lookup_identifiers, x509_selector_categories_match_chain,
32 },
33 verify_ecdsa_signature_spki, verify_ecdsa_signature_spki_with_encoding,
34 x509::verify_x509_certificate_chain_with_provider_and_crls,
35};
36use super::{ResolvedVerificationKey, TrustedPublicKey, X509TrustEvidence};
37
38#[derive(Clone)]
45pub struct HmacVerificationKey {
46 secret: Zeroizing<Vec<u8>>,
47}
48
49impl fmt::Debug for HmacVerificationKey {
50 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
51 formatter
52 .debug_struct("HmacVerificationKey")
53 .finish_non_exhaustive()
54 }
55}
56
57impl HmacVerificationKey {
58 pub fn new(secret: impl Into<Vec<u8>>) -> Result<Self, KeyResolutionError> {
60 let secret = secret.into();
61 if secret.is_empty() {
62 return Err(KeyResolutionError::InvalidPublicKey);
63 }
64 Ok(Self {
65 secret: Zeroizing::new(secret),
66 })
67 }
68
69 fn validate_output(
70 &self,
71 policy: crate::policy::HmacPolicy,
72 algorithm: SignatureAlgorithm,
73 signature_value: &[u8],
74 ) -> Result<(), DsigError> {
75 if algorithm.hmac_output_bits().is_none() {
76 return Err(KeyResolutionError::AlgorithmMismatch.into());
77 }
78 policy.validate_key_bytes(self.secret.len())?;
79 policy.validate_output(algorithm, signature_value.len().saturating_mul(8))?;
80 Ok(())
81 }
82
83 fn verify_with_hmac_policy(
84 &self,
85 policy: crate::policy::HmacPolicy,
86 algorithm: SignatureAlgorithm,
87 signed_data: &[u8],
88 signature_value: &[u8],
89 ) -> Result<bool, DsigError> {
90 self.validate_output(policy, algorithm, signature_value)?;
91 macro_rules! verify_hmac {
92 ($digest:ty) => {{
93 let mut mac = hmac::Hmac::<$digest>::new_from_slice(&self.secret)
94 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
95 mac.update(signed_data);
96 let expected = mac.finalize().into_bytes();
97 subtle::ConstantTimeEq::ct_eq(&expected[..signature_value.len()], signature_value)
98 .into()
99 }};
100 }
101 Ok(match algorithm {
102 #[cfg(feature = "legacy-algorithms")]
103 SignatureAlgorithm::HmacMd5 => verify_hmac!(md5::Md5),
104 #[cfg(feature = "legacy-algorithms")]
105 SignatureAlgorithm::HmacRipemd160 => verify_hmac!(ripemd::Ripemd160),
106 SignatureAlgorithm::HmacSha1 => verify_hmac!(sha1::Sha1),
107 SignatureAlgorithm::HmacSha224 => verify_hmac!(sha2::Sha224),
108 SignatureAlgorithm::HmacSha256 => verify_hmac!(sha2::Sha256),
109 SignatureAlgorithm::HmacSha384 => verify_hmac!(sha2::Sha384),
110 SignatureAlgorithm::HmacSha512 => verify_hmac!(sha2::Sha512),
111 _ => return Err(KeyResolutionError::AlgorithmMismatch.into()),
112 })
113 }
114}
115
116impl VerifyingKey for HmacVerificationKey {
117 fn validate_policy(&self, policy: &crate::policy::VerificationPolicy) -> Result<(), DsigError> {
118 policy
119 .hmac
120 .validate_key_bytes(self.secret.len())
121 .map_err(Into::into)
122 }
123
124 fn validate_signature_value(
125 &self,
126 algorithm: SignatureAlgorithm,
127 signature_value: &[u8],
128 ) -> Result<bool, DsigError> {
129 self.validate_output(
130 crate::policy::HmacPolicy::default(),
131 algorithm,
132 signature_value,
133 )?;
134 Ok(true)
135 }
136
137 fn validate_signature_value_with_policy(
138 &self,
139 policy: &crate::policy::VerificationPolicy,
140 algorithm: SignatureAlgorithm,
141 signature_value: &[u8],
142 ) -> Result<bool, DsigError> {
143 self.validate_output(policy.hmac, algorithm, signature_value)?;
144 Ok(true)
145 }
146
147 fn verify(
148 &self,
149 algorithm: SignatureAlgorithm,
150 signed_data: &[u8],
151 signature_value: &[u8],
152 ) -> Result<bool, DsigError> {
153 self.verify_with_hmac_policy(
154 crate::policy::HmacPolicy::default(),
155 algorithm,
156 signed_data,
157 signature_value,
158 )
159 }
160
161 fn verify_with_policy(
162 &self,
163 policy: &crate::policy::VerificationPolicy,
164 algorithm: SignatureAlgorithm,
165 signed_data: &[u8],
166 signature_value: &[u8],
167 ) -> Result<bool, DsigError> {
168 self.verify_with_hmac_policy(policy.hmac, algorithm, signed_data, signature_value)
169 }
170}
171
172pub type HmacSha1VerificationKey = HmacVerificationKey;
174
175#[derive(Debug, Clone, PartialEq, Eq)]
177pub struct VerificationKey {
178 pub algorithm: SignatureAlgorithm,
180 pub public_key_bytes: Vec<u8>,
182 pub certificate_der: Option<Vec<u8>>,
184 pub name: Option<String>,
186}
187
188impl VerifyingKey for VerificationKey {
189 fn verification_spki(&self, algorithm: SignatureAlgorithm) -> Result<Option<&[u8]>, DsigError> {
190 if algorithm != self.algorithm {
191 return Err(KeyResolutionError::AlgorithmMismatch.into());
192 }
193 Ok(Some(&self.public_key_bytes))
194 }
195 fn verify_with_context(
196 &self,
197 algorithm: SignatureAlgorithm,
198 context: &super::SignatureContext,
199 data: &[u8],
200 signature: &[u8],
201 ) -> Result<bool, DsigError> {
202 if algorithm != self.algorithm {
203 return Err(KeyResolutionError::AlgorithmMismatch.into());
204 }
205 if algorithm.eddsa_signature_len().is_some()
206 || matches!(algorithm, SignatureAlgorithm::PostQuantum(_))
207 {
208 return super::modern::verify_with_context(
209 algorithm,
210 &self.public_key_bytes,
211 context,
212 data,
213 signature,
214 )
215 .map_err(DsigError::Crypto);
216 }
217 if !context.as_bytes().is_empty() {
218 return Err(KeyResolutionError::AlgorithmMismatch.into());
219 }
220 self.verify(algorithm, data, signature)
221 }
222 fn validate_policy(&self, policy: &crate::policy::VerificationPolicy) -> Result<(), DsigError> {
223 let result = match self.algorithm {
224 #[cfg(feature = "legacy-algorithms")]
225 SignatureAlgorithm::RsaMd5 | SignatureAlgorithm::RsaRipemd160 => {
226 validate_rsa_signature_spki_with_minimum(
227 self.algorithm,
228 &self.public_key_bytes,
229 policy.key_trust.rsa_keys.minimum_modulus_bits,
230 )
231 }
232 #[cfg(feature = "legacy-algorithms")]
233 SignatureAlgorithm::HmacMd5
234 | SignatureAlgorithm::HmacRipemd160
235 | SignatureAlgorithm::EcdsaRipemd160 => Ok(()),
236 SignatureAlgorithm::Ed25519
237 | SignatureAlgorithm::Ed25519Ctx
238 | SignatureAlgorithm::Ed25519Ph
239 | SignatureAlgorithm::Ed448
240 | SignatureAlgorithm::Ed448Ph
241 | SignatureAlgorithm::PostQuantum(_) => {
242 super::modern::validate_public_key(self.algorithm, &self.public_key_bytes)
243 }
244 SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256 => {
245 validate_dsa_signature_spki_with_minimum(
246 &self.public_key_bytes,
247 policy.key_trust.dsa_keys.minimum_modulus_bits,
248 )
249 }
250 SignatureAlgorithm::RsaSha1
251 | SignatureAlgorithm::RsaSha224
252 | SignatureAlgorithm::RsaSha256
253 | SignatureAlgorithm::RsaSha384
254 | SignatureAlgorithm::RsaSha512 => validate_rsa_signature_spki_with_minimum(
255 self.algorithm,
256 &self.public_key_bytes,
257 policy.key_trust.rsa_keys.minimum_modulus_bits,
258 ),
259 SignatureAlgorithm::HmacSha1
260 | SignatureAlgorithm::HmacSha224
261 | SignatureAlgorithm::HmacSha256
262 | SignatureAlgorithm::HmacSha384
263 | SignatureAlgorithm::HmacSha512
264 | SignatureAlgorithm::EcdsaSha1
265 | SignatureAlgorithm::EcdsaSha224
266 | SignatureAlgorithm::EcdsaSha256
267 | SignatureAlgorithm::EcdsaSha384
268 | SignatureAlgorithm::EcdsaSha512
269 | SignatureAlgorithm::EcdsaSha3_224
270 | SignatureAlgorithm::EcdsaSha3_256
271 | SignatureAlgorithm::EcdsaSha3_384
272 | SignatureAlgorithm::EcdsaSha3_512 => Ok(()),
273 };
274 result.map_err(DsigError::Crypto)
275 }
276
277 fn validate_signature_value(
278 &self,
279 algorithm: SignatureAlgorithm,
280 signature_value: &[u8],
281 ) -> Result<bool, DsigError> {
282 if algorithm != self.algorithm {
283 return Err(KeyResolutionError::AlgorithmMismatch.into());
284 }
285 signature_value_matches_spki(algorithm, &self.public_key_bytes, signature_value)
286 .map_err(DsigError::Crypto)
287 }
288
289 fn validate_signature_value_with_policy(
290 &self,
291 policy: &crate::policy::VerificationPolicy,
292 algorithm: SignatureAlgorithm,
293 signature_value: &[u8],
294 ) -> Result<bool, DsigError> {
295 if algorithm != self.algorithm {
296 return Err(KeyResolutionError::AlgorithmMismatch.into());
297 }
298 signature_value_matches_spki_with_encoding(
299 algorithm,
300 &self.public_key_bytes,
301 signature_value,
302 policy.ecdsa_signature_value_encoding,
303 )
304 .map_err(DsigError::Crypto)
305 }
306
307 fn verify(
308 &self,
309 algorithm: SignatureAlgorithm,
310 signed_data: &[u8],
311 signature_value: &[u8],
312 ) -> Result<bool, DsigError> {
313 if algorithm != self.algorithm {
314 return Err(KeyResolutionError::AlgorithmMismatch.into());
315 }
316 let result = match algorithm {
317 #[cfg(feature = "legacy-algorithms")]
318 SignatureAlgorithm::RsaMd5 | SignatureAlgorithm::RsaRipemd160 => {
319 verify_rsa_signature_spki_primitive(
320 algorithm,
321 &self.public_key_bytes,
322 signed_data,
323 signature_value,
324 )
325 }
326 #[cfg(feature = "legacy-algorithms")]
327 SignatureAlgorithm::EcdsaRipemd160 => verify_ecdsa_signature_spki(
328 algorithm,
329 &self.public_key_bytes,
330 signed_data,
331 signature_value,
332 ),
333 #[cfg(feature = "legacy-algorithms")]
334 SignatureAlgorithm::HmacMd5 | SignatureAlgorithm::HmacRipemd160 => {
335 return Err(KeyResolutionError::AlgorithmMismatch.into());
336 }
337 SignatureAlgorithm::Ed25519
338 | SignatureAlgorithm::Ed25519Ctx
339 | SignatureAlgorithm::Ed25519Ph
340 | SignatureAlgorithm::Ed448
341 | SignatureAlgorithm::Ed448Ph
342 | SignatureAlgorithm::PostQuantum(_) => super::modern::verify(
343 algorithm,
344 &self.public_key_bytes,
345 signed_data,
346 signature_value,
347 ),
348 SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256 => {
349 verify_dsa_signature_spki_primitive(
350 algorithm,
351 &self.public_key_bytes,
352 signed_data,
353 signature_value,
354 )
355 }
356 SignatureAlgorithm::HmacSha1
357 | SignatureAlgorithm::HmacSha224
358 | SignatureAlgorithm::HmacSha256
359 | SignatureAlgorithm::HmacSha384
360 | SignatureAlgorithm::HmacSha512 => {
361 return Err(KeyResolutionError::AlgorithmMismatch.into());
362 }
363 SignatureAlgorithm::RsaSha1
364 | SignatureAlgorithm::RsaSha224
365 | SignatureAlgorithm::RsaSha256
366 | SignatureAlgorithm::RsaSha384
367 | SignatureAlgorithm::RsaSha512 => verify_rsa_signature_spki_primitive(
368 algorithm,
369 &self.public_key_bytes,
370 signed_data,
371 signature_value,
372 ),
373 SignatureAlgorithm::EcdsaSha1
374 | SignatureAlgorithm::EcdsaSha224
375 | SignatureAlgorithm::EcdsaSha256
376 | SignatureAlgorithm::EcdsaSha384
377 | SignatureAlgorithm::EcdsaSha512
378 | SignatureAlgorithm::EcdsaSha3_224
379 | SignatureAlgorithm::EcdsaSha3_256
380 | SignatureAlgorithm::EcdsaSha3_384
381 | SignatureAlgorithm::EcdsaSha3_512 => verify_ecdsa_signature_spki(
382 algorithm,
383 &self.public_key_bytes,
384 signed_data,
385 signature_value,
386 ),
387 };
388 result.map_err(DsigError::Crypto)
389 }
390
391 fn verify_with_policy(
392 &self,
393 policy: &crate::policy::VerificationPolicy,
394 algorithm: SignatureAlgorithm,
395 signed_data: &[u8],
396 signature_value: &[u8],
397 ) -> Result<bool, DsigError> {
398 if algorithm != self.algorithm {
399 return Err(KeyResolutionError::AlgorithmMismatch.into());
400 }
401 if algorithm.ecdsa_digest().is_some() {
402 return verify_ecdsa_signature_spki_with_encoding(
403 algorithm,
404 &self.public_key_bytes,
405 signed_data,
406 signature_value,
407 policy.ecdsa_signature_value_encoding,
408 )
409 .map_err(DsigError::Crypto);
410 }
411 self.verify(algorithm, signed_data, signature_value)
412 }
413}
414
415struct PolicyBoundVerificationKey {
416 key: VerificationKey,
417 rsa_minimum_bits: usize,
418 dsa_minimum_bits: usize,
419}
420
421impl VerifyingKey for PolicyBoundVerificationKey {
422 fn verification_spki(&self, algorithm: SignatureAlgorithm) -> Result<Option<&[u8]>, DsigError> {
423 if algorithm.is_rsa() {
425 validate_rsa_signature_spki_with_minimum(
426 algorithm,
427 &self.key.public_key_bytes,
428 self.rsa_minimum_bits,
429 )
430 .map_err(DsigError::Crypto)?;
431 }
432 self.key.verification_spki(algorithm)
433 }
434 fn verify_with_context(
435 &self,
436 algorithm: SignatureAlgorithm,
437 context: &super::SignatureContext,
438 data: &[u8],
439 signature: &[u8],
440 ) -> Result<bool, DsigError> {
441 if context.as_bytes().is_empty() {
442 return self.verify(algorithm, data, signature);
443 }
444 self.key
445 .verify_with_context(algorithm, context, data, signature)
446 }
447 fn validate_signature_value(
448 &self,
449 algorithm: SignatureAlgorithm,
450 signature_value: &[u8],
451 ) -> Result<bool, DsigError> {
452 self.key
453 .validate_signature_value(algorithm, signature_value)
454 }
455
456 fn validate_signature_value_with_policy(
457 &self,
458 policy: &crate::policy::VerificationPolicy,
459 algorithm: SignatureAlgorithm,
460 signature_value: &[u8],
461 ) -> Result<bool, DsigError> {
462 self.key
463 .validate_signature_value_with_policy(policy, algorithm, signature_value)
464 }
465
466 fn verify(
467 &self,
468 algorithm: SignatureAlgorithm,
469 signed_data: &[u8],
470 signature_value: &[u8],
471 ) -> Result<bool, DsigError> {
472 if algorithm != self.key.algorithm {
473 return Err(KeyResolutionError::AlgorithmMismatch.into());
474 }
475 let result = match algorithm {
476 SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256 => {
477 verify_dsa_signature_spki_with_minimum(
478 algorithm,
479 &self.key.public_key_bytes,
480 signed_data,
481 signature_value,
482 self.dsa_minimum_bits,
483 )
484 }
485 algorithm if algorithm.is_rsa() => verify_rsa_signature_spki_with_minimum(
486 algorithm,
487 &self.key.public_key_bytes,
488 signed_data,
489 signature_value,
490 self.rsa_minimum_bits,
491 ),
492 _ => return self.key.verify(algorithm, signed_data, signature_value),
493 };
494 result.map_err(DsigError::Crypto)
495 }
496
497 fn verify_with_policy(
498 &self,
499 policy: &crate::policy::VerificationPolicy,
500 algorithm: SignatureAlgorithm,
501 signed_data: &[u8],
502 signature_value: &[u8],
503 ) -> Result<bool, DsigError> {
504 if algorithm.ecdsa_digest().is_some() {
505 return self
506 .key
507 .verify_with_policy(policy, algorithm, signed_data, signature_value);
508 }
509 self.verify(algorithm, signed_data, signature_value)
510 }
511}
512
513#[derive(Debug, thiserror::Error)]
515#[non_exhaustive]
516pub enum KeyResolutionError {
517 #[error("verification key does not match the signature algorithm")]
519 AlgorithmMismatch,
520 #[error("invalid embedded certificate DER")]
522 InvalidCertificate,
523 #[error("invalid public key DER")]
525 InvalidPublicKey,
526 #[error("X.509 lookup selectors match multiple configured certificates")]
528 AmbiguousCertificate,
529 #[error("unsupported X.509 digest algorithm: {0}")]
531 UnsupportedDigestAlgorithm(String),
532 #[error("certificate chain validation failed: {0}")]
534 Chain(#[from] super::X509ChainError),
535 #[error("system time is unavailable")]
537 SystemTime,
538}
539
540#[derive(Debug, Clone, Default, PartialEq, Eq)]
546pub struct KeyResolverConfig {
547 pub lookup_certs: Vec<Vec<u8>>,
551 pub trusted_certs: Vec<Vec<u8>>,
553 pub crls: Vec<Vec<u8>>,
555 pub named_keys: HashMap<String, VerificationKey>,
557}
558
559#[derive(Debug, Clone, Default)]
561pub struct DefaultKeyResolver {
562 config: KeyResolverConfig,
563}
564
565#[derive(Clone, Copy)]
566pub(crate) enum ResolutionScope {
567 Document,
568 Trusted,
569 DocumentPrefix(usize),
570 TrustedPrefix(usize),
571 DocumentSuffix(usize),
572 TrustedSuffix(usize),
573}
574
575pub(crate) struct SourceResolution {
578 pub(crate) key: Option<ResolvedVerificationKey<'static>>,
579 pub(crate) deferred_error: Option<KeyResolutionError>,
580}
581
582impl SourceResolution {
583 pub(crate) fn finish(self) -> Result<Option<ResolvedVerificationKey<'static>>, DsigError> {
584 if let Some(error) = self.deferred_error {
585 return Err(error.into());
586 }
587 Ok(self.key)
588 }
589}
590
591#[derive(Debug)]
599pub struct InspectedKeyCandidateBudget {
600 maximum: usize,
601 attempted: usize,
602}
603
604impl InspectedKeyCandidateBudget {
605 #[must_use]
607 pub fn new(policy: &crate::policy::VerificationPolicy) -> Self {
608 Self {
609 maximum: policy.resources.max_key_candidates,
610 attempted: 0,
611 }
612 }
613
614 pub fn charge(&mut self) -> Result<(), DsigError> {
616 self.charge_many(1)
617 }
618
619 pub(crate) fn charge_many(&mut self, count: usize) -> Result<(), DsigError> {
620 if self.attempted > self.maximum || count > self.maximum - self.attempted {
621 return Err(crate::policy::PolicyViolation::ResourceLimit {
622 resource: crate::policy::resource_name::KEY_CANDIDATES,
623 maximum: self.maximum,
624 actual: self.attempted.saturating_add(count),
625 }
626 .into());
627 }
628 debug_assert!(self.attempted <= self.maximum);
629 self.attempted += count;
630 Ok(())
631 }
632}
633
634pub(crate) fn validate_key_info_source_permissions(
635 key_info: &KeyInfo,
636 allowed: crate::policy::KeySourcePolicy,
637) -> Result<(), crate::policy::PolicyViolation> {
638 for source in &key_info.sources {
639 let disabled_reason = match source {
640 KeyInfoSource::X509Data(_) if !allowed.x509_data => {
641 Some("X509Data key sources are disabled")
642 }
643 KeyInfoSource::DerEncodedKeyValue(_) if !allowed.der_encoded_key_value => {
644 Some("DEREncodedKeyValue key sources are disabled")
645 }
646 KeyInfoSource::KeyName(_) if !allowed.key_name => {
647 Some("KeyName key sources are disabled")
648 }
649 KeyInfoSource::KeyValue(_) if !allowed.key_value => {
650 Some("KeyValue key sources are disabled")
651 }
652 KeyInfoSource::KeyInfoReference { .. } if !allowed.key_info_reference => {
653 Some("KeyInfoReference key sources are disabled")
654 }
655 KeyInfoSource::X509Data(_)
656 | KeyInfoSource::DerEncodedKeyValue(_)
657 | KeyInfoSource::KeyName(_)
658 | KeyInfoSource::KeyValue(_)
659 | KeyInfoSource::RetrievalMethod { .. }
660 | KeyInfoSource::KeyInfoReference { .. } => None,
661 };
662 if let Some(reason) = disabled_reason {
663 return Err(crate::policy::PolicyViolation::KeyTrust { reason });
664 }
665 }
666 Ok(())
667}
668
669impl DefaultKeyResolver {
670 pub fn resolve_with_candidate_budget(
674 &self,
675 key_info: Option<&KeyInfo>,
676 algorithm: SignatureAlgorithm,
677 policy: &crate::policy::VerificationPolicy,
678 provider: &dyn crate::provider::CryptoProvider,
679 candidate_budget: &mut InspectedKeyCandidateBudget,
680 ) -> Result<Option<ResolvedVerificationKey<'static>>, DsigError> {
681 candidate_budget.maximum = candidate_budget
682 .maximum
683 .min(policy.resources.max_key_candidates);
684 candidate_budget.charge_many(0)?;
685 self.resolve_with_trust(
686 key_info,
687 algorithm,
688 policy,
689 provider,
690 candidate_budget,
691 ResolutionScope::Document,
692 )
693 }
694
695 pub(crate) fn resolve_trusted_material_with_candidate_budget(
696 &self,
697 key_info: &KeyInfo,
698 algorithm: SignatureAlgorithm,
699 policy: &crate::policy::VerificationPolicy,
700 provider: &dyn crate::provider::CryptoProvider,
701 candidate_budget: &mut InspectedKeyCandidateBudget,
702 ) -> Result<Option<ResolvedVerificationKey<'static>>, DsigError> {
703 self.resolve_with_trust(
704 Some(key_info),
705 algorithm,
706 policy,
707 provider,
708 candidate_budget,
709 ResolutionScope::Trusted,
710 )
711 }
712
713 pub(crate) fn resolve_sources_with_candidate_budget(
714 &self,
715 key_info: &KeyInfo,
716 algorithm: SignatureAlgorithm,
717 policy: &crate::policy::VerificationPolicy,
718 provider: &dyn crate::provider::CryptoProvider,
719 candidate_budget: &mut InspectedKeyCandidateBudget,
720 scope: ResolutionScope,
721 ) -> Result<SourceResolution, DsigError> {
722 self.resolve_source_range(
723 Some(key_info),
724 algorithm,
725 policy,
726 provider,
727 candidate_budget,
728 scope,
729 )
730 }
731 #[must_use]
733 pub fn new(config: KeyResolverConfig) -> Self {
734 Self { config }
735 }
736
737 #[must_use]
739 pub fn config(&self) -> &KeyResolverConfig {
740 &self.config
741 }
742
743 fn check_configured_x509_material(
744 &self,
745 info: &X509DataInfo,
746 resources: &crate::policy::ResourcePolicy,
747 trust: &crate::policy::KeyTrustPolicy,
748 budget: &mut InspectedKeyCandidateBudget,
749 charge_crls: bool,
750 ) -> Result<(), DsigError> {
751 if charge_crls && trust.check_crls && trust.verify_x509_chains {
752 budget.charge_many(self.config.crls.len())?;
753 }
754 let certificates = self
755 .config
756 .trusted_certs
757 .iter()
758 .chain(&self.config.lookup_certs);
759 let crls = self
760 .config
761 .crls
762 .iter()
763 .filter(|_| trust.check_crls && trust.verify_x509_chains);
764 let mut total = 0_usize;
765 for material in info
768 .certificates
769 .iter()
770 .chain(&info.crls)
771 .chain(certificates)
772 .chain(crls)
773 {
774 if material.len() > resources.max_external_resource_bytes {
775 return Err(crate::policy::PolicyViolation::ResourceLimit {
776 resource: crate::policy::resource_name::EXTERNAL_RESOURCE_BYTES,
777 maximum: resources.max_external_resource_bytes,
778 actual: material.len(),
779 }
780 .into());
781 }
782 debug_assert!(total <= resources.max_external_resource_total_bytes);
783 if material.len() > resources.max_external_resource_total_bytes - total {
784 return Err(crate::policy::PolicyViolation::ResourceLimit {
785 resource: crate::policy::resource_name::AGGREGATE_EXTERNAL_RESOURCE_BYTES,
786 maximum: resources.max_external_resource_total_bytes,
787 actual: total.saturating_add(material.len()),
788 }
789 .into());
790 }
791 total += material.len();
792 }
793 Ok(())
794 }
795
796 fn resolve_x509(
797 &self,
798 info: &X509DataInfo,
799 algorithm: SignatureAlgorithm,
800 trust: &crate::policy::KeyTrustPolicy,
801 provider: &dyn crate::provider::CryptoProvider,
802 budget: &mut InspectedKeyCandidateBudget,
803 ) -> Result<Option<(VerificationKey, Option<X509TrustEvidence>)>, DsigError> {
804 let mut evidence = None;
805 let effective_trust;
806 let trust = if trust.verify_x509_chains && trust.verification_time.is_none() {
807 effective_trust = {
808 let mut captured = trust.clone();
809 captured.verification_time = Some(SystemTime::now());
810 captured
811 };
812 &effective_trust
813 } else {
814 trust
815 };
816 let certificate_der = if let Some(&signing_index) = info.certificate_chain.first() {
817 if trust.verify_x509_chains {
818 let path =
819 self.prepare_embedded_x509(info, signing_index, trust, provider, budget)?;
820 evidence = Some(Self::x509_trust_evidence(&path, trust)?);
821 } else {
822 budget.charge_many(info.certificates.len())?;
823 }
824 info.certificates
825 .get(signing_index)
826 .ok_or(KeyResolutionError::InvalidCertificate)?
827 .clone()
828 } else {
829 let Some(selected) = self.resolve_configured_x509(info, trust, provider, budget)?
830 else {
831 return Ok(None);
832 };
833 if trust.verify_x509_chains {
834 evidence = Some(Self::x509_trust_evidence(&selected, trust)?);
835 }
836 selected
837 .certificate_chain
838 .first()
839 .and_then(|index| selected.certificates.get(*index))
840 .ok_or(KeyResolutionError::InvalidCertificate)?
841 .clone()
842 };
843
844 let (rest, certificate) = X509Certificate::from_der(&certificate_der)
845 .map_err(|_| KeyResolutionError::InvalidCertificate)?;
846 if !rest.is_empty() {
847 return Err(KeyResolutionError::InvalidCertificate.into());
848 }
849 let public_key_bytes = certificate.public_key().raw.to_vec();
850 validate_spki_algorithm(&public_key_bytes, algorithm)?;
851 Ok(Some((
852 VerificationKey {
853 algorithm,
854 public_key_bytes,
855 certificate_der: Some(certificate_der),
856 name: None,
857 },
858 evidence,
859 )))
860 }
861
862 fn x509_trust_evidence(
863 info: &X509DataInfo,
864 trust: &crate::policy::KeyTrustPolicy,
865 ) -> Result<X509TrustEvidence, DsigError> {
866 let time = trust
867 .verification_time
868 .ok_or(KeyResolutionError::SystemTime)?;
869 X509TrustEvidence::new(
870 info.certificate_chain
871 .iter()
872 .map(|index| info.certificates[*index].as_slice()),
873 time,
874 trust.check_crls,
875 )
876 }
877
878 fn verify_x509_policy(
879 &self,
880 info: &X509DataInfo,
881 trust: &crate::policy::KeyTrustPolicy,
882 provider: &dyn crate::provider::CryptoProvider,
883 ) -> Result<(), KeyResolutionError> {
884 let options = X509ChainOptions {
885 trusted_certs: &self.config.trusted_certs,
886 verification_time: trust.verification_time.unwrap_or_else(SystemTime::now),
887 max_chain_depth: trust.max_x509_chain_depth,
888 check_crls: trust.check_crls,
889 allowed_extended_key_usages: Some(&trust.allowed_extended_key_usages),
890 rsa_keys: trust.rsa_keys,
891 dsa_keys: trust.dsa_keys,
892 certificate_signature_algorithms: trust.certificate_signature_algorithms.as_ref(),
893 };
894 verify_x509_certificate_chain_with_provider_and_crls(
895 info,
896 &options,
897 provider,
898 &self.config.crls,
899 )?;
900 Ok(())
901 }
902
903 fn prepare_embedded_x509(
904 &self,
905 info: &X509DataInfo,
906 signing_index: usize,
907 trust: &crate::policy::KeyTrustPolicy,
908 provider: &dyn crate::provider::CryptoProvider,
909 budget: &mut InspectedKeyCandidateBudget,
910 ) -> Result<X509DataInfo, DsigError> {
911 let signing_der = info
912 .certificates
913 .get(signing_index)
914 .ok_or(KeyResolutionError::InvalidCertificate)?;
915 let mut available = X509DataInfo {
916 crls: info.crls.clone(),
917 ..X509DataInfo::default()
918 };
919 let mut trusted_prefix_len = 0;
920 for certificate in &self.config.trusted_certs {
921 budget.charge()?;
922 if available
923 .certificates
924 .iter()
925 .any(|known| known == certificate)
926 {
927 continue;
928 }
929 available.parsed_certificates.push(
930 parse_x509_certificate(certificate)
931 .map_err(|_| KeyResolutionError::InvalidCertificate)?,
932 );
933 available.certificates.push(certificate.clone());
934 trusted_prefix_len += 1;
935 }
936 for certificate in self.config.lookup_certs.iter().chain(&info.certificates) {
937 budget.charge()?;
938 if available
939 .certificates
940 .iter()
941 .any(|known| known == certificate)
942 {
943 continue;
944 }
945 available.parsed_certificates.push(
946 parse_x509_certificate(certificate)
947 .map_err(|_| KeyResolutionError::InvalidCertificate)?,
948 );
949 available.certificates.push(certificate.clone());
950 }
951 let signing_index = available
952 .certificates
953 .iter()
954 .position(|certificate| certificate == signing_der)
955 .ok_or(KeyResolutionError::InvalidCertificate)?;
956 self.select_valid_x509_path(
957 &mut available,
958 signing_index,
959 trusted_prefix_len,
960 trust,
961 provider,
962 None,
963 )?;
964 Ok(available)
965 }
966
967 fn select_valid_x509_path(
968 &self,
969 available: &mut X509DataInfo,
970 signing_index: usize,
971 trusted_prefix_len: usize,
972 trust: &crate::policy::KeyTrustPolicy,
973 provider: &dyn crate::provider::CryptoProvider,
974 selectors: Option<&X509DataInfo>,
975 ) -> Result<bool, KeyResolutionError> {
976 let candidates = build_x509_certificate_paths_to_trusted_prefix(
977 available,
978 signing_index,
979 trusted_prefix_len,
980 trust.max_x509_chain_depth,
981 trust.max_x509_candidate_paths,
982 provider,
983 trust.certificate_signature_algorithms.as_ref(),
984 )
985 .map_err(|error| match error {
986 X509ChainBuildError::AmbiguousIssuer => KeyResolutionError::AmbiguousCertificate,
987 X509ChainBuildError::Policy(error) => {
988 KeyResolutionError::Chain(super::X509ChainError::Policy(error))
989 }
990 X509ChainBuildError::Provider(error) => {
991 KeyResolutionError::Chain(super::X509ChainError::Provider(error))
992 }
993 X509ChainBuildError::UnsupportedSignatureAlgorithm { oid } => {
994 KeyResolutionError::Chain(super::X509ChainError::UnsupportedSignatureAlgorithm {
995 oid,
996 })
997 }
998 _ => KeyResolutionError::InvalidCertificate,
999 })?;
1000 let mut first_error = None;
1001 let mut valid_path_without_selector_match = false;
1002 for candidate in candidates {
1003 available.certificate_chain = candidate;
1004 match self.verify_x509_policy(available, trust, provider) {
1005 Ok(()) => {
1006 if match selectors {
1007 Some(selectors) => {
1008 selected_x509_path_matches_selectors(available, selectors, provider)?
1009 }
1010 None => true,
1011 } {
1012 return Ok(true);
1013 }
1014 valid_path_without_selector_match = true;
1015 }
1016 Err(error) => {
1017 first_error.get_or_insert(error);
1018 }
1019 }
1020 }
1021 if valid_path_without_selector_match {
1022 return Ok(false);
1023 }
1024 Err(first_error.unwrap_or(KeyResolutionError::Chain(
1025 super::X509ChainError::UntrustedRoot,
1026 )))
1027 }
1028
1029 fn select_x509_selector_path(
1030 &self,
1031 available: &mut X509DataInfo,
1032 signing_index: usize,
1033 matching_indices: &[usize],
1034 trust: &crate::policy::KeyTrustPolicy,
1035 provider: &dyn crate::provider::CryptoProvider,
1036 selectors: &X509DataInfo,
1037 ) -> Result<bool, KeyResolutionError> {
1038 let targets = matching_indices
1039 .iter()
1040 .copied()
1041 .filter(|index| *index != signing_index)
1042 .collect::<Vec<_>>();
1043 if targets.is_empty() {
1044 return Ok(false);
1045 }
1046 let candidates = build_x509_certificate_paths_to_selector_targets(
1047 available,
1048 signing_index,
1049 &targets,
1050 trust.max_x509_chain_depth,
1051 trust.max_x509_candidate_paths,
1052 provider,
1053 trust.certificate_signature_algorithms.as_ref(),
1054 )
1055 .map_err(|error| match error {
1056 X509ChainBuildError::AmbiguousIssuer => KeyResolutionError::AmbiguousCertificate,
1057 X509ChainBuildError::Policy(error) => {
1058 KeyResolutionError::Chain(super::X509ChainError::Policy(error))
1059 }
1060 X509ChainBuildError::Provider(error) => {
1061 KeyResolutionError::Chain(super::X509ChainError::Provider(error))
1062 }
1063 X509ChainBuildError::UnsupportedSignatureAlgorithm { oid } => {
1064 KeyResolutionError::Chain(super::X509ChainError::UnsupportedSignatureAlgorithm {
1065 oid,
1066 })
1067 }
1068 _ => KeyResolutionError::InvalidCertificate,
1069 })?;
1070 for candidate in candidates {
1071 available.certificate_chain = candidate;
1072 if selected_x509_path_matches_selectors(available, selectors, provider)? {
1073 return Ok(true);
1074 }
1075 }
1076 Ok(false)
1077 }
1078
1079 fn resolve_configured_x509(
1080 &self,
1081 info: &X509DataInfo,
1082 trust: &crate::policy::KeyTrustPolicy,
1083 provider: &dyn crate::provider::CryptoProvider,
1084 budget: &mut InspectedKeyCandidateBudget,
1085 ) -> Result<Option<X509DataInfo>, DsigError> {
1086 if !x509_data_has_lookup_identifiers(info) {
1087 return Ok(None);
1088 }
1089
1090 let mut available = X509DataInfo {
1091 subject_names: info.subject_names.clone(),
1092 issuer_serials: info.issuer_serials.clone(),
1093 skis: info.skis.clone(),
1094 crls: info.crls.clone(),
1095 digests: info.digests.clone(),
1096 ..X509DataInfo::default()
1097 };
1098 let mut matches = Vec::new();
1099 let mut trusted_prefix_len = 0usize;
1100 for (trusted, certificate_der) in self
1101 .config
1102 .trusted_certs
1103 .iter()
1104 .map(|certificate| (true, certificate))
1105 .chain(
1106 self.config
1107 .lookup_certs
1108 .iter()
1109 .map(|certificate| (false, certificate)),
1110 )
1111 {
1112 budget.charge()?;
1113 if available
1114 .certificates
1115 .iter()
1116 .any(|available_der| available_der == certificate_der)
1117 {
1118 continue;
1119 }
1120 let parsed = parse_x509_certificate(certificate_der)
1121 .map_err(|_| KeyResolutionError::InvalidCertificate)?;
1122 let is_match =
1123 x509_certificate_matches_any_selector(info, &parsed, certificate_der, provider)
1124 .map_err(map_x509_selector_error)?;
1125 if is_match {
1126 matches.push((available.certificates.len(), parsed.clone()));
1127 }
1128 available.certificates.push(certificate_der.clone());
1129 available.parsed_certificates.push(parsed);
1130 if trusted {
1131 trusted_prefix_len += 1;
1132 }
1133 }
1134
1135 let matched_chain = X509DataInfo {
1136 certificates: matches
1137 .iter()
1138 .map(|(index, _)| available.certificates[*index].clone())
1139 .collect(),
1140 parsed_certificates: matches.iter().map(|(_, parsed)| parsed.clone()).collect(),
1141 ..X509DataInfo::default()
1142 };
1143 if !x509_selector_categories_match_chain(
1144 &X509DataInfo {
1145 subject_names: info.subject_names.clone(),
1146 issuer_serials: info.issuer_serials.clone(),
1147 skis: info.skis.clone(),
1148 digests: info.digests.clone(),
1149 ..matched_chain
1150 },
1151 provider,
1152 )
1153 .map_err(map_x509_selector_error)?
1154 {
1155 return Ok(None);
1156 }
1157
1158 let signing_index = match matches.as_slice() {
1159 [] => return Ok(None),
1160 [(index, _)] => *index,
1161 _ => {
1162 let leaves = matches
1163 .iter()
1164 .filter(|(_, candidate)| {
1165 !distinguished_names_equal(&candidate.subject_dn, &candidate.issuer_dn)
1166 && !matches.iter().any(|(_, other)| {
1167 distinguished_names_equal(&other.issuer_dn, &candidate.subject_dn)
1168 })
1169 })
1170 .collect::<Vec<_>>();
1171 match leaves.as_slice() {
1172 [(index, _)] => *index,
1173 _ => return Err(KeyResolutionError::AmbiguousCertificate.into()),
1174 }
1175 }
1176 };
1177 let matching_indices = matches.iter().map(|(index, _)| *index).collect::<Vec<_>>();
1178 available.certificate_chain =
1182 if signing_index < trusted_prefix_len || !trust.verify_x509_chains {
1183 vec![signing_index]
1184 } else {
1185 if !self.select_valid_x509_path(
1186 &mut available,
1187 signing_index,
1188 trusted_prefix_len,
1189 trust,
1190 provider,
1191 Some(info),
1192 )? {
1193 return Ok(None);
1194 }
1195 available.certificate_chain.clone()
1196 };
1197 if trust.verify_x509_chains && signing_index < trusted_prefix_len {
1198 self.verify_x509_policy(&available, trust, provider)?;
1199 }
1200 if !trust.verify_x509_chains || signing_index < trusted_prefix_len {
1201 let direct_match = selected_x509_path_matches_selectors(&available, info, provider)?;
1202 if !direct_match
1203 && (signing_index < trusted_prefix_len
1204 || !self.select_x509_selector_path(
1205 &mut available,
1206 signing_index,
1207 &matching_indices,
1208 trust,
1209 provider,
1210 info,
1211 )?)
1212 {
1213 return Ok(None);
1214 }
1215 }
1216 Ok(Some(available))
1217 }
1218
1219 fn resolve_key_value(
1220 key_value: &KeyValueInfo,
1221 algorithm: SignatureAlgorithm,
1222 ) -> Result<Option<VerificationKey>, KeyResolutionError> {
1223 let public_key_bytes = match key_value {
1224 KeyValueInfo::Dsa { p, q, g, y } => {
1225 if !matches!(
1226 algorithm,
1227 SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256
1228 ) {
1229 return Err(KeyResolutionError::AlgorithmMismatch);
1230 }
1231 let (Some(p), Some(q), Some(g)) = (p.as_deref(), q.as_deref(), g.as_deref()) else {
1232 return Err(KeyResolutionError::InvalidPublicKey);
1233 };
1234 dsa_key_value_to_spki_der(p, q, g, y)?
1235 }
1236 KeyValueInfo::Rsa { modulus, exponent } => {
1237 if !algorithm.is_rsa() {
1238 return Err(KeyResolutionError::AlgorithmMismatch);
1239 }
1240 rsa_key_value_to_spki_der(modulus, exponent)?
1241 }
1242 KeyValueInfo::Ec {
1243 curve_oid,
1244 public_key,
1245 } => {
1246 if algorithm.ecdsa_digest().is_none() {
1247 return Ok(None);
1248 }
1249 ec_key_value_to_spki_der(curve_oid, public_key)?
1250 }
1251 KeyValueInfo::InvalidEcKeyValue => return Err(KeyResolutionError::InvalidPublicKey),
1252 KeyValueInfo::Unsupported { .. } => return Ok(None),
1253 };
1254 validate_spki_algorithm(&public_key_bytes, algorithm)?;
1255
1256 Ok(Some(VerificationKey {
1257 algorithm,
1258 public_key_bytes,
1259 certificate_der: None,
1260 name: None,
1261 }))
1262 }
1263
1264 fn resolve_with_trust(
1265 &self,
1266 key_info: Option<&KeyInfo>,
1267 algorithm: SignatureAlgorithm,
1268 policy: &crate::policy::VerificationPolicy,
1269 provider: &dyn crate::provider::CryptoProvider,
1270 candidate_budget: &mut InspectedKeyCandidateBudget,
1271 scope: ResolutionScope,
1272 ) -> Result<Option<ResolvedVerificationKey<'static>>, DsigError> {
1273 self.resolve_source_range(
1274 key_info,
1275 algorithm,
1276 policy,
1277 provider,
1278 candidate_budget,
1279 scope,
1280 )?
1281 .finish()
1282 }
1283
1284 fn resolve_source_range(
1285 &self,
1286 key_info: Option<&KeyInfo>,
1287 algorithm: SignatureAlgorithm,
1288 policy: &crate::policy::VerificationPolicy,
1289 provider: &dyn crate::provider::CryptoProvider,
1290 candidate_budget: &mut InspectedKeyCandidateBudget,
1291 scope: ResolutionScope,
1292 ) -> Result<SourceResolution, DsigError> {
1293 let trust = &policy.key_trust;
1294 let resources = &policy.resources;
1295 trust.validate()?;
1296 resources.validate()?;
1297 let Some(key_info) = key_info else {
1298 return Ok(SourceResolution {
1299 key: None,
1300 deferred_error: None,
1301 });
1302 };
1303 let document_sources = matches!(
1304 scope,
1305 ResolutionScope::Document
1306 | ResolutionScope::DocumentPrefix(_)
1307 | ResolutionScope::DocumentSuffix(_)
1308 );
1309 if document_sources {
1310 validate_key_info_source_permissions(key_info, policy.key_sources)?;
1311 }
1312 let source_end = match scope {
1313 ResolutionScope::DocumentPrefix(end) | ResolutionScope::TrustedPrefix(end) => end,
1314 _ => key_info.sources.len(),
1315 };
1316 let source_start = match scope {
1317 ResolutionScope::DocumentSuffix(start) | ResolutionScope::TrustedSuffix(start) => start,
1318 _ => 0,
1319 };
1320 let mut deferred_key_value_error = None;
1321 let mut configured_material_checked = false;
1322 for source in &key_info.sources[source_start..source_end] {
1323 if !document_sources && matches!(source, KeyInfoSource::KeyName(_)) {
1324 continue;
1325 }
1326 let mut path_evidence = None;
1327 let mut caller_trusted =
1328 !document_sources || matches!(source, KeyInfoSource::KeyName(_));
1329 let resolved = match source {
1330 KeyInfoSource::X509Data(info) => {
1331 for (uri, _) in &info.digests {
1334 let algorithm = super::DigestAlgorithm::from_uri(uri).ok_or_else(|| {
1335 KeyResolutionError::UnsupportedDigestAlgorithm(uri.clone())
1336 })?;
1337 policy.check_digest_algorithm(algorithm)?;
1338 }
1339 if if info.certificate_chain.is_empty() {
1340 x509_data_has_lookup_identifiers(info)
1341 } else {
1342 trust.verify_x509_chains
1343 } {
1344 self.check_configured_x509_material(
1345 info,
1346 resources,
1347 trust,
1348 candidate_budget,
1349 !configured_material_checked,
1350 )?;
1351 configured_material_checked = true;
1352 }
1353 match self.resolve_x509(info, algorithm, trust, provider, candidate_budget)? {
1354 Some((key, evidence)) => {
1355 if evidence.is_none()
1356 && !caller_trusted
1357 && trust.mode
1358 == crate::policy::VerificationTrustMode::RequireTrustedKey
1359 && let Some(der) = key.certificate_der.as_ref()
1360 {
1361 for anchor in &self.config.trusted_certs {
1364 candidate_budget.charge()?;
1365 if anchor == der {
1366 caller_trusted = true;
1367 break;
1368 }
1369 }
1370 }
1371 path_evidence = evidence;
1372 Some(key)
1373 }
1374 None => None,
1375 }
1376 }
1377 KeyInfoSource::DerEncodedKeyValue(public_key_bytes) => {
1378 candidate_budget.charge()?;
1379 validate_spki_algorithm(public_key_bytes, algorithm)?;
1380 Some(VerificationKey {
1381 algorithm,
1382 public_key_bytes: public_key_bytes.clone(),
1383 certificate_der: None,
1384 name: None,
1385 })
1386 }
1387 KeyInfoSource::KeyName(name) => {
1388 candidate_budget.charge()?;
1389 self.config
1390 .named_keys
1391 .get(name)
1392 .map(|key| {
1393 if key.algorithm != algorithm {
1394 return Err(KeyResolutionError::AlgorithmMismatch);
1395 }
1396 validate_spki_algorithm(&key.public_key_bytes, algorithm)?;
1397 Ok(key.clone())
1398 })
1399 .transpose()?
1400 }
1401 KeyInfoSource::KeyValue(key_value) => {
1402 candidate_budget.charge()?;
1403 match Self::resolve_key_value(key_value, algorithm) {
1404 Ok(resolved) => resolved,
1405 Err(error) if key_value_error_allows_fallback(key_value, &error) => {
1406 deferred_key_value_error.get_or_insert(error);
1407 None
1408 }
1409 Err(error) => return Err(error.into()),
1410 }
1411 }
1412 KeyInfoSource::RetrievalMethod { .. } => {
1413 candidate_budget.charge()?;
1414 None
1415 }
1416 KeyInfoSource::KeyInfoReference { .. } => {
1417 candidate_budget.charge()?;
1418 None
1419 }
1420 };
1421 if let Some(key) = resolved {
1422 let key = Box::new(PolicyBoundVerificationKey {
1423 key,
1424 rsa_minimum_bits: trust.rsa_keys.minimum_modulus_bits,
1425 dsa_minimum_bits: trust.dsa_keys.minimum_modulus_bits,
1426 });
1427 let key = if policy.key_trust.mode
1428 == crate::policy::VerificationTrustMode::CryptographicOnly
1429 {
1430 ResolvedVerificationKey::Candidate(key)
1431 } else if let Some(evidence) = path_evidence {
1432 ResolvedVerificationKey::Validated(TrustedPublicKey::new(
1433 key,
1434 trust.clone(),
1435 evidence,
1436 ))
1437 } else if caller_trusted {
1438 ResolvedVerificationKey::CallerTrusted(key)
1439 } else {
1440 ResolvedVerificationKey::Candidate(key)
1441 };
1442 return Ok(SourceResolution {
1443 key: Some(key),
1444 deferred_error: None,
1445 });
1446 }
1447 }
1448 Ok(SourceResolution {
1449 key: None,
1450 deferred_error: deferred_key_value_error,
1451 })
1452 }
1453}
1454
1455impl KeyResolver for DefaultKeyResolver {
1456 fn resolve_for_verification<'a>(
1457 &'a self,
1458 key_info: Option<&KeyInfo>,
1459 algorithm: SignatureAlgorithm,
1460 policy: &crate::policy::VerificationPolicy,
1461 provider: &dyn crate::provider::CryptoProvider,
1462 ) -> Result<Option<ResolvedVerificationKey<'a>>, DsigError> {
1463 let mut budget = InspectedKeyCandidateBudget::new(policy);
1464 self.resolve_with_candidate_budget(key_info, algorithm, policy, provider, &mut budget)
1465 }
1466 fn resolve<'a>(
1467 &'a self,
1468 key_info: Option<&KeyInfo>,
1469 algorithm: SignatureAlgorithm,
1470 ) -> Result<Option<Box<dyn VerifyingKey + 'a>>, DsigError> {
1471 let policy = crate::policy::VerificationPolicy::default();
1472 let mut candidate_budget = InspectedKeyCandidateBudget::new(&policy);
1473 self.resolve_with_trust(
1474 key_info,
1475 algorithm,
1476 &policy,
1477 crate::provider::default_provider(),
1478 &mut candidate_budget,
1479 ResolutionScope::Document,
1480 )
1481 .map(|key| key.map(ResolvedVerificationKey::into_key))
1482 }
1483
1484 fn resolve_with_policy<'a>(
1485 &'a self,
1486 key_info: Option<&KeyInfo>,
1487 algorithm: SignatureAlgorithm,
1488 policy: &crate::policy::VerificationPolicy,
1489 ) -> Result<Option<Box<dyn VerifyingKey + 'a>>, DsigError> {
1490 self.resolve_with_policy_and_provider(
1491 key_info,
1492 algorithm,
1493 policy,
1494 crate::provider::default_provider(),
1495 )
1496 }
1497
1498 fn resolve_with_policy_and_provider<'a>(
1499 &'a self,
1500 key_info: Option<&KeyInfo>,
1501 algorithm: SignatureAlgorithm,
1502 policy: &crate::policy::VerificationPolicy,
1503 provider: &dyn crate::provider::CryptoProvider,
1504 ) -> Result<Option<Box<dyn VerifyingKey + 'a>>, DsigError> {
1505 let mut candidate_budget = InspectedKeyCandidateBudget::new(policy);
1506 self.resolve_with_candidate_budget(
1507 key_info,
1508 algorithm,
1509 policy,
1510 provider,
1511 &mut candidate_budget,
1512 )
1513 .map(|key| key.map(ResolvedVerificationKey::into_key))
1514 }
1515
1516 fn consumes_document_key_info(&self) -> bool {
1517 true
1518 }
1519}
1520
1521fn map_x509_selector_error(error: ParseError) -> DsigError {
1522 match error {
1523 ParseError::Provider(error) => DsigError::Provider(error),
1524 ParseError::UnsupportedAlgorithm { uri } => {
1525 KeyResolutionError::UnsupportedDigestAlgorithm(uri).into()
1526 }
1527 _ => KeyResolutionError::InvalidCertificate.into(),
1528 }
1529}
1530
1531fn selected_x509_path_matches_selectors(
1532 available: &X509DataInfo,
1533 selectors: &X509DataInfo,
1534 provider: &dyn crate::provider::CryptoProvider,
1535) -> Result<bool, KeyResolutionError> {
1536 let selected = X509DataInfo {
1537 subject_names: selectors.subject_names.clone(),
1538 issuer_serials: selectors.issuer_serials.clone(),
1539 skis: selectors.skis.clone(),
1540 digests: selectors.digests.clone(),
1541 certificates: available
1542 .certificate_chain
1543 .iter()
1544 .map(|index| available.certificates[*index].clone())
1545 .collect(),
1546 parsed_certificates: available
1547 .certificate_chain
1548 .iter()
1549 .map(|index| available.parsed_certificates[*index].clone())
1550 .collect(),
1551 ..X509DataInfo::default()
1552 };
1553 x509_selector_categories_match_chain(&selected, provider).map_err(|error| match error {
1554 ParseError::Provider(error) => {
1555 KeyResolutionError::Chain(super::X509ChainError::Provider(error))
1556 }
1557 ParseError::UnsupportedAlgorithm { uri } => {
1558 KeyResolutionError::UnsupportedDigestAlgorithm(uri)
1559 }
1560 _ => KeyResolutionError::InvalidCertificate,
1561 })
1562}
1563
1564fn rsa_key_value_to_spki_der(
1565 modulus: &[u8],
1566 exponent: &[u8],
1567) -> Result<Vec<u8>, KeyResolutionError> {
1568 let (modulus, exponent) = bounded_rsa_public_components(modulus, exponent)?;
1569 let key = rsa::RsaPublicKey::new(
1570 BoxedUint::from_be_slice_vartime(modulus),
1571 BoxedUint::from_be_slice_vartime(exponent),
1572 )
1573 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1574 key.to_public_key_der()
1575 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1576 .map(|der| der.as_bytes().to_vec())
1577}
1578
1579pub(crate) fn bounded_rsa_public_components<'a>(
1580 modulus: &'a [u8],
1581 exponent: &'a [u8],
1582) -> Result<(&'a [u8], &'a [u8]), KeyResolutionError> {
1583 let modulus = &modulus[modulus
1584 .iter()
1585 .position(|byte| *byte != 0)
1586 .unwrap_or(modulus.len())..];
1587 let exponent = &exponent[exponent
1588 .iter()
1589 .position(|byte| *byte != 0)
1590 .unwrap_or(exponent.len())..];
1591 let maximum = crate::hard_limits::RSA_MODULUS_BIT_CEILING;
1592 if modulus.is_empty()
1593 || exponent.is_empty()
1594 || modulus.len() > maximum.div_ceil(8)
1595 || exponent.len() > maximum.div_ceil(8)
1596 || (modulus.len() * 8 - modulus[0].leading_zeros() as usize) > maximum
1597 {
1598 return Err(KeyResolutionError::InvalidPublicKey);
1599 }
1600 Ok((modulus, exponent))
1601}
1602
1603fn dsa_key_value_to_spki_der(
1604 p: &[u8],
1605 q: &[u8],
1606 g: &[u8],
1607 y: &[u8],
1608) -> Result<Vec<u8>, KeyResolutionError> {
1609 let trim = |bytes: &[u8]| bytes.iter().take_while(|byte| **byte == 0).count();
1612 let p = &p[trim(p)..];
1613 let q = &q[trim(q)..];
1614 let g = &g[trim(g)..];
1615 let y = &y[trim(y)..];
1616 for value in [p, q, g, y] {
1617 if value.is_empty() || value.len() > crate::hard_limits::DSA_KEY_COMPONENT_BYTE_CEILING {
1618 return Err(KeyResolutionError::InvalidPublicKey);
1619 }
1620 }
1621 let components = dsa::Components::from_components(
1622 BoxedUint::from_be_slice_vartime(p),
1623 BoxedUint::from_be_slice_vartime(q),
1624 BoxedUint::from_be_slice_vartime(g),
1625 )
1626 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1627 dsa::VerifyingKey::from_components(components, BoxedUint::from_be_slice_vartime(y))
1628 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
1629 .to_public_key_der()
1630 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1631 .map(|der| der.as_bytes().to_vec())
1632}
1633
1634fn ec_key_value_to_spki_der(
1635 curve_oid: &str,
1636 public_key: &[u8],
1637) -> Result<Vec<u8>, KeyResolutionError> {
1638 match curve_oid {
1639 EC_P256_OID => p256::PublicKey::from_sec1_bytes(public_key)
1640 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
1641 .to_public_key_der()
1642 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1643 .map(|der| der.as_bytes().to_vec()),
1644 EC_P384_OID => p384::PublicKey::from_sec1_bytes(public_key)
1645 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
1646 .to_public_key_der()
1647 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1648 .map(|der| der.as_bytes().to_vec()),
1649 EC_P521_OID => p521::PublicKey::from_sec1_bytes(public_key)
1650 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
1651 .to_public_key_der()
1652 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1653 .map(|der| der.as_bytes().to_vec()),
1654 _ => Err(KeyResolutionError::InvalidPublicKey),
1655 }
1656}
1657
1658fn key_value_error_allows_fallback(key_value: &KeyValueInfo, error: &KeyResolutionError) -> bool {
1659 matches!(
1660 key_value,
1661 KeyValueInfo::Dsa { .. } | KeyValueInfo::Ec { .. } | KeyValueInfo::InvalidEcKeyValue
1662 ) && matches!(
1663 error,
1664 KeyResolutionError::InvalidPublicKey | KeyResolutionError::AlgorithmMismatch
1665 )
1666}
1667
1668fn validate_spki_algorithm(
1669 public_key_bytes: &[u8],
1670 algorithm: SignatureAlgorithm,
1671) -> Result<(), KeyResolutionError> {
1672 if algorithm.eddsa_signature_len().is_some()
1673 || matches!(algorithm, SignatureAlgorithm::PostQuantum(_))
1674 {
1675 return super::modern::validate_public_key(algorithm, public_key_bytes)
1676 .map_err(|_| KeyResolutionError::InvalidPublicKey);
1677 }
1678 let (rest, spki) = SubjectPublicKeyInfo::from_der(public_key_bytes)
1679 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1680 if !rest.is_empty() {
1681 return Err(KeyResolutionError::InvalidPublicKey);
1682 }
1683 let parsed = spki
1684 .parsed()
1685 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1686 let curve_oid = spki
1687 .algorithm
1688 .parameters
1689 .as_ref()
1690 .and_then(|value| value.as_oid().ok())
1691 .map(|oid| oid.to_id_string());
1692 match (algorithm, parsed) {
1693 (SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256, PublicKey::DSA(_)) => {
1694 let _ = decode_dsa_verifying_key(public_key_bytes)
1695 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1696 Ok(())
1697 }
1698 (method, PublicKey::RSA(_)) if method.is_rsa() => Ok(()),
1699 (method, PublicKey::EC(ec))
1700 if method.ecdsa_digest().is_some()
1701 && matches!(
1702 curve_oid.as_deref(),
1703 Some(EC_P256_OID | EC_P384_OID | EC_P521_OID)
1704 ) =>
1705 {
1706 validate_ec_public_key_encoding(&ec, spki.subject_public_key.data.as_ref())
1707 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1708 validate_ec_point(curve_oid.as_deref(), spki.subject_public_key.data.as_ref())?;
1709 Ok(())
1710 }
1711 _ => Err(KeyResolutionError::AlgorithmMismatch),
1712 }
1713}
1714
1715pub(crate) fn supported_parsed_spki_is_rsa(
1716 spki: &SubjectPublicKeyInfo<'_>,
1717 public_key_bytes: &[u8],
1718) -> Result<bool, KeyResolutionError> {
1719 let borrowed = pkcs8::SubjectPublicKeyInfoRef::try_from(public_key_bytes)
1720 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1721 if let Some(parameter) = super::PqAlgorithm::from_oid(borrowed.algorithm.oid) {
1722 super::modern::validate_public_key(
1723 SignatureAlgorithm::PostQuantum(parameter),
1724 public_key_bytes,
1725 )
1726 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1727 return Ok(false);
1728 }
1729 let eddsa = match spki.algorithm.algorithm.to_id_string().as_str() {
1730 "1.3.101.112" => Some(SignatureAlgorithm::Ed25519),
1731 "1.3.101.113" => Some(SignatureAlgorithm::Ed448),
1732 _ => None,
1733 };
1734 if let Some(algorithm) = eddsa {
1735 super::modern::validate_public_key(algorithm, public_key_bytes)
1736 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1737 return Ok(false);
1738 }
1739 let parsed = spki
1740 .parsed()
1741 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1742 match parsed {
1743 PublicKey::RSA(key) => {
1744 bounded_rsa_public_components(key.modulus, key.exponent)?;
1745 rsa::RsaPublicKey::from_public_key_der(public_key_bytes)
1746 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1747 Ok(true)
1748 }
1749 PublicKey::DSA(_) => {
1750 let _ = decode_dsa_verifying_key(public_key_bytes)
1751 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1752 Ok(false)
1753 }
1754 PublicKey::EC(ec) => {
1755 validate_ec_public_key_encoding(&ec, spki.subject_public_key.data.as_ref())
1756 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1757 let curve_oid = spki
1758 .algorithm
1759 .parameters
1760 .as_ref()
1761 .and_then(|value| value.as_oid().ok())
1762 .map(|oid| oid.to_id_string());
1763 validate_ec_point(curve_oid.as_deref(), spki.subject_public_key.data.as_ref())?;
1764 Ok(false)
1765 }
1766 _ => Err(KeyResolutionError::AlgorithmMismatch),
1767 }
1768}
1769
1770fn validate_ec_point(curve_oid: Option<&str>, point: &[u8]) -> Result<(), KeyResolutionError> {
1771 match curve_oid {
1772 Some(EC_P256_OID) => p256::PublicKey::from_sec1_bytes(point).map(|_| ()),
1773 Some(EC_P384_OID) => p384::PublicKey::from_sec1_bytes(point).map(|_| ()),
1774 Some(EC_P521_OID) => p521::PublicKey::from_sec1_bytes(point).map(|_| ()),
1775 _ => return Err(KeyResolutionError::AlgorithmMismatch),
1776 }
1777 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1778}
1779
1780pub(crate) fn supported_key_value_is_rsa(value: &KeyValueInfo) -> Result<bool, KeyResolutionError> {
1781 let (spki, is_rsa) = match value {
1782 KeyValueInfo::Rsa { modulus, exponent } => {
1783 (rsa_key_value_to_spki_der(modulus, exponent)?, true)
1784 }
1785 KeyValueInfo::Dsa {
1786 p: Some(p),
1787 q: Some(q),
1788 g: Some(g),
1789 y,
1790 } => (dsa_key_value_to_spki_der(p, q, g, y)?, false),
1791 KeyValueInfo::Ec {
1792 curve_oid,
1793 public_key,
1794 } => (ec_key_value_to_spki_der(curve_oid, public_key)?, false),
1795 _ => return Err(KeyResolutionError::InvalidPublicKey),
1796 };
1797 let algorithm = if is_rsa {
1798 SignatureAlgorithm::RsaSha256
1799 } else if matches!(value, KeyValueInfo::Dsa { .. }) {
1800 SignatureAlgorithm::DsaSha256
1801 } else {
1802 SignatureAlgorithm::EcdsaSha256
1803 };
1804 validate_spki_algorithm(&spki, algorithm)?;
1805 Ok(is_rsa)
1806}
1807
1808#[cfg(test)]
1809mod tests {
1810 use crate::xml::dom as roxmltree;
1811 use std::sync::atomic::{AtomicUsize, Ordering};
1812
1813 use base64::{Engine, engine::general_purpose::STANDARD};
1814 use der::Decode as _;
1815 use rcgen::{
1816 CertificateRevocationListParams, Issuer, KeyIdMethod, KeyPair, KeyUsagePurpose,
1817 RevokedCertParams, SerialNumber, date_time_ymd,
1818 };
1819 use rsa::{pkcs8::DecodePublicKey, traits::PublicKeyParts};
1820
1821 use super::*;
1822
1823 #[test]
1824 fn shared_candidate_budget_cannot_relax_active_policy() {
1825 let resolver = DefaultKeyResolver::new(KeyResolverConfig::default());
1828 let info = KeyInfo {
1829 sources: vec![KeyInfoSource::KeyName("missing".into())],
1830 };
1831 let mut policy = crate::policy::VerificationPolicy::default();
1832 policy.resources.max_key_candidates = 1;
1833 let mut budget = InspectedKeyCandidateBudget::new(&policy);
1834 assert!(
1835 resolver
1836 .resolve_with_candidate_budget(
1837 Some(&info),
1838 SignatureAlgorithm::RsaSha256,
1839 &policy,
1840 crate::provider::default_provider(),
1841 &mut budget
1842 )
1843 .expect("first candidate fits the active policy")
1844 .is_none()
1845 );
1846 assert!(matches!(
1847 resolver.resolve_with_candidate_budget(
1848 Some(&info),
1849 SignatureAlgorithm::RsaSha256,
1850 &policy,
1851 crate::provider::default_provider(),
1852 &mut budget
1853 ),
1854 Err(DsigError::Policy(
1855 crate::policy::PolicyViolation::ResourceLimit {
1856 maximum: 1,
1857 actual: 2,
1858 ..
1859 }
1860 ))
1861 ));
1862 let mut spent =
1863 InspectedKeyCandidateBudget::new(&crate::policy::VerificationPolicy::default());
1864 spent
1865 .charge_many(2)
1866 .expect("initial budget admits two candidates");
1867 assert!(matches!(
1868 resolver.resolve_with_candidate_budget(
1869 None,
1870 SignatureAlgorithm::RsaSha256,
1871 &policy,
1872 crate::provider::default_provider(),
1873 &mut spent
1874 ),
1875 Err(DsigError::Policy(
1876 crate::policy::PolicyViolation::ResourceLimit {
1877 maximum: 1,
1878 actual: 2,
1879 ..
1880 }
1881 ))
1882 ));
1883 }
1884
1885 #[test]
1886 fn dsa_key_value_components_are_bounded_before_bigint_decode() {
1887 let public = dsa::VerifyingKey::from_public_key_pem(include_str!(
1890 "../../tests/fixtures/keys/dsa/dsa-2048-public.pem"
1891 ))
1892 .expect("DSA fixture");
1893 let components = public.components();
1894 let values = [
1895 components.p().to_be_bytes_trimmed_vartime().to_vec(),
1896 components.q().to_be_bytes_trimmed_vartime().to_vec(),
1897 components.g().to_be_bytes_trimmed_vartime().to_vec(),
1898 public.y().to_be_bytes_trimmed_vartime().to_vec(),
1899 ];
1900 let expected = dsa_key_value_to_spki_der(&values[0], &values[1], &values[2], &values[3])
1901 .expect("valid DSA");
1902 for index in 0..4 {
1903 let mut oversized = values.clone();
1904 oversized[index] = vec![1; crate::hard_limits::DSA_KEY_COMPONENT_BYTE_CEILING + 1];
1905 assert!(
1906 dsa_key_value_to_spki_der(
1907 &oversized[0],
1908 &oversized[1],
1909 &oversized[2],
1910 &oversized[3]
1911 )
1912 .is_err()
1913 );
1914 }
1915 let padded = values.map(|value| {
1916 let mut padded = vec![0; 1024];
1917 padded.extend(value);
1918 padded
1919 });
1920 assert_eq!(
1921 dsa_key_value_to_spki_der(&padded[0], &padded[1], &padded[2], &padded[3])
1922 .expect("zero padding preserves unsigned DSA value"),
1923 expected
1924 );
1925 }
1926
1927 #[test]
1928 fn xml_rsa_components_are_bounded_before_bigint_decode() {
1929 let oversized = vec![1_u8; crate::hard_limits::RSA_MODULUS_BIT_CEILING.div_ceil(8) + 1];
1931 assert!(matches!(
1932 rsa_key_value_to_spki_der(&oversized, &[1, 0, 1]),
1933 Err(KeyResolutionError::InvalidPublicKey)
1934 ));
1935 }
1936
1937 #[test]
1938 fn oversized_dsa_spki_parameter_is_rejected_before_bigint_decode() {
1939 let oversized = vec![1_u8; crate::hard_limits::DSA_KEY_COMPONENT_BYTE_CEILING + 1];
1942 let one = [1_u8];
1943 let params = der::Encode::to_der(&super::super::signature::BorrowedDsaPublicParameters {
1944 p: der::asn1::UintRef::new(&oversized).expect("positive P"),
1945 q: der::asn1::UintRef::new(&one).expect("positive Q"),
1946 g: der::asn1::UintRef::new(&one).expect("positive G"),
1947 })
1948 .expect("parameters encode");
1949 let y = der::Encode::to_der(&der::asn1::UintRef::new(&one).expect("positive Y"))
1950 .expect("public value encodes");
1951 let spki = rsa::pkcs8::SubjectPublicKeyInfoRef {
1952 algorithm: rsa::pkcs8::AlgorithmIdentifierRef {
1953 oid: dsa::OID,
1954 parameters: Some(der::asn1::AnyRef::from_der(¶ms).expect("parameters")),
1955 },
1956 subject_public_key: der::asn1::BitStringRef::new(0, &y).expect("bit string"),
1957 };
1958 let encoded = der::Encode::to_der(&spki).expect("SPKI encodes");
1959 assert!(matches!(
1960 decode_dsa_verifying_key(&encoded),
1961 Err(super::super::signature::SignatureVerificationError::InvalidKeyDer)
1962 ));
1963 assert!(matches!(
1966 validate_spki_algorithm(&encoded, SignatureAlgorithm::DsaSha256),
1967 Err(KeyResolutionError::InvalidPublicKey)
1968 ));
1969 }
1970
1971 struct RejectSecondSha512Provider {
1972 sha512_calls: AtomicUsize,
1973 verification_calls: AtomicUsize,
1974 reject_verification_call: Option<usize>,
1975 rejected_verification_data: Option<Vec<u8>>,
1976 }
1977
1978 impl crate::provider::CryptoProvider for RejectSecondSha512Provider {
1979 fn name(&self) -> &'static str {
1980 "reject-second-sha512"
1981 }
1982
1983 fn supports(&self, capability: crate::provider::ProviderCapability<'_>) -> bool {
1984 crate::provider::default_provider().supports(capability)
1985 }
1986
1987 fn fill_random(&self, output: &mut [u8]) -> Result<(), crate::provider::ProviderError> {
1988 crate::provider::default_provider().fill_random(output)
1989 }
1990
1991 fn derive_key(
1992 &self,
1993 parameters: &crate::provider::KdfParameters<'_>,
1994 secret: &[u8],
1995 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1996 crate::provider::default_provider().derive_key(parameters, secret)
1997 }
1998
1999 fn digest(
2000 &self,
2001 algorithm: super::super::DigestAlgorithm,
2002 data: &[u8],
2003 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2004 if algorithm == super::super::DigestAlgorithm::Sha512
2005 && self.sha512_calls.fetch_add(1, Ordering::Relaxed) > 0
2006 {
2007 return Err(crate::provider::ProviderError::Unsupported {
2008 operation: crate::provider::ProviderOperation::Digest,
2009 algorithm: Some(algorithm.uri().to_owned()),
2010 });
2011 }
2012 crate::provider::default_provider().digest(algorithm, data)
2013 }
2014
2015 fn sign(
2016 &self,
2017 key: &dyn super::super::SigningKey,
2018 algorithm: SignatureAlgorithm,
2019 data: &[u8],
2020 ) -> Result<Vec<u8>, super::super::SigningKeyError> {
2021 crate::provider::default_provider().sign(key, algorithm, data)
2022 }
2023
2024 fn verify(
2025 &self,
2026 key: &dyn VerifyingKey,
2027 algorithm: SignatureAlgorithm,
2028 data: &[u8],
2029 signature: &[u8],
2030 ) -> Result<bool, DsigError> {
2031 let call = self.verification_calls.fetch_add(1, Ordering::Relaxed);
2032 if self.reject_verification_call == Some(call)
2033 || self
2034 .rejected_verification_data
2035 .as_deref()
2036 .is_some_and(|rejected| rejected == data)
2037 {
2038 return Err(crate::provider::ProviderError::Unsupported {
2039 operation: crate::provider::ProviderOperation::Verify,
2040 algorithm: Some(algorithm.uri().to_owned()),
2041 }
2042 .into());
2043 }
2044 crate::provider::default_provider().verify(key, algorithm, data, signature)
2045 }
2046
2047 fn verify_x509_signature(
2048 &self,
2049 algorithm: crate::provider::X509SignatureAlgorithm,
2050 data: &[u8],
2051 signature: &[u8],
2052 issuer_spki_der: &[u8],
2053 ) -> Result<bool, crate::provider::ProviderError> {
2054 let call = self.verification_calls.fetch_add(1, Ordering::Relaxed);
2055 if self.reject_verification_call == Some(call)
2056 || self
2057 .rejected_verification_data
2058 .as_deref()
2059 .is_some_and(|rejected| rejected == data)
2060 {
2061 return Err(crate::provider::ProviderError::Unsupported {
2062 operation: crate::provider::ProviderOperation::VerifyCertificate,
2063 algorithm: algorithm.oid().map(str::to_owned),
2064 });
2065 }
2066 crate::provider::default_provider().verify_x509_signature(
2067 algorithm,
2068 data,
2069 signature,
2070 issuer_spki_der,
2071 )
2072 }
2073
2074 #[cfg(feature = "xmlenc")]
2075 fn encrypt_data(
2076 &self,
2077 algorithm: crate::xmlenc::DataEncryptionAlgorithm,
2078 key: &[u8],
2079 plaintext: &[u8],
2080 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2081 crate::provider::default_provider().encrypt_data(algorithm, key, plaintext)
2082 }
2083
2084 #[cfg(feature = "xmlenc")]
2085 fn decrypt_data(
2086 &self,
2087 algorithm: crate::xmlenc::DataEncryptionAlgorithm,
2088 key: &[u8],
2089 ciphertext: &[u8],
2090 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2091 crate::provider::default_provider().decrypt_data(algorithm, key, ciphertext)
2092 }
2093
2094 #[cfg(feature = "xmlenc")]
2095 fn wrap_key(
2096 &self,
2097 algorithm: crate::xmlenc::KeyWrapAlgorithm,
2098 kek: &[u8],
2099 key: &[u8],
2100 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2101 crate::provider::default_provider().wrap_key(algorithm, kek, key)
2102 }
2103
2104 #[cfg(feature = "xmlenc")]
2105 fn unwrap_key(
2106 &self,
2107 algorithm: crate::xmlenc::KeyWrapAlgorithm,
2108 kek: &[u8],
2109 wrapped: &[u8],
2110 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2111 crate::provider::default_provider().unwrap_key(algorithm, kek, wrapped)
2112 }
2113
2114 #[cfg(feature = "xmlenc")]
2115 fn transport_key(
2116 &self,
2117 key: &dyn crate::provider::KeyTransportKey,
2118 parameters: &crate::xmlenc::RsaOaepParameters,
2119 plaintext: &[u8],
2120 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2121 crate::provider::default_provider().transport_key(key, parameters, plaintext)
2122 }
2123
2124 #[cfg(feature = "xmlenc")]
2125 fn recover_key(
2126 &self,
2127 key: &dyn crate::provider::KeyRecoveryKey,
2128 parameters: &crate::xmlenc::RsaOaepParameters,
2129 ciphertext: &[u8],
2130 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2131 crate::provider::default_provider().recover_key(key, parameters, ciphertext)
2132 }
2133 }
2134
2135 fn chain_policy() -> crate::policy::KeyTrustPolicy {
2136 crate::policy::KeyTrustPolicy {
2137 verify_x509_chains: true,
2138 ..crate::policy::KeyTrustPolicy::default()
2139 }
2140 }
2141
2142 fn cryptographic_policy() -> crate::policy::VerificationPolicy {
2143 verification_policy_with_trust(crate::policy::KeyTrustPolicy {
2145 mode: crate::policy::VerificationTrustMode::CryptographicOnly,
2146 ..crate::policy::KeyTrustPolicy::default()
2147 })
2148 }
2149
2150 fn chain_policy_at(verification_time: SystemTime) -> crate::policy::KeyTrustPolicy {
2151 crate::policy::KeyTrustPolicy {
2152 verification_time: Some(verification_time),
2153 ..chain_policy()
2154 }
2155 }
2156
2157 fn verification_policy_with_trust(
2158 key_trust: crate::policy::KeyTrustPolicy,
2159 ) -> crate::policy::VerificationPolicy {
2160 crate::policy::VerificationPolicy {
2161 key_trust,
2162 ..crate::policy::VerificationPolicy::default()
2163 }
2164 }
2165
2166 const SIGNED_SAML: &str =
2167 include_str!("../../tests/fixtures/saml/response_signed_by_idp_ecdsa.xml");
2168 const SAML_PUBLIC_KEY: &str =
2169 include_str!("../../tests/fixtures/keys/ec/saml-idp-ecdsa-pubkey.pem");
2170 const RSA_PUBLIC_KEY: &str = include_str!("../../tests/fixtures/keys/rsa/rsa-2048-pubkey.pem");
2171 const RSA_4096_CERTIFICATE: &str =
2172 include_str!("../../tests/fixtures/keys/rsa/rsa-4096-cert.pem");
2173 const X509_DIGEST_SIGNATURE: &str = include_str!(
2174 "../../tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloped-x509-digest-sha512.xml"
2175 );
2176 const X509_DIGEST_SHA256_SIGNATURE: &str = include_str!(
2177 "../../tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloped-x509-digest-sha256.xml"
2178 );
2179 const RSA_KEY_VALUE_SIGNATURE: &str = include_str!(
2180 "../../tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloping-sha256-rsa-sha256.xml"
2181 );
2182 const LEGACY_RSA_KEY_VALUE_SIGNATURE: &str = include_str!(
2183 "../../tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-rsa.xml"
2184 );
2185 const EC_P256_KEY_VALUE_SIGNATURE: &str = include_str!(
2186 "../../tests/fixtures/xmldsig/xmldsig11-interop-2012/signature-enveloping-p256_sha256.xml"
2187 );
2188 const EC_P384_KEY_VALUE_SIGNATURE: &str = include_str!(
2189 "../../tests/fixtures/xmldsig/xmldsig11-interop-2012/signature-enveloping-p384_sha384.xml"
2190 );
2191
2192 fn replace_key_info(xml: &str, replacement: &str) -> String {
2193 let start = xml.find("<ds:KeyInfo>").expect("fixture has KeyInfo");
2194 let end = xml
2195 .find("</ds:KeyInfo>")
2196 .expect("fixture has closing KeyInfo")
2197 + "</ds:KeyInfo>".len();
2198 format!("{}{}{}", &xml[..start], replacement, &xml[end..])
2199 }
2200
2201 fn replace_unprefixed_key_info(xml: &str, replacement: &str) -> String {
2202 let start = xml.find("<KeyInfo>").expect("fixture has KeyInfo");
2203 let end = xml.find("</KeyInfo>").expect("fixture has closing KeyInfo") + "</KeyInfo>".len();
2204 format!("{}{}{}", &xml[..start], replacement, &xml[end..])
2205 }
2206
2207 fn rsa_key_value_parts(public_key: &rsa::RsaPublicKey) -> (String, String) {
2208 (
2209 STANDARD.encode(public_key.n().to_be_bytes_trimmed_vartime()),
2210 STANDARD.encode(public_key.e().to_be_bytes_trimmed_vartime()),
2211 )
2212 }
2213
2214 fn x509_signature_with_leaf_subject() -> String {
2215 replace_unprefixed_key_info(
2216 X509_DIGEST_SIGNATURE,
2217 "<KeyInfo><X509Data><X509SubjectName>CN=Test Key rsa-4096,O=XML Security Library (http://www.aleksey.com/xmlsec),ST=California,C=US</X509SubjectName></X509Data></KeyInfo>",
2218 )
2219 }
2220
2221 fn fixture_certificate_time() -> SystemTime {
2222 SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_800_000_000)
2224 }
2225
2226 fn public_key_der(pem_text: &str) -> Vec<u8> {
2227 let (rest, pem) = x509_parser::pem::parse_x509_pem(pem_text.as_bytes())
2228 .expect("fixture public key is PEM");
2229 assert!(rest.iter().all(|byte| byte.is_ascii_whitespace()));
2230 assert_eq!(pem.label, "PUBLIC KEY");
2231 pem.contents
2232 }
2233
2234 fn certificate_der(pem_text: &str) -> Vec<u8> {
2235 let (rest, pem) = x509_parser::pem::parse_x509_pem(pem_text.as_bytes())
2236 .expect("fixture certificate is PEM");
2237 assert!(rest.iter().all(|byte| byte.is_ascii_whitespace()));
2238 assert_eq!(pem.label, "CERTIFICATE");
2239 pem.contents
2240 }
2241
2242 fn crl_der(pem_text: &str) -> Vec<u8> {
2243 let (rest, pem) =
2244 x509_parser::pem::parse_x509_pem(pem_text.as_bytes()).expect("fixture CRL is PEM");
2245 assert!(rest.iter().all(|byte| byte.is_ascii_whitespace()));
2246 assert_eq!(pem.label, "X509 CRL");
2247 pem.contents
2248 }
2249
2250 fn generated_certificate_params(common_name: &str, is_ca: bool) -> rcgen::CertificateParams {
2251 let mut params = rcgen::CertificateParams::new(Vec::new())
2252 .expect("empty SAN list should produce valid certificate parameters");
2253 params
2254 .distinguished_name
2255 .push(rcgen::DnType::CommonName, common_name);
2256 if is_ca {
2257 params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2258 params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2259 }
2260 params
2261 }
2262
2263 fn authorized_revoked_chain() -> (X509DataInfo, Vec<u8>) {
2264 let mut root_params = generated_certificate_params("revocation root", true);
2265 root_params.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign];
2266 let root = rcgen::CertifiedIssuer::self_signed(
2267 root_params,
2268 KeyPair::generate().expect("root key generation should succeed"),
2269 )
2270 .expect("root should be self-signable");
2271
2272 let issuer_key = KeyPair::generate().expect("issuer key generation should succeed");
2273 let mut issuer_params = generated_certificate_params("revocation issuer", true);
2274 issuer_params.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign];
2275 let issuer_certificate = issuer_params
2276 .signed_by(&issuer_key, &root)
2277 .expect("root should sign issuer certificate");
2278 let issuer = Issuer::new(issuer_params, issuer_key);
2279
2280 let mut leaf_params = generated_certificate_params("revoked signer", false);
2281 leaf_params.serial_number = Some(SerialNumber::from(42_u64));
2282 leaf_params.key_usages = vec![KeyUsagePurpose::DigitalSignature];
2283 let leaf = leaf_params
2284 .signed_by(
2285 &KeyPair::generate().expect("leaf key generation should succeed"),
2286 &issuer,
2287 )
2288 .expect("issuer should sign leaf certificate");
2289 let crl = CertificateRevocationListParams {
2290 this_update: date_time_ymd(2026, 3, 15),
2291 next_update: date_time_ymd(2026, 4, 15),
2292 crl_number: SerialNumber::from(1_u64),
2293 issuing_distribution_point: None,
2294 revoked_certs: vec![RevokedCertParams {
2295 serial_number: SerialNumber::from(42_u64),
2296 revocation_time: date_time_ymd(2026, 3, 16),
2297 reason_code: None,
2298 invalidity_date: None,
2299 }],
2300 key_identifier_method: KeyIdMethod::Sha256,
2301 }
2302 .signed_by(&issuer)
2303 .expect("issuer should sign CRL");
2304 let mut info = x509_info(
2305 vec![
2306 leaf.der().to_vec(),
2307 issuer_certificate.der().to_vec(),
2308 root.der().to_vec(),
2309 ],
2310 0,
2311 );
2312 info.crls.push(crl.der().to_vec());
2313 (info, root.der().to_vec())
2314 }
2315
2316 fn x509_info(certificates: Vec<Vec<u8>>, signing_index: usize) -> X509DataInfo {
2317 let parsed_certificates = certificates
2318 .iter()
2319 .map(|certificate| {
2320 parse_x509_certificate(certificate)
2321 .expect("generated certificate should have supported metadata")
2322 })
2323 .collect();
2324 X509DataInfo {
2325 certificates,
2326 parsed_certificates,
2327 certificate_chain: vec![signing_index],
2328 ..X509DataInfo::default()
2329 }
2330 }
2331
2332 #[test]
2333 fn defaults_match_key_resolution_policy() {
2334 let config = KeyResolverConfig::default();
2336
2337 assert!(config.trusted_certs.is_empty());
2338 assert!(config.lookup_certs.is_empty());
2339 assert!(config.named_keys.is_empty());
2340 let trust = crate::policy::VerificationPolicy::default().key_trust;
2341 assert!(!trust.verify_x509_chains);
2342 assert!(!trust.check_crls);
2343 assert_eq!(trust.verification_time, None);
2344 assert_eq!(trust.max_x509_chain_depth, 9);
2345 }
2346
2347 #[test]
2348 fn verification_policy_controls_leaf_extended_key_usage() {
2349 let root = rcgen::CertifiedIssuer::self_signed(
2352 generated_certificate_params("EKU policy root", true),
2353 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2354 )
2355 .expect("root should be self-signable");
2356 let mut leaf_params = generated_certificate_params("TLS-only XML signer", false);
2357 leaf_params.key_usages = vec![rcgen::KeyUsagePurpose::DigitalSignature];
2358 leaf_params.extended_key_usages = vec![rcgen::ExtendedKeyUsagePurpose::ServerAuth];
2359 let leaf = leaf_params
2360 .signed_by(
2361 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2362 &root,
2363 )
2364 .expect("root should sign leaf certificate");
2365 let key_info = KeyInfo {
2366 sources: vec![KeyInfoSource::X509Data(x509_info(
2367 vec![leaf.der().to_vec(), root.der().to_vec()],
2368 0,
2369 ))],
2370 };
2371 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2372 trusted_certs: vec![root.der().to_vec()],
2373 ..KeyResolverConfig::default()
2374 });
2375 let mut policy = crate::policy::VerificationPolicy::default();
2376 policy.key_trust.verify_x509_chains = true;
2377
2378 let error = match resolver.resolve_with_policy(
2379 Some(&key_info),
2380 SignatureAlgorithm::EcdsaSha256,
2381 &policy,
2382 ) {
2383 Ok(_) => panic!("unapproved restricted EKU must be rejected"),
2384 Err(error) => error,
2385 };
2386 assert!(matches!(
2387 error,
2388 DsigError::KeyResolution(KeyResolutionError::Chain(
2389 super::super::X509ChainError::InvalidKeyUsage {
2390 position: 0,
2391 required: "an approved extended key usage",
2392 }
2393 ))
2394 ));
2395
2396 policy.key_trust.allowed_extended_key_usages =
2397 std::collections::HashSet::from([crate::policy::ExtendedKeyPurpose::ServerAuth]);
2398 assert!(
2399 resolver
2400 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::EcdsaSha256, &policy,)
2401 .expect("approved restricted EKU must pass path validation")
2402 .is_some()
2403 );
2404 }
2405
2406 #[test]
2407 fn operation_policy_rejects_zero_x509_resource_limits() {
2408 for trust in [
2411 crate::policy::KeyTrustPolicy {
2412 verify_x509_chains: true,
2413 max_x509_chain_depth: 0,
2414 ..crate::policy::KeyTrustPolicy::default()
2415 },
2416 crate::policy::KeyTrustPolicy {
2417 verify_x509_chains: true,
2418 max_x509_candidate_paths: 0,
2419 ..crate::policy::KeyTrustPolicy::default()
2420 },
2421 ] {
2422 let certificate = certificate_der(RSA_4096_CERTIFICATE);
2423 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2424 trusted_certs: vec![certificate],
2425 ..KeyResolverConfig::default()
2426 });
2427 let policy = crate::policy::VerificationPolicy {
2428 key_trust: trust,
2429 ..crate::policy::VerificationPolicy::default()
2430 };
2431 let error = super::super::VerifyContext::new()
2432 .policy(policy)
2433 .key_resolver(&resolver)
2434 .verify(&x509_signature_with_leaf_subject())
2435 .expect_err("zero composed X.509 limits must fail as policy errors");
2436
2437 assert!(matches!(
2438 error,
2439 DsigError::Policy(crate::policy::PolicyViolation::InvalidResourceLimit {
2440 requirement: "limit must be nonzero",
2441 actual: 0,
2442 ..
2443 })
2444 ));
2445 }
2446 }
2447
2448 #[test]
2449 fn operation_policy_rejects_crl_checking_without_chain_validation() {
2450 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2453 lookup_certs: vec![certificate_der(RSA_4096_CERTIFICATE)],
2454 ..KeyResolverConfig::default()
2455 });
2456 let policy = crate::policy::VerificationPolicy {
2457 key_trust: crate::policy::KeyTrustPolicy {
2458 check_crls: true,
2459 ..crate::policy::KeyTrustPolicy::default()
2460 },
2461 ..crate::policy::VerificationPolicy::default()
2462 };
2463 let error = super::super::VerifyContext::new()
2464 .policy(policy)
2465 .key_resolver(&resolver)
2466 .verify(&x509_signature_with_leaf_subject())
2467 .expect_err("CRL-only trust policy must fail before certificate use");
2468
2469 assert!(matches!(
2470 error,
2471 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust {
2472 reason: "CRL checking requires X.509 chain validation"
2473 })
2474 ));
2475 }
2476
2477 #[test]
2478 fn hmac_key_rejects_empty_secret_and_wrong_algorithm() {
2479 assert!(matches!(
2481 HmacSha1VerificationKey::new(Vec::new()),
2482 Err(KeyResolutionError::InvalidPublicKey)
2483 ));
2484 let key = HmacSha1VerificationKey::new(b"secret".to_vec())
2485 .expect("non-empty HMAC secret must be accepted");
2486 assert!(matches!(
2487 key.verify(SignatureAlgorithm::RsaSha256, b"data", b"signature"),
2488 Err(DsigError::KeyResolution(
2489 KeyResolutionError::AlgorithmMismatch
2490 ))
2491 ));
2492 }
2493
2494 #[test]
2495 fn hmac_key_uses_the_operation_policy_for_truncation() {
2496 let key = HmacVerificationKey::new(b"secret".to_vec())
2500 .expect("the fixture HMAC secret is non-empty");
2501 let mut mac = hmac::Hmac::<sha1::Sha1>::new_from_slice(b"secret")
2502 .expect("HMAC accepts an arbitrary non-empty secret");
2503 mac.update(b"data");
2504 let expected = mac.finalize().into_bytes();
2505
2506 let policy = crate::policy::VerificationPolicy {
2507 hmac: crate::policy::HmacPolicy {
2508 minimum_key_bits: 40,
2509 minimum_output_bits: 80,
2510 },
2511 ..crate::policy::VerificationPolicy::default()
2512 };
2513 assert!(
2514 key.verify_with_policy(
2515 &policy,
2516 SignatureAlgorithm::HmacSha1,
2517 b"data",
2518 &expected[..10],
2519 )
2520 .expect("the compatibility policy and algorithm match")
2521 );
2522 assert!(
2523 !key.verify_with_policy(&policy, SignatureAlgorithm::HmacSha1, b"data", &[0_u8; 10],)
2524 .expect("a mismatched truncated MAC must be rejected")
2525 );
2526 }
2527
2528 #[test]
2529 fn hmac_key_direct_api_rejects_attacker_selected_short_output() {
2530 let key = HmacVerificationKey::new([0x42; 16]).expect("fixed HMAC key must parse");
2533 let mut mac = hmac::Hmac::<sha2::Sha256>::new_from_slice(&[0x42; 16])
2534 .expect("HMAC accepts the fixed secret");
2535 mac.update(b"data");
2536 let expected = mac.finalize().into_bytes();
2537
2538 assert!(matches!(
2539 key.verify(SignatureAlgorithm::HmacSha256, b"data", &expected[..1]),
2540 Err(DsigError::Policy(
2541 crate::policy::PolicyViolation::HmacOutputLength {
2542 minimum: 128,
2543 maximum: 256,
2544 actual: 8,
2545 }
2546 ))
2547 ));
2548 }
2549
2550 #[test]
2551 fn hmac_key_debug_redacts_secret_material() {
2552 let secret = b"unique-debug-secret-marker";
2554 let key = HmacVerificationKey::new(secret.to_vec())
2555 .expect("the fixture HMAC secret is non-empty");
2556
2557 let debug = format!("{key:?}");
2558 assert!(
2559 !debug
2560 .contains(std::str::from_utf8(secret).expect("the debug marker is literal ASCII"))
2561 );
2562 assert!(!debug.contains(&format!("{secret:?}")));
2563 assert!(!debug.contains("output_length_bits"));
2564 }
2565
2566 #[test]
2567 fn stores_named_verification_key_metadata() {
2568 let key = VerificationKey {
2570 algorithm: SignatureAlgorithm::RsaSha256,
2571 public_key_bytes: vec![1, 2, 3],
2572 certificate_der: Some(vec![4, 5, 6]),
2573 name: Some("idp-signing".into()),
2574 };
2575 let mut config = KeyResolverConfig::default();
2576 config.named_keys.insert("idp-signing".into(), key.clone());
2577
2578 assert_eq!(config.named_keys.get("idp-signing"), Some(&key));
2579 }
2580
2581 #[test]
2582 fn resolves_embedded_certificate_end_to_end() {
2583 let resolver = DefaultKeyResolver::default();
2585 let result = super::super::VerifyContext::new()
2586 .policy(cryptographic_policy())
2587 .key_resolver(&resolver)
2588 .verify(SIGNED_SAML)
2589 .expect("embedded certificate should resolve");
2590
2591 assert_eq!(result.status, super::super::DsigStatus::Valid);
2592 assert_eq!(
2593 result.key_trust,
2594 super::super::KeyTrustEvidence::NotEstablished
2595 );
2596 }
2597
2598 #[test]
2599 fn embedded_certificate_requires_trust_but_explicit_pin_authorizes_it() {
2600 let untrusted = DefaultKeyResolver::default();
2602 let error = super::super::VerifyContext::new()
2603 .key_resolver(&untrusted)
2604 .verify(SIGNED_SAML)
2605 .expect_err("an embedded certificate is not a trust declaration");
2606 assert!(matches!(
2607 error,
2608 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust { .. })
2609 ));
2610
2611 let xml = roxmltree::Document::parse(SIGNED_SAML).expect("signed SAML fixture must parse");
2612 let certificate = xml
2613 .descendants()
2614 .find(|node| {
2615 node.has_tag_name(("http://www.w3.org/2000/09/xmldsig#", "X509Certificate"))
2616 })
2617 .expect("signed SAML must embed its certificate");
2618 let der = STANDARD
2619 .decode(
2620 certificate
2621 .text()
2622 .expect("fixture certificate must contain Base64 text")
2623 .split_whitespace()
2624 .collect::<String>(),
2625 )
2626 .expect("fixture certificate must be valid Base64");
2627 let trusted = DefaultKeyResolver::new(KeyResolverConfig {
2628 trusted_certs: vec![der],
2629 ..KeyResolverConfig::default()
2630 });
2631 let result = super::super::VerifyContext::new()
2632 .key_resolver(&trusted)
2633 .verify(SIGNED_SAML)
2634 .expect("an exact caller certificate pin authorizes the key");
2635 assert_eq!(result.status, super::super::DsigStatus::Valid);
2636 assert_eq!(
2637 result.key_trust,
2638 super::super::KeyTrustEvidence::CallerTrusted
2639 );
2640
2641 assert!(
2643 super::super::VerifyContext::new()
2644 .key_resolver(&untrusted)
2645 .verify(SIGNED_SAML)
2646 .is_err()
2647 );
2648 }
2649
2650 #[test]
2651 fn certificate_pin_inspections_share_the_candidate_budget() {
2652 let xml = roxmltree::Document::parse(SIGNED_SAML).expect("fixture must parse");
2654 let text = xml
2655 .descendants()
2656 .find(|node| {
2657 node.has_tag_name(("http://www.w3.org/2000/09/xmldsig#", "X509Certificate"))
2658 })
2659 .and_then(|node| node.text())
2660 .expect("fixture embeds a certificate");
2661 let certificate = STANDARD
2662 .decode(text.split_whitespace().collect::<String>())
2663 .expect("fixture certificate must decode");
2664 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2665 trusted_certs: vec![certificate],
2666 ..KeyResolverConfig::default()
2667 });
2668 let mut policy = crate::policy::VerificationPolicy::default();
2669 policy.resources.max_key_candidates = 1;
2670 let error = super::super::VerifyContext::new()
2671 .policy(policy)
2672 .key_resolver(&resolver)
2673 .verify(SIGNED_SAML)
2674 .expect_err("the certificate and pin are separate inspections");
2675 assert!(matches!(
2676 error,
2677 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
2678 resource: crate::policy::resource_name::KEY_CANDIDATES,
2679 maximum: 1,
2680 actual: 2,
2681 })
2682 ));
2683 }
2684
2685 #[test]
2686 fn resolves_x509_digest_from_configured_certificates() {
2687 let leaf_certificate_der = certificate_der(RSA_4096_CERTIFICATE);
2690 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2691 lookup_certs: vec![leaf_certificate_der],
2692 trusted_certs: vec![
2693 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
2694 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
2695 ],
2696 ..KeyResolverConfig::default()
2697 });
2698 for signature in [X509_DIGEST_SHA256_SIGNATURE, X509_DIGEST_SIGNATURE] {
2699 let result = super::super::VerifyContext::new()
2700 .policy(cryptographic_policy())
2701 .key_resolver(&resolver)
2702 .verify(signature)
2703 .expect("X509Digest should resolve a configured certificate");
2704
2705 assert_eq!(result.status, super::super::DsigStatus::Valid);
2706 }
2707 }
2708
2709 #[test]
2710 fn selector_resolved_certificate_obeys_chain_policy() {
2711 let leaf_certificate_der = certificate_der(RSA_4096_CERTIFICATE);
2714 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2715 lookup_certs: vec![leaf_certificate_der],
2716 trusted_certs: vec![
2717 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
2718 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
2719 ],
2720 ..KeyResolverConfig::default()
2721 });
2722 let error = super::super::VerifyContext::new()
2723 .policy(verification_policy_with_trust(chain_policy_at(
2724 SystemTime::UNIX_EPOCH,
2725 )))
2726 .key_resolver(&resolver)
2727 .verify(&x509_signature_with_leaf_subject())
2728 .expect_err("selector-resolved certificate must satisfy chain policy");
2729
2730 assert!(
2731 matches!(
2732 &error,
2733 DsigError::KeyResolution(KeyResolutionError::Chain(
2734 super::super::X509ChainError::CertificateNotValid(_)
2735 ))
2736 ),
2737 "unexpected selector policy error: {error:?}"
2738 );
2739 }
2740
2741 #[test]
2742 fn selector_resolved_configured_root_remains_a_trust_anchor() {
2743 let mut params = rcgen::CertificateParams::new(Vec::new())
2746 .expect("empty SAN list should produce valid certificate parameters");
2747 params
2748 .distinguished_name
2749 .push(rcgen::DnType::CommonName, "configured root");
2750 params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2751 let key_pair = rcgen::KeyPair::generate().expect("test key generation should succeed");
2752 let certificate = params
2753 .self_signed(&key_pair)
2754 .expect("test root should be self-signable");
2755 let certificate_der = certificate.der().to_vec();
2756 let key_info_xml = concat!(
2757 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
2758 "<X509Data><X509SubjectName>CN=configured root</X509SubjectName></X509Data>",
2759 "</KeyInfo>"
2760 );
2761 let document = roxmltree::Document::parse(key_info_xml)
2762 .expect("static selector KeyInfo should parse as XML");
2763 let key_info = super::super::parse_key_info(document.root_element())
2764 .expect("static selector KeyInfo should satisfy XMLDSig structure");
2765 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2766 trusted_certs: vec![certificate_der],
2767 ..KeyResolverConfig::default()
2768 });
2769
2770 let resolved = resolver
2771 .resolve_with_policy(
2772 Some(&key_info),
2773 SignatureAlgorithm::EcdsaSha256,
2774 &verification_policy_with_trust(chain_policy()),
2775 )
2776 .expect("configured self-signed certificate should validate as its own anchor");
2777
2778 assert!(resolved.is_some());
2779 }
2780
2781 #[test]
2782 fn selector_resolved_non_self_signed_trust_anchor_terminates_the_path() {
2783 let mut issuer_params = rcgen::CertificateParams::new(Vec::new())
2787 .expect("empty issuer SAN list should be valid");
2788 issuer_params
2789 .distinguished_name
2790 .push(rcgen::DnType::CommonName, "lookup-only issuer");
2791 issuer_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2792 issuer_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2793 let issuer = rcgen::CertifiedIssuer::self_signed(
2794 issuer_params,
2795 rcgen::KeyPair::generate().expect("issuer key generation should succeed"),
2796 )
2797 .expect("issuer certificate should be self-signable");
2798
2799 let mut anchor_params = rcgen::CertificateParams::new(Vec::new())
2800 .expect("empty anchor SAN list should be valid");
2801 anchor_params
2802 .distinguished_name
2803 .push(rcgen::DnType::CommonName, "direct trust anchor");
2804 let anchor = anchor_params
2805 .signed_by(
2806 &rcgen::KeyPair::generate().expect("anchor key generation should succeed"),
2807 &issuer,
2808 )
2809 .expect("issuer should sign the directly trusted certificate");
2810 let key_info_xml = concat!(
2811 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
2812 "<X509Data><X509SubjectName>CN=direct trust anchor</X509SubjectName></X509Data>",
2813 "</KeyInfo>"
2814 );
2815 let document = roxmltree::Document::parse(key_info_xml)
2816 .expect("static selector KeyInfo should parse as XML");
2817 let key_info = super::super::parse_key_info(document.root_element())
2818 .expect("static selector KeyInfo should satisfy XMLDSig structure");
2819 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2820 trusted_certs: vec![anchor.der().to_vec()],
2821 lookup_certs: vec![issuer.der().to_vec()],
2822 ..KeyResolverConfig::default()
2823 });
2824
2825 let resolved = resolver
2826 .resolve_with_policy(
2827 Some(&key_info),
2828 SignatureAlgorithm::EcdsaSha256,
2829 &verification_policy_with_trust(chain_policy()),
2830 )
2831 .expect("an explicitly trusted selected certificate must terminate its path");
2832
2833 assert!(resolved.is_some());
2834 }
2835
2836 #[test]
2837 fn selector_resolved_leaf_stops_at_non_self_signed_trust_anchor() {
2838 let external_issuer = rcgen::CertifiedIssuer::self_signed(
2841 generated_certificate_params("external issuer", true),
2842 rcgen::KeyPair::generate().expect("external issuer key generation should succeed"),
2843 )
2844 .expect("external issuer should be self-signable");
2845 let anchor = rcgen::CertifiedIssuer::signed_by(
2846 generated_certificate_params("non-self-signed anchor", true),
2847 rcgen::KeyPair::generate().expect("anchor key generation should succeed"),
2848 &external_issuer,
2849 )
2850 .expect("external issuer should sign the anchor");
2851 let leaf = generated_certificate_params("anchor leaf", false)
2852 .signed_by(
2853 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2854 &anchor,
2855 )
2856 .expect("anchor should sign the leaf");
2857 let leaf_metadata = parse_x509_certificate(leaf.der())
2858 .expect("generated leaf should have supported metadata");
2859 let key_info = KeyInfo {
2860 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
2861 subject_names: vec![leaf_metadata.subject_dn],
2862 ..X509DataInfo::default()
2863 })],
2864 };
2865 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2866 trusted_certs: vec![anchor.der().to_vec()],
2867 lookup_certs: vec![leaf.der().to_vec(), external_issuer.der().to_vec()],
2868 ..KeyResolverConfig::default()
2869 });
2870
2871 let resolved = resolver
2872 .resolve_with_policy(
2873 Some(&key_info),
2874 SignatureAlgorithm::EcdsaSha256,
2875 &verification_policy_with_trust(chain_policy()),
2876 )
2877 .expect("path construction must stop at the configured anchor");
2878
2879 assert!(resolved.is_some());
2880 }
2881
2882 #[test]
2883 fn selector_resolved_leaf_does_not_anchor_itself() {
2884 let certificate_der = certificate_der(RSA_4096_CERTIFICATE);
2887 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2888 lookup_certs: vec![certificate_der],
2889 ..KeyResolverConfig::default()
2890 });
2891 let error = super::super::VerifyContext::new()
2892 .policy(verification_policy_with_trust(chain_policy_at(
2893 fixture_certificate_time(),
2894 )))
2895 .key_resolver(&resolver)
2896 .verify(&x509_signature_with_leaf_subject())
2897 .expect_err("selector-resolved leaf must not trust itself");
2898
2899 assert!(matches!(
2900 error,
2901 DsigError::KeyResolution(KeyResolutionError::Chain(
2902 super::super::X509ChainError::UntrustedRoot
2903 ))
2904 ));
2905 }
2906
2907 #[test]
2908 fn selector_resolved_leaf_uses_separate_anchor() {
2909 let leaf = certificate_der(RSA_4096_CERTIFICATE);
2912 let issuer = certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem"));
2913 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2914 lookup_certs: vec![leaf],
2915 trusted_certs: vec![issuer],
2916 ..KeyResolverConfig::default()
2917 });
2918 let result = super::super::VerifyContext::new()
2919 .policy(verification_policy_with_trust(chain_policy_at(
2920 fixture_certificate_time(),
2921 )))
2922 .key_resolver(&resolver)
2923 .verify(&x509_signature_with_leaf_subject())
2924 .expect("selector-resolved leaf should chain to its configured issuer");
2925
2926 assert_eq!(result.status, super::super::DsigStatus::Valid);
2927 }
2928
2929 #[test]
2930 fn selector_resolved_leaf_uses_lookup_intermediate() {
2931 let mut root_params =
2934 rcgen::CertificateParams::new(Vec::new()).expect("empty root SAN list should be valid");
2935 root_params
2936 .distinguished_name
2937 .push(rcgen::DnType::CommonName, "lookup root");
2938 root_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2939 root_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2940 let root = rcgen::CertifiedIssuer::self_signed(
2941 root_params,
2942 rcgen::KeyPair::generate().expect("root key generation should succeed"),
2943 )
2944 .expect("root certificate should be self-signable");
2945
2946 let mut intermediate_params = rcgen::CertificateParams::new(Vec::new())
2947 .expect("empty intermediate SAN list should be valid");
2948 intermediate_params
2949 .distinguished_name
2950 .push(rcgen::DnType::CommonName, "lookup intermediate");
2951 intermediate_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2952 intermediate_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2953 let intermediate = rcgen::CertifiedIssuer::signed_by(
2954 intermediate_params,
2955 rcgen::KeyPair::generate().expect("intermediate key generation should succeed"),
2956 &root,
2957 )
2958 .expect("root should sign the intermediate certificate");
2959
2960 let mut leaf_params =
2961 rcgen::CertificateParams::new(Vec::new()).expect("empty leaf SAN list should be valid");
2962 leaf_params
2963 .distinguished_name
2964 .push(rcgen::DnType::CommonName, "lookup leaf");
2965 let leaf = leaf_params
2966 .signed_by(
2967 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
2968 &intermediate,
2969 )
2970 .expect("intermediate should sign the leaf certificate");
2971 let key_info_xml = concat!(
2972 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
2973 "<X509Data><X509SubjectName>CN=lookup leaf</X509SubjectName></X509Data>",
2974 "</KeyInfo>"
2975 );
2976 let document = roxmltree::Document::parse(key_info_xml)
2977 .expect("static selector KeyInfo should parse as XML");
2978 let key_info = super::super::parse_key_info(document.root_element())
2979 .expect("static selector KeyInfo should satisfy XMLDSig structure");
2980 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2981 lookup_certs: vec![leaf.der().to_vec(), intermediate.der().to_vec()],
2982 trusted_certs: vec![root.der().to_vec()],
2983 ..KeyResolverConfig::default()
2984 });
2985
2986 let resolved = resolver
2987 .resolve_with_policy(
2988 Some(&key_info),
2989 SignatureAlgorithm::EcdsaSha256,
2990 &verification_policy_with_trust(chain_policy()),
2991 )
2992 .expect("selector-resolved leaf should chain through the lookup intermediate");
2993
2994 assert!(resolved.is_some());
2995 }
2996
2997 #[test]
2998 fn x509_path_signatures_use_the_operation_provider() {
2999 let root = rcgen::CertifiedIssuer::self_signed(
3003 generated_certificate_params("provider root", true),
3004 rcgen::KeyPair::generate().expect("root key generation should succeed"),
3005 )
3006 .expect("root should be self-signable");
3007 let leaf = generated_certificate_params("provider leaf", false)
3008 .signed_by(
3009 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3010 &root,
3011 )
3012 .expect("root should sign the leaf");
3013 let leaf_der = leaf.der().to_vec();
3014 let leaf_metadata =
3015 parse_x509_certificate(&leaf_der).expect("generated leaf metadata should parse");
3016 let policy = crate::policy::VerificationPolicy {
3017 key_trust: chain_policy(),
3018 ..crate::policy::VerificationPolicy::default()
3019 };
3020
3021 let cases = [
3022 (
3023 KeyInfo {
3024 sources: vec![KeyInfoSource::X509Data(x509_info(
3025 vec![leaf_der.clone()],
3026 0,
3027 ))],
3028 },
3029 Vec::new(),
3030 ),
3031 (
3032 KeyInfo {
3033 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
3034 subject_names: vec![leaf_metadata.subject_dn],
3035 ..X509DataInfo::default()
3036 })],
3037 },
3038 vec![leaf_der],
3039 ),
3040 ];
3041
3042 for (key_info, lookup_certs) in cases {
3043 let provider = RejectSecondSha512Provider {
3044 sha512_calls: AtomicUsize::new(0),
3045 verification_calls: AtomicUsize::new(0),
3046 reject_verification_call: Some(0),
3047 rejected_verification_data: None,
3048 };
3049 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3050 trusted_certs: vec![root.der().to_vec()],
3051 lookup_certs,
3052 ..KeyResolverConfig::default()
3053 });
3054 let error = match resolver.resolve_with_policy_and_provider(
3055 Some(&key_info),
3056 SignatureAlgorithm::EcdsaSha256,
3057 &policy,
3058 &provider,
3059 ) {
3060 Ok(_) => panic!("the operation provider must gate every X.509 path signature"),
3061 Err(error) => error,
3062 };
3063
3064 assert!(matches!(
3065 error,
3066 DsigError::KeyResolution(KeyResolutionError::Chain(
3067 super::super::X509ChainError::UnsupportedSignatureAlgorithm { ref oid }
3068 )) if oid == "1.2.840.10045.4.3.2"
3069 ));
3070 assert_eq!(provider.verification_calls.load(Ordering::Relaxed), 1);
3071 }
3072
3073 let provider = RejectSecondSha512Provider {
3076 sha512_calls: AtomicUsize::new(0),
3077 verification_calls: AtomicUsize::new(0),
3078 reject_verification_call: Some(1),
3079 rejected_verification_data: None,
3080 };
3081 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3082 trusted_certs: vec![root.der().to_vec()],
3083 ..KeyResolverConfig::default()
3084 });
3085 let key_info = KeyInfo {
3086 sources: vec![KeyInfoSource::X509Data(x509_info(
3087 vec![leaf.der().to_vec()],
3088 0,
3089 ))],
3090 };
3091 let error = match resolver.resolve_with_policy_and_provider(
3092 Some(&key_info),
3093 SignatureAlgorithm::EcdsaSha256,
3094 &policy,
3095 &provider,
3096 ) {
3097 Ok(_) => panic!("complete-path validation must retain the operation provider"),
3098 Err(error) => error,
3099 };
3100 assert!(matches!(
3101 error,
3102 DsigError::KeyResolution(KeyResolutionError::Chain(
3103 super::super::X509ChainError::Provider(_)
3104 ))
3105 ));
3106 assert_eq!(provider.verification_calls.load(Ordering::Relaxed), 2);
3107 }
3108
3109 #[test]
3110 fn embedded_leaf_uses_lookup_intermediate_with_duplicate_anchor() {
3111 let trusted_root = rcgen::CertifiedIssuer::self_signed(
3114 generated_certificate_params("unrelated trusted root", true),
3115 rcgen::KeyPair::generate().expect("root key generation should succeed"),
3116 )
3117 .expect("root should be self-signable");
3118 let issuer_root = rcgen::CertifiedIssuer::self_signed(
3119 generated_certificate_params("untrusted issuer root", true),
3120 rcgen::KeyPair::generate().expect("issuer root key generation should succeed"),
3121 )
3122 .expect("issuer root should be self-signable");
3123 let intermediate = rcgen::CertifiedIssuer::signed_by(
3124 generated_certificate_params("embedded intermediate", true),
3125 rcgen::KeyPair::generate().expect("intermediate key generation should succeed"),
3126 &issuer_root,
3127 )
3128 .expect("issuer root should sign the intermediate");
3129 let leaf = generated_certificate_params("embedded leaf", false)
3130 .signed_by(
3131 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3132 &intermediate,
3133 )
3134 .expect("intermediate should sign the leaf");
3135 let key_info = KeyInfo {
3136 sources: vec![KeyInfoSource::X509Data(x509_info(
3137 vec![leaf.der().to_vec()],
3138 0,
3139 ))],
3140 };
3141 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3142 lookup_certs: vec![intermediate.der().to_vec()],
3143 trusted_certs: vec![trusted_root.der().to_vec(), trusted_root.der().to_vec()],
3144 ..KeyResolverConfig::default()
3145 });
3146
3147 let policy = verification_policy_with_trust(chain_policy());
3148 let error = match resolver.resolve_with_policy(
3149 Some(&key_info),
3150 SignatureAlgorithm::EcdsaSha256,
3151 &policy,
3152 ) {
3153 Ok(_) => panic!("an untrusted lookup intermediate must not become a trust anchor"),
3154 Err(error) => error,
3155 };
3156
3157 assert!(matches!(
3158 error,
3159 DsigError::KeyResolution(KeyResolutionError::Chain(
3160 super::super::X509ChainError::UntrustedRoot
3161 ))
3162 ));
3163 }
3164
3165 #[test]
3166 fn selector_resolved_leaf_chooses_unique_valid_same_key_path() {
3167 let trusted_root = rcgen::CertifiedIssuer::self_signed(
3171 generated_certificate_params("trusted cross-sign root", true),
3172 rcgen::KeyPair::generate().expect("trusted root key generation should succeed"),
3173 )
3174 .expect("trusted root should be self-signable");
3175 let untrusted_root = rcgen::CertifiedIssuer::self_signed(
3176 generated_certificate_params("untrusted cross-sign root", true),
3177 rcgen::KeyPair::generate().expect("untrusted root key generation should succeed"),
3178 )
3179 .expect("untrusted root should be self-signable");
3180 let shared_params = generated_certificate_params("shared cross-sign issuer", true);
3181 let shared_key =
3182 rcgen::KeyPair::generate().expect("shared issuer key generation should succeed");
3183 let trusted_intermediate = shared_params
3184 .signed_by(&shared_key, &trusted_root)
3185 .expect("trusted root should cross-sign the shared issuer key");
3186 let untrusted_intermediate = shared_params
3187 .signed_by(&shared_key, &untrusted_root)
3188 .expect("untrusted root should cross-sign the shared issuer key");
3189 let shared_issuer = rcgen::Issuer::from_params(&shared_params, &shared_key);
3190 let leaf = generated_certificate_params("cross-signed leaf", false)
3191 .signed_by(
3192 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3193 &shared_issuer,
3194 )
3195 .expect("shared issuer key should sign the leaf");
3196 let leaf_metadata = parse_x509_certificate(leaf.der())
3197 .expect("generated leaf should have supported metadata");
3198 let key_info = KeyInfo {
3199 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
3200 subject_names: vec![leaf_metadata.subject_dn],
3201 ..X509DataInfo::default()
3202 })],
3203 };
3204 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3205 trusted_certs: vec![trusted_root.der().to_vec()],
3206 lookup_certs: vec![
3207 leaf.der().to_vec(),
3208 untrusted_intermediate.der().to_vec(),
3209 trusted_intermediate.der().to_vec(),
3210 untrusted_root.der().to_vec(),
3211 ],
3212 ..KeyResolverConfig::default()
3213 });
3214
3215 let resolved = resolver
3216 .resolve_with_policy(
3217 Some(&key_info),
3218 SignatureAlgorithm::EcdsaSha256,
3219 &verification_policy_with_trust(chain_policy()),
3220 )
3221 .expect("the sole path to a configured anchor should be selected");
3222
3223 assert!(resolved.is_some());
3224 }
3225
3226 #[test]
3227 fn self_issued_rollover_continues_to_same_name_trusted_signer() {
3228 let root = rcgen::CertifiedIssuer::self_signed(
3231 generated_certificate_params("rollover authority", true),
3232 rcgen::KeyPair::generate().expect("root key generation should succeed"),
3233 )
3234 .expect("root should be self-signable");
3235 let rollover_params = generated_certificate_params("rollover authority", true);
3236 let rollover_key =
3237 rcgen::KeyPair::generate().expect("rollover key generation should succeed");
3238 let rollover_certificate = rollover_params
3239 .signed_by(&rollover_key, &root)
3240 .expect("root should sign the same-name rollover certificate");
3241 let rollover_issuer = rcgen::Issuer::from_params(&rollover_params, &rollover_key);
3242 let leaf = generated_certificate_params("rollover leaf", false)
3243 .signed_by(
3244 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3245 &rollover_issuer,
3246 )
3247 .expect("rollover key should sign the leaf");
3248 let leaf_metadata =
3249 parse_x509_certificate(leaf.der()).expect("generated leaf metadata should parse");
3250 let key_info = KeyInfo {
3251 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
3252 subject_names: vec![leaf_metadata.subject_dn],
3253 ..X509DataInfo::default()
3254 })],
3255 };
3256 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3257 trusted_certs: vec![root.der().to_vec()],
3258 lookup_certs: vec![leaf.der().to_vec(), rollover_certificate.der().to_vec()],
3259 ..KeyResolverConfig::default()
3260 });
3261
3262 let resolved = resolver
3263 .resolve_with_policy(
3264 Some(&key_info),
3265 SignatureAlgorithm::EcdsaSha256,
3266 &verification_policy_with_trust(chain_policy()),
3267 )
3268 .expect("same-name rollover path must reach its configured signer");
3269
3270 assert!(resolved.is_some());
3271 }
3272
3273 #[test]
3274 fn x509_candidate_limit_counts_generated_partial_paths() {
3275 let root = rcgen::CertifiedIssuer::self_signed(
3278 generated_certificate_params("candidate root", true),
3279 rcgen::KeyPair::generate().expect("root key generation should succeed"),
3280 )
3281 .expect("root should be self-signable");
3282 let intermediate = rcgen::CertifiedIssuer::signed_by(
3283 generated_certificate_params("candidate intermediate", true),
3284 rcgen::KeyPair::generate().expect("intermediate key generation should succeed"),
3285 &root,
3286 )
3287 .expect("root should sign the intermediate");
3288 let leaf = generated_certificate_params("candidate leaf", false)
3289 .signed_by(
3290 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3291 &intermediate,
3292 )
3293 .expect("intermediate should sign the leaf");
3294 let info = x509_info(
3295 vec![
3296 root.der().to_vec(),
3297 intermediate.der().to_vec(),
3298 leaf.der().to_vec(),
3299 ],
3300 2,
3301 );
3302
3303 assert!(matches!(
3304 build_x509_certificate_paths_to_trusted_prefix(
3305 &info,
3306 2,
3307 1,
3308 9,
3309 2,
3310 crate::provider::default_provider(),
3311 None,
3312 ),
3313 Err(X509ChainBuildError::AmbiguousIssuer)
3314 ));
3315 }
3316
3317 #[test]
3318 fn selector_resolved_leaf_disambiguates_same_subject_issuers_by_signature() {
3319 let mut root_params =
3323 rcgen::CertificateParams::new(Vec::new()).expect("empty root SAN list should be valid");
3324 root_params
3325 .distinguished_name
3326 .push(rcgen::DnType::CommonName, "shared-issuer root");
3327 root_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
3328 root_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
3329 let root = rcgen::CertifiedIssuer::self_signed(
3330 root_params,
3331 rcgen::KeyPair::generate().expect("root key generation should succeed"),
3332 )
3333 .expect("root certificate should be self-signable");
3334
3335 let intermediate = |key: rcgen::KeyPair| {
3336 let mut params = rcgen::CertificateParams::new(Vec::new())
3337 .expect("empty intermediate SAN list should be valid");
3338 params
3339 .distinguished_name
3340 .push(rcgen::DnType::CommonName, "renewed intermediate");
3341 params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
3342 params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
3343 rcgen::CertifiedIssuer::signed_by(params, key, &root)
3344 .expect("root should sign the intermediate certificate")
3345 };
3346 let unrelated_intermediate = intermediate(
3347 rcgen::KeyPair::generate().expect("unrelated intermediate key generation should work"),
3348 );
3349 let signing_intermediate = intermediate(
3350 rcgen::KeyPair::generate().expect("signing intermediate key generation should work"),
3351 );
3352
3353 let mut leaf_params =
3354 rcgen::CertificateParams::new(Vec::new()).expect("empty leaf SAN list should be valid");
3355 leaf_params
3356 .distinguished_name
3357 .push(rcgen::DnType::CommonName, "same-subject leaf");
3358 let leaf = leaf_params
3359 .signed_by(
3360 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3361 &signing_intermediate,
3362 )
3363 .expect("the selected intermediate should sign the leaf certificate");
3364 let key_info_xml = concat!(
3365 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
3366 "<X509Data><X509SubjectName>CN=same-subject leaf</X509SubjectName></X509Data>",
3367 "</KeyInfo>"
3368 );
3369 let document = roxmltree::Document::parse(key_info_xml)
3370 .expect("static selector KeyInfo should parse as XML");
3371 let key_info = super::super::parse_key_info(document.root_element())
3372 .expect("static selector KeyInfo should satisfy XMLDSig structure");
3373 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3374 lookup_certs: vec![
3375 leaf.der().to_vec(),
3376 unrelated_intermediate.der().to_vec(),
3377 signing_intermediate.der().to_vec(),
3378 ],
3379 trusted_certs: vec![root.der().to_vec()],
3380 ..KeyResolverConfig::default()
3381 });
3382
3383 let resolved = resolver
3384 .resolve_with_policy(
3385 Some(&key_info),
3386 SignatureAlgorithm::EcdsaSha256,
3387 &verification_policy_with_trust(chain_policy()),
3388 )
3389 .expect("the leaf signature should select its unique same-subject issuer");
3390
3391 assert!(resolved.is_some());
3392 }
3393
3394 #[test]
3395 fn x509_path_builder_skips_policy_rejected_alternatives() {
3396 use crate::provider::X509SignatureAlgorithm;
3397 use std::collections::HashSet;
3398 let root = rcgen::CertifiedIssuer::self_signed(
3401 generated_certificate_params("policy root", true),
3402 rcgen::KeyPair::generate().expect("root key"),
3403 )
3404 .expect("root certificate");
3405 let alternate_root = rcgen::CertifiedIssuer::self_signed(
3406 generated_certificate_params("policy alternate root", true),
3407 rcgen::KeyPair::generate_for(&rcgen::PKCS_ECDSA_P384_SHA384)
3408 .expect("alternate root key"),
3409 )
3410 .expect("alternate root certificate");
3411 let shared_params = generated_certificate_params("policy shared issuer", true);
3412 let shared_key = rcgen::KeyPair::generate().expect("issuer key");
3413 let rejected = shared_params
3414 .signed_by(&shared_key, &alternate_root)
3415 .expect("cross-signed issuer");
3416 let shared = rcgen::CertifiedIssuer::signed_by(shared_params, shared_key, &root)
3417 .expect("issuer certificate");
3418 let leaf = generated_certificate_params("policy leaf", false)
3419 .signed_by(&rcgen::KeyPair::generate().expect("leaf key"), &shared)
3420 .expect("leaf certificate");
3421 let rejected = rejected.der().to_vec();
3422 let allowed = crate::policy::CertificateSignatureAlgorithms::Allowlist(HashSet::from([
3423 X509SignatureAlgorithm::Ecdsa(super::super::DigestAlgorithm::Sha256),
3424 ]));
3425 for rejected_first in [true, false] {
3426 let mut alternatives = vec![shared.der().to_vec(), rejected.clone()];
3427 if rejected_first {
3428 alternatives.reverse();
3429 }
3430 let permitted_index = if rejected_first { 3 } else { 2 };
3431 let info = x509_info(
3432 vec![
3433 root.der().to_vec(),
3434 leaf.der().to_vec(),
3435 alternatives.remove(0),
3436 alternatives.remove(0),
3437 alternate_root.der().to_vec(),
3438 ],
3439 1,
3440 );
3441 assert_eq!(
3442 build_x509_certificate_paths_to_trusted_prefix(
3443 &info,
3444 1,
3445 1,
3446 4,
3447 8,
3448 crate::provider::default_provider(),
3449 Some(&allowed),
3450 )
3451 .expect("forbidden alternative must not abort search"),
3452 vec![vec![1, permitted_index, 0]]
3453 );
3454 }
3455 let info = x509_info(
3456 vec![
3457 root.der().to_vec(),
3458 leaf.der().to_vec(),
3459 rejected,
3460 alternate_root.der().to_vec(),
3461 ],
3462 1,
3463 );
3464 assert!(matches!(
3465 build_x509_certificate_paths_to_trusted_prefix(
3466 &info,
3467 1,
3468 1,
3469 4,
3470 8,
3471 crate::provider::default_provider(),
3472 Some(&allowed),
3473 ),
3474 Err(X509ChainBuildError::Policy(_))
3475 ));
3476 }
3477
3478 #[test]
3479 fn x509_path_builder_skips_branch_local_unsupported_algorithms() {
3480 let root = rcgen::CertifiedIssuer::self_signed(
3484 generated_certificate_params("unsupported-edge root", true),
3485 rcgen::KeyPair::generate().expect("root key generation should succeed"),
3486 )
3487 .expect("root certificate should be self-signable");
3488 let signing_intermediate = rcgen::CertifiedIssuer::signed_by(
3489 generated_certificate_params("shared unsupported-edge issuer", true),
3490 rcgen::KeyPair::generate().expect("signing issuer key generation should succeed"),
3491 &root,
3492 )
3493 .expect("root should sign the intermediate certificate");
3494 let key_unsupported_intermediate = rcgen::CertifiedIssuer::signed_by(
3495 generated_certificate_params("shared unsupported-edge issuer", true),
3496 rcgen::KeyPair::generate().expect("unsupported issuer key generation should succeed"),
3497 &root,
3498 )
3499 .expect("root should sign the alternate intermediate certificate");
3500 let leaf = generated_certificate_params("unsupported-edge leaf", false)
3501 .signed_by(
3502 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3503 &signing_intermediate,
3504 )
3505 .expect("signing intermediate should sign the leaf");
3506
3507 let ordered = x509_info(
3508 vec![
3509 leaf.der().to_vec(),
3510 key_unsupported_intermediate.der().to_vec(),
3511 signing_intermediate.der().to_vec(),
3512 root.der().to_vec(),
3513 ],
3514 0,
3515 );
3516 let key_selective_provider = RejectSecondSha512Provider {
3517 sha512_calls: AtomicUsize::new(0),
3518 verification_calls: AtomicUsize::new(0),
3519 reject_verification_call: Some(0),
3520 rejected_verification_data: None,
3521 };
3522 assert_eq!(
3523 super::super::parse::build_x509_certificate_chain_from(
3524 &ordered,
3525 0,
3526 &key_selective_provider,
3527 None,
3528 )
3529 .expect("one unsupported issuer key must not suppress a usable candidate"),
3530 vec![0, 2, 3]
3531 );
3532
3533 let anchored_same_edge = x509_info(
3534 vec![
3535 root.der().to_vec(),
3536 leaf.der().to_vec(),
3537 key_unsupported_intermediate.der().to_vec(),
3538 signing_intermediate.der().to_vec(),
3539 ],
3540 1,
3541 );
3542 let first_candidate_unsupported = RejectSecondSha512Provider {
3543 sha512_calls: AtomicUsize::new(0),
3544 verification_calls: AtomicUsize::new(0),
3545 reject_verification_call: Some(0),
3546 rejected_verification_data: None,
3547 };
3548 assert_eq!(
3549 build_x509_certificate_paths_to_trusted_prefix(
3550 &anchored_same_edge,
3551 1,
3552 1,
3553 4,
3554 8,
3555 &first_candidate_unsupported,
3556 None,
3557 )
3558 .expect("a later same-DN issuer must survive an earlier provider capability miss"),
3559 vec![vec![1, 3, 0]]
3560 );
3561
3562 let mut unsupported_intermediate = signing_intermediate.der().to_vec();
3563 let ecdsa_sha256_oid = [0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02];
3564 let offsets = unsupported_intermediate
3565 .windows(ecdsa_sha256_oid.len())
3566 .enumerate()
3567 .filter_map(|(offset, window)| (window == ecdsa_sha256_oid).then_some(offset))
3568 .collect::<Vec<_>>();
3569 assert_eq!(
3570 offsets.len(),
3571 2,
3572 "certificate must repeat its signature OID"
3573 );
3574 for offset in offsets {
3575 unsupported_intermediate[offset + ecdsa_sha256_oid.len() - 1] = 0x05;
3576 }
3577
3578 let anchored = x509_info(
3579 vec![
3580 root.der().to_vec(),
3581 leaf.der().to_vec(),
3582 signing_intermediate.der().to_vec(),
3583 unsupported_intermediate,
3584 ],
3585 1,
3586 );
3587 assert_eq!(
3588 build_x509_certificate_paths_to_trusted_prefix(
3589 &anchored,
3590 1,
3591 1,
3592 4,
3593 8,
3594 crate::provider::default_provider(),
3595 None,
3596 )
3597 .expect("a branch-local provider gap must not abort path enumeration"),
3598 vec![vec![1, 2, 0]]
3599 );
3600
3601 let unsupported_only = x509_info(
3602 vec![
3603 root.der().to_vec(),
3604 leaf.der().to_vec(),
3605 anchored.certificates[3].clone(),
3606 ],
3607 1,
3608 );
3609 assert!(matches!(
3610 build_x509_certificate_paths_to_trusted_prefix(
3611 &unsupported_only,
3612 1,
3613 1,
3614 4,
3615 8,
3616 crate::provider::default_provider(),
3617 None,
3618 ),
3619 Err(X509ChainBuildError::UnsupportedSignatureAlgorithm { ref oid })
3620 if oid == "1.2.840.10045.4.3.5"
3621 ));
3622 }
3623
3624 #[test]
3625 fn selector_resolved_certificate_preserves_supplied_crls() {
3626 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>";
3627 let crl = crl_der(include_str!(
3628 "../../tests/fixtures/keys/rsa/rsa-2048-cert-revoked-crl.pem"
3629 ));
3630 let (_, parsed_crl) =
3631 x509_parser::revocation_list::CertificateRevocationList::from_der(&crl)
3632 .expect("tracked CRL must parse");
3633 let crl_signed_data = parsed_crl.tbs_cert_list.as_ref().to_vec();
3634 let xml = replace_unprefixed_key_info(
3635 RSA_KEY_VALUE_SIGNATURE,
3636 &selector.replace("CRL_PLACEHOLDER", &STANDARD.encode(&crl)),
3637 );
3638 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3639 lookup_certs: vec![certificate_der(include_str!(
3640 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
3641 ))],
3642 trusted_certs: vec![
3643 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
3644 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
3645 ],
3646 ..KeyResolverConfig::default()
3647 });
3648 let policy = verification_policy_with_trust(crate::policy::KeyTrustPolicy {
3649 check_crls: true,
3650 max_x509_chain_depth: 3,
3651 ..chain_policy_at(
3652 SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_773_964_800),
3653 )
3654 });
3655
3656 let error = super::super::VerifyContext::new()
3657 .policy(policy.clone())
3658 .key_resolver(&resolver)
3659 .verify(&xml)
3660 .expect_err("selector lookup must retain and enforce the supplied CRL");
3661 assert!(matches!(
3665 error,
3666 DsigError::KeyResolution(KeyResolutionError::Chain(
3667 super::super::X509ChainError::InvalidKeyUsage {
3668 position: 1,
3669 required: "cRLSign"
3670 }
3671 ))
3672 ));
3673
3674 let provider = RejectSecondSha512Provider {
3678 sha512_calls: AtomicUsize::new(0),
3679 verification_calls: AtomicUsize::new(0),
3680 reject_verification_call: None,
3681 rejected_verification_data: Some(crl_signed_data),
3682 };
3683 let error = super::super::VerifyContext::new()
3684 .policy(policy)
3685 .key_resolver(&resolver)
3686 .provider(&provider)
3687 .verify(&xml)
3688 .expect_err("CRL authentication must retain the operation provider");
3689 assert!(matches!(
3690 error,
3691 DsigError::KeyResolution(KeyResolutionError::Chain(
3692 super::super::X509ChainError::Provider(_)
3693 ))
3694 ));
3695 }
3696
3697 #[test]
3698 fn resolver_rejects_revoked_leaf_with_authorized_crl_issuer() {
3699 let (mut info, root) = authorized_revoked_chain();
3702 let issuer = info.certificates[1].clone();
3703 info.certificates.truncate(1);
3704 info.parsed_certificates.truncate(1);
3705 let key_info = KeyInfo {
3706 sources: vec![KeyInfoSource::X509Data(info)],
3707 };
3708 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3709 lookup_certs: vec![issuer],
3710 trusted_certs: vec![root],
3711 ..KeyResolverConfig::default()
3712 });
3713 let policy = verification_policy_with_trust(crate::policy::KeyTrustPolicy {
3714 check_crls: true,
3715 max_x509_chain_depth: 3,
3716 ..chain_policy_at(
3717 SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_773_964_800),
3718 )
3719 });
3720
3721 let error = match resolver.resolve_with_policy(
3722 Some(&key_info),
3723 SignatureAlgorithm::EcdsaSha256,
3724 &policy,
3725 ) {
3726 Ok(_) => panic!("an authenticated CRL must reject its revoked leaf"),
3727 Err(error) => error,
3728 };
3729 assert!(matches!(
3730 error,
3731 DsigError::KeyResolution(KeyResolutionError::Chain(
3732 super::super::X509ChainError::Revoked(0)
3733 ))
3734 ));
3735 }
3736
3737 #[test]
3738 fn resolves_each_x509_selector_from_configured_certificates() {
3739 let selectors = [
3742 "<X509SubjectName>CN=Test Key rsa-2048,O=XML Security Library (http://www.aleksey.com/xmlsec),ST=California,C=US</X509SubjectName>",
3743 "<X509SubjectName>CN= test key rsa-2048 ,O=xml security library (HTTP://WWW.ALEKSEY.COM/XMLSEC),ST=california,C=us</X509SubjectName>",
3744 "<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>",
3745 "<X509SKI>bcOXN/nsVl8GatRbcKrPbzIbw0Y=</X509SKI>",
3746 ];
3747 let configured_certificate = certificate_der(include_str!(
3748 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
3749 ));
3750
3751 for selector in selectors {
3752 let key_info = format!("<KeyInfo><X509Data>{selector}</X509Data></KeyInfo>");
3753 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
3754 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3755 lookup_certs: vec![configured_certificate.clone()],
3756 ..KeyResolverConfig::default()
3757 });
3758 let result = super::super::VerifyContext::new()
3759 .policy(cryptographic_policy())
3760 .key_resolver(&resolver)
3761 .verify(&xml)
3762 .expect("X509 selector should resolve configured certificate");
3763
3764 assert_eq!(result.status, super::super::DsigStatus::Valid);
3765 }
3766 }
3767
3768 #[test]
3769 fn resolves_configured_chain_selectors_across_certificates() {
3770 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>"#;
3773 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
3774 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3775 lookup_certs: vec![
3776 certificate_der(include_str!(
3777 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
3778 )),
3779 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
3780 ],
3781 ..KeyResolverConfig::default()
3782 });
3783 let result = super::super::VerifyContext::new()
3784 .policy(cryptographic_policy())
3785 .key_resolver(&resolver)
3786 .verify(&xml)
3787 .expect("selectors across one configured chain should resolve its leaf");
3788
3789 assert_eq!(result.status, super::super::DsigStatus::Valid);
3790 }
3791
3792 #[test]
3793 fn selectors_must_all_match_the_selected_certificate_path() {
3794 let signing_certificate = certificate_der(include_str!(
3797 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
3798 ));
3799 let issuer_certificate =
3800 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem"));
3801 let unrelated = generated_certificate_params("unrelated selector certificate", false)
3802 .self_signed(
3803 &rcgen::KeyPair::generate().expect("unrelated key generation should succeed"),
3804 )
3805 .expect("unrelated certificate should be self-signable")
3806 .der()
3807 .to_vec();
3808 let digest = crate::provider::default_provider()
3809 .digest(super::super::DigestAlgorithm::Sha256, &unrelated)
3810 .expect("SHA-256 selector digest must be available");
3811 let key_info_xml = format!(
3812 "<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>",
3813 STANDARD.encode(digest)
3814 );
3815 let document = roxmltree::Document::parse(&key_info_xml)
3816 .expect("generated selector KeyInfo must be XML");
3817 let key_info = super::super::parse_key_info(document.root_element())
3818 .expect("generated selector KeyInfo must be structurally valid");
3819 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3820 lookup_certs: vec![signing_certificate, issuer_certificate, unrelated],
3821 ..KeyResolverConfig::default()
3822 });
3823
3824 assert!(
3825 resolver
3826 .resolve(Some(&key_info), SignatureAlgorithm::RsaSha256)
3827 .expect("disjoint selector matches are a key miss")
3828 .is_none()
3829 );
3830 }
3831
3832 #[test]
3833 fn unmatched_x509_selector_does_not_resolve() {
3834 let key_info = "<KeyInfo><X509Data><X509SubjectName>CN=not-the-signer</X509SubjectName></X509Data></KeyInfo>";
3836 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
3837 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3838 lookup_certs: vec![certificate_der(include_str!(
3839 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
3840 ))],
3841 ..KeyResolverConfig::default()
3842 });
3843 let result = super::super::VerifyContext::new()
3844 .key_resolver(&resolver)
3845 .verify(&xml)
3846 .expect("an unmatched selector is a key miss, not a parser failure");
3847
3848 assert!(matches!(
3849 result.status,
3850 super::super::DsigStatus::Invalid(super::super::FailureReason::KeyNotFound)
3851 ));
3852 }
3853
3854 #[test]
3855 fn overlapping_trusted_and_lookup_certificate_preserves_trust() {
3856 let certificate = certificate_der(RSA_4096_CERTIFICATE);
3859 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3860 trusted_certs: vec![certificate.clone()],
3861 lookup_certs: vec![certificate],
3862 ..KeyResolverConfig::default()
3863 });
3864 let result = super::super::VerifyContext::new()
3865 .policy(verification_policy_with_trust(chain_policy_at(
3866 fixture_certificate_time(),
3867 )))
3868 .key_resolver(&resolver)
3869 .verify(&x509_signature_with_leaf_subject())
3870 .expect("trusted/lookup overlap must resolve as one trusted candidate");
3871
3872 assert_eq!(result.status, super::super::DsigStatus::Valid);
3873 let super::super::KeyTrustEvidence::ValidatedX509(evidence) = result.key_trust else {
3874 panic!("successful path validation must retain typed evidence");
3875 };
3876 assert_eq!(evidence.verification_time(), fixture_certificate_time());
3877 assert!(!evidence.revocation_checked());
3878 assert_eq!(evidence.certificate_fingerprints().len(), 1);
3879 assert_eq!(
3880 evidence.anchor_fingerprint(),
3881 &evidence.certificate_fingerprints()[0]
3882 );
3883
3884 let document = crate::XmlDocument::parse(x509_signature_with_leaf_subject())
3887 .expect("signed certificate selector fixture must parse");
3888 let report = super::super::VerifyContext::new()
3889 .policy(verification_policy_with_trust(chain_policy_at(
3890 fixture_certificate_time(),
3891 )))
3892 .key_resolver(&resolver)
3893 .verify_all(&document)
3894 .expect("batch verification must preserve the validated path");
3895 assert!(
3896 report
3897 .accepted(&document)
3898 .expect("current document acceptance")
3899 );
3900 assert_eq!(
3901 report.signatures()[0]
3902 .result()
3903 .as_ref()
3904 .expect("the individually processed Signature must verify")
3905 .key_trust,
3906 super::super::KeyTrustEvidence::ValidatedX509(evidence)
3907 );
3908 }
3909
3910 #[test]
3911 fn distinct_x509_selector_matches_remain_ambiguous() {
3912 let certificate = || {
3915 generated_certificate_params("ambiguous selector", false)
3916 .self_signed(
3917 &rcgen::KeyPair::generate().expect("test key generation should succeed"),
3918 )
3919 .expect("test certificate should be self-signable")
3920 .der()
3921 .to_vec()
3922 };
3923 let xml = replace_unprefixed_key_info(
3924 X509_DIGEST_SIGNATURE,
3925 "<KeyInfo><X509Data><X509SubjectName>CN=ambiguous selector</X509SubjectName></X509Data></KeyInfo>",
3926 );
3927 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3928 lookup_certs: vec![certificate(), certificate()],
3929 ..KeyResolverConfig::default()
3930 });
3931 let error = super::super::VerifyContext::new()
3932 .key_resolver(&resolver)
3933 .verify(&xml)
3934 .expect_err("distinct selector matches must fail closed");
3935
3936 assert!(matches!(
3937 error,
3938 DsigError::KeyResolution(KeyResolutionError::AmbiguousCertificate)
3939 ));
3940 }
3941
3942 #[test]
3943 fn unsupported_x509_digest_selector_fails_closed() {
3944 let key_info = "<KeyInfo xmlns:dsig11=\"http://www.w3.org/2009/xmldsig11#\"><X509Data><dsig11:X509Digest Algorithm=\"urn:unsupported\">AQ==</dsig11:X509Digest></X509Data></KeyInfo>";
3947 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
3948 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3949 lookup_certs: vec![certificate_der(include_str!(
3950 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
3951 ))],
3952 ..KeyResolverConfig::default()
3953 });
3954 let error = super::super::VerifyContext::new()
3955 .key_resolver(&resolver)
3956 .verify(&xml)
3957 .expect_err("unsupported X509Digest algorithm must fail closed");
3958
3959 assert!(matches!(
3960 error,
3961 DsigError::KeyResolution(KeyResolutionError::UnsupportedDigestAlgorithm(uri))
3962 if uri == "urn:unsupported"
3963 ));
3964 }
3965
3966 #[test]
3967 fn x509_digest_selector_uses_operation_provider() {
3968 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3971 lookup_certs: vec![certificate_der(RSA_4096_CERTIFICATE)],
3972 trusted_certs: vec![
3973 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
3974 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
3975 ],
3976 ..KeyResolverConfig::default()
3977 });
3978 let provider = RejectSecondSha512Provider {
3979 sha512_calls: AtomicUsize::new(0),
3980 verification_calls: AtomicUsize::new(0),
3981 reject_verification_call: None,
3982 rejected_verification_data: None,
3983 };
3984 let error = super::super::VerifyContext::new()
3985 .key_resolver(&resolver)
3986 .provider(&provider)
3987 .verify(X509_DIGEST_SIGNATURE)
3988 .expect_err("X509Digest selection must use the operation provider");
3989
3990 assert!(
3991 matches!(
3992 error,
3993 DsigError::Provider(crate::provider::ProviderError::Unsupported {
3994 operation: crate::provider::ProviderOperation::Digest,
3995 algorithm: Some(ref uri),
3996 }) if uri == super::super::DigestAlgorithm::Sha512.uri()
3997 ),
3998 "unexpected error: {error:?}"
3999 );
4000 }
4001
4002 #[test]
4003 fn resolves_named_key_end_to_end() {
4004 let xml = replace_key_info(
4006 SIGNED_SAML,
4007 "<ds:KeyInfo><ds:KeyName>idp-signing</ds:KeyName></ds:KeyInfo>",
4008 );
4009 let mut config = KeyResolverConfig::default();
4010 config.named_keys.insert(
4011 "idp-signing".into(),
4012 VerificationKey {
4013 algorithm: SignatureAlgorithm::EcdsaSha256,
4014 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4015 certificate_der: None,
4016 name: Some("idp-signing".into()),
4017 },
4018 );
4019 let resolver = DefaultKeyResolver::new(config);
4020 let result = super::super::VerifyContext::new()
4021 .key_resolver(&resolver)
4022 .verify(&xml)
4023 .expect("named key should resolve");
4024
4025 assert_eq!(result.status, super::super::DsigStatus::Valid);
4026 }
4027
4028 #[test]
4029 fn resolves_der_encoded_key_end_to_end() {
4030 let encoded = STANDARD.encode(public_key_der(SAML_PUBLIC_KEY));
4032 let xml = replace_key_info(
4033 SIGNED_SAML,
4034 &format!(
4035 "<ds:KeyInfo><dsig11:DEREncodedKeyValue xmlns:dsig11=\"http://www.w3.org/2009/xmldsig11#\">{encoded}</dsig11:DEREncodedKeyValue></ds:KeyInfo>"
4036 ),
4037 );
4038 let resolver = DefaultKeyResolver::default();
4039 let result = super::super::VerifyContext::new()
4040 .policy(cryptographic_policy())
4041 .key_resolver(&resolver)
4042 .verify(&xml)
4043 .expect("DER key should resolve");
4044
4045 assert_eq!(result.status, super::super::DsigStatus::Valid);
4046 }
4047
4048 #[test]
4049 fn resolves_rsa_key_value_end_to_end() {
4050 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
4052 .expect("fixture must contain an RSA public key");
4053 let (modulus, exponent) = rsa_key_value_parts(&public_key);
4054 let key_info = format!(
4055 "<KeyInfo><KeyValue><RSAKeyValue><Modulus>{}</Modulus><Exponent>{}</Exponent></RSAKeyValue></KeyValue></KeyInfo>",
4056 modulus, exponent,
4057 );
4058 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
4059 let resolver = DefaultKeyResolver::default();
4060 let result = super::super::VerifyContext::new()
4061 .policy(cryptographic_policy())
4062 .key_resolver(&resolver)
4063 .verify(&xml)
4064 .expect("RSAKeyValue should resolve");
4065
4066 assert_eq!(result.status, super::super::DsigStatus::Valid);
4067 }
4068
4069 #[test]
4070 fn rsa_key_value_rejects_legacy_weak_modulus() {
4071 let resolver = DefaultKeyResolver::default();
4074 let error = super::super::VerifyContext::new()
4075 .key_resolver(&resolver)
4076 .verify(LEGACY_RSA_KEY_VALUE_SIGNATURE)
4077 .expect_err("context policy must override permissive resolver defaults");
4078
4079 assert!(matches!(
4080 error,
4081 DsigError::Policy(crate::policy::PolicyViolation::Algorithm {
4082 operation: "verification",
4083 ..
4084 })
4085 ));
4086 }
4087
4088 #[test]
4089 fn operation_policy_rejects_disabled_embedded_key_source() {
4090 let key_info = KeyInfo {
4093 sources: vec![KeyInfoSource::KeyValue(KeyValueInfo::Rsa {
4094 modulus: vec![0x80; 256],
4095 exponent: vec![1, 0, 1],
4096 })],
4097 };
4098 let mut policy = crate::policy::VerificationPolicy::default();
4099 policy.key_sources.key_value = false;
4100
4101 let error = match DefaultKeyResolver::default().resolve_with_policy(
4102 Some(&key_info),
4103 SignatureAlgorithm::RsaSha256,
4104 &policy,
4105 ) {
4106 Ok(_) => panic!("disabled KeyValue must fail before key construction"),
4107 Err(error) => error,
4108 };
4109
4110 assert!(matches!(
4111 error,
4112 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust {
4113 reason: "KeyValue key sources are disabled"
4114 })
4115 ));
4116 }
4117
4118 #[test]
4119 fn operation_policy_preflights_every_key_info_source_before_resolution() {
4120 let mut config = KeyResolverConfig::default();
4123 config.named_keys.insert(
4124 "idp-signing".into(),
4125 VerificationKey {
4126 algorithm: SignatureAlgorithm::EcdsaSha256,
4127 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4128 certificate_der: None,
4129 name: Some("idp-signing".into()),
4130 },
4131 );
4132 let resolver = DefaultKeyResolver::new(config);
4133 let mut policy = crate::policy::VerificationPolicy::default();
4134 policy.key_sources.x509_data = false;
4135
4136 for sources in [
4137 vec![
4138 KeyInfoSource::KeyName("idp-signing".into()),
4139 KeyInfoSource::X509Data(X509DataInfo::default()),
4140 ],
4141 vec![
4142 KeyInfoSource::X509Data(X509DataInfo::default()),
4143 KeyInfoSource::KeyName("idp-signing".into()),
4144 ],
4145 ] {
4146 let error = match resolver.resolve_with_policy(
4147 Some(&KeyInfo { sources }),
4148 SignatureAlgorithm::EcdsaSha256,
4149 &policy,
4150 ) {
4151 Ok(_) => panic!("source order must not hide disabled X509Data"),
4152 Err(error) => error,
4153 };
4154
4155 assert!(matches!(
4156 error,
4157 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust {
4158 reason: "X509Data key sources are disabled"
4159 })
4160 ));
4161 }
4162 }
4163
4164 #[test]
4165 fn operation_policy_bounds_ordered_key_info_candidates() {
4166 let mut config = KeyResolverConfig::default();
4169 config.named_keys.insert(
4170 "idp-signing".into(),
4171 VerificationKey {
4172 algorithm: SignatureAlgorithm::EcdsaSha256,
4173 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4174 certificate_der: None,
4175 name: Some("idp-signing".into()),
4176 },
4177 );
4178 let resolver = DefaultKeyResolver::new(config);
4179 let key_info = KeyInfo {
4180 sources: vec![
4181 KeyInfoSource::KeyValue(KeyValueInfo::Ec {
4182 curve_oid: "1.3.132.0.35".into(),
4183 public_key: vec![4],
4184 }),
4185 KeyInfoSource::KeyName("idp-signing".into()),
4186 ],
4187 };
4188
4189 for maximum in [0, 1] {
4190 let mut policy = crate::policy::VerificationPolicy::default();
4191 policy.resources.max_key_candidates = maximum;
4192 let error = match resolver.resolve_with_policy(
4193 Some(&key_info),
4194 SignatureAlgorithm::EcdsaSha256,
4195 &policy,
4196 ) {
4197 Ok(_) => panic!("candidate ceiling {maximum} must stop resolution"),
4198 Err(error) => error,
4199 };
4200 assert!(matches!(
4201 error,
4202 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4203 resource: crate::policy::resource_name::KEY_CANDIDATES,
4204 maximum: observed,
4205 actual,
4206 }) if observed == maximum && actual == maximum + 1
4207 ));
4208 }
4209
4210 let mut policy = crate::policy::VerificationPolicy::default();
4211 policy.resources.max_key_candidates = 2;
4212 assert!(
4213 resolver
4214 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::EcdsaSha256, &policy,)
4215 .expect("two allowed attempts must reach the named key")
4216 .is_some()
4217 );
4218 }
4219
4220 #[test]
4221 fn operation_policy_bounds_configured_x509_selector_candidates() {
4222 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4226 lookup_certs: vec![
4227 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
4228 certificate_der(RSA_4096_CERTIFICATE),
4229 ],
4230 ..KeyResolverConfig::default()
4231 });
4232 let mut policy = crate::policy::VerificationPolicy::default();
4233 policy.resources.max_key_candidates = 1;
4234
4235 let error = super::super::VerifyContext::new()
4236 .policy(policy)
4237 .key_resolver(&resolver)
4238 .verify(&x509_signature_with_leaf_subject())
4239 .expect_err("the second configured certificate must exceed the candidate budget");
4240
4241 assert!(matches!(
4242 error,
4243 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4244 resource: crate::policy::resource_name::KEY_CANDIDATES,
4245 maximum: 1,
4246 actual: 2,
4247 })
4248 ));
4249 }
4250
4251 #[test]
4252 fn configured_crls_are_bounded_before_der_parsing() {
4253 let key_info = KeyInfo {
4255 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
4256 subject_names: vec!["CN=selected".into()],
4257 ..X509DataInfo::default()
4258 })],
4259 };
4260 let mut policy = crate::policy::VerificationPolicy::default();
4261 policy.key_trust.check_crls = true;
4262 policy.key_trust.verify_x509_chains = true;
4263 policy.resources.max_external_resource_bytes = 4;
4264 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4265 crls: vec![vec![0; 5]],
4266 ..KeyResolverConfig::default()
4267 });
4268 let error = resolver
4269 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::RsaSha256, &policy)
4270 .err()
4271 .expect("oversized CRL must fail before DER parsing");
4272 assert!(
4273 matches!(
4274 error,
4275 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4276 resource: crate::policy::resource_name::EXTERNAL_RESOURCE_BYTES,
4277 ..
4278 })
4279 ),
4280 "{error:?}"
4281 );
4282
4283 policy.resources.max_external_resource_bytes = 4;
4284 policy.resources.max_external_resource_total_bytes = 7;
4285 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4286 crls: vec![vec![0; 4], vec![0; 4]],
4287 ..KeyResolverConfig::default()
4288 });
4289 let error = resolver
4290 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::RsaSha256, &policy)
4291 .err()
4292 .expect("aggregate CRL bytes must fail before DER parsing");
4293 assert!(matches!(
4294 error,
4295 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4296 resource: crate::policy::resource_name::AGGREGATE_EXTERNAL_RESOURCE_BYTES,
4297 ..
4298 })
4299 ));
4300
4301 policy.resources.max_external_resource_total_bytes = 8;
4302 policy.resources.max_key_candidates = 1;
4303 let error = resolver
4304 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::RsaSha256, &policy)
4305 .err()
4306 .expect("CRL candidate count must fail before DER parsing");
4307 assert!(matches!(
4308 error,
4309 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4310 resource: crate::policy::resource_name::KEY_CANDIDATES,
4311 ..
4312 })
4313 ));
4314 }
4315
4316 #[test]
4317 fn configured_certificates_and_crls_share_external_byte_budget() {
4318 let key_info = KeyInfo {
4322 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
4323 subject_names: vec!["CN=selected".into()],
4324 ..X509DataInfo::default()
4325 })],
4326 };
4327 let mut policy = crate::policy::VerificationPolicy::default();
4328 policy.key_trust.check_crls = true;
4329 policy.key_trust.verify_x509_chains = true;
4330 policy.resources.max_external_resource_bytes = 8;
4331 policy.resources.max_external_resource_total_bytes = 12;
4332 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4333 trusted_certs: vec![vec![0; 8]],
4334 crls: vec![vec![0; 8]],
4335 ..KeyResolverConfig::default()
4336 });
4337 let error = resolver
4338 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::RsaSha256, &policy)
4339 .err()
4340 .expect("combined external material exceeds the operation limit");
4341 assert!(matches!(
4342 error,
4343 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4344 resource: crate::policy::resource_name::AGGREGATE_EXTERNAL_RESOURCE_BYTES,
4345 ..
4346 })
4347 ));
4348 }
4349
4350 #[test]
4351 fn embedded_and_configured_x509_share_one_byte_budget() {
4352 let mut info = KeyInfo {
4355 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
4356 certificates: vec![vec![0; 8]],
4357 certificate_chain: vec![0],
4358 crls: vec![vec![0; 2]],
4359 ..X509DataInfo::default()
4360 })],
4361 };
4362 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4363 crls: vec![vec![0; 8]],
4364 ..KeyResolverConfig::default()
4365 });
4366 let mut policy = crate::policy::VerificationPolicy::default();
4367 policy.key_trust.check_crls = true;
4368 policy.key_trust.verify_x509_chains = true;
4369 policy.resources.max_external_resource_total_bytes = 17;
4370 let error = resolver
4371 .resolve_with_policy(Some(&info), SignatureAlgorithm::RsaSha256, &policy)
4372 .err()
4373 .expect("combined material must be rejected");
4374 assert!(
4375 matches!(
4376 error,
4377 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4378 resource: crate::policy::resource_name::AGGREGATE_EXTERNAL_RESOURCE_BYTES,
4379 actual: 18,
4380 ..
4381 })
4382 ),
4383 "{error:?}"
4384 );
4385 policy.resources.max_external_resource_total_bytes = 18;
4386 let error = resolver
4387 .resolve_with_policy(Some(&info), SignatureAlgorithm::RsaSha256, &policy)
4388 .err()
4389 .expect("exact byte allowance reaches DER parsing");
4390 assert!(
4391 matches!(
4392 error,
4393 DsigError::KeyResolution(KeyResolutionError::InvalidCertificate)
4394 ),
4395 "{error:?}"
4396 );
4397 info.sources.insert(
4400 0,
4401 KeyInfoSource::X509Data(X509DataInfo {
4402 subject_names: vec!["CN=absent".into()],
4403 ..X509DataInfo::default()
4404 }),
4405 );
4406 policy.resources.max_external_resource_total_bytes = 17;
4407 policy.resources.max_key_candidates = 2;
4408 assert!(matches!(
4409 resolver.resolve_with_policy(Some(&info), SignatureAlgorithm::RsaSha256, &policy),
4410 Err(DsigError::Policy(
4411 crate::policy::PolicyViolation::ResourceLimit {
4412 resource: crate::policy::resource_name::AGGREGATE_EXTERNAL_RESOURCE_BYTES,
4413 actual: 18,
4414 ..
4415 }
4416 ))
4417 ));
4418 }
4419
4420 #[test]
4421 fn direct_certificate_does_not_charge_unused_configured_store() {
4422 let certificate = certificate_der(RSA_4096_CERTIFICATE);
4425 let key_info = KeyInfo {
4426 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
4427 certificates: vec![certificate],
4428 certificate_chain: vec![0],
4429 subject_names: vec!["CN=unused-selector".into()],
4430 ..X509DataInfo::default()
4431 })],
4432 };
4433 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4434 lookup_certs: vec![vec![0; 4096]],
4435 trusted_certs: vec![vec![0; 4096]],
4436 ..KeyResolverConfig::default()
4437 });
4438 let mut policy = crate::policy::VerificationPolicy::default();
4439 policy.resources.max_external_resource_bytes = 1024;
4440 policy.resources.max_external_resource_total_bytes = 1024;
4441 assert!(
4442 resolver
4443 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::RsaSha256, &policy)
4444 .expect("unused configured certificates are not charged")
4445 .is_some()
4446 );
4447 }
4448
4449 #[test]
4450 fn operation_policy_bounds_embedded_x509_certificate_candidates() {
4451 let key_info = KeyInfo {
4455 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
4456 certificates: vec![
4457 certificate_der(RSA_4096_CERTIFICATE),
4458 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
4459 ],
4460 certificate_chain: vec![0],
4461 ..X509DataInfo::default()
4462 })],
4463 };
4464 let mut policy = crate::policy::VerificationPolicy::default();
4465 policy.resources.max_key_candidates = 1;
4466
4467 let error = match DefaultKeyResolver::default().resolve_with_policy(
4468 Some(&key_info),
4469 SignatureAlgorithm::RsaSha256,
4470 &policy,
4471 ) {
4472 Ok(_) => panic!("the second embedded certificate must exceed the candidate budget"),
4473 Err(error) => error,
4474 };
4475
4476 assert!(matches!(
4477 error,
4478 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4479 resource: crate::policy::resource_name::KEY_CANDIDATES,
4480 maximum: 1,
4481 actual: 2,
4482 })
4483 ));
4484 }
4485
4486 #[test]
4487 fn operation_policy_charges_duplicate_configured_x509_candidates() {
4488 let certificate = certificate_der(RSA_4096_CERTIFICATE);
4491 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4492 lookup_certs: vec![certificate.clone(), certificate],
4493 ..KeyResolverConfig::default()
4494 });
4495 let mut policy = crate::policy::VerificationPolicy::default();
4496 policy.resources.max_key_candidates = 1;
4497
4498 let error = super::super::VerifyContext::new()
4499 .policy(policy)
4500 .key_resolver(&resolver)
4501 .verify(&x509_signature_with_leaf_subject())
4502 .expect_err("the duplicate configured entry must consume candidate work");
4503
4504 assert!(matches!(
4505 error,
4506 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4507 resource: crate::policy::resource_name::KEY_CANDIDATES,
4508 maximum: 1,
4509 actual: 2,
4510 })
4511 ));
4512 }
4513
4514 #[test]
4515 fn operation_policy_charges_duplicate_embedded_x509_candidates() {
4516 let certificate = certificate_der(RSA_4096_CERTIFICATE);
4519 let key_info = KeyInfo {
4520 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
4521 certificates: vec![certificate.clone(), certificate],
4522 certificate_chain: vec![0],
4523 ..X509DataInfo::default()
4524 })],
4525 };
4526 let mut policy = crate::policy::VerificationPolicy::default();
4527 policy.resources.max_key_candidates = 1;
4528
4529 let error = match DefaultKeyResolver::default().resolve_with_policy(
4530 Some(&key_info),
4531 SignatureAlgorithm::RsaSha256,
4532 &policy,
4533 ) {
4534 Ok(_) => panic!("the duplicate embedded entry must consume candidate work"),
4535 Err(error) => error,
4536 };
4537
4538 assert!(matches!(
4539 error,
4540 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4541 resource: crate::policy::resource_name::KEY_CANDIDATES,
4542 maximum: 1,
4543 actual: 2,
4544 })
4545 ));
4546 }
4547
4548 #[test]
4549 fn policy_aware_resolver_rejects_resources_above_hard_ceiling() {
4550 let mut policy = crate::policy::VerificationPolicy::default();
4553 policy.resources.max_key_candidates = usize::MAX;
4554
4555 let error = match DefaultKeyResolver::default().resolve_with_policy(
4556 None,
4557 SignatureAlgorithm::RsaSha256,
4558 &policy,
4559 ) {
4560 Ok(_) => panic!("invalid resource policy must fail before key resolution"),
4561 Err(error) => error,
4562 };
4563
4564 assert!(matches!(
4565 error,
4566 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
4567 resource: crate::policy::resource_name::KEY_CANDIDATES,
4568 actual: usize::MAX,
4569 ..
4570 })
4571 ));
4572 }
4573
4574 #[test]
4575 fn embedded_x509_digest_selection_uses_operation_provider() {
4576 let certificate = certificate_der(RSA_4096_CERTIFICATE);
4579 let digest =
4580 super::super::compute_digest(super::super::DigestAlgorithm::Sha512, &certificate);
4581 let xml = format!(
4582 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><X509Data><X509Certificate>{}</X509Certificate><X509Digest xmlns=\"http://www.w3.org/2009/xmldsig11#\" Algorithm=\"{}\">{}</X509Digest></X509Data></KeyInfo>",
4583 STANDARD.encode(&certificate),
4584 super::super::DigestAlgorithm::Sha512.uri(),
4585 STANDARD.encode(digest),
4586 );
4587 let document = roxmltree::Document::parse(&xml).expect("generated KeyInfo must be XML");
4588 let provider = RejectSecondSha512Provider {
4589 sha512_calls: AtomicUsize::new(1),
4590 verification_calls: AtomicUsize::new(0),
4591 reject_verification_call: None,
4592 rejected_verification_data: None,
4593 };
4594
4595 let error =
4596 super::super::parse::parse_key_info_with_provider(document.root_element(), &provider)
4597 .expect_err("embedded X509Digest selection must use the operation provider");
4598
4599 assert!(
4600 matches!(
4601 error,
4602 ParseError::Provider(crate::provider::ProviderError::Unsupported {
4603 operation: crate::provider::ProviderOperation::Digest,
4604 algorithm: Some(ref uri),
4605 }) if uri == super::super::DigestAlgorithm::Sha512.uri()
4606 ),
4607 "unexpected error: {error:?}"
4608 );
4609 }
4610
4611 #[cfg(feature = "legacy-algorithms")]
4612 #[test]
4613 fn x509_digest_selectors_obey_operation_policy() {
4614 for algorithm in [
4617 super::super::DigestAlgorithm::Md5,
4618 super::super::DigestAlgorithm::Ripemd160,
4619 ] {
4620 let certificate = certificate_der(RSA_4096_CERTIFICATE);
4621 let digest = super::super::compute_digest(algorithm, &certificate);
4622 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4623 lookup_certs: vec![certificate.clone()],
4624 trusted_certs: vec![
4625 certificate.clone(),
4626 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
4627 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
4628 ],
4629 ..KeyResolverConfig::default()
4630 });
4631 for embedded in [false, true] {
4632 let cert_xml = if embedded {
4633 format!(
4634 "<X509Certificate>{}</X509Certificate>",
4635 STANDARD.encode(&certificate)
4636 )
4637 } else {
4638 String::new()
4639 };
4640 let xml = replace_unprefixed_key_info(
4641 X509_DIGEST_SIGNATURE,
4642 &format!(
4643 "<KeyInfo><X509Data>{cert_xml}<X509Digest xmlns=\"http://www.w3.org/2009/xmldsig11#\" Algorithm=\"{}\">{}</X509Digest></X509Data></KeyInfo>",
4644 algorithm.uri(),
4645 STANDARD.encode(&digest)
4646 ),
4647 );
4648 let provider = RejectSecondSha512Provider {
4649 sha512_calls: AtomicUsize::new(0),
4650 verification_calls: AtomicUsize::new(0),
4651 reject_verification_call: None,
4652 rejected_verification_data: None,
4653 };
4654 assert!(
4655 matches!(super::super::VerifyContext::new().key_resolver(&resolver).provider(&provider).verify(&xml),
4656 Err(DsigError::Policy(crate::policy::PolicyViolation::Algorithm { algorithm: uri, .. })) if uri == algorithm.uri())
4657 );
4658 assert_eq!(provider.sha512_calls.load(Ordering::SeqCst), 0);
4659 assert_eq!(provider.verification_calls.load(Ordering::SeqCst), 0);
4660 let info = KeyInfo {
4662 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
4663 digests: vec![(algorithm.uri().into(), digest.clone())],
4664 ..X509DataInfo::default()
4665 })],
4666 };
4667 assert!(matches!(
4668 resolver.resolve_with_policy(
4669 Some(&info),
4670 SignatureAlgorithm::RsaSha512,
4671 &crate::policy::VerificationPolicy::default()
4672 ),
4673 Err(DsigError::Policy(_))
4674 ));
4675 let policy = crate::policy::VerificationPolicy {
4676 digest_algorithms: Some(
4677 [algorithm, super::super::DigestAlgorithm::Sha512].into(),
4678 ),
4679 ..crate::policy::VerificationPolicy::default()
4680 };
4681 assert_eq!(
4682 super::super::VerifyContext::new()
4683 .key_resolver(&resolver)
4684 .policy(policy.clone())
4685 .verify(&xml)
4686 .expect("explicitly permitted selector must verify")
4687 .status,
4688 super::super::DsigStatus::Valid
4689 );
4690 let start = xml.find("<KeyInfo>").expect("fixture has KeyInfo");
4693 let end =
4694 xml.find("</KeyInfo>").expect("fixture closes KeyInfo") + "</KeyInfo>".len();
4695 let target = &xml[start..end];
4696 let referenced = replace_unprefixed_key_info(
4697 &xml,
4698 &format!(
4699 "<KeyInfo><KeyInfoReference xmlns=\"http://www.w3.org/2009/xmldsig11#\" URI=\"#selector\"/></KeyInfo><Object>{}</Object>",
4700 target.replace("<KeyInfo>", "<KeyInfo Id=\"selector\">")
4701 ),
4702 );
4703 let retrieved = replace_unprefixed_key_info(
4704 &xml,
4705 &format!(
4706 "<KeyInfo><RetrievalMethod URI=\"#selector\" Type=\"http://www.w3.org/2000/09/xmldsig#X509Data\"/></KeyInfo><Object>{}</Object>",
4707 target
4708 .strip_prefix("<KeyInfo>")
4709 .expect("selected range starts at KeyInfo")
4710 .strip_suffix("</KeyInfo>")
4711 .expect("selected range ends at KeyInfo")
4712 .replace("<X509Data>", "<X509Data Id=\"selector\">")
4713 ),
4714 );
4715 for indirect in [referenced, retrieved] {
4716 assert!(
4717 matches!(super::super::VerifyContext::new().key_resolver(&resolver).verify(&indirect),
4718 Err(DsigError::Policy(crate::policy::PolicyViolation::Algorithm { algorithm: uri, .. })) if uri == algorithm.uri())
4719 );
4720 assert_eq!(
4721 super::super::VerifyContext::new()
4722 .key_resolver(&resolver)
4723 .policy(policy.clone())
4724 .verify(&indirect)
4725 .expect("permitted indirect selector must verify")
4726 .status,
4727 super::super::DsigStatus::Valid
4728 );
4729 }
4730 }
4731 }
4732 }
4733
4734 #[test]
4735 fn generic_key_resolution_keeps_legacy_capability_source_independent() {
4736 let certificate =
4737 include_bytes!("../../tests/fixtures/xmldsig/phaos-xmldsig-three/certs/rsa-cert.der")
4738 .to_vec();
4739 let (_, parsed_certificate) = X509Certificate::from_der(&certificate)
4740 .expect("the Phaos fixture is a DER certificate");
4741 let public_key = parsed_certificate.public_key().raw.to_vec();
4742 let rsa_public_key = rsa::RsaPublicKey::from_public_key_der(&public_key)
4743 .expect("the Phaos certificate contains an RSA public key");
4744 let certificate_metadata = parse_x509_certificate(&certificate)
4745 .expect("the Phaos fixture has supported X.509 metadata");
4746 let named_key = VerificationKey {
4747 algorithm: SignatureAlgorithm::RsaSha1,
4748 public_key_bytes: public_key.clone(),
4749 certificate_der: None,
4750 name: Some("legacy".into()),
4751 };
4752 let key_infos = [
4753 KeyInfo {
4754 sources: vec![KeyInfoSource::KeyName("legacy".into())],
4755 },
4756 KeyInfo {
4757 sources: vec![KeyInfoSource::DerEncodedKeyValue(public_key.clone())],
4758 },
4759 KeyInfo {
4760 sources: vec![KeyInfoSource::KeyValue(KeyValueInfo::Rsa {
4761 modulus: rsa_public_key.n().to_be_bytes_trimmed_vartime().to_vec(),
4762 exponent: rsa_public_key.e().to_be_bytes_trimmed_vartime().to_vec(),
4763 })],
4764 },
4765 KeyInfo {
4766 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
4767 certificates: vec![certificate],
4768 parsed_certificates: vec![certificate_metadata],
4769 certificate_chain: vec![0],
4770 ..X509DataInfo::default()
4771 })],
4772 },
4773 ];
4774 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4775 named_keys: HashMap::from([("legacy".into(), named_key.clone())]),
4776 ..KeyResolverConfig::default()
4777 });
4778 let mut policy = crate::policy::VerificationPolicy::default();
4779 policy.key_trust.rsa_keys.minimum_modulus_bits = 1024;
4780 policy
4781 .key_trust
4782 .allowed_legacy_signature_algorithms
4783 .insert(SignatureAlgorithm::RsaSha1);
4784
4785 for key_info in &key_infos {
4786 let key = resolver
4787 .resolve_with_policy(Some(key_info), SignatureAlgorithm::RsaSha1, &policy)
4788 .expect("the key source is valid")
4789 .expect("key resolution remains independent from operation policy");
4790 assert!(
4791 !key.verify(SignatureAlgorithm::RsaSha1, b"data", &[0; 128])
4792 .expect("the legacy RSA key is structurally valid")
4793 );
4794 }
4795 }
4796
4797 #[test]
4798 fn rsa_key_value_rejects_ecdsa_signature_method() {
4799 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
4801 .expect("fixture must contain an RSA public key");
4802 let (modulus, exponent) = rsa_key_value_parts(&public_key);
4803 let key_info = format!(
4804 "<ds:KeyInfo><ds:KeyValue><ds:RSAKeyValue><ds:Modulus>{}</ds:Modulus><ds:Exponent>{}</ds:Exponent></ds:RSAKeyValue></ds:KeyValue></ds:KeyInfo>",
4805 modulus, exponent,
4806 );
4807 let xml = replace_key_info(SIGNED_SAML, &key_info);
4808 let resolver = DefaultKeyResolver::default();
4809 let error = super::super::VerifyContext::new()
4810 .key_resolver(&resolver)
4811 .verify(&xml)
4812 .expect_err("RSAKeyValue must not resolve for ECDSA");
4813
4814 assert!(matches!(
4815 error,
4816 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
4817 ));
4818 }
4819
4820 #[test]
4821 fn resolves_ec_p256_key_value_end_to_end() {
4822 let resolver = DefaultKeyResolver::default();
4824 let result = super::super::VerifyContext::new()
4825 .policy(cryptographic_policy())
4826 .key_resolver(&resolver)
4827 .verify(EC_P256_KEY_VALUE_SIGNATURE)
4828 .expect("P-256 ECKeyValue should resolve");
4829
4830 assert_eq!(result.status, super::super::DsigStatus::Valid);
4831 }
4832
4833 #[test]
4834 fn resolves_ec_p384_key_value_end_to_end() {
4835 let resolver = DefaultKeyResolver::default();
4837 let result = super::super::VerifyContext::new()
4838 .policy(cryptographic_policy())
4839 .key_resolver(&resolver)
4840 .verify(EC_P384_KEY_VALUE_SIGNATURE)
4841 .expect("P-384 ECKeyValue should resolve");
4842
4843 assert_eq!(result.status, super::super::DsigStatus::Valid);
4844 }
4845
4846 #[test]
4847 fn ec_key_value_ignored_for_rsa_signature_method() {
4848 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>"#;
4850 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
4851 let resolver = DefaultKeyResolver::default();
4852 let result = super::super::VerifyContext::new()
4853 .key_resolver(&resolver)
4854 .verify(&xml)
4855 .expect("single incompatible ECKeyValue should be ignored");
4856
4857 assert_eq!(
4858 result.status,
4859 super::super::DsigStatus::Invalid(super::super::FailureReason::KeyNotFound)
4860 );
4861 }
4862
4863 #[test]
4864 fn incompatible_ec_key_value_falls_back_to_later_rsa_key_value() {
4865 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
4867 .expect("fixture must contain an RSA public key");
4868 let (modulus, exponent) = rsa_key_value_parts(&public_key);
4869 let key_info = format!(
4870 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>"#,
4871 modulus, exponent,
4872 );
4873 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
4874 let resolver = DefaultKeyResolver::default();
4875 let result = super::super::VerifyContext::new()
4876 .policy(cryptographic_policy())
4877 .key_resolver(&resolver)
4878 .verify(&xml)
4879 .expect("later RSAKeyValue should resolve");
4880
4881 assert_eq!(result.status, super::super::DsigStatus::Valid);
4882 }
4883
4884 #[test]
4885 fn unsupported_ec_key_value_falls_back_to_later_key_name() {
4886 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>"#;
4888 let xml = replace_key_info(SIGNED_SAML, key_info);
4889 let mut config = KeyResolverConfig::default();
4890 config.named_keys.insert(
4891 "idp-signing".into(),
4892 VerificationKey {
4893 algorithm: SignatureAlgorithm::EcdsaSha256,
4894 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4895 certificate_der: None,
4896 name: Some("idp-signing".into()),
4897 },
4898 );
4899 let resolver = DefaultKeyResolver::new(config);
4900 let result = super::super::VerifyContext::new()
4901 .key_resolver(&resolver)
4902 .verify(&xml)
4903 .expect("later KeyName should resolve");
4904
4905 assert_eq!(result.status, super::super::DsigStatus::Valid);
4906 }
4907
4908 #[test]
4909 fn invalid_ec_key_value_falls_back_to_later_key_name() {
4910 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>"#;
4912 let xml = replace_key_info(SIGNED_SAML, key_info);
4913 let mut config = KeyResolverConfig::default();
4914 config.named_keys.insert(
4915 "idp-signing".into(),
4916 VerificationKey {
4917 algorithm: SignatureAlgorithm::EcdsaSha256,
4918 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4919 certificate_der: None,
4920 name: Some("idp-signing".into()),
4921 },
4922 );
4923 let resolver = DefaultKeyResolver::new(config);
4924 let result = super::super::VerifyContext::new()
4925 .key_resolver(&resolver)
4926 .verify(&xml)
4927 .expect("later KeyName should resolve after invalid ECKeyValue");
4928
4929 assert_eq!(result.status, super::super::DsigStatus::Valid);
4930 }
4931
4932 #[test]
4933 fn malformed_ec_key_value_falls_back_to_later_key_name() {
4934 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>"#;
4936 let xml = replace_key_info(SIGNED_SAML, key_info);
4937 let mut config = KeyResolverConfig::default();
4938 config.named_keys.insert(
4939 "idp-signing".into(),
4940 VerificationKey {
4941 algorithm: SignatureAlgorithm::EcdsaSha256,
4942 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4943 certificate_der: None,
4944 name: Some("idp-signing".into()),
4945 },
4946 );
4947 let resolver = DefaultKeyResolver::new(config);
4948 let result = super::super::VerifyContext::new()
4949 .key_resolver(&resolver)
4950 .verify(&xml)
4951 .expect("later KeyName should resolve after malformed ECKeyValue");
4952
4953 assert_eq!(result.status, super::super::DsigStatus::Valid);
4954 }
4955
4956 #[test]
4957 fn invalid_base64_ec_key_value_falls_back_to_later_key_name() {
4958 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>"#;
4961 let xml = replace_key_info(SIGNED_SAML, key_info);
4962 let mut config = KeyResolverConfig::default();
4963 config.named_keys.insert(
4964 "idp-signing".into(),
4965 VerificationKey {
4966 algorithm: SignatureAlgorithm::EcdsaSha256,
4967 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4968 certificate_der: None,
4969 name: Some("idp-signing".into()),
4970 },
4971 );
4972 let resolver = DefaultKeyResolver::new(config);
4973 let result = super::super::VerifyContext::new()
4974 .key_resolver(&resolver)
4975 .verify(&xml)
4976 .expect("later KeyName should resolve after bad ECKeyValue base64");
4977
4978 assert_eq!(result.status, super::super::DsigStatus::Valid);
4979 }
4980
4981 #[test]
4982 fn missing_curve_uri_ec_key_value_falls_back_to_later_key_name() {
4983 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>"#;
4985 let xml = replace_key_info(SIGNED_SAML, key_info);
4986 let mut config = KeyResolverConfig::default();
4987 config.named_keys.insert(
4988 "idp-signing".into(),
4989 VerificationKey {
4990 algorithm: SignatureAlgorithm::EcdsaSha256,
4991 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4992 certificate_der: None,
4993 name: Some("idp-signing".into()),
4994 },
4995 );
4996 let resolver = DefaultKeyResolver::new(config);
4997 let result = super::super::VerifyContext::new()
4998 .key_resolver(&resolver)
4999 .verify(&xml)
5000 .expect("later KeyName should resolve after missing EC curve URI");
5001
5002 assert_eq!(result.status, super::super::DsigStatus::Valid);
5003 }
5004
5005 #[test]
5006 fn malformed_ec_key_value_children_fall_back_to_later_key_name() {
5007 let malformed_ec_key_values = [
5010 r#"<dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/>"#,
5011 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"/>"#,
5012 r#"<dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/><dsig11:PublicKey>BA==</dsig11:PublicKey><dsig11:PublicKey>BA==</dsig11:PublicKey>"#,
5013 ];
5014
5015 for malformed_children in malformed_ec_key_values {
5016 let key_info = format!(
5017 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>"#
5018 );
5019 let xml = replace_key_info(SIGNED_SAML, &key_info);
5020 let mut config = KeyResolverConfig::default();
5021 config.named_keys.insert(
5022 "idp-signing".into(),
5023 VerificationKey {
5024 algorithm: SignatureAlgorithm::EcdsaSha256,
5025 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
5026 certificate_der: None,
5027 name: Some("idp-signing".into()),
5028 },
5029 );
5030 let resolver = DefaultKeyResolver::new(config);
5031 let result = super::super::VerifyContext::new()
5032 .key_resolver(&resolver)
5033 .verify(&xml)
5034 .expect("later KeyName should resolve after malformed EC child shape");
5035
5036 assert_eq!(result.status, super::super::DsigStatus::Valid);
5037 }
5038 }
5039
5040 #[test]
5041 fn supported_ec_curve_does_not_fall_back_to_later_key_name() {
5042 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>"#;
5046 let xml = replace_key_info(SIGNED_SAML, key_info);
5047 let mut config = KeyResolverConfig::default();
5048 config.named_keys.insert(
5049 "idp-signing".into(),
5050 VerificationKey {
5051 algorithm: SignatureAlgorithm::EcdsaSha256,
5052 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
5053 certificate_der: None,
5054 name: Some("idp-signing".into()),
5055 },
5056 );
5057 let resolver = DefaultKeyResolver::new(config);
5058 let error = super::super::VerifyContext::new()
5059 .policy(cryptographic_policy())
5060 .key_resolver(&resolver)
5061 .verify(&xml)
5062 .expect_err("a usable first key source must not fall through after verification");
5063
5064 assert!(matches!(
5065 error,
5066 DsigError::Crypto(super::super::SignatureVerificationError::InvalidSignatureFormat)
5067 ));
5068 }
5069
5070 #[test]
5071 fn lone_malformed_ec_key_value_reports_invalid_public_key() {
5072 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>"#;
5073 let xml = replace_key_info(SIGNED_SAML, key_info);
5074 let error = super::super::VerifyContext::new()
5075 .key_resolver(&DefaultKeyResolver::default())
5076 .verify(&xml)
5077 .expect_err("lone malformed ECKeyValue should surface typed key error");
5078
5079 assert!(matches!(
5080 error,
5081 DsigError::KeyResolution(KeyResolutionError::InvalidPublicKey)
5082 ));
5083 }
5084
5085 #[test]
5086 fn lone_supported_ec_curve_reaches_signature_verification() {
5087 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>"#;
5088 let xml = replace_key_info(SIGNED_SAML, key_info);
5089 let error = super::super::VerifyContext::new()
5090 .policy(cryptographic_policy())
5091 .key_resolver(&DefaultKeyResolver::default())
5092 .verify(&xml)
5093 .expect_err("a supported EC curve must reach signature verification");
5094
5095 assert!(matches!(
5096 error,
5097 DsigError::Crypto(super::super::SignatureVerificationError::InvalidSignatureFormat)
5098 ));
5099 }
5100
5101 #[test]
5102 fn chain_verification_rejects_untrusted_embedded_certificate() {
5103 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
5105 ..KeyResolverConfig::default()
5106 });
5107 let error = super::super::VerifyContext::new()
5108 .policy(verification_policy_with_trust(chain_policy()))
5109 .key_resolver(&resolver)
5110 .verify(SIGNED_SAML)
5111 .expect_err("untrusted certificate must fail chain validation");
5112
5113 assert!(matches!(
5114 error,
5115 DsigError::KeyResolution(KeyResolutionError::Chain(
5116 super::super::X509ChainError::UntrustedRoot
5117 ))
5118 ));
5119 }
5120
5121 #[test]
5122 fn named_key_algorithm_mismatch_fails_closed() {
5123 let xml = replace_key_info(
5125 SIGNED_SAML,
5126 "<ds:KeyInfo><ds:KeyName>wrong-algorithm</ds:KeyName></ds:KeyInfo>",
5127 );
5128 let mut config = KeyResolverConfig::default();
5129 config.named_keys.insert(
5130 "wrong-algorithm".into(),
5131 VerificationKey {
5132 algorithm: SignatureAlgorithm::RsaSha256,
5133 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
5134 certificate_der: None,
5135 name: Some("wrong-algorithm".into()),
5136 },
5137 );
5138 let resolver = DefaultKeyResolver::new(config);
5139 let error = super::super::VerifyContext::new()
5140 .key_resolver(&resolver)
5141 .verify(&xml)
5142 .expect_err("algorithm mismatch must fail closed");
5143
5144 assert!(matches!(
5145 error,
5146 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
5147 ));
5148 }
5149
5150 #[test]
5151 fn named_key_spki_type_mismatch_fails_during_resolution() {
5152 let xml = replace_key_info(
5154 SIGNED_SAML,
5155 "<ds:KeyInfo><ds:KeyName>mislabeled</ds:KeyName></ds:KeyInfo>",
5156 );
5157 let mut config = KeyResolverConfig::default();
5158 config.named_keys.insert(
5159 "mislabeled".into(),
5160 VerificationKey {
5161 algorithm: SignatureAlgorithm::EcdsaSha256,
5162 public_key_bytes: public_key_der(RSA_PUBLIC_KEY),
5163 certificate_der: None,
5164 name: Some("mislabeled".into()),
5165 },
5166 );
5167 let resolver = DefaultKeyResolver::new(config);
5168 let error = super::super::VerifyContext::new()
5169 .key_resolver(&resolver)
5170 .verify(&xml)
5171 .expect_err("mislabeled named key must fail during resolution");
5172
5173 assert!(matches!(
5174 error,
5175 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
5176 ));
5177 }
5178
5179 #[test]
5180 fn malformed_named_key_reports_public_key_error() {
5181 let xml = replace_key_info(
5183 SIGNED_SAML,
5184 "<ds:KeyInfo><ds:KeyName>malformed</ds:KeyName></ds:KeyInfo>",
5185 );
5186 let mut config = KeyResolverConfig::default();
5187 config.named_keys.insert(
5188 "malformed".into(),
5189 VerificationKey {
5190 algorithm: SignatureAlgorithm::EcdsaSha256,
5191 public_key_bytes: vec![1, 2, 3],
5192 certificate_der: None,
5193 name: Some("malformed".into()),
5194 },
5195 );
5196 let resolver = DefaultKeyResolver::new(config);
5197 let error = super::super::VerifyContext::new()
5198 .key_resolver(&resolver)
5199 .verify(&xml)
5200 .expect_err("malformed named key must fail during resolution");
5201
5202 assert!(matches!(
5203 error,
5204 DsigError::KeyResolution(KeyResolutionError::InvalidPublicKey)
5205 ));
5206 }
5207}