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