1use std::{collections::HashMap, fmt, time::SystemTime};
4
5#[cfg(test)]
6use super::parse::parse_x509_certificate;
7use crate::rsa_encoding::RsaPublicKeyEncoding as _;
8use crypto_bigint::BoxedUint;
9use dsa::pkcs8::EncodePublicKey as DsaEncodePublicKey;
10use hmac::{KeyInit, Mac};
11#[cfg(test)]
12use x509_parser::prelude::FromDer;
13#[cfg(test)]
14use x509_parser::prelude::X509Certificate;
15use zeroize::Zeroizing;
16
17use super::pkix::X509DataSource;
18use super::signature::{
19 decode_dsa_verifying_key, signature_value_matches_spki,
20 signature_value_matches_spki_with_encoding, validate_dsa_signature_spki_with_minimum,
21 validate_rsa_signature_spki_with_minimum, verify_dsa_signature_spki_primitive,
22 verify_dsa_signature_spki_with_minimum, verify_rsa_signature_spki_primitive,
23 verify_rsa_signature_spki_with_minimum,
24};
25use super::{
26 DsigError, KeyInfo, KeyInfoSource, KeyResolver, KeyValueInfo, SignatureAlgorithm, VerifyingKey,
27 X509ChainOptions, X509DataInfo,
28 parse::{
29 EC_P256_OID, EC_P384_OID, EC_P521_OID, ParseError, X509ChainBuildError,
30 build_x509_certificate_paths_to_selector_targets,
31 build_x509_certificate_paths_to_trusted_prefix, x509_certificate_matches_any_selector,
32 x509_data_has_lookup_identifiers, x509_selector_categories_match_candidates,
33 },
34 verify_ecdsa_signature_spki, verify_ecdsa_signature_spki_with_encoding,
35 x509::verify_x509_certificate_chain_in_session,
36};
37use super::{ResolvedVerificationKey, TrustedPublicKey, X509TrustEvidence};
38
39struct BorrowedX509Pool<'a> {
42 certificates: structured_asn1::memory::OwnedVec<&'a [u8]>,
43 crls: &'a [Vec<u8>],
44 certificate_chain: structured_asn1::memory::OwnedVec<usize>,
45}
46
47impl<'a> BorrowedX509Pool<'a> {
48 fn new(crls: &'a [Vec<u8>], session: &super::pkix::CertificateSession) -> Self {
49 Self {
50 certificates: session.memory().vector(),
51 crls,
52 certificate_chain: session.memory().vector(),
53 }
54 }
55
56 fn insert(
57 &mut self,
58 encoded: &'a [u8],
59 session: &super::pkix::CertificateSession,
60 ) -> Result<usize, KeyResolutionError> {
61 for (index, known) in self.certificates.iter().enumerate() {
62 if known.len() != encoded.len() {
63 continue;
64 }
65 if known.as_ptr() == encoded.as_ptr() {
66 return Ok(index);
67 }
68 session
69 .memory()
70 .charge_work(encoded.len() as u64)
71 .map_err(|reason| {
72 certificate_resolution_error(session.error(structured_pkix::Error::resource(
73 reason,
74 "certificate.pool_identity",
75 0,
76 )))
77 })?;
78 if *known == encoded {
79 return Ok(index);
80 }
81 }
82 self.certificates.try_push(encoded).map_err(|reason| {
83 certificate_resolution_error(session.error(structured_pkix::Error::resource(
84 reason,
85 "certificate.pool",
86 0,
87 )))
88 })?;
89 Ok(self.certificates.len() - 1)
90 }
91}
92
93impl X509DataSource for BorrowedX509Pool<'_> {
94 fn certificate_count(&self) -> usize {
95 self.certificates.len()
96 }
97 fn certificate(&self, index: usize) -> Option<&[u8]> {
98 self.certificates.get(index).copied()
99 }
100 fn chain(&self) -> &[usize] {
101 &self.certificate_chain
102 }
103 fn crls(&self) -> &[Vec<u8>] {
104 self.crls
105 }
106}
107
108#[derive(Clone)]
115pub struct HmacVerificationKey {
116 secret: Zeroizing<Vec<u8>>,
117}
118
119impl fmt::Debug for HmacVerificationKey {
120 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
121 formatter
122 .debug_struct("HmacVerificationKey")
123 .finish_non_exhaustive()
124 }
125}
126
127impl HmacVerificationKey {
128 pub fn new(secret: impl Into<Vec<u8>>) -> Result<Self, KeyResolutionError> {
130 let secret = secret.into();
131 if secret.is_empty() {
132 return Err(KeyResolutionError::InvalidPublicKey);
133 }
134 Ok(Self {
135 secret: Zeroizing::new(secret),
136 })
137 }
138
139 fn validate_output(
140 &self,
141 policy: crate::policy::HmacPolicy,
142 algorithm: SignatureAlgorithm,
143 signature_value: &[u8],
144 ) -> Result<(), DsigError> {
145 if algorithm.hmac_output_bits().is_none() {
146 return Err(KeyResolutionError::AlgorithmMismatch.into());
147 }
148 policy.validate_key_bytes(self.secret.len())?;
149 policy.validate_output(algorithm, signature_value.len().saturating_mul(8))?;
150 Ok(())
151 }
152
153 fn verify_with_hmac_policy(
154 &self,
155 policy: crate::policy::HmacPolicy,
156 algorithm: SignatureAlgorithm,
157 signed_data: &[u8],
158 signature_value: &[u8],
159 ) -> Result<bool, DsigError> {
160 self.validate_output(policy, algorithm, signature_value)?;
161 macro_rules! verify_hmac {
162 ($digest:ty) => {{
163 let mut mac = hmac::Hmac::<$digest>::new_from_slice(&self.secret)
164 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
165 mac.update(signed_data);
166 let expected = mac.finalize().into_bytes();
167 subtle::ConstantTimeEq::ct_eq(&expected[..signature_value.len()], signature_value)
168 .into()
169 }};
170 }
171 Ok(match algorithm {
172 #[cfg(feature = "legacy-algorithms")]
173 SignatureAlgorithm::HmacMd5 => verify_hmac!(md5::Md5),
174 #[cfg(feature = "legacy-algorithms")]
175 SignatureAlgorithm::HmacRipemd160 => verify_hmac!(ripemd::Ripemd160),
176 SignatureAlgorithm::HmacSha1 => verify_hmac!(sha1::Sha1),
177 SignatureAlgorithm::HmacSha224 => verify_hmac!(sha2::Sha224),
178 SignatureAlgorithm::HmacSha256 => verify_hmac!(sha2::Sha256),
179 SignatureAlgorithm::HmacSha384 => verify_hmac!(sha2::Sha384),
180 SignatureAlgorithm::HmacSha512 => verify_hmac!(sha2::Sha512),
181 _ => return Err(KeyResolutionError::AlgorithmMismatch.into()),
182 })
183 }
184}
185
186impl VerifyingKey for HmacVerificationKey {
187 fn validate_policy(&self, policy: &crate::policy::VerificationPolicy) -> Result<(), DsigError> {
188 policy
189 .hmac
190 .validate_key_bytes(self.secret.len())
191 .map_err(Into::into)
192 }
193
194 fn validate_signature_value(
195 &self,
196 algorithm: SignatureAlgorithm,
197 signature_value: &[u8],
198 ) -> Result<bool, DsigError> {
199 self.validate_output(
200 crate::policy::HmacPolicy::default(),
201 algorithm,
202 signature_value,
203 )?;
204 Ok(true)
205 }
206
207 fn validate_signature_value_with_policy(
208 &self,
209 policy: &crate::policy::VerificationPolicy,
210 algorithm: SignatureAlgorithm,
211 signature_value: &[u8],
212 ) -> Result<bool, DsigError> {
213 self.validate_output(policy.hmac, algorithm, signature_value)?;
214 Ok(true)
215 }
216
217 fn verify(
218 &self,
219 algorithm: SignatureAlgorithm,
220 signed_data: &[u8],
221 signature_value: &[u8],
222 ) -> Result<bool, DsigError> {
223 self.verify_with_hmac_policy(
224 crate::policy::HmacPolicy::default(),
225 algorithm,
226 signed_data,
227 signature_value,
228 )
229 }
230
231 fn verify_with_policy(
232 &self,
233 policy: &crate::policy::VerificationPolicy,
234 algorithm: SignatureAlgorithm,
235 signed_data: &[u8],
236 signature_value: &[u8],
237 ) -> Result<bool, DsigError> {
238 self.verify_with_hmac_policy(policy.hmac, algorithm, signed_data, signature_value)
239 }
240}
241
242pub type HmacSha1VerificationKey = HmacVerificationKey;
244
245#[derive(Debug, Clone, PartialEq, Eq)]
247pub struct VerificationKey {
248 pub algorithm: SignatureAlgorithm,
250 pub public_key_bytes: Vec<u8>,
252 pub certificate_der: Option<Vec<u8>>,
254 pub name: Option<String>,
256}
257
258impl VerifyingKey for VerificationKey {
259 fn association_spki(&self, algorithm: SignatureAlgorithm) -> Option<&[u8]> {
260 if algorithm == self.algorithm {
261 Some(&self.public_key_bytes)
262 } else {
263 None
264 }
265 }
266 fn verification_spki(&self, algorithm: SignatureAlgorithm) -> Result<Option<&[u8]>, DsigError> {
267 if algorithm != self.algorithm {
268 return Err(KeyResolutionError::AlgorithmMismatch.into());
269 }
270 Ok(Some(&self.public_key_bytes))
271 }
272 fn verify_with_context(
273 &self,
274 algorithm: SignatureAlgorithm,
275 context: &super::SignatureContext,
276 data: &[u8],
277 signature: &[u8],
278 ) -> Result<bool, DsigError> {
279 if algorithm != self.algorithm {
280 return Err(KeyResolutionError::AlgorithmMismatch.into());
281 }
282 if algorithm.eddsa_signature_len().is_some()
283 || matches!(algorithm, SignatureAlgorithm::PostQuantum(_))
284 {
285 return super::modern::verify_with_context(
286 algorithm,
287 &self.public_key_bytes,
288 context,
289 data,
290 signature,
291 )
292 .map_err(DsigError::Crypto);
293 }
294 if !context.as_bytes().is_empty() {
295 return Err(KeyResolutionError::AlgorithmMismatch.into());
296 }
297 self.verify(algorithm, data, signature)
298 }
299 fn validate_policy(&self, policy: &crate::policy::VerificationPolicy) -> Result<(), DsigError> {
300 let result = match self.algorithm {
301 #[cfg(feature = "legacy-algorithms")]
302 SignatureAlgorithm::RsaMd5 | SignatureAlgorithm::RsaRipemd160 => {
303 validate_rsa_signature_spki_with_minimum(
304 self.algorithm,
305 &self.public_key_bytes,
306 policy.key_trust.rsa_keys.minimum_modulus_bits,
307 )
308 }
309 #[cfg(feature = "legacy-algorithms")]
310 SignatureAlgorithm::HmacMd5
311 | SignatureAlgorithm::HmacRipemd160
312 | SignatureAlgorithm::EcdsaRipemd160 => Ok(()),
313 SignatureAlgorithm::Ed25519
314 | SignatureAlgorithm::Ed25519Ctx
315 | SignatureAlgorithm::Ed25519Ph
316 | SignatureAlgorithm::Ed448
317 | SignatureAlgorithm::Ed448Ph
318 | SignatureAlgorithm::PostQuantum(_) => {
319 super::modern::validate_public_key(self.algorithm, &self.public_key_bytes)
320 }
321 SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256 => {
322 validate_dsa_signature_spki_with_minimum(
323 &self.public_key_bytes,
324 policy.key_trust.dsa_keys.minimum_modulus_bits,
325 )
326 }
327 SignatureAlgorithm::RsaSha1
328 | SignatureAlgorithm::RsaSha224
329 | SignatureAlgorithm::RsaSha256
330 | SignatureAlgorithm::RsaSha384
331 | SignatureAlgorithm::RsaSha512
332 | SignatureAlgorithm::RsaPssSha1
333 | SignatureAlgorithm::RsaPssSha224
334 | SignatureAlgorithm::RsaPssSha256
335 | SignatureAlgorithm::RsaPssSha384
336 | SignatureAlgorithm::RsaPssSha512
337 | SignatureAlgorithm::RsaPssSha3_224
338 | SignatureAlgorithm::RsaPssSha3_256
339 | SignatureAlgorithm::RsaPssSha3_384
340 | SignatureAlgorithm::RsaPssSha3_512
341 | SignatureAlgorithm::RsaPss(_) => validate_rsa_signature_spki_with_minimum(
342 self.algorithm,
343 &self.public_key_bytes,
344 policy.key_trust.rsa_keys.minimum_modulus_bits,
345 ),
346 SignatureAlgorithm::HmacSha1
347 | SignatureAlgorithm::HmacSha224
348 | SignatureAlgorithm::HmacSha256
349 | SignatureAlgorithm::HmacSha384
350 | SignatureAlgorithm::HmacSha512
351 | SignatureAlgorithm::EcdsaSha1
352 | SignatureAlgorithm::EcdsaSha224
353 | SignatureAlgorithm::EcdsaSha256
354 | SignatureAlgorithm::EcdsaSha384
355 | SignatureAlgorithm::EcdsaSha512
356 | SignatureAlgorithm::EcdsaSha3_224
357 | SignatureAlgorithm::EcdsaSha3_256
358 | SignatureAlgorithm::EcdsaSha3_384
359 | SignatureAlgorithm::EcdsaSha3_512 => Ok(()),
360 };
361 result.map_err(DsigError::Crypto)
362 }
363
364 fn validate_signature_value(
365 &self,
366 algorithm: SignatureAlgorithm,
367 signature_value: &[u8],
368 ) -> Result<bool, DsigError> {
369 if algorithm != self.algorithm {
370 return Err(KeyResolutionError::AlgorithmMismatch.into());
371 }
372 signature_value_matches_spki(algorithm, &self.public_key_bytes, signature_value)
373 .map_err(DsigError::Crypto)
374 }
375
376 fn validate_signature_value_with_policy(
377 &self,
378 policy: &crate::policy::VerificationPolicy,
379 algorithm: SignatureAlgorithm,
380 signature_value: &[u8],
381 ) -> Result<bool, DsigError> {
382 if algorithm != self.algorithm {
383 return Err(KeyResolutionError::AlgorithmMismatch.into());
384 }
385 signature_value_matches_spki_with_encoding(
386 algorithm,
387 &self.public_key_bytes,
388 signature_value,
389 policy.ecdsa_signature_value_encoding,
390 )
391 .map_err(DsigError::Crypto)
392 }
393
394 fn verify(
395 &self,
396 algorithm: SignatureAlgorithm,
397 signed_data: &[u8],
398 signature_value: &[u8],
399 ) -> Result<bool, DsigError> {
400 if algorithm != self.algorithm {
401 return Err(KeyResolutionError::AlgorithmMismatch.into());
402 }
403 let result = match algorithm {
404 #[cfg(feature = "legacy-algorithms")]
405 SignatureAlgorithm::RsaMd5 | SignatureAlgorithm::RsaRipemd160 => {
406 verify_rsa_signature_spki_primitive(
407 algorithm,
408 &self.public_key_bytes,
409 signed_data,
410 signature_value,
411 )
412 }
413 #[cfg(feature = "legacy-algorithms")]
414 SignatureAlgorithm::EcdsaRipemd160 => verify_ecdsa_signature_spki(
415 algorithm,
416 &self.public_key_bytes,
417 signed_data,
418 signature_value,
419 ),
420 #[cfg(feature = "legacy-algorithms")]
421 SignatureAlgorithm::HmacMd5 | SignatureAlgorithm::HmacRipemd160 => {
422 return Err(KeyResolutionError::AlgorithmMismatch.into());
423 }
424 SignatureAlgorithm::Ed25519
425 | SignatureAlgorithm::Ed25519Ctx
426 | SignatureAlgorithm::Ed25519Ph
427 | SignatureAlgorithm::Ed448
428 | SignatureAlgorithm::Ed448Ph
429 | SignatureAlgorithm::PostQuantum(_) => super::modern::verify(
430 algorithm,
431 &self.public_key_bytes,
432 signed_data,
433 signature_value,
434 ),
435 SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256 => {
436 verify_dsa_signature_spki_primitive(
437 algorithm,
438 &self.public_key_bytes,
439 signed_data,
440 signature_value,
441 )
442 }
443 SignatureAlgorithm::HmacSha1
444 | SignatureAlgorithm::HmacSha224
445 | SignatureAlgorithm::HmacSha256
446 | SignatureAlgorithm::HmacSha384
447 | SignatureAlgorithm::HmacSha512 => {
448 return Err(KeyResolutionError::AlgorithmMismatch.into());
449 }
450 SignatureAlgorithm::RsaSha1
451 | SignatureAlgorithm::RsaSha224
452 | SignatureAlgorithm::RsaSha256
453 | SignatureAlgorithm::RsaSha384
454 | SignatureAlgorithm::RsaSha512
455 | SignatureAlgorithm::RsaPssSha1
456 | SignatureAlgorithm::RsaPssSha224
457 | SignatureAlgorithm::RsaPssSha256
458 | SignatureAlgorithm::RsaPssSha384
459 | SignatureAlgorithm::RsaPssSha512
460 | SignatureAlgorithm::RsaPssSha3_224
461 | SignatureAlgorithm::RsaPssSha3_256
462 | SignatureAlgorithm::RsaPssSha3_384
463 | SignatureAlgorithm::RsaPssSha3_512
464 | SignatureAlgorithm::RsaPss(_) => verify_rsa_signature_spki_primitive(
465 algorithm,
466 &self.public_key_bytes,
467 signed_data,
468 signature_value,
469 ),
470 SignatureAlgorithm::EcdsaSha1
471 | SignatureAlgorithm::EcdsaSha224
472 | SignatureAlgorithm::EcdsaSha256
473 | SignatureAlgorithm::EcdsaSha384
474 | SignatureAlgorithm::EcdsaSha512
475 | SignatureAlgorithm::EcdsaSha3_224
476 | SignatureAlgorithm::EcdsaSha3_256
477 | SignatureAlgorithm::EcdsaSha3_384
478 | SignatureAlgorithm::EcdsaSha3_512 => verify_ecdsa_signature_spki(
479 algorithm,
480 &self.public_key_bytes,
481 signed_data,
482 signature_value,
483 ),
484 };
485 result.map_err(DsigError::Crypto)
486 }
487
488 fn verify_with_policy(
489 &self,
490 policy: &crate::policy::VerificationPolicy,
491 algorithm: SignatureAlgorithm,
492 signed_data: &[u8],
493 signature_value: &[u8],
494 ) -> Result<bool, DsigError> {
495 if algorithm != self.algorithm {
496 return Err(KeyResolutionError::AlgorithmMismatch.into());
497 }
498 if algorithm.ecdsa_digest().is_some() {
499 return verify_ecdsa_signature_spki_with_encoding(
500 algorithm,
501 &self.public_key_bytes,
502 signed_data,
503 signature_value,
504 policy.ecdsa_signature_value_encoding,
505 )
506 .map_err(DsigError::Crypto);
507 }
508 self.verify(algorithm, signed_data, signature_value)
509 }
510}
511
512struct PolicyBoundVerificationKey {
513 key: VerificationKey,
514 rsa_minimum_bits: usize,
515 dsa_minimum_bits: usize,
516 _storage: Option<VerificationKeyStorage>,
518}
519
520struct VerificationKeyStorage {
521 _reservation: structured_asn1::memory::MemoryReservation,
522}
523
524impl VerificationKeyStorage {
525 fn reserve(
526 session: &super::pkix::CertificateSession,
527 public_key_bytes: usize,
528 certificate_bytes: usize,
529 name_bytes: usize,
530 ) -> Result<Self, KeyResolutionError> {
531 let reserve = |bytes| {
532 session.memory().reserve(bytes).map_err(|reason| {
533 certificate_resolution_error(session.error(structured_pkix::Error::resource(
534 reason,
535 "verification.key",
536 0,
537 )))
538 })
539 };
540 let work = (public_key_bytes as u64)
541 .checked_add(certificate_bytes as u64)
542 .and_then(|work| work.checked_add(name_bytes as u64))
543 .ok_or_else(|| {
544 certificate_resolution_error(session.error(structured_pkix::Error::resource(
545 structured_asn1::memory::MemoryError::WorkExceeded,
546 "verification.key",
547 0,
548 )))
549 })?;
550 session.memory().charge_work(work).map_err(|reason| {
551 certificate_resolution_error(session.error(structured_pkix::Error::resource(
552 reason,
553 "verification.key",
554 0,
555 )))
556 })?;
557 let capacity = usize::try_from(work)
558 .ok()
559 .and_then(|bytes| bytes.checked_add(core::mem::size_of::<PolicyBoundVerificationKey>()))
560 .ok_or_else(|| {
561 certificate_resolution_error(session.error(structured_pkix::Error::resource(
562 structured_asn1::memory::MemoryError::CapacityOverflow,
563 "verification.key",
564 0,
565 )))
566 })?;
567 Ok(Self {
568 _reservation: reserve(capacity)?,
569 })
570 }
571}
572
573impl VerifyingKey for PolicyBoundVerificationKey {
574 fn association_spki(&self, algorithm: SignatureAlgorithm) -> Option<&[u8]> {
575 self.key.association_spki(algorithm)
576 }
577 fn verification_spki(&self, algorithm: SignatureAlgorithm) -> Result<Option<&[u8]>, DsigError> {
578 if algorithm.is_rsa() {
580 validate_rsa_signature_spki_with_minimum(
581 algorithm,
582 &self.key.public_key_bytes,
583 self.rsa_minimum_bits,
584 )
585 .map_err(DsigError::Crypto)?;
586 }
587 self.key.verification_spki(algorithm)
588 }
589 fn verify_with_context(
590 &self,
591 algorithm: SignatureAlgorithm,
592 context: &super::SignatureContext,
593 data: &[u8],
594 signature: &[u8],
595 ) -> Result<bool, DsigError> {
596 if context.as_bytes().is_empty() {
597 return self.verify(algorithm, data, signature);
598 }
599 self.key
600 .verify_with_context(algorithm, context, data, signature)
601 }
602 fn validate_signature_value(
603 &self,
604 algorithm: SignatureAlgorithm,
605 signature_value: &[u8],
606 ) -> Result<bool, DsigError> {
607 self.key
608 .validate_signature_value(algorithm, signature_value)
609 }
610
611 fn validate_signature_value_with_policy(
612 &self,
613 policy: &crate::policy::VerificationPolicy,
614 algorithm: SignatureAlgorithm,
615 signature_value: &[u8],
616 ) -> Result<bool, DsigError> {
617 self.key
618 .validate_signature_value_with_policy(policy, algorithm, signature_value)
619 }
620
621 fn verify(
622 &self,
623 algorithm: SignatureAlgorithm,
624 signed_data: &[u8],
625 signature_value: &[u8],
626 ) -> Result<bool, DsigError> {
627 if algorithm != self.key.algorithm {
628 return Err(KeyResolutionError::AlgorithmMismatch.into());
629 }
630 let result = match algorithm {
631 SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256 => {
632 verify_dsa_signature_spki_with_minimum(
633 algorithm,
634 &self.key.public_key_bytes,
635 signed_data,
636 signature_value,
637 self.dsa_minimum_bits,
638 )
639 }
640 algorithm if algorithm.is_rsa() => verify_rsa_signature_spki_with_minimum(
641 algorithm,
642 &self.key.public_key_bytes,
643 signed_data,
644 signature_value,
645 self.rsa_minimum_bits,
646 ),
647 _ => return self.key.verify(algorithm, signed_data, signature_value),
648 };
649 result.map_err(DsigError::Crypto)
650 }
651
652 fn verify_with_policy(
653 &self,
654 policy: &crate::policy::VerificationPolicy,
655 algorithm: SignatureAlgorithm,
656 signed_data: &[u8],
657 signature_value: &[u8],
658 ) -> Result<bool, DsigError> {
659 if algorithm.ecdsa_digest().is_some() {
660 return self
661 .key
662 .verify_with_policy(policy, algorithm, signed_data, signature_value);
663 }
664 self.verify(algorithm, signed_data, signature_value)
665 }
666}
667
668#[derive(Debug, thiserror::Error)]
670#[non_exhaustive]
671pub enum KeyResolutionError {
672 #[error("verification key does not match the signature algorithm")]
674 AlgorithmMismatch,
675 #[error("invalid embedded certificate DER")]
677 InvalidCertificate,
678 #[error("invalid public key DER")]
680 InvalidPublicKey,
681 #[error("X.509 lookup selectors match multiple configured certificates")]
683 AmbiguousCertificate,
684 #[error("unsupported X.509 digest algorithm: {0}")]
686 UnsupportedDigestAlgorithm(String),
687 #[error("certificate chain validation failed: {0}")]
689 Chain(#[from] super::X509ChainError),
690 #[error("system time is unavailable")]
692 SystemTime,
693}
694
695#[derive(Debug, Clone, Default, PartialEq, Eq)]
701pub struct KeyResolverConfig {
702 pub lookup_certs: Vec<Vec<u8>>,
706 pub trusted_certs: Vec<Vec<u8>>,
708 pub crls: Vec<Vec<u8>>,
710 pub named_keys: HashMap<String, VerificationKey>,
712}
713
714#[derive(Debug, Clone, Default)]
716pub struct DefaultKeyResolver {
717 config: KeyResolverConfig,
718}
719
720#[derive(Clone, Copy)]
721pub(crate) enum ResolutionScope {
722 Document,
723 Trusted,
724 DocumentPrefix(usize),
725 TrustedPrefix(usize),
726 DocumentSuffix(usize),
727 TrustedSuffix(usize),
728}
729
730pub(crate) struct SourceResolution {
733 pub(crate) key: Option<ResolvedVerificationKey<'static>>,
734 pub(crate) deferred_error: Option<KeyResolutionError>,
735}
736
737impl SourceResolution {
738 pub(crate) fn finish(self) -> Result<Option<ResolvedVerificationKey<'static>>, DsigError> {
739 if let Some(error) = self.deferred_error {
740 return Err(error.into());
741 }
742 Ok(self.key)
743 }
744}
745
746#[derive(Debug)]
754pub struct InspectedKeyCandidateBudget<'a> {
755 maximum: usize,
756 attempted: usize,
757 certificates: super::pkix::CertificateSession,
758 utc_facts: Option<structured_pkix::temporal::LeapTable<'a>>,
759}
760
761impl<'a> InspectedKeyCandidateBudget<'a> {
762 #[must_use]
764 pub fn new(policy: &crate::policy::VerificationPolicy) -> Self {
765 Self::from_inputs(policy, None)
766 }
767
768 #[must_use]
771 pub fn new_with_utc_facts(
772 policy: &crate::policy::VerificationPolicy,
773 facts: structured_pkix::temporal::LeapTable<'a>,
774 ) -> Self {
775 Self::from_inputs(policy, Some(facts))
776 }
777
778 fn from_inputs(
779 policy: &crate::policy::VerificationPolicy,
780 utc_facts: Option<structured_pkix::temporal::LeapTable<'a>>,
781 ) -> Self {
782 Self {
783 maximum: policy.resources.max_key_candidates,
784 attempted: 0,
785 certificates: super::pkix::CertificateSession::new(&policy.resources),
786 utc_facts,
787 }
788 }
789
790 pub(crate) fn with_ingestion(
791 policy: &crate::policy::VerificationPolicy,
792 certificates: &super::pkix::CertificateSession,
793 utc_facts: Option<structured_pkix::temporal::LeapTable<'a>>,
794 ) -> Self {
795 Self {
796 maximum: policy.resources.max_key_candidates,
797 attempted: 0,
798 certificates: certificates.share(),
799 utc_facts,
800 }
801 }
802
803 #[must_use]
806 pub fn utc_facts(&self) -> Option<&structured_pkix::temporal::LeapTable<'a>> {
807 self.utc_facts.as_ref()
808 }
809
810 #[must_use]
814 pub fn execution(&self) -> &structured_asn1::memory::Memory {
815 self.certificates.memory()
816 }
817
818 pub(crate) fn bind_policy(
819 &mut self,
820 policy: &crate::policy::VerificationPolicy,
821 ) -> Result<(), DsigError> {
822 policy.resources.validate()?;
823 self.certificates.require_resources(&policy.resources)?;
824 self.maximum = self.maximum.min(policy.resources.max_key_candidates);
825 self.charge_many(0)
826 }
827
828 pub fn charge(&mut self) -> Result<(), DsigError> {
830 self.charge_many(1)
831 }
832
833 pub(crate) fn charge_many(&mut self, count: usize) -> Result<(), DsigError> {
834 self.charge_policy(count).map_err(Into::into)
835 }
836
837 pub(crate) fn charge_policy(
838 &mut self,
839 count: usize,
840 ) -> Result<(), crate::policy::PolicyViolation> {
841 if self.attempted > self.maximum || count > self.maximum - self.attempted {
842 return Err(crate::policy::PolicyViolation::ResourceLimit {
843 resource: crate::policy::resource_name::KEY_CANDIDATES,
844 maximum: self.maximum,
845 actual: self.attempted.saturating_add(count),
846 });
847 }
848 debug_assert!(self.attempted <= self.maximum);
849 self.attempted += count;
850 Ok(())
851 }
852}
853
854pub(crate) fn validate_key_info_source_permissions(
855 key_info: &KeyInfo,
856 allowed: crate::policy::KeySourcePolicy,
857) -> Result<(), crate::policy::PolicyViolation> {
858 for source in &key_info.sources {
859 let disabled_reason = match source {
860 KeyInfoSource::X509Data(_) if !allowed.x509_data => {
861 Some("X509Data key sources are disabled")
862 }
863 KeyInfoSource::DerEncodedKeyValue(_) if !allowed.der_encoded_key_value => {
864 Some("DEREncodedKeyValue key sources are disabled")
865 }
866 KeyInfoSource::KeyName(_) if !allowed.key_name => {
867 Some("KeyName key sources are disabled")
868 }
869 KeyInfoSource::KeyValue(_) if !allowed.key_value => {
870 Some("KeyValue key sources are disabled")
871 }
872 KeyInfoSource::KeyInfoReference { .. } if !allowed.key_info_reference => {
873 Some("KeyInfoReference key sources are disabled")
874 }
875 KeyInfoSource::X509Data(_)
876 | KeyInfoSource::DerEncodedKeyValue(_)
877 | KeyInfoSource::KeyName(_)
878 | KeyInfoSource::KeyValue(_)
879 | KeyInfoSource::RetrievalMethod { .. }
880 | KeyInfoSource::KeyInfoReference { .. } => None,
881 };
882 if let Some(reason) = disabled_reason {
883 return Err(crate::policy::PolicyViolation::KeyTrust { reason });
884 }
885 }
886 Ok(())
887}
888
889impl DefaultKeyResolver {
890 pub fn resolve_with_candidate_budget(
894 &self,
895 key_info: Option<&KeyInfo>,
896 algorithm: SignatureAlgorithm,
897 policy: &crate::policy::VerificationPolicy,
898 provider: &dyn crate::provider::CryptoProvider,
899 candidate_budget: &mut InspectedKeyCandidateBudget,
900 ) -> Result<Option<ResolvedVerificationKey<'static>>, DsigError> {
901 candidate_budget.bind_policy(policy)?;
902 self.resolve_with_trust(
903 key_info,
904 algorithm,
905 policy,
906 provider,
907 candidate_budget,
908 ResolutionScope::Document,
909 )
910 }
911
912 pub(crate) fn resolve_trusted_material_with_candidate_budget(
913 &self,
914 key_info: &KeyInfo,
915 algorithm: SignatureAlgorithm,
916 policy: &crate::policy::VerificationPolicy,
917 provider: &dyn crate::provider::CryptoProvider,
918 candidate_budget: &mut InspectedKeyCandidateBudget,
919 ) -> Result<Option<ResolvedVerificationKey<'static>>, DsigError> {
920 self.resolve_with_trust(
921 Some(key_info),
922 algorithm,
923 policy,
924 provider,
925 candidate_budget,
926 ResolutionScope::Trusted,
927 )
928 }
929
930 pub(crate) fn resolve_sources_with_candidate_budget(
931 &self,
932 key_info: &KeyInfo,
933 algorithm: SignatureAlgorithm,
934 policy: &crate::policy::VerificationPolicy,
935 provider: &dyn crate::provider::CryptoProvider,
936 candidate_budget: &mut InspectedKeyCandidateBudget,
937 scope: ResolutionScope,
938 ) -> Result<SourceResolution, DsigError> {
939 self.resolve_source_range(
940 Some(key_info),
941 algorithm,
942 policy,
943 provider,
944 candidate_budget,
945 scope,
946 )
947 }
948 #[must_use]
950 pub fn new(config: KeyResolverConfig) -> Self {
951 Self { config }
952 }
953
954 #[must_use]
956 pub fn config(&self) -> &KeyResolverConfig {
957 &self.config
958 }
959
960 fn check_configured_x509_material(
961 &self,
962 info: &X509DataInfo,
963 resources: &crate::policy::ResourcePolicy,
964 trust: &crate::policy::KeyTrustPolicy,
965 budget: &mut InspectedKeyCandidateBudget,
966 charge_crls: bool,
967 ) -> Result<(), DsigError> {
968 if charge_crls && trust.check_crls && trust.verify_x509_chains {
969 budget.charge_many(self.config.crls.len())?;
970 }
971 let certificates = self
972 .config
973 .trusted_certs
974 .iter()
975 .chain(&self.config.lookup_certs);
976 let crls = self
977 .config
978 .crls
979 .iter()
980 .filter(|_| trust.check_crls && trust.verify_x509_chains);
981 let mut total = 0_usize;
982 for material in info
985 .certificates
986 .iter()
987 .chain(&info.crls)
988 .chain(certificates)
989 .chain(crls)
990 {
991 if material.len() > resources.max_external_resource_bytes {
992 return Err(crate::policy::PolicyViolation::ResourceLimit {
993 resource: crate::policy::resource_name::EXTERNAL_RESOURCE_BYTES,
994 maximum: resources.max_external_resource_bytes,
995 actual: material.len(),
996 }
997 .into());
998 }
999 debug_assert!(total <= resources.max_external_resource_total_bytes);
1000 if material.len() > resources.max_external_resource_total_bytes - total {
1001 return Err(crate::policy::PolicyViolation::ResourceLimit {
1002 resource: crate::policy::resource_name::AGGREGATE_EXTERNAL_RESOURCE_BYTES,
1003 maximum: resources.max_external_resource_total_bytes,
1004 actual: total.saturating_add(material.len()),
1005 }
1006 .into());
1007 }
1008 total += material.len();
1009 }
1010 Ok(())
1011 }
1012
1013 fn resolve_x509(
1014 &self,
1015 info: &X509DataInfo,
1016 algorithm: SignatureAlgorithm,
1017 trust: &crate::policy::KeyTrustPolicy,
1018 provider: &dyn crate::provider::CryptoProvider,
1019 budget: &mut InspectedKeyCandidateBudget,
1020 ) -> Result<
1021 Option<(
1022 VerificationKey,
1023 Option<X509TrustEvidence>,
1024 VerificationKeyStorage,
1025 )>,
1026 DsigError,
1027 > {
1028 let mut evidence = None;
1029 let effective_trust;
1030 let trust = if trust.verify_x509_chains && trust.verification_time.is_none() {
1031 effective_trust = {
1032 let mut captured = trust.clone();
1033 captured.verification_time = Some(SystemTime::now());
1034 captured
1035 };
1036 &effective_trust
1037 } else {
1038 trust
1039 };
1040 let configured;
1041 let mut effective_key = None;
1042 let certificate_der = if let Some(&signing_index) = info.certificate_chain.first() {
1043 if trust.verify_x509_chains {
1044 let (path, key) =
1045 self.prepare_embedded_x509(info, signing_index, trust, provider, budget)?;
1046 evidence = Some(Self::x509_trust_evidence(
1047 &path,
1048 trust,
1049 &budget.certificates,
1050 )?);
1051 effective_key = key.effective_spki;
1052 } else {
1053 budget.charge_many(info.certificates.len())?;
1054 }
1055 info.certificates
1056 .get(signing_index)
1057 .ok_or(KeyResolutionError::InvalidCertificate)?
1058 .as_slice()
1059 } else {
1060 let Some((selected, key)) =
1061 self.resolve_configured_x509(info, trust, provider, budget)?
1062 else {
1063 return Ok(None);
1064 };
1065 if trust.verify_x509_chains {
1066 evidence = Some(Self::x509_trust_evidence(
1067 &selected,
1068 trust,
1069 &budget.certificates,
1070 )?);
1071 }
1072 effective_key = key.effective_spki;
1073 configured = selected;
1074 configured
1075 .certificate_chain
1076 .first()
1077 .and_then(|index| configured.certificates.get(*index))
1078 .copied()
1079 .ok_or(KeyResolutionError::InvalidCertificate)?
1080 };
1081
1082 let certificate = budget
1083 .certificates
1084 .read(certificate_der)
1085 .map_err(certificate_resolution_error)?;
1086 let spki = effective_key
1087 .as_deref()
1088 .unwrap_or_else(|| certificate.tbs().public_key().as_bytes());
1089 validate_spki_algorithm(&budget.certificates, spki, algorithm)?;
1090 let storage = VerificationKeyStorage::reserve(
1091 &budget.certificates,
1092 spki.len(),
1093 certificate_der.len(),
1094 0,
1095 )?;
1096 let public_key_bytes = spki.to_vec();
1097 drop(certificate);
1098 Ok(Some((
1099 VerificationKey {
1100 algorithm,
1101 public_key_bytes,
1102 certificate_der: Some(certificate_der.to_vec()),
1103 name: None,
1104 },
1105 evidence,
1106 storage,
1107 )))
1108 }
1109
1110 fn x509_trust_evidence(
1111 info: &impl X509DataSource,
1112 trust: &crate::policy::KeyTrustPolicy,
1113 session: &super::pkix::CertificateSession,
1114 ) -> Result<X509TrustEvidence, DsigError> {
1115 let time = trust
1116 .verification_time
1117 .ok_or(KeyResolutionError::SystemTime)?;
1118 for index in info.chain() {
1121 session
1122 .memory()
1123 .charge_work(
1124 info.certificate(*index)
1125 .ok_or(KeyResolutionError::InvalidCertificate)?
1126 .len() as u64,
1127 )
1128 .map_err(|reason| {
1129 certificate_resolution_error(session.error(structured_pkix::Error::resource(
1130 reason,
1131 "certificate.path_identity",
1132 0,
1133 )))
1134 })?;
1135 }
1136 X509TrustEvidence::new(
1137 info.chain()
1138 .iter()
1139 .map(|index| info.certificate(*index).expect("validated path index")),
1140 time,
1141 trust.check_crls,
1142 )
1143 }
1144
1145 fn verify_x509_policy(
1146 &self,
1147 info: &impl X509DataSource,
1148 trust: &crate::policy::KeyTrustPolicy,
1149 provider: &dyn crate::provider::CryptoProvider,
1150 budget: &InspectedKeyCandidateBudget<'_>,
1151 ) -> Result<super::pkix::ValidatedX509Key, KeyResolutionError> {
1152 let options = X509ChainOptions {
1153 utc_facts: budget.utc_facts().copied(),
1154 trusted_certs: &self.config.trusted_certs,
1155 verification_time: trust.verification_time.unwrap_or_else(SystemTime::now),
1156 max_chain_depth: trust.max_x509_chain_depth,
1157 check_crls: trust.check_crls,
1158 allowed_extended_key_usages: Some(&trust.allowed_extended_key_usages),
1159 rsa_keys: trust.rsa_keys,
1160 dsa_keys: trust.dsa_keys,
1161 certificate_signature_algorithms: trust.certificate_signature_algorithms.as_ref(),
1162 };
1163 Ok(verify_x509_certificate_chain_in_session(
1164 info,
1165 &options,
1166 provider,
1167 &self.config.crls,
1168 &budget.certificates,
1169 )?)
1170 }
1171
1172 fn prepare_embedded_x509<'a>(
1173 &'a self,
1174 info: &'a X509DataInfo,
1175 signing_index: usize,
1176 trust: &crate::policy::KeyTrustPolicy,
1177 provider: &dyn crate::provider::CryptoProvider,
1178 budget: &mut InspectedKeyCandidateBudget,
1179 ) -> Result<(BorrowedX509Pool<'a>, super::pkix::ValidatedX509Key), DsigError> {
1180 if signing_index >= info.certificates.len() {
1181 return Err(KeyResolutionError::InvalidCertificate.into());
1182 }
1183 let mut available = BorrowedX509Pool::new(&info.crls, &budget.certificates);
1184 let mut trusted_prefix_len = 0;
1185 for certificate in &self.config.trusted_certs {
1186 budget.charge()?;
1187 available.insert(certificate, &budget.certificates)?;
1188 trusted_prefix_len = available.certificates.len();
1189 }
1190 for certificate in &self.config.lookup_certs {
1191 budget.charge()?;
1192 available.insert(certificate, &budget.certificates)?;
1193 }
1194 let mut selected_index = None;
1195 for (index, certificate) in info.certificates.iter().enumerate() {
1196 budget.charge()?;
1197 let pool_index = available.insert(certificate, &budget.certificates)?;
1198 if index == signing_index {
1199 selected_index = Some(pool_index);
1200 }
1201 }
1202 let signing_index = selected_index.ok_or(KeyResolutionError::InvalidCertificate)?;
1203 let effective_key = self
1204 .select_valid_x509_path(
1205 &mut available,
1206 signing_index,
1207 trusted_prefix_len,
1208 trust,
1209 None,
1210 (provider, budget),
1211 )?
1212 .ok_or(KeyResolutionError::InvalidCertificate)?;
1213 Ok((available, effective_key))
1214 }
1215
1216 fn select_valid_x509_path(
1217 &self,
1218 available: &mut BorrowedX509Pool<'_>,
1219 signing_index: usize,
1220 trusted_prefix_len: usize,
1221 trust: &crate::policy::KeyTrustPolicy,
1222 selectors: Option<&X509DataInfo>,
1223 execution: (
1224 &dyn crate::provider::CryptoProvider,
1225 &InspectedKeyCandidateBudget<'_>,
1226 ),
1227 ) -> Result<Option<super::pkix::ValidatedX509Key>, KeyResolutionError> {
1228 let (provider, budget) = execution;
1229 let certificates = &budget.certificates;
1230 let candidates = build_x509_certificate_paths_to_trusted_prefix(
1231 available,
1232 signing_index,
1233 trusted_prefix_len,
1234 super::parse::X509PathBounds {
1235 max_depth: trust.max_x509_chain_depth,
1236 max_candidate_paths: trust.max_x509_candidate_paths,
1237 },
1238 provider,
1239 trust.certificate_signature_algorithms.as_ref(),
1240 certificates,
1241 )
1242 .map_err(|error| match error {
1243 X509ChainBuildError::AmbiguousIssuer => KeyResolutionError::AmbiguousCertificate,
1244 X509ChainBuildError::Certificate(error) => KeyResolutionError::Chain(error),
1245 X509ChainBuildError::Policy(error) => {
1246 KeyResolutionError::Chain(super::X509ChainError::Policy(error))
1247 }
1248 X509ChainBuildError::Provider(error) => {
1249 KeyResolutionError::Chain(super::X509ChainError::Provider(error))
1250 }
1251 X509ChainBuildError::UnsupportedSignatureAlgorithm { oid } => {
1252 KeyResolutionError::Chain(super::X509ChainError::UnsupportedSignatureAlgorithm {
1253 oid,
1254 })
1255 }
1256 _ => KeyResolutionError::InvalidCertificate,
1257 })?;
1258 let mut first_error = None;
1259 let mut valid_path_without_selector_match = false;
1260 for candidate in candidates {
1261 available.certificate_chain = candidate;
1262 match self.verify_x509_policy(available, trust, provider, budget) {
1263 Ok(effective_key) => {
1264 if match selectors {
1265 Some(selectors) => selected_x509_path_matches_selectors(
1266 available,
1267 selectors,
1268 provider,
1269 certificates,
1270 )?,
1271 None => true,
1272 } {
1273 return Ok(Some(effective_key));
1274 }
1275 valid_path_without_selector_match = true;
1276 }
1277 Err(error) => {
1278 if matches!(&error, KeyResolutionError::Chain(failure) if failure.is_execution_failure())
1279 {
1280 return Err(error);
1281 }
1282 first_error.get_or_insert(error);
1283 }
1284 }
1285 }
1286 if valid_path_without_selector_match {
1287 return Ok(None);
1288 }
1289 Err(first_error.unwrap_or(KeyResolutionError::Chain(
1290 super::X509ChainError::UntrustedRoot,
1291 )))
1292 }
1293
1294 fn select_x509_selector_path(
1295 &self,
1296 available: &mut BorrowedX509Pool<'_>,
1297 signing_index: usize,
1298 matching_indices: &[usize],
1299 trust: &crate::policy::KeyTrustPolicy,
1300 selectors: &X509DataInfo,
1301 execution: (
1302 &dyn crate::provider::CryptoProvider,
1303 &super::pkix::CertificateSession,
1304 ),
1305 ) -> Result<bool, KeyResolutionError> {
1306 let (provider, certificates) = execution;
1307 let targets = matching_indices
1308 .iter()
1309 .copied()
1310 .filter(|index| *index != signing_index)
1311 .collect::<Vec<_>>();
1312 if targets.is_empty() {
1313 return Ok(false);
1314 }
1315 let candidates = build_x509_certificate_paths_to_selector_targets(
1316 available,
1317 signing_index,
1318 &targets,
1319 super::parse::X509PathBounds {
1320 max_depth: trust.max_x509_chain_depth,
1321 max_candidate_paths: trust.max_x509_candidate_paths,
1322 },
1323 provider,
1324 trust.certificate_signature_algorithms.as_ref(),
1325 certificates,
1326 )
1327 .map_err(|error| match error {
1328 X509ChainBuildError::AmbiguousIssuer => KeyResolutionError::AmbiguousCertificate,
1329 X509ChainBuildError::Certificate(error) => KeyResolutionError::Chain(error),
1330 X509ChainBuildError::Policy(error) => {
1331 KeyResolutionError::Chain(super::X509ChainError::Policy(error))
1332 }
1333 X509ChainBuildError::Provider(error) => {
1334 KeyResolutionError::Chain(super::X509ChainError::Provider(error))
1335 }
1336 X509ChainBuildError::UnsupportedSignatureAlgorithm { oid } => {
1337 KeyResolutionError::Chain(super::X509ChainError::UnsupportedSignatureAlgorithm {
1338 oid,
1339 })
1340 }
1341 _ => KeyResolutionError::InvalidCertificate,
1342 })?;
1343 for candidate in candidates {
1344 available.certificate_chain = candidate;
1345 if selected_x509_path_matches_selectors(available, selectors, provider, certificates)? {
1346 return Ok(true);
1347 }
1348 }
1349 Ok(false)
1350 }
1351
1352 fn resolve_configured_x509<'a>(
1353 &'a self,
1354 info: &'a X509DataInfo,
1355 trust: &crate::policy::KeyTrustPolicy,
1356 provider: &dyn crate::provider::CryptoProvider,
1357 budget: &mut InspectedKeyCandidateBudget,
1358 ) -> Result<Option<(BorrowedX509Pool<'a>, super::pkix::ValidatedX509Key)>, DsigError> {
1359 if !x509_data_has_lookup_identifiers(info) {
1360 return Ok(None);
1361 }
1362
1363 let mut available = BorrowedX509Pool::new(&info.crls, &budget.certificates);
1364 let mut matches = budget.certificates.memory().vector();
1365 let mut trusted_prefix_len = 0usize;
1366 for (trusted, certificate_der) in self
1367 .config
1368 .trusted_certs
1369 .iter()
1370 .map(|certificate| (true, certificate))
1371 .chain(
1372 self.config
1373 .lookup_certs
1374 .iter()
1375 .map(|certificate| (false, certificate)),
1376 )
1377 {
1378 budget.charge()?;
1379 let previous_len = available.certificates.len();
1380 let pool_index = available.insert(certificate_der, &budget.certificates)?;
1381 if pool_index < previous_len {
1382 continue;
1383 }
1384 let is_match = x509_certificate_matches_any_selector(
1385 info,
1386 certificate_der,
1387 provider,
1388 &budget.certificates,
1389 )
1390 .map_err(map_x509_selector_error)?;
1391 if is_match {
1392 matches.try_push(pool_index).map_err(|reason| {
1393 certificate_resolution_error(budget.certificates.error(
1394 structured_pkix::Error::resource(reason, "certificate.selection", 0),
1395 ))
1396 })?;
1397 }
1398 if trusted {
1399 trusted_prefix_len += 1;
1400 }
1401 }
1402
1403 if !x509_selector_categories_match_candidates(
1404 info,
1405 matches.iter().map(|index| available.certificates[*index]),
1406 provider,
1407 &budget.certificates,
1408 )
1409 .map_err(map_x509_selector_error)?
1410 {
1411 return Ok(None);
1412 }
1413
1414 let signing_index = match &matches[..] {
1415 [] => return Ok(None),
1416 [index] => *index,
1417 _ => {
1418 let source = budget
1419 .certificates
1420 .read_sources(available.encoded_certificates())
1421 .map_err(certificate_resolution_error)?;
1422 let mut leaves = budget.certificates.memory().vector();
1423 for candidate in &matches {
1424 let certificate = &source[*candidate];
1425 if budget
1426 .certificates
1427 .source_names_equal(certificate.tbs().subject(), certificate.tbs().issuer())
1428 .map_err(certificate_resolution_error)?
1429 {
1430 continue;
1431 }
1432 let mut issuer = false;
1433 for index in &matches {
1434 if budget
1435 .certificates
1436 .source_names_equal(
1437 source[*index].tbs().issuer(),
1438 certificate.tbs().subject(),
1439 )
1440 .map_err(certificate_resolution_error)?
1441 {
1442 issuer = true;
1443 break;
1444 }
1445 }
1446 if !issuer {
1447 leaves.try_push(*candidate).map_err(|reason| {
1448 certificate_resolution_error(budget.certificates.error(
1449 structured_pkix::Error::resource(
1450 reason,
1451 "certificate.selection",
1452 0,
1453 ),
1454 ))
1455 })?;
1456 }
1457 }
1458 match &leaves[..] {
1459 [index] => *index,
1460 _ => return Err(KeyResolutionError::AmbiguousCertificate.into()),
1461 }
1462 }
1463 };
1464 let effective_key = if signing_index < trusted_prefix_len || !trust.verify_x509_chains {
1468 available
1469 .certificate_chain
1470 .try_push(signing_index)
1471 .map_err(|reason| {
1472 certificate_resolution_error(budget.certificates.error(
1473 structured_pkix::Error::resource(reason, "certificate.path", 0),
1474 ))
1475 })?;
1476 if trust.verify_x509_chains {
1477 self.verify_x509_policy(&available, trust, provider, budget)?
1478 } else {
1479 super::pkix::ValidatedX509Key {
1480 effective_spki: None,
1481 }
1482 }
1483 } else {
1484 let Some(key) = self.select_valid_x509_path(
1485 &mut available,
1486 signing_index,
1487 trusted_prefix_len,
1488 trust,
1489 Some(info),
1490 (provider, budget),
1491 )?
1492 else {
1493 return Ok(None);
1494 };
1495 key
1496 };
1497 if !trust.verify_x509_chains || signing_index < trusted_prefix_len {
1498 let direct_match = selected_x509_path_matches_selectors(
1499 &available,
1500 info,
1501 provider,
1502 &budget.certificates,
1503 )?;
1504 if !direct_match
1505 && (signing_index < trusted_prefix_len
1506 || !self.select_x509_selector_path(
1507 &mut available,
1508 signing_index,
1509 &matches,
1510 trust,
1511 info,
1512 (provider, &budget.certificates),
1513 )?)
1514 {
1515 return Ok(None);
1516 }
1517 }
1518 Ok(Some((available, effective_key)))
1519 }
1520
1521 fn resolve_key_value(
1522 key_value: &KeyValueInfo,
1523 algorithm: SignatureAlgorithm,
1524 session: &super::pkix::CertificateSession,
1525 ) -> Result<Option<VerificationKey>, KeyResolutionError> {
1526 let public_key_bytes = match key_value {
1527 KeyValueInfo::Dsa { p, q, g, y } => {
1528 if !matches!(
1529 algorithm,
1530 SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256
1531 ) {
1532 return Err(KeyResolutionError::AlgorithmMismatch);
1533 }
1534 let (Some(p), Some(q), Some(g)) = (p.as_deref(), q.as_deref(), g.as_deref()) else {
1535 return Err(KeyResolutionError::InvalidPublicKey);
1536 };
1537 dsa_key_value_to_spki_der(p, q, g, y)?
1538 }
1539 KeyValueInfo::Rsa { modulus, exponent } => {
1540 if !algorithm.is_rsa() {
1541 return Err(KeyResolutionError::AlgorithmMismatch);
1542 }
1543 rsa_key_value_to_spki_der(modulus, exponent)?
1544 }
1545 KeyValueInfo::Ec {
1546 curve_oid,
1547 public_key,
1548 } => {
1549 if algorithm.ecdsa_digest().is_none() {
1550 return Ok(None);
1551 }
1552 ec_key_value_to_spki_der(curve_oid, public_key)?
1553 }
1554 KeyValueInfo::InvalidEcKeyValue => return Err(KeyResolutionError::InvalidPublicKey),
1555 KeyValueInfo::Dh { .. } | KeyValueInfo::Unsupported { .. } => return Ok(None),
1557 };
1558 validate_spki_algorithm(session, &public_key_bytes, algorithm)?;
1559
1560 Ok(Some(VerificationKey {
1561 algorithm,
1562 public_key_bytes,
1563 certificate_der: None,
1564 name: None,
1565 }))
1566 }
1567
1568 fn resolve_with_trust(
1569 &self,
1570 key_info: Option<&KeyInfo>,
1571 algorithm: SignatureAlgorithm,
1572 policy: &crate::policy::VerificationPolicy,
1573 provider: &dyn crate::provider::CryptoProvider,
1574 candidate_budget: &mut InspectedKeyCandidateBudget,
1575 scope: ResolutionScope,
1576 ) -> Result<Option<ResolvedVerificationKey<'static>>, DsigError> {
1577 self.resolve_source_range(
1578 key_info,
1579 algorithm,
1580 policy,
1581 provider,
1582 candidate_budget,
1583 scope,
1584 )?
1585 .finish()
1586 }
1587
1588 fn resolve_source_range(
1589 &self,
1590 key_info: Option<&KeyInfo>,
1591 algorithm: SignatureAlgorithm,
1592 policy: &crate::policy::VerificationPolicy,
1593 provider: &dyn crate::provider::CryptoProvider,
1594 candidate_budget: &mut InspectedKeyCandidateBudget,
1595 scope: ResolutionScope,
1596 ) -> Result<SourceResolution, DsigError> {
1597 let trust = &policy.key_trust;
1598 let resources = &policy.resources;
1599 trust.validate()?;
1600 resources.validate()?;
1601 candidate_budget.certificates.require_resources(resources)?;
1602 let Some(key_info) = key_info else {
1603 return Ok(SourceResolution {
1604 key: None,
1605 deferred_error: None,
1606 });
1607 };
1608 let document_sources = matches!(
1609 scope,
1610 ResolutionScope::Document
1611 | ResolutionScope::DocumentPrefix(_)
1612 | ResolutionScope::DocumentSuffix(_)
1613 );
1614 if document_sources {
1615 validate_key_info_source_permissions(key_info, policy.key_sources)?;
1616 }
1617 let source_end = match scope {
1618 ResolutionScope::DocumentPrefix(end) | ResolutionScope::TrustedPrefix(end) => end,
1619 _ => key_info.sources.len(),
1620 };
1621 let source_start = match scope {
1622 ResolutionScope::DocumentSuffix(start) | ResolutionScope::TrustedSuffix(start) => start,
1623 _ => 0,
1624 };
1625 let mut deferred_key_value_error = None;
1626 let mut configured_material_checked = false;
1627 for source in &key_info.sources[source_start..source_end] {
1628 if !document_sources && matches!(source, KeyInfoSource::KeyName(_)) {
1629 continue;
1630 }
1631 let mut path_evidence = None;
1632 let mut storage = None;
1633 let mut caller_trusted =
1634 !document_sources || matches!(source, KeyInfoSource::KeyName(_));
1635 let resolved = match source {
1636 KeyInfoSource::X509Data(info) => {
1637 for (uri, _) in &info.digests {
1640 let algorithm = super::DigestAlgorithm::from_uri(uri).ok_or_else(|| {
1641 KeyResolutionError::UnsupportedDigestAlgorithm(uri.clone())
1642 })?;
1643 policy.check_digest_algorithm(algorithm)?;
1644 }
1645 if if info.certificate_chain.is_empty() {
1646 x509_data_has_lookup_identifiers(info)
1647 } else {
1648 trust.verify_x509_chains
1649 } {
1650 self.check_configured_x509_material(
1651 info,
1652 resources,
1653 trust,
1654 candidate_budget,
1655 !configured_material_checked,
1656 )?;
1657 configured_material_checked = true;
1658 }
1659 match self.resolve_x509(info, algorithm, trust, provider, candidate_budget)? {
1660 Some((key, evidence, reservation)) => {
1661 if evidence.is_none()
1662 && !caller_trusted
1663 && trust.mode
1664 == crate::policy::VerificationTrustMode::RequireTrustedKey
1665 && let Some(der) = key.certificate_der.as_ref()
1666 {
1667 for anchor in &self.config.trusted_certs {
1670 candidate_budget.charge()?;
1671 if anchor == der {
1672 caller_trusted = true;
1673 break;
1674 }
1675 }
1676 }
1677 path_evidence = evidence;
1678 storage = Some(reservation);
1679 Some(key)
1680 }
1681 None => None,
1682 }
1683 }
1684 KeyInfoSource::DerEncodedKeyValue(public_key_bytes) => {
1685 candidate_budget.charge()?;
1686 validate_spki_algorithm(
1687 &candidate_budget.certificates,
1688 public_key_bytes,
1689 algorithm,
1690 )?;
1691 storage = Some(VerificationKeyStorage::reserve(
1692 &candidate_budget.certificates,
1693 public_key_bytes.len(),
1694 0,
1695 0,
1696 )?);
1697 Some(VerificationKey {
1698 algorithm,
1699 public_key_bytes: public_key_bytes.clone(),
1700 certificate_der: None,
1701 name: None,
1702 })
1703 }
1704 KeyInfoSource::KeyName(name) => {
1705 candidate_budget.charge()?;
1706 self.config
1707 .named_keys
1708 .get(name)
1709 .map(|key| {
1710 if key.algorithm != algorithm {
1711 return Err(KeyResolutionError::AlgorithmMismatch);
1712 }
1713 validate_spki_algorithm(
1714 &candidate_budget.certificates,
1715 &key.public_key_bytes,
1716 algorithm,
1717 )?;
1718 storage = Some(VerificationKeyStorage::reserve(
1719 &candidate_budget.certificates,
1720 key.public_key_bytes.len(),
1721 key.certificate_der.as_ref().map_or(0, Vec::len),
1722 key.name.as_ref().map_or(0, String::len),
1723 )?);
1724 Ok(key.clone())
1725 })
1726 .transpose()?
1727 }
1728 KeyInfoSource::KeyValue(key_value) => {
1729 candidate_budget.charge()?;
1730 match Self::resolve_key_value(
1731 key_value,
1732 algorithm,
1733 &candidate_budget.certificates,
1734 ) {
1735 Ok(resolved) => resolved,
1736 Err(error) if key_value_error_allows_fallback(key_value, &error) => {
1737 deferred_key_value_error.get_or_insert(error);
1738 None
1739 }
1740 Err(error) => return Err(error.into()),
1741 }
1742 }
1743 KeyInfoSource::RetrievalMethod { .. } => {
1744 candidate_budget.charge()?;
1745 None
1746 }
1747 KeyInfoSource::KeyInfoReference { .. } => {
1748 candidate_budget.charge()?;
1749 None
1750 }
1751 };
1752 if let Some(key) = resolved {
1753 let key = Box::new(PolicyBoundVerificationKey {
1754 key,
1755 rsa_minimum_bits: trust.rsa_keys.minimum_modulus_bits,
1756 dsa_minimum_bits: trust.dsa_keys.minimum_modulus_bits,
1757 _storage: storage,
1758 });
1759 let key = if policy.key_trust.mode
1760 == crate::policy::VerificationTrustMode::CryptographicOnly
1761 {
1762 ResolvedVerificationKey::Candidate(key)
1763 } else if let Some(evidence) = path_evidence {
1764 ResolvedVerificationKey::Validated(TrustedPublicKey::new(
1765 key,
1766 trust.clone(),
1767 evidence,
1768 ))
1769 } else if caller_trusted {
1770 ResolvedVerificationKey::CallerTrusted(key)
1771 } else {
1772 ResolvedVerificationKey::Candidate(key)
1773 };
1774 return Ok(SourceResolution {
1775 key: Some(key),
1776 deferred_error: None,
1777 });
1778 }
1779 }
1780 Ok(SourceResolution {
1781 key: None,
1782 deferred_error: deferred_key_value_error,
1783 })
1784 }
1785}
1786
1787impl KeyResolver for DefaultKeyResolver {
1788 fn resolve_for_verification_with_budget<'a>(
1789 &'a self,
1790 key_info: Option<&KeyInfo>,
1791 algorithm: SignatureAlgorithm,
1792 policy: &crate::policy::VerificationPolicy,
1793 provider: &dyn crate::provider::CryptoProvider,
1794 budget: &mut InspectedKeyCandidateBudget,
1795 ) -> Result<Option<ResolvedVerificationKey<'a>>, DsigError> {
1796 self.resolve_with_candidate_budget(key_info, algorithm, policy, provider, budget)
1797 }
1798
1799 fn resolve_for_verification<'a>(
1800 &'a self,
1801 key_info: Option<&KeyInfo>,
1802 algorithm: SignatureAlgorithm,
1803 policy: &crate::policy::VerificationPolicy,
1804 provider: &dyn crate::provider::CryptoProvider,
1805 ) -> Result<Option<ResolvedVerificationKey<'a>>, DsigError> {
1806 let mut budget = InspectedKeyCandidateBudget::new(policy);
1807 self.resolve_with_candidate_budget(key_info, algorithm, policy, provider, &mut budget)
1808 }
1809 fn resolve<'a>(
1810 &'a self,
1811 key_info: Option<&KeyInfo>,
1812 algorithm: SignatureAlgorithm,
1813 ) -> Result<Option<Box<dyn VerifyingKey + 'a>>, DsigError> {
1814 let policy = crate::policy::VerificationPolicy::default();
1815 let mut candidate_budget = InspectedKeyCandidateBudget::new(&policy);
1816 self.resolve_with_trust(
1817 key_info,
1818 algorithm,
1819 &policy,
1820 crate::provider::default_provider(),
1821 &mut candidate_budget,
1822 ResolutionScope::Document,
1823 )
1824 .map(|key| key.map(ResolvedVerificationKey::into_key))
1825 }
1826
1827 fn resolve_with_policy<'a>(
1828 &'a self,
1829 key_info: Option<&KeyInfo>,
1830 algorithm: SignatureAlgorithm,
1831 policy: &crate::policy::VerificationPolicy,
1832 ) -> Result<Option<Box<dyn VerifyingKey + 'a>>, DsigError> {
1833 self.resolve_with_policy_and_provider(
1834 key_info,
1835 algorithm,
1836 policy,
1837 crate::provider::default_provider(),
1838 )
1839 }
1840
1841 fn resolve_with_policy_and_provider<'a>(
1842 &'a self,
1843 key_info: Option<&KeyInfo>,
1844 algorithm: SignatureAlgorithm,
1845 policy: &crate::policy::VerificationPolicy,
1846 provider: &dyn crate::provider::CryptoProvider,
1847 ) -> Result<Option<Box<dyn VerifyingKey + 'a>>, DsigError> {
1848 let mut candidate_budget = InspectedKeyCandidateBudget::new(policy);
1849 self.resolve_with_candidate_budget(
1850 key_info,
1851 algorithm,
1852 policy,
1853 provider,
1854 &mut candidate_budget,
1855 )
1856 .map(|key| key.map(ResolvedVerificationKey::into_key))
1857 }
1858
1859 fn consumes_document_key_info(&self) -> bool {
1860 true
1861 }
1862}
1863
1864fn map_x509_selector_error(error: ParseError) -> DsigError {
1865 match error {
1866 ParseError::Provider(error) => DsigError::Provider(error),
1867 ParseError::Policy(error) => error.into(),
1868 error => selector_resolution_error(error).into(),
1869 }
1870}
1871
1872fn selector_resolution_error(error: ParseError) -> KeyResolutionError {
1873 match error {
1874 ParseError::Provider(error) => {
1875 KeyResolutionError::Chain(super::X509ChainError::Provider(error))
1876 }
1877 ParseError::Policy(error) => {
1878 KeyResolutionError::Chain(super::X509ChainError::Policy(error))
1879 }
1880 ParseError::Certificate(error) => {
1881 KeyResolutionError::Chain(super::X509ChainError::Processing(error))
1882 }
1883 ParseError::UnsupportedAlgorithm { uri } => {
1884 KeyResolutionError::UnsupportedDigestAlgorithm(uri)
1885 }
1886 _ => KeyResolutionError::InvalidCertificate,
1887 }
1888}
1889
1890fn certificate_resolution_error(error: super::X509ChainError) -> KeyResolutionError {
1891 match error {
1892 error if error.is_execution_failure() => KeyResolutionError::Chain(error),
1893 super::X509ChainError::Processing(error) => {
1894 KeyResolutionError::Chain(super::X509ChainError::Processing(error))
1895 }
1896 _ => KeyResolutionError::InvalidCertificate,
1897 }
1898}
1899
1900fn selected_x509_path_matches_selectors(
1901 available: &impl X509DataSource,
1902 selectors: &X509DataInfo,
1903 provider: &dyn crate::provider::CryptoProvider,
1904 certificates: &super::pkix::CertificateSession,
1905) -> Result<bool, KeyResolutionError> {
1906 x509_selector_categories_match_candidates(
1907 selectors,
1908 available
1909 .chain()
1910 .iter()
1911 .map(|index| available.certificate(*index).expect("selected path index")),
1912 provider,
1913 certificates,
1914 )
1915 .map_err(selector_resolution_error)
1916}
1917
1918fn rsa_key_value_to_spki_der(
1919 modulus: &[u8],
1920 exponent: &[u8],
1921) -> Result<Vec<u8>, KeyResolutionError> {
1922 let (modulus, exponent) = bounded_rsa_public_components(modulus, exponent)?;
1923 let key = rsa::RsaPublicKey::new(
1924 BoxedUint::from_be_slice_vartime(modulus),
1925 BoxedUint::from_be_slice_vartime(exponent),
1926 )
1927 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1928 key.to_public_key_der()
1929 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1930 .map(|der| der.as_bytes().to_vec())
1931}
1932
1933pub(crate) fn bounded_rsa_public_components<'a>(
1934 modulus: &'a [u8],
1935 exponent: &'a [u8],
1936) -> Result<(&'a [u8], &'a [u8]), KeyResolutionError> {
1937 let modulus = &modulus[modulus
1938 .iter()
1939 .position(|byte| *byte != 0)
1940 .unwrap_or(modulus.len())..];
1941 let exponent = &exponent[exponent
1942 .iter()
1943 .position(|byte| *byte != 0)
1944 .unwrap_or(exponent.len())..];
1945 let maximum = crate::hard_limits::RSA_MODULUS_BIT_CEILING;
1946 if modulus.is_empty()
1947 || exponent.is_empty()
1948 || modulus.len() > maximum.div_ceil(8)
1949 || exponent.len() > maximum.div_ceil(8)
1950 || (modulus.len() * 8 - modulus[0].leading_zeros() as usize) > maximum
1951 {
1952 return Err(KeyResolutionError::InvalidPublicKey);
1953 }
1954 Ok((modulus, exponent))
1955}
1956
1957fn dsa_key_value_to_spki_der(
1958 p: &[u8],
1959 q: &[u8],
1960 g: &[u8],
1961 y: &[u8],
1962) -> Result<Vec<u8>, KeyResolutionError> {
1963 let trim = |bytes: &[u8]| bytes.iter().take_while(|byte| **byte == 0).count();
1966 let p = &p[trim(p)..];
1967 let q = &q[trim(q)..];
1968 let g = &g[trim(g)..];
1969 let y = &y[trim(y)..];
1970 for value in [p, q, g, y] {
1971 if value.is_empty() || value.len() > crate::hard_limits::DSA_KEY_COMPONENT_BYTE_CEILING {
1972 return Err(KeyResolutionError::InvalidPublicKey);
1973 }
1974 }
1975 let components = dsa::Components::from_components(
1976 BoxedUint::from_be_slice_vartime(p),
1977 BoxedUint::from_be_slice_vartime(q),
1978 BoxedUint::from_be_slice_vartime(g),
1979 )
1980 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
1981 dsa::VerifyingKey::from_components(components, BoxedUint::from_be_slice_vartime(y))
1982 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
1983 .to_public_key_der()
1984 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1985 .map(|der| der.as_bytes().to_vec())
1986}
1987
1988fn ec_key_value_to_spki_der(
1989 curve_oid: &str,
1990 public_key: &[u8],
1991) -> Result<Vec<u8>, KeyResolutionError> {
1992 match curve_oid {
1993 EC_P256_OID => p256::PublicKey::from_sec1_bytes(public_key)
1994 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
1995 .to_public_key_der()
1996 .map_err(|_| KeyResolutionError::InvalidPublicKey)
1997 .map(|der| der.as_bytes().to_vec()),
1998 EC_P384_OID => p384::PublicKey::from_sec1_bytes(public_key)
1999 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
2000 .to_public_key_der()
2001 .map_err(|_| KeyResolutionError::InvalidPublicKey)
2002 .map(|der| der.as_bytes().to_vec()),
2003 EC_P521_OID => p521::PublicKey::from_sec1_bytes(public_key)
2004 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
2005 .to_public_key_der()
2006 .map_err(|_| KeyResolutionError::InvalidPublicKey)
2007 .map(|der| der.as_bytes().to_vec()),
2008 _ => Err(KeyResolutionError::InvalidPublicKey),
2009 }
2010}
2011
2012fn key_value_error_allows_fallback(key_value: &KeyValueInfo, error: &KeyResolutionError) -> bool {
2013 matches!(
2014 key_value,
2015 KeyValueInfo::Dsa { .. } | KeyValueInfo::Ec { .. } | KeyValueInfo::InvalidEcKeyValue
2016 ) && matches!(
2017 error,
2018 KeyResolutionError::InvalidPublicKey | KeyResolutionError::AlgorithmMismatch
2019 )
2020}
2021
2022fn validate_spki_algorithm(
2023 session: &super::pkix::CertificateSession,
2024 public_key_bytes: &[u8],
2025 algorithm: SignatureAlgorithm,
2026) -> Result<(), KeyResolutionError> {
2027 if algorithm.rsa_pss_parameters().is_some() {
2028 return validate_rsa_signature_spki_with_minimum(algorithm, public_key_bytes, 8)
2035 .map_err(|_| KeyResolutionError::InvalidPublicKey);
2036 }
2037 if algorithm.eddsa_signature_len().is_some()
2038 || matches!(algorithm, SignatureAlgorithm::PostQuantum(_))
2039 {
2040 return super::modern::validate_public_key(algorithm, public_key_bytes)
2041 .map_err(|_| KeyResolutionError::InvalidPublicKey);
2042 }
2043 use der::Decode as _;
2044 let spki = pkcs8::SubjectPublicKeyInfoRef::from_der(public_key_bytes)
2045 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
2046 match (algorithm, spki.algorithm.oid) {
2049 (SignatureAlgorithm::DsaSha1 | SignatureAlgorithm::DsaSha256, dsa::OID) => {
2050 let _ = decode_dsa_verifying_key(public_key_bytes)
2051 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
2052 Ok(())
2053 }
2054 (method, pkcs1::ALGORITHM_OID) if method.is_rsa() => {
2055 validate_rsa_spki(session, public_key_bytes)
2056 }
2057 (method, oid)
2058 if method.ecdsa_digest().is_some() && oid == p256::elliptic_curve::ALGORITHM_OID =>
2059 {
2060 validate_ec_spki_point(session, public_key_bytes)
2061 }
2062 _ => Err(KeyResolutionError::AlgorithmMismatch),
2063 }
2064}
2065
2066pub(crate) fn supported_parsed_spki_is_rsa(
2067 session: &super::pkix::CertificateSession,
2068 spki: &pkcs8::SubjectPublicKeyInfoRef<'_>,
2069 public_key_bytes: &[u8],
2070) -> Result<bool, KeyResolutionError> {
2071 if let Some(parameter) = super::PqAlgorithm::from_oid(spki.algorithm.oid) {
2072 super::modern::validate_public_key(
2073 SignatureAlgorithm::PostQuantum(parameter),
2074 public_key_bytes,
2075 )
2076 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
2077 return Ok(false);
2078 }
2079 let eddsa = match spki.algorithm.oid {
2080 ed25519_dalek::pkcs8::ALGORITHM_OID => Some(SignatureAlgorithm::Ed25519),
2081 oid if oid == der::asn1::ObjectIdentifier::new_unwrap("1.3.101.113") => {
2082 Some(SignatureAlgorithm::Ed448)
2083 }
2084 _ => None,
2085 };
2086 if let Some(algorithm) = eddsa {
2087 super::modern::validate_public_key(algorithm, public_key_bytes)
2088 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
2089 return Ok(false);
2090 }
2091 match spki.algorithm.oid {
2092 pkcs1::ALGORITHM_OID => {
2093 validate_rsa_spki(session, public_key_bytes)?;
2094 rsa::RsaPublicKey::from_public_key_der(public_key_bytes)
2095 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
2096 Ok(true)
2097 }
2098 dsa::OID => {
2099 let _ = decode_dsa_verifying_key(public_key_bytes)
2100 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
2101 Ok(false)
2102 }
2103 oid if oid == p256::elliptic_curve::ALGORITHM_OID => {
2104 validate_ec_spki_point(session, public_key_bytes)?;
2105 Ok(false)
2106 }
2107 _ => Err(KeyResolutionError::AlgorithmMismatch),
2108 }
2109}
2110
2111fn structured_key_error(
2114 session: &super::pkix::CertificateSession,
2115 error: structured_pkix::Error,
2116) -> KeyResolutionError {
2117 if error.is_resource() {
2118 certificate_resolution_error(session.error(error))
2119 } else {
2120 KeyResolutionError::InvalidPublicKey
2121 }
2122}
2123
2124fn validate_rsa_spki(
2125 session: &super::pkix::CertificateSession,
2126 spki: &[u8],
2127) -> Result<(), KeyResolutionError> {
2128 let key = match session.read_public_key(spki) {
2129 Ok(super::pkix::PublicKey::Rsa(key)) => key,
2130 Ok(super::pkix::PublicKey::Ec(_)) => return Err(KeyResolutionError::InvalidPublicKey),
2131 Err(error) => return Err(structured_key_error(session, error)),
2132 };
2133 bounded_rsa_public_components(key.modulus().as_bytes(), key.exponent().as_bytes())?;
2134 Ok(())
2135}
2136
2137fn validate_ec_spki_point(
2138 session: &super::pkix::CertificateSession,
2139 spki: &[u8],
2140) -> Result<(), KeyResolutionError> {
2141 let key = match session.read_public_key(spki) {
2142 Ok(super::pkix::PublicKey::Ec(key)) => key,
2143 Err(error) if error.code() == structured_pkix::ErrorCode::MissingField => {
2145 return Err(KeyResolutionError::AlgorithmMismatch);
2146 }
2147 Err(error) => return Err(structured_key_error(session, error)),
2148 Ok(super::pkix::PublicKey::Rsa(_)) => return Err(KeyResolutionError::InvalidPublicKey),
2149 };
2150 let structured_pkix::key::ec::Curve::Named(curve) = key.curve() else {
2153 return Err(KeyResolutionError::AlgorithmMismatch);
2154 };
2155 let curve = super::signature::EcCurve::from_oid_bytes(curve.as_bytes())
2156 .ok_or(KeyResolutionError::AlgorithmMismatch)?;
2157 let point = key.as_bytes();
2158 curve
2159 .validate_point(point)
2160 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
2161 match curve {
2162 super::signature::EcCurve::P256 => p256::PublicKey::from_sec1_bytes(point).map(|_| ()),
2163 super::signature::EcCurve::P384 => p384::PublicKey::from_sec1_bytes(point).map(|_| ()),
2164 super::signature::EcCurve::P521 => p521::PublicKey::from_sec1_bytes(point).map(|_| ()),
2165 }
2166 .map_err(|_| KeyResolutionError::InvalidPublicKey)
2167}
2168
2169pub(crate) fn supported_key_value_is_rsa(
2170 session: &super::pkix::CertificateSession,
2171 value: &KeyValueInfo,
2172) -> Result<bool, KeyResolutionError> {
2173 let (spki, is_rsa) = match value {
2174 KeyValueInfo::Rsa { modulus, exponent } => {
2175 (rsa_key_value_to_spki_der(modulus, exponent)?, true)
2176 }
2177 KeyValueInfo::Dsa {
2178 p: Some(p),
2179 q: Some(q),
2180 g: Some(g),
2181 y,
2182 } => (dsa_key_value_to_spki_der(p, q, g, y)?, false),
2183 KeyValueInfo::Ec {
2184 curve_oid,
2185 public_key,
2186 } => (ec_key_value_to_spki_der(curve_oid, public_key)?, false),
2187 _ => return Err(KeyResolutionError::InvalidPublicKey),
2188 };
2189 let algorithm = if is_rsa {
2190 SignatureAlgorithm::RsaSha256
2191 } else if matches!(value, KeyValueInfo::Dsa { .. }) {
2192 SignatureAlgorithm::DsaSha256
2193 } else {
2194 SignatureAlgorithm::EcdsaSha256
2195 };
2196 validate_spki_algorithm(session, &spki, algorithm)?;
2197 Ok(is_rsa)
2198}
2199
2200#[cfg(test)]
2201mod tests {
2202 use crate::xml::dom as roxmltree;
2203 use std::sync::atomic::{AtomicUsize, Ordering};
2204
2205 use base64::{Engine, engine::general_purpose::STANDARD};
2206 use der::Decode as _;
2207 use pkcs8::DecodePublicKey as _;
2208 use rcgen::{
2209 CertificateRevocationListParams, Issuer, KeyIdMethod, KeyPair, KeyUsagePurpose,
2210 RevokedCertParams, SerialNumber, date_time_ymd,
2211 };
2212 use rsa::traits::PublicKeyParts;
2213
2214 use super::*;
2215
2216 #[test]
2217 fn shared_candidate_budget_cannot_relax_active_policy() {
2218 let resolver = DefaultKeyResolver::new(KeyResolverConfig::default());
2221 let info = KeyInfo {
2222 sources: vec![KeyInfoSource::KeyName("missing".into())],
2223 };
2224 let mut policy = crate::policy::VerificationPolicy::default();
2225 policy.resources.max_key_candidates = 1;
2226 let mut budget = InspectedKeyCandidateBudget::new(&policy);
2227 assert!(
2228 resolver
2229 .resolve_with_candidate_budget(
2230 Some(&info),
2231 SignatureAlgorithm::RsaSha256,
2232 &policy,
2233 crate::provider::default_provider(),
2234 &mut budget
2235 )
2236 .expect("first candidate fits the active policy")
2237 .is_none()
2238 );
2239 assert!(matches!(
2240 resolver.resolve_with_candidate_budget(
2241 Some(&info),
2242 SignatureAlgorithm::RsaSha256,
2243 &policy,
2244 crate::provider::default_provider(),
2245 &mut budget
2246 ),
2247 Err(DsigError::Policy(
2248 crate::policy::PolicyViolation::ResourceLimit {
2249 maximum: 1,
2250 actual: 2,
2251 ..
2252 }
2253 ))
2254 ));
2255 let mut spent =
2256 InspectedKeyCandidateBudget::new(&crate::policy::VerificationPolicy::default());
2257 spent
2258 .charge_many(2)
2259 .expect("initial budget admits two candidates");
2260 assert!(matches!(
2261 resolver.resolve_with_candidate_budget(
2262 None,
2263 SignatureAlgorithm::RsaSha256,
2264 &policy,
2265 crate::provider::default_provider(),
2266 &mut spent
2267 ),
2268 Err(DsigError::Policy(
2269 crate::policy::PolicyViolation::ResourceLimit {
2270 maximum: 1,
2271 actual: 2,
2272 ..
2273 }
2274 ))
2275 ));
2276 }
2277
2278 #[test]
2279 fn dsa_key_value_components_are_bounded_before_bigint_decode() {
2280 let public = dsa::VerifyingKey::from_public_key_pem(include_str!(
2283 "../../tests/fixtures/keys/dsa/dsa-2048-public.pem"
2284 ))
2285 .expect("DSA fixture");
2286 let components = public.components();
2287 let values = [
2288 components.p().to_be_bytes_trimmed_vartime().to_vec(),
2289 components.q().to_be_bytes_trimmed_vartime().to_vec(),
2290 components.g().to_be_bytes_trimmed_vartime().to_vec(),
2291 public.y().to_be_bytes_trimmed_vartime().to_vec(),
2292 ];
2293 let expected = dsa_key_value_to_spki_der(&values[0], &values[1], &values[2], &values[3])
2294 .expect("valid DSA");
2295 for index in 0..4 {
2296 let mut oversized = values.clone();
2297 oversized[index] = vec![1; crate::hard_limits::DSA_KEY_COMPONENT_BYTE_CEILING + 1];
2298 assert!(
2299 dsa_key_value_to_spki_der(
2300 &oversized[0],
2301 &oversized[1],
2302 &oversized[2],
2303 &oversized[3]
2304 )
2305 .is_err()
2306 );
2307 }
2308 let padded = values.map(|value| {
2309 let mut padded = vec![0; 1024];
2310 padded.extend(value);
2311 padded
2312 });
2313 assert_eq!(
2314 dsa_key_value_to_spki_der(&padded[0], &padded[1], &padded[2], &padded[3])
2315 .expect("zero padding preserves unsigned DSA value"),
2316 expected
2317 );
2318 }
2319
2320 #[test]
2321 fn opaque_spki_reports_algorithm_mismatch_before_key_octet_rules()
2322 -> Result<(), Box<dyn std::error::Error>> {
2323 let opaque = pkcs8::SubjectPublicKeyInfoRef {
2327 algorithm: pkcs8::AlgorithmIdentifierRef {
2328 oid: der::asn1::ObjectIdentifier::new_unwrap("1.2.3.4"),
2329 parameters: None,
2330 },
2331 subject_public_key: der::asn1::BitStringRef::new(1, &[0])?,
2332 };
2333 let encoded = der::Encode::to_der(&opaque)?;
2334 let session =
2335 super::super::pkix::CertificateSession::new(&crate::policy::ResourcePolicy::default());
2336 assert!(matches!(
2337 supported_parsed_spki_is_rsa(&session, &opaque, &encoded),
2338 Err(KeyResolutionError::AlgorithmMismatch)
2339 ));
2340 for method in [
2341 SignatureAlgorithm::RsaSha256,
2342 SignatureAlgorithm::DsaSha256,
2343 SignatureAlgorithm::EcdsaSha256,
2344 ] {
2345 assert!(matches!(
2346 validate_spki_algorithm(&session, &encoded, method),
2347 Err(KeyResolutionError::AlgorithmMismatch)
2348 ));
2349 }
2350 Ok(())
2351 }
2352
2353 #[test]
2354 fn borrowed_certificate_pool_retains_identity_and_capacity_charge()
2355 -> Result<(), Box<dyn std::error::Error>> {
2356 let bytes = [7u8; 1024];
2359 let duplicate = bytes;
2360 let session =
2361 super::super::pkix::CertificateSession::new(&crate::policy::ResourcePolicy::default());
2362 let mut pool = BorrowedX509Pool::new(&[], &session);
2363 assert_eq!(pool.insert(&bytes, &session)?, 0);
2364 let allocated_work = session.memory().work_used();
2365 assert_eq!(pool.insert(&bytes, &session)?, 0);
2366 assert_eq!(session.memory().work_used(), allocated_work);
2367 assert_eq!(pool.insert(&duplicate, &session)?, 0);
2368 assert_eq!(pool.certificates.len(), 1);
2369 assert_eq!(
2370 pool.certificate(0).map(<[u8]>::as_ptr),
2371 Some(bytes.as_ptr())
2372 );
2373 assert_eq!(
2374 session.memory().used(),
2375 pool.certificates.capacity() * core::mem::size_of::<&[u8]>(),
2376 );
2377 assert_eq!(session.memory().work_used() - allocated_work, bytes.len());
2378 drop(pool);
2379 assert_eq!(session.memory().used(), 0);
2380 let bounded = super::super::pkix::CertificateSession::new(&crate::policy::ResourcePolicy {
2381 max_x509_workspace_bytes: core::mem::size_of::<&[u8]>() - 1,
2382 ..Default::default()
2383 });
2384 let mut pool = BorrowedX509Pool::new(&[], &bounded);
2385 assert!(pool.insert(&bytes, &bounded).is_err());
2386 assert!(pool.certificates.is_empty());
2387 assert_eq!(bounded.memory().used(), 0);
2388 Ok(())
2389 }
2390
2391 #[test]
2392 fn resolved_key_storage_keeps_its_execution_reservation() {
2393 let key = rcgen::KeyPair::generate().expect("EC key generation");
2396 let encoded = rcgen::PublicKeyData::subject_public_key_info(&key);
2397 let policy = crate::policy::VerificationPolicy::default();
2398 let mut budget = InspectedKeyCandidateBudget::new(&policy);
2399 let memory = budget.certificates.memory().clone();
2400 let resolver = DefaultKeyResolver::new(KeyResolverConfig::default());
2401 let info = KeyInfo {
2402 sources: vec![KeyInfoSource::DerEncodedKeyValue(encoded.clone())],
2403 };
2404 let resolved = resolver
2405 .resolve_with_candidate_budget(
2406 Some(&info),
2407 SignatureAlgorithm::EcdsaSha256,
2408 &policy,
2409 crate::provider::default_provider(),
2410 &mut budget,
2411 )
2412 .expect("key resolution")
2413 .expect("resolved key");
2414 assert_eq!(
2415 memory.used(),
2416 encoded.len() + core::mem::size_of::<PolicyBoundVerificationKey>()
2417 );
2418 drop(budget);
2419 assert_eq!(
2420 memory.used(),
2421 encoded.len() + core::mem::size_of::<PolicyBoundVerificationKey>()
2422 );
2423 drop(resolved);
2424 assert_eq!(
2425 memory.used(),
2426 0,
2427 "deallocation releases the original account"
2428 );
2429 }
2430
2431 #[test]
2432 fn authenticated_dsa_target_uses_the_paths_effective_parameters()
2433 -> Result<(), Box<dyn std::error::Error>> {
2434 use der::{Decode as _, Encode as _};
2438 use dsa::pkcs8::DecodePrivateKey as _;
2439 use rand_chacha::{ChaCha20Rng, rand_core::SeedableRng as _};
2440 use signature::hazmat::RandomizedPrehashSigner as _;
2441 let private = pkcs8::EncryptedPrivateKeyInfoRef::from_der(include_bytes!(
2442 "../../tests/fixtures/xmldsig/keys/dsa/dsa-2048-key.p8-der"
2443 ))?
2444 .decrypt(b"secret123")?;
2445 let key = dsa::SigningKey::from_pkcs8_der(private.as_bytes())?;
2446 let public = key.verifying_key().to_public_key_der()?;
2447 let complete = pkcs8::SubjectPublicKeyInfoRef::from_der(public.as_bytes())?;
2448 let incomplete = pkcs8::SubjectPublicKeyInfoRef {
2449 algorithm: pkcs8::AlgorithmIdentifierRef {
2450 oid: dsa::OID,
2451 parameters: None,
2452 },
2453 subject_public_key: complete.subject_public_key,
2454 }
2455 .to_der()?;
2456 let root_name: x509_cert::name::Name = "CN=parameter-root".parse()?;
2457 let leaf_name: x509_cert::name::Name = "CN=parameter-leaf".parse()?;
2458 let template_key = rcgen::KeyPair::generate()?;
2459 let template = rcgen::CertificateParams::new(Vec::new())?.self_signed(&template_key)?;
2460 let template = x509_cert::Certificate::from_der(template.der())?;
2461 let algorithm = pkcs8::AlgorithmIdentifierRef {
2462 oid: der::asn1::ObjectIdentifier::new_unwrap("1.2.840.10040.4.3"),
2463 parameters: None,
2464 }
2465 .to_der()?;
2466 let make_certificate = |root: bool| -> Result<Vec<u8>, Box<dyn std::error::Error>> {
2467 let mut body = Vec::new();
2468 if root {
2469 body.extend_from_slice(&[0xa0, 3, 2, 1, 2]);
2470 }
2471 body.extend_from_slice(if root { &[2, 1, 1] } else { &[2, 1, 2] });
2472 body.extend_from_slice(&algorithm);
2473 body.extend(root_name.to_der()?);
2474 body.extend(template.tbs_certificate().validity().to_der()?);
2475 body.extend(if root {
2476 root_name.to_der()?
2477 } else {
2478 leaf_name.to_der()?
2479 });
2480 body.extend_from_slice(if root { public.as_bytes() } else { &incomplete });
2481 if root {
2482 let extensions = vec![
2483 x509_cert::ext::Extension {
2484 extn_id: der::asn1::ObjectIdentifier::new_unwrap("2.5.29.19"),
2485 critical: true,
2486 extn_value: der::asn1::OctetString::new([0x30, 3, 1, 1, 0xff])?,
2487 },
2488 x509_cert::ext::Extension {
2489 extn_id: der::asn1::ObjectIdentifier::new_unwrap("2.5.29.15"),
2490 critical: true,
2491 extn_value: der::asn1::OctetString::new([3, 2, 1, 6])?,
2494 },
2495 ]
2496 .to_der()?;
2497 body.extend(
2498 der::asn1::Any::new(
2499 der::Tag::ContextSpecific {
2500 constructed: true,
2501 number: der::TagNumber(3),
2502 },
2503 extensions,
2504 )?
2505 .to_der()?,
2506 );
2507 }
2508 let signed = der::asn1::Any::new(der::Tag::Sequence, body)?.to_der()?;
2509 let digest = crate::provider::default_provider()
2510 .digest(super::super::DigestAlgorithm::Sha1, &signed)?;
2511 let signature: dsa::Signature =
2513 key.sign_prehash_with_rng(&mut ChaCha20Rng::from_seed([root as u8; 32]), &digest)?;
2514 let mut body = signed;
2515 body.extend_from_slice(&algorithm);
2516 body.extend(der::asn1::BitString::from_bytes(&signature.to_der()?)?.to_der()?);
2517 Ok(der::asn1::Any::new(der::Tag::Sequence, body)?.to_der()?)
2518 };
2519 let root = make_certificate(true)?;
2520 let leaf = make_certificate(false)?;
2521 let info = KeyInfo {
2522 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
2523 certificates: vec![leaf.clone()],
2524 parsed_certificates: vec![parse_x509_certificate(&leaf)?],
2525 certificate_chain: vec![0],
2526 ..Default::default()
2527 })],
2528 };
2529 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
2530 trusted_certs: vec![root],
2531 ..Default::default()
2532 });
2533 let mut policy = crate::policy::VerificationPolicy::default();
2534 policy.key_trust.verify_x509_chains = true;
2535 let resolved = resolver
2536 .resolve_with_policy_and_provider(
2537 Some(&info),
2538 SignatureAlgorithm::DsaSha256,
2539 &policy,
2540 crate::provider::default_provider(),
2541 )
2542 .expect("authenticated inherited DSA key")
2543 .expect("resolved DSA target");
2544 let effective = resolved
2545 .verification_spki(SignatureAlgorithm::DsaSha256)?
2546 .expect("effective DSA SPKI is present");
2547 assert_eq!(
2548 effective,
2549 public.as_bytes(),
2550 "data verification receives the effective SPKI"
2551 );
2552 let signer = super::super::DsaSigningKey::from_pkcs8_der(private.as_bytes())?;
2553 let message = b"authenticated target with inherited DSA parameters";
2554 let signature = crate::provider::default_provider().sign(
2555 &signer,
2556 SignatureAlgorithm::DsaSha256,
2557 message,
2558 )?;
2559 assert!(crate::provider::default_provider().verify(
2560 &*resolved,
2561 SignatureAlgorithm::DsaSha256,
2562 message,
2563 &signature
2564 )?);
2565 let original = super::super::pkix::CertificateSession::new(&policy.resources);
2566 let source = original.read(&leaf)?;
2567 assert!(
2568 source.tbs().public_key().algorithm().parameters().is_none(),
2569 "source certificate is not rewritten"
2570 );
2571 let root_source = original.read(&resolver.config.trusted_certs[0])?;
2575 let standing = structured_pkix::path::WorkingKey::standing(source.tbs().public_key());
2576 let inherited = structured_pkix::path::WorkingKey::standing(root_source.tbs().public_key())
2577 .subject(&source, original.memory())?;
2578 let verification_key = VerificationKey {
2579 algorithm: SignatureAlgorithm::DsaSha256,
2580 public_key_bytes: effective.to_vec(),
2581 certificate_der: None,
2582 name: None,
2583 };
2584 let builder = super::super::SignatureBuilder::new(
2585 crate::c14n::C14nAlgorithm::new(crate::c14n::C14nMode::Exclusive1_0, false),
2586 SignatureAlgorithm::DsaSha256,
2587 )
2588 .add_reference(
2589 super::super::ReferenceBuilder::new(super::super::DigestAlgorithm::Sha256)
2590 .uri("")
2591 .transform(super::super::Transform::Enveloped),
2592 );
2593 let xml = super::super::SignContext::new(&signer).sign_with_builder("<root/>", &builder)?;
2594 let document = crate::XmlDocument::parse(xml)?;
2595 let context = super::super::VerifyContext::new().key(&verification_key);
2596 super::super::with_verified_request(
2597 &document,
2598 &context,
2599 &super::super::VerificationRequest::default(),
2600 original.memory(),
2601 |session| {
2602 let selected =
2603 session.select_signature(session.evidence().signatures()[0].identity())?;
2604 selected
2605 .with_key_receipt(|receipt| {
2606 for (expected, outcome) in [
2607 (standing, crate::provider::KeyAssociation::Unproven),
2608 (inherited, crate::provider::KeyAssociation::Same),
2609 ] {
2610 selected
2611 .associate_key(&receipt, expected, |actual| {
2612 assert_eq!(actual, outcome);
2613 Ok::<_, ()>(())
2614 })
2615 .expect("inherited DSA key association");
2616 }
2617 Ok::<_, ()>(())
2618 })
2619 .expect("original successful DSA receipt");
2620 Ok(())
2621 },
2622 )?;
2623 Ok(())
2624 }
2625
2626 #[test]
2627 fn xml_rsa_components_are_bounded_before_bigint_decode() {
2628 let oversized = vec![1_u8; crate::hard_limits::RSA_MODULUS_BIT_CEILING.div_ceil(8) + 1];
2630 assert!(matches!(
2631 rsa_key_value_to_spki_der(&oversized, &[1, 0, 1]),
2632 Err(KeyResolutionError::InvalidPublicKey)
2633 ));
2634 }
2635
2636 #[test]
2637 fn oversized_dsa_spki_parameter_is_rejected_before_bigint_decode() {
2638 let oversized = vec![1_u8; crate::hard_limits::DSA_KEY_COMPONENT_BYTE_CEILING + 1];
2641 let one = [1_u8];
2642 let params = der::Encode::to_der(&super::super::signature::BorrowedDsaPublicParameters {
2643 p: der::asn1::UintRef::new(&oversized).expect("positive P"),
2644 q: der::asn1::UintRef::new(&one).expect("positive Q"),
2645 g: der::asn1::UintRef::new(&one).expect("positive G"),
2646 })
2647 .expect("parameters encode");
2648 let y = der::Encode::to_der(&der::asn1::UintRef::new(&one).expect("positive Y"))
2649 .expect("public value encodes");
2650 let spki = pkcs8::SubjectPublicKeyInfoRef {
2651 algorithm: pkcs8::AlgorithmIdentifierRef {
2652 oid: dsa::OID,
2653 parameters: Some(der::asn1::AnyRef::from_der(¶ms).expect("parameters")),
2654 },
2655 subject_public_key: der::asn1::BitStringRef::new(0, &y).expect("bit string"),
2656 };
2657 let encoded = der::Encode::to_der(&spki).expect("SPKI encodes");
2658 assert!(matches!(
2659 decode_dsa_verifying_key(&encoded),
2660 Err(super::super::signature::SignatureVerificationError::InvalidKeyDer)
2661 ));
2662 let session =
2665 super::super::pkix::CertificateSession::new(&crate::policy::ResourcePolicy::default());
2666 assert!(matches!(
2667 validate_spki_algorithm(&session, &encoded, SignatureAlgorithm::DsaSha256),
2668 Err(KeyResolutionError::InvalidPublicKey)
2669 ));
2670 }
2671
2672 struct RejectSecondSha512Provider {
2673 sha512_calls: AtomicUsize,
2674 verification_calls: AtomicUsize,
2675 reject_verification_call: Option<usize>,
2676 rejected_verification_data: Option<Vec<u8>>,
2677 }
2678
2679 impl crate::provider::CryptoProvider for RejectSecondSha512Provider {
2680 fn name(&self) -> &'static str {
2681 "reject-second-sha512"
2682 }
2683
2684 fn supports(&self, capability: crate::provider::ProviderCapability<'_>) -> bool {
2685 crate::provider::default_provider().supports(capability)
2686 }
2687
2688 fn fill_random(&self, output: &mut [u8]) -> Result<(), crate::provider::ProviderError> {
2689 crate::provider::default_provider().fill_random(output)
2690 }
2691
2692 fn derive_key(
2693 &self,
2694 parameters: &crate::provider::KdfParameters<'_>,
2695 secret: &[u8],
2696 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2697 crate::provider::default_provider().derive_key(parameters, secret)
2698 }
2699
2700 fn digest(
2701 &self,
2702 algorithm: super::super::DigestAlgorithm,
2703 data: &[u8],
2704 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2705 if algorithm == super::super::DigestAlgorithm::Sha512
2706 && self.sha512_calls.fetch_add(1, Ordering::Relaxed) > 0
2707 {
2708 return Err(crate::provider::ProviderError::Unsupported {
2709 operation: crate::provider::ProviderOperation::Digest,
2710 algorithm: Some(algorithm.uri().to_owned()),
2711 });
2712 }
2713 crate::provider::default_provider().digest(algorithm, data)
2714 }
2715
2716 fn sign(
2717 &self,
2718 key: &dyn super::super::SigningKey,
2719 algorithm: SignatureAlgorithm,
2720 data: &[u8],
2721 ) -> Result<Vec<u8>, super::super::SigningKeyError> {
2722 crate::provider::default_provider().sign(key, algorithm, data)
2723 }
2724
2725 fn verify(
2726 &self,
2727 key: &dyn VerifyingKey,
2728 algorithm: SignatureAlgorithm,
2729 data: &[u8],
2730 signature: &[u8],
2731 ) -> Result<bool, DsigError> {
2732 let call = self.verification_calls.fetch_add(1, Ordering::Relaxed);
2733 if self.reject_verification_call == Some(call)
2734 || self
2735 .rejected_verification_data
2736 .as_deref()
2737 .is_some_and(|rejected| rejected == data)
2738 {
2739 return Err(crate::provider::ProviderError::Unsupported {
2740 operation: crate::provider::ProviderOperation::Verify,
2741 algorithm: Some(algorithm.uri().to_owned()),
2742 }
2743 .into());
2744 }
2745 crate::provider::default_provider().verify(key, algorithm, data, signature)
2746 }
2747
2748 fn verify_x509_signature(
2749 &self,
2750 algorithm: crate::provider::X509SignatureAlgorithm,
2751 data: &[u8],
2752 signature: &[u8],
2753 issuer_spki_der: &[u8],
2754 ) -> Result<bool, crate::provider::ProviderError> {
2755 let call = self.verification_calls.fetch_add(1, Ordering::Relaxed);
2756 if self.reject_verification_call == Some(call)
2757 || self
2758 .rejected_verification_data
2759 .as_deref()
2760 .is_some_and(|rejected| rejected == data)
2761 {
2762 return Err(crate::provider::ProviderError::Unsupported {
2763 operation: crate::provider::ProviderOperation::VerifyCertificate,
2764 algorithm: algorithm.oid().map(str::to_owned),
2765 });
2766 }
2767 crate::provider::default_provider().verify_x509_signature(
2768 algorithm,
2769 data,
2770 signature,
2771 issuer_spki_der,
2772 )
2773 }
2774
2775 #[cfg(feature = "xmlenc")]
2776 fn encrypt_data(
2777 &self,
2778 algorithm: crate::xmlenc::DataEncryptionAlgorithm,
2779 key: &[u8],
2780 plaintext: &[u8],
2781 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2782 crate::provider::default_provider().encrypt_data(algorithm, key, plaintext)
2783 }
2784
2785 #[cfg(feature = "xmlenc")]
2786 fn decrypt_data(
2787 &self,
2788 algorithm: crate::xmlenc::DataEncryptionAlgorithm,
2789 key: &[u8],
2790 ciphertext: &[u8],
2791 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2792 crate::provider::default_provider().decrypt_data(algorithm, key, ciphertext)
2793 }
2794
2795 #[cfg(feature = "xmlenc")]
2796 fn wrap_key(
2797 &self,
2798 algorithm: crate::xmlenc::KeyWrapAlgorithm,
2799 kek: &[u8],
2800 key: &[u8],
2801 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2802 crate::provider::default_provider().wrap_key(algorithm, kek, key)
2803 }
2804
2805 #[cfg(feature = "xmlenc")]
2806 fn unwrap_key(
2807 &self,
2808 algorithm: crate::xmlenc::KeyWrapAlgorithm,
2809 kek: &[u8],
2810 wrapped: &[u8],
2811 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2812 crate::provider::default_provider().unwrap_key(algorithm, kek, wrapped)
2813 }
2814
2815 #[cfg(feature = "xmlenc")]
2816 fn transport_key(
2817 &self,
2818 key: &dyn crate::provider::KeyTransportKey,
2819 parameters: &crate::xmlenc::RsaOaepParameters,
2820 plaintext: &[u8],
2821 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2822 crate::provider::default_provider().transport_key(key, parameters, plaintext)
2823 }
2824
2825 #[cfg(feature = "xmlenc")]
2826 fn recover_key(
2827 &self,
2828 key: &dyn crate::provider::KeyRecoveryKey,
2829 parameters: &crate::xmlenc::RsaOaepParameters,
2830 ciphertext: &[u8],
2831 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
2832 crate::provider::default_provider().recover_key(key, parameters, ciphertext)
2833 }
2834 }
2835
2836 fn chain_policy() -> crate::policy::KeyTrustPolicy {
2837 crate::policy::KeyTrustPolicy {
2838 verify_x509_chains: true,
2839 ..crate::policy::KeyTrustPolicy::default()
2840 }
2841 }
2842
2843 fn cryptographic_policy() -> crate::policy::VerificationPolicy {
2844 verification_policy_with_trust(crate::policy::KeyTrustPolicy {
2846 mode: crate::policy::VerificationTrustMode::CryptographicOnly,
2847 ..crate::policy::KeyTrustPolicy::default()
2848 })
2849 }
2850
2851 fn chain_policy_at(verification_time: SystemTime) -> crate::policy::KeyTrustPolicy {
2852 crate::policy::KeyTrustPolicy {
2853 verification_time: Some(verification_time),
2854 ..chain_policy()
2855 }
2856 }
2857
2858 fn verification_policy_with_trust(
2859 key_trust: crate::policy::KeyTrustPolicy,
2860 ) -> crate::policy::VerificationPolicy {
2861 crate::policy::VerificationPolicy {
2862 key_trust,
2863 ..crate::policy::VerificationPolicy::default()
2864 }
2865 }
2866
2867 const SIGNED_SAML: &str =
2868 include_str!("../../tests/fixtures/saml/response_signed_by_idp_ecdsa.xml");
2869 const SAML_PUBLIC_KEY: &str =
2870 include_str!("../../tests/fixtures/keys/ec/saml-idp-ecdsa-pubkey.pem");
2871 const RSA_PUBLIC_KEY: &str = include_str!("../../tests/fixtures/keys/rsa/rsa-2048-pubkey.pem");
2872 const RSA_4096_CERTIFICATE: &str =
2873 include_str!("../../tests/fixtures/keys/rsa/rsa-4096-cert.pem");
2874 const X509_DIGEST_SIGNATURE: &str = include_str!(
2875 "../../tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloped-x509-digest-sha512.xml"
2876 );
2877 const X509_DIGEST_SHA256_SIGNATURE: &str = include_str!(
2878 "../../tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloped-x509-digest-sha256.xml"
2879 );
2880 const RSA_KEY_VALUE_SIGNATURE: &str = include_str!(
2881 "../../tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloping-sha256-rsa-sha256.xml"
2882 );
2883 const LEGACY_RSA_KEY_VALUE_SIGNATURE: &str = include_str!(
2884 "../../tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-rsa.xml"
2885 );
2886 const EC_P256_KEY_VALUE_SIGNATURE: &str = include_str!(
2887 "../../tests/fixtures/xmldsig/xmldsig11-interop-2012/signature-enveloping-p256_sha256.xml"
2888 );
2889 const EC_P384_KEY_VALUE_SIGNATURE: &str = include_str!(
2890 "../../tests/fixtures/xmldsig/xmldsig11-interop-2012/signature-enveloping-p384_sha384.xml"
2891 );
2892
2893 fn replace_key_info(xml: &str, replacement: &str) -> String {
2894 let start = xml.find("<ds:KeyInfo>").expect("fixture has KeyInfo");
2895 let end = xml
2896 .find("</ds:KeyInfo>")
2897 .expect("fixture has closing KeyInfo")
2898 + "</ds:KeyInfo>".len();
2899 format!("{}{}{}", &xml[..start], replacement, &xml[end..])
2900 }
2901
2902 fn replace_unprefixed_key_info(xml: &str, replacement: &str) -> String {
2903 let start = xml.find("<KeyInfo>").expect("fixture has KeyInfo");
2904 let end = xml.find("</KeyInfo>").expect("fixture has closing KeyInfo") + "</KeyInfo>".len();
2905 format!("{}{}{}", &xml[..start], replacement, &xml[end..])
2906 }
2907
2908 fn rsa_key_value_parts(public_key: &rsa::RsaPublicKey) -> (String, String) {
2909 (
2910 STANDARD.encode(public_key.n().to_be_bytes_trimmed_vartime()),
2911 STANDARD.encode(public_key.e().to_be_bytes_trimmed_vartime()),
2912 )
2913 }
2914
2915 fn x509_signature_with_leaf_subject() -> String {
2916 replace_unprefixed_key_info(
2917 X509_DIGEST_SIGNATURE,
2918 "<KeyInfo><X509Data><X509SubjectName>CN=Test Key rsa-4096,O=XML Security Library (http://www.aleksey.com/xmlsec),ST=California,C=US</X509SubjectName></X509Data></KeyInfo>",
2919 )
2920 }
2921
2922 fn fixture_certificate_time() -> SystemTime {
2923 SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_800_000_000)
2925 }
2926
2927 fn public_key_der(pem_text: &str) -> Vec<u8> {
2928 let (rest, pem) = x509_parser::pem::parse_x509_pem(pem_text.as_bytes())
2929 .expect("fixture public key is PEM");
2930 assert!(rest.iter().all(|byte| byte.is_ascii_whitespace()));
2931 assert_eq!(pem.label, "PUBLIC KEY");
2932 pem.contents
2933 }
2934
2935 fn certificate_der(pem_text: &str) -> Vec<u8> {
2936 let (rest, pem) = x509_parser::pem::parse_x509_pem(pem_text.as_bytes())
2937 .expect("fixture certificate is PEM");
2938 assert!(rest.iter().all(|byte| byte.is_ascii_whitespace()));
2939 assert_eq!(pem.label, "CERTIFICATE");
2940 pem.contents
2941 }
2942
2943 fn crl_der(pem_text: &str) -> Vec<u8> {
2944 let (rest, pem) =
2945 x509_parser::pem::parse_x509_pem(pem_text.as_bytes()).expect("fixture CRL is PEM");
2946 assert!(rest.iter().all(|byte| byte.is_ascii_whitespace()));
2947 assert_eq!(pem.label, "X509 CRL");
2948 pem.contents
2949 }
2950
2951 fn generated_certificate_params(common_name: &str, is_ca: bool) -> rcgen::CertificateParams {
2952 let mut params = rcgen::CertificateParams::new(Vec::new())
2953 .expect("empty SAN list should produce valid certificate parameters");
2954 params
2955 .distinguished_name
2956 .push(rcgen::DnType::CommonName, common_name);
2957 if is_ca {
2958 params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
2959 params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
2960 }
2961 params
2962 }
2963
2964 fn authorized_revoked_chain() -> (X509DataInfo, Vec<u8>) {
2965 let mut root_params = generated_certificate_params("revocation root", true);
2966 root_params.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign];
2967 let root = rcgen::CertifiedIssuer::self_signed(
2968 root_params,
2969 KeyPair::generate().expect("root key generation should succeed"),
2970 )
2971 .expect("root should be self-signable");
2972
2973 let issuer_key = KeyPair::generate().expect("issuer key generation should succeed");
2974 let mut issuer_params = generated_certificate_params("revocation issuer", true);
2975 issuer_params.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign];
2976 let issuer_certificate = issuer_params
2977 .signed_by(&issuer_key, &root)
2978 .expect("root should sign issuer certificate");
2979 let issuer = Issuer::new(issuer_params, issuer_key);
2980
2981 let mut leaf_params = generated_certificate_params("revoked signer", false);
2982 leaf_params.serial_number = Some(SerialNumber::from(42_u64));
2983 leaf_params.key_usages = vec![KeyUsagePurpose::DigitalSignature];
2984 let leaf = leaf_params
2985 .signed_by(
2986 &KeyPair::generate().expect("leaf key generation should succeed"),
2987 &issuer,
2988 )
2989 .expect("issuer should sign leaf certificate");
2990 let crl = CertificateRevocationListParams {
2991 this_update: date_time_ymd(2026, 3, 15),
2992 next_update: date_time_ymd(2026, 4, 15),
2993 crl_number: SerialNumber::from(1_u64),
2994 issuing_distribution_point: None,
2995 revoked_certs: vec![RevokedCertParams {
2996 serial_number: SerialNumber::from(42_u64),
2997 revocation_time: date_time_ymd(2026, 3, 16),
2998 reason_code: None,
2999 invalidity_date: None,
3000 }],
3001 key_identifier_method: KeyIdMethod::Sha256,
3002 }
3003 .signed_by(&issuer)
3004 .expect("issuer should sign CRL");
3005 let mut info = x509_info(
3006 vec![
3007 leaf.der().to_vec(),
3008 issuer_certificate.der().to_vec(),
3009 root.der().to_vec(),
3010 ],
3011 0,
3012 );
3013 info.crls.push(crl.der().to_vec());
3014 (info, root.der().to_vec())
3015 }
3016
3017 fn x509_info(certificates: Vec<Vec<u8>>, signing_index: usize) -> X509DataInfo {
3018 let parsed_certificates = certificates
3019 .iter()
3020 .map(|certificate| {
3021 parse_x509_certificate(certificate)
3022 .expect("generated certificate should have supported metadata")
3023 })
3024 .collect();
3025 X509DataInfo {
3026 certificates,
3027 parsed_certificates,
3028 certificate_chain: vec![signing_index],
3029 ..X509DataInfo::default()
3030 }
3031 }
3032
3033 #[test]
3034 fn defaults_match_key_resolution_policy() {
3035 let config = KeyResolverConfig::default();
3037
3038 assert!(config.trusted_certs.is_empty());
3039 assert!(config.lookup_certs.is_empty());
3040 assert!(config.named_keys.is_empty());
3041 let trust = crate::policy::VerificationPolicy::default().key_trust;
3042 assert!(!trust.verify_x509_chains);
3043 assert!(!trust.check_crls);
3044 assert_eq!(trust.verification_time, None);
3045 assert_eq!(trust.max_x509_chain_depth, 9);
3046 }
3047
3048 #[test]
3049 fn verification_policy_controls_leaf_extended_key_usage() {
3050 let root = rcgen::CertifiedIssuer::self_signed(
3053 generated_certificate_params("EKU policy root", true),
3054 rcgen::KeyPair::generate().expect("root key generation should succeed"),
3055 )
3056 .expect("root should be self-signable");
3057 let mut leaf_params = generated_certificate_params("TLS-only XML signer", false);
3058 leaf_params.key_usages = vec![rcgen::KeyUsagePurpose::DigitalSignature];
3059 leaf_params.extended_key_usages = vec![rcgen::ExtendedKeyUsagePurpose::ServerAuth];
3060 let leaf = leaf_params
3061 .signed_by(
3062 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3063 &root,
3064 )
3065 .expect("root should sign leaf certificate");
3066 let key_info = KeyInfo {
3067 sources: vec![KeyInfoSource::X509Data(x509_info(
3068 vec![leaf.der().to_vec(), root.der().to_vec()],
3069 0,
3070 ))],
3071 };
3072 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3073 trusted_certs: vec![root.der().to_vec()],
3074 ..KeyResolverConfig::default()
3075 });
3076 let mut policy = crate::policy::VerificationPolicy::default();
3077 policy.key_trust.verify_x509_chains = true;
3078
3079 let error = match resolver.resolve_with_policy(
3080 Some(&key_info),
3081 SignatureAlgorithm::EcdsaSha256,
3082 &policy,
3083 ) {
3084 Ok(_) => panic!("unapproved restricted EKU must be rejected"),
3085 Err(error) => error,
3086 };
3087 assert!(matches!(
3088 error,
3089 DsigError::KeyResolution(KeyResolutionError::Chain(
3090 super::super::X509ChainError::InvalidKeyUsage {
3091 position: 0,
3092 required: "an approved extended key usage",
3093 }
3094 ))
3095 ));
3096
3097 policy.key_trust.allowed_extended_key_usages =
3098 std::collections::HashSet::from([crate::policy::ExtendedKeyPurpose::ServerAuth]);
3099 assert!(
3100 resolver
3101 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::EcdsaSha256, &policy,)
3102 .expect("approved restricted EKU must pass path validation")
3103 .is_some()
3104 );
3105 }
3106
3107 #[test]
3108 fn operation_policy_rejects_zero_x509_resource_limits() {
3109 for trust in [
3112 crate::policy::KeyTrustPolicy {
3113 verify_x509_chains: true,
3114 max_x509_chain_depth: 0,
3115 ..crate::policy::KeyTrustPolicy::default()
3116 },
3117 crate::policy::KeyTrustPolicy {
3118 verify_x509_chains: true,
3119 max_x509_candidate_paths: 0,
3120 ..crate::policy::KeyTrustPolicy::default()
3121 },
3122 ] {
3123 let certificate = certificate_der(RSA_4096_CERTIFICATE);
3124 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3125 trusted_certs: vec![certificate],
3126 ..KeyResolverConfig::default()
3127 });
3128 let policy = crate::policy::VerificationPolicy {
3129 key_trust: trust,
3130 ..crate::policy::VerificationPolicy::default()
3131 };
3132 let error = super::super::VerifyContext::new()
3133 .policy(policy)
3134 .key_resolver(&resolver)
3135 .verify(&x509_signature_with_leaf_subject())
3136 .expect_err("zero composed X.509 limits must fail as policy errors");
3137
3138 assert!(matches!(
3139 error,
3140 DsigError::Policy(crate::policy::PolicyViolation::InvalidResourceLimit {
3141 requirement: "limit must be nonzero",
3142 actual: 0,
3143 ..
3144 })
3145 ));
3146 }
3147 }
3148
3149 #[test]
3150 fn operation_policy_rejects_crl_checking_without_chain_validation() {
3151 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3154 lookup_certs: vec![certificate_der(RSA_4096_CERTIFICATE)],
3155 ..KeyResolverConfig::default()
3156 });
3157 let policy = crate::policy::VerificationPolicy {
3158 key_trust: crate::policy::KeyTrustPolicy {
3159 check_crls: true,
3160 ..crate::policy::KeyTrustPolicy::default()
3161 },
3162 ..crate::policy::VerificationPolicy::default()
3163 };
3164 let error = super::super::VerifyContext::new()
3165 .policy(policy)
3166 .key_resolver(&resolver)
3167 .verify(&x509_signature_with_leaf_subject())
3168 .expect_err("CRL-only trust policy must fail before certificate use");
3169
3170 assert!(matches!(
3171 error,
3172 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust {
3173 reason: "CRL checking requires X.509 chain validation"
3174 })
3175 ));
3176 }
3177
3178 #[test]
3179 fn hmac_key_rejects_empty_secret_and_wrong_algorithm() {
3180 assert!(matches!(
3182 HmacSha1VerificationKey::new(Vec::new()),
3183 Err(KeyResolutionError::InvalidPublicKey)
3184 ));
3185 let key = HmacSha1VerificationKey::new(b"secret".to_vec())
3186 .expect("non-empty HMAC secret must be accepted");
3187 assert!(matches!(
3188 key.verify(SignatureAlgorithm::RsaSha256, b"data", b"signature"),
3189 Err(DsigError::KeyResolution(
3190 KeyResolutionError::AlgorithmMismatch
3191 ))
3192 ));
3193 }
3194
3195 #[test]
3196 fn hmac_key_uses_the_operation_policy_for_truncation() {
3197 let key = HmacVerificationKey::new(b"secret".to_vec())
3201 .expect("the fixture HMAC secret is non-empty");
3202 let mut mac = hmac::Hmac::<sha1::Sha1>::new_from_slice(b"secret")
3203 .expect("HMAC accepts an arbitrary non-empty secret");
3204 mac.update(b"data");
3205 let expected = mac.finalize().into_bytes();
3206
3207 let policy = crate::policy::VerificationPolicy {
3208 hmac: crate::policy::HmacPolicy {
3209 minimum_key_bits: 40,
3210 minimum_output_bits: 80,
3211 },
3212 ..crate::policy::VerificationPolicy::default()
3213 };
3214 assert!(
3215 key.verify_with_policy(
3216 &policy,
3217 SignatureAlgorithm::HmacSha1,
3218 b"data",
3219 &expected[..10],
3220 )
3221 .expect("the compatibility policy and algorithm match")
3222 );
3223 assert!(
3224 !key.verify_with_policy(&policy, SignatureAlgorithm::HmacSha1, b"data", &[0_u8; 10],)
3225 .expect("a mismatched truncated MAC must be rejected")
3226 );
3227 }
3228
3229 #[test]
3230 fn hmac_key_direct_api_rejects_attacker_selected_short_output() {
3231 let key = HmacVerificationKey::new([0x42; 16]).expect("fixed HMAC key must parse");
3234 let mut mac = hmac::Hmac::<sha2::Sha256>::new_from_slice(&[0x42; 16])
3235 .expect("HMAC accepts the fixed secret");
3236 mac.update(b"data");
3237 let expected = mac.finalize().into_bytes();
3238
3239 assert!(matches!(
3240 key.verify(SignatureAlgorithm::HmacSha256, b"data", &expected[..1]),
3241 Err(DsigError::Policy(
3242 crate::policy::PolicyViolation::HmacOutputLength {
3243 minimum: 128,
3244 maximum: 256,
3245 actual: 8,
3246 }
3247 ))
3248 ));
3249 }
3250
3251 #[test]
3252 fn hmac_key_debug_redacts_secret_material() {
3253 let secret = b"unique-debug-secret-marker";
3255 let key = HmacVerificationKey::new(secret.to_vec())
3256 .expect("the fixture HMAC secret is non-empty");
3257
3258 let debug = format!("{key:?}");
3259 assert!(
3260 !debug
3261 .contains(std::str::from_utf8(secret).expect("the debug marker is literal ASCII"))
3262 );
3263 assert!(!debug.contains(&format!("{secret:?}")));
3264 assert!(!debug.contains("output_length_bits"));
3265 }
3266
3267 #[test]
3268 fn stores_named_verification_key_metadata() {
3269 let key = VerificationKey {
3271 algorithm: SignatureAlgorithm::RsaSha256,
3272 public_key_bytes: vec![1, 2, 3],
3273 certificate_der: Some(vec![4, 5, 6]),
3274 name: Some("idp-signing".into()),
3275 };
3276 let mut config = KeyResolverConfig::default();
3277 config.named_keys.insert("idp-signing".into(), key.clone());
3278
3279 assert_eq!(config.named_keys.get("idp-signing"), Some(&key));
3280 }
3281
3282 #[test]
3283 fn resolves_embedded_certificate_end_to_end() {
3284 let resolver = DefaultKeyResolver::default();
3286 let result = super::super::VerifyContext::new()
3287 .policy(cryptographic_policy())
3288 .key_resolver(&resolver)
3289 .verify(SIGNED_SAML)
3290 .expect("embedded certificate should resolve");
3291
3292 assert_eq!(result.status, super::super::DsigStatus::Valid);
3293 assert_eq!(
3294 result.key_trust,
3295 super::super::KeyTrustEvidence::NotEstablished
3296 );
3297 }
3298
3299 #[test]
3300 fn embedded_certificate_requires_trust_but_explicit_pin_authorizes_it() {
3301 let untrusted = DefaultKeyResolver::default();
3303 let error = super::super::VerifyContext::new()
3304 .key_resolver(&untrusted)
3305 .verify(SIGNED_SAML)
3306 .expect_err("an embedded certificate is not a trust declaration");
3307 assert!(matches!(
3308 error,
3309 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust { .. })
3310 ));
3311
3312 let xml = roxmltree::Document::parse(SIGNED_SAML).expect("signed SAML fixture must parse");
3313 let certificate = xml
3314 .descendants()
3315 .find(|node| {
3316 node.has_tag_name(("http://www.w3.org/2000/09/xmldsig#", "X509Certificate"))
3317 })
3318 .expect("signed SAML must embed its certificate");
3319 let der = STANDARD
3320 .decode(
3321 certificate
3322 .text()
3323 .expect("fixture certificate must contain Base64 text")
3324 .split_whitespace()
3325 .collect::<String>(),
3326 )
3327 .expect("fixture certificate must be valid Base64");
3328 let trusted = DefaultKeyResolver::new(KeyResolverConfig {
3329 trusted_certs: vec![der],
3330 ..KeyResolverConfig::default()
3331 });
3332 let result = super::super::VerifyContext::new()
3333 .key_resolver(&trusted)
3334 .verify(SIGNED_SAML)
3335 .expect("an exact caller certificate pin authorizes the key");
3336 assert_eq!(result.status, super::super::DsigStatus::Valid);
3337 assert_eq!(
3338 result.key_trust,
3339 super::super::KeyTrustEvidence::CallerTrusted
3340 );
3341
3342 assert!(
3344 super::super::VerifyContext::new()
3345 .key_resolver(&untrusted)
3346 .verify(SIGNED_SAML)
3347 .is_err()
3348 );
3349 }
3350
3351 #[test]
3352 fn certificate_pin_inspections_share_the_candidate_budget() {
3353 let xml = roxmltree::Document::parse(SIGNED_SAML).expect("fixture must parse");
3355 let text = xml
3356 .descendants()
3357 .find(|node| {
3358 node.has_tag_name(("http://www.w3.org/2000/09/xmldsig#", "X509Certificate"))
3359 })
3360 .and_then(|node| node.text())
3361 .expect("fixture embeds a certificate");
3362 let certificate = STANDARD
3363 .decode(text.split_whitespace().collect::<String>())
3364 .expect("fixture certificate must decode");
3365 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3366 trusted_certs: vec![certificate],
3367 ..KeyResolverConfig::default()
3368 });
3369 let mut policy = crate::policy::VerificationPolicy::default();
3370 policy.resources.max_key_candidates = 1;
3371 let error = super::super::VerifyContext::new()
3372 .policy(policy)
3373 .key_resolver(&resolver)
3374 .verify(SIGNED_SAML)
3375 .expect_err("the certificate and pin are separate inspections");
3376 assert!(matches!(
3377 error,
3378 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
3379 resource: crate::policy::resource_name::KEY_CANDIDATES,
3380 maximum: 1,
3381 actual: 2,
3382 })
3383 ));
3384 }
3385
3386 #[test]
3387 fn resolves_x509_digest_from_configured_certificates() {
3388 let leaf_certificate_der = certificate_der(RSA_4096_CERTIFICATE);
3391 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3392 lookup_certs: vec![leaf_certificate_der],
3393 trusted_certs: vec![
3394 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
3395 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
3396 ],
3397 ..KeyResolverConfig::default()
3398 });
3399 for signature in [X509_DIGEST_SHA256_SIGNATURE, X509_DIGEST_SIGNATURE] {
3400 let result = super::super::VerifyContext::new()
3401 .policy(cryptographic_policy())
3402 .key_resolver(&resolver)
3403 .verify(signature)
3404 .expect("X509Digest should resolve a configured certificate");
3405
3406 assert_eq!(result.status, super::super::DsigStatus::Valid);
3407 }
3408 }
3409
3410 #[test]
3411 fn selector_resolved_certificate_obeys_chain_policy() {
3412 let leaf_certificate_der = certificate_der(RSA_4096_CERTIFICATE);
3415 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3416 lookup_certs: vec![leaf_certificate_der],
3417 trusted_certs: vec![
3418 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
3419 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
3420 ],
3421 ..KeyResolverConfig::default()
3422 });
3423 let error = super::super::VerifyContext::new()
3424 .policy(verification_policy_with_trust(chain_policy_at(
3425 SystemTime::UNIX_EPOCH,
3426 )))
3427 .key_resolver(&resolver)
3428 .verify(&x509_signature_with_leaf_subject())
3429 .expect_err("selector-resolved certificate must satisfy chain policy");
3430
3431 assert!(
3432 matches!(
3433 &error,
3434 DsigError::KeyResolution(KeyResolutionError::Chain(
3435 super::super::X509ChainError::CertificateNotValid(_)
3436 ))
3437 ),
3438 "unexpected selector policy error: {error:?}"
3439 );
3440 }
3441
3442 #[test]
3443 fn selector_resolved_configured_root_remains_a_trust_anchor() {
3444 let mut params = rcgen::CertificateParams::new(Vec::new())
3447 .expect("empty SAN list should produce valid certificate parameters");
3448 params
3449 .distinguished_name
3450 .push(rcgen::DnType::CommonName, "configured root");
3451 params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
3452 let key_pair = rcgen::KeyPair::generate().expect("test key generation should succeed");
3453 let certificate = params
3454 .self_signed(&key_pair)
3455 .expect("test root should be self-signable");
3456 let certificate_der = certificate.der().to_vec();
3457 let key_info_xml = concat!(
3458 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
3459 "<X509Data><X509SubjectName>CN=configured root</X509SubjectName></X509Data>",
3460 "</KeyInfo>"
3461 );
3462 let document = roxmltree::Document::parse(key_info_xml)
3463 .expect("static selector KeyInfo should parse as XML");
3464 let key_info = super::super::parse_key_info(document.root_element())
3465 .expect("static selector KeyInfo should satisfy XMLDSig structure");
3466 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3467 trusted_certs: vec![certificate_der],
3468 ..KeyResolverConfig::default()
3469 });
3470
3471 let resolved = resolver
3472 .resolve_with_policy(
3473 Some(&key_info),
3474 SignatureAlgorithm::EcdsaSha256,
3475 &verification_policy_with_trust(chain_policy()),
3476 )
3477 .expect("configured self-signed certificate should validate as its own anchor");
3478
3479 assert!(resolved.is_some());
3480 }
3481
3482 #[test]
3483 fn selector_resolved_non_self_signed_trust_anchor_terminates_the_path() {
3484 let mut issuer_params = rcgen::CertificateParams::new(Vec::new())
3488 .expect("empty issuer SAN list should be valid");
3489 issuer_params
3490 .distinguished_name
3491 .push(rcgen::DnType::CommonName, "lookup-only issuer");
3492 issuer_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
3493 issuer_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
3494 let issuer = rcgen::CertifiedIssuer::self_signed(
3495 issuer_params,
3496 rcgen::KeyPair::generate().expect("issuer key generation should succeed"),
3497 )
3498 .expect("issuer certificate should be self-signable");
3499
3500 let mut anchor_params = rcgen::CertificateParams::new(Vec::new())
3501 .expect("empty anchor SAN list should be valid");
3502 anchor_params
3503 .distinguished_name
3504 .push(rcgen::DnType::CommonName, "direct trust anchor");
3505 let anchor = anchor_params
3506 .signed_by(
3507 &rcgen::KeyPair::generate().expect("anchor key generation should succeed"),
3508 &issuer,
3509 )
3510 .expect("issuer should sign the directly trusted certificate");
3511 let key_info_xml = concat!(
3512 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
3513 "<X509Data><X509SubjectName>CN=direct trust anchor</X509SubjectName></X509Data>",
3514 "</KeyInfo>"
3515 );
3516 let document = roxmltree::Document::parse(key_info_xml)
3517 .expect("static selector KeyInfo should parse as XML");
3518 let key_info = super::super::parse_key_info(document.root_element())
3519 .expect("static selector KeyInfo should satisfy XMLDSig structure");
3520 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3521 trusted_certs: vec![anchor.der().to_vec()],
3522 lookup_certs: vec![issuer.der().to_vec()],
3523 ..KeyResolverConfig::default()
3524 });
3525
3526 let resolved = resolver
3527 .resolve_with_policy(
3528 Some(&key_info),
3529 SignatureAlgorithm::EcdsaSha256,
3530 &verification_policy_with_trust(chain_policy()),
3531 )
3532 .expect("an explicitly trusted selected certificate must terminate its path");
3533
3534 assert!(resolved.is_some());
3535 }
3536
3537 #[test]
3538 fn selector_resolved_leaf_stops_at_non_self_signed_trust_anchor() {
3539 let external_issuer = rcgen::CertifiedIssuer::self_signed(
3542 generated_certificate_params("external issuer", true),
3543 rcgen::KeyPair::generate().expect("external issuer key generation should succeed"),
3544 )
3545 .expect("external issuer should be self-signable");
3546 let anchor = rcgen::CertifiedIssuer::signed_by(
3547 generated_certificate_params("non-self-signed anchor", true),
3548 rcgen::KeyPair::generate().expect("anchor key generation should succeed"),
3549 &external_issuer,
3550 )
3551 .expect("external issuer should sign the anchor");
3552 let leaf = generated_certificate_params("anchor leaf", false)
3553 .signed_by(
3554 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3555 &anchor,
3556 )
3557 .expect("anchor should sign the leaf");
3558 let leaf_metadata = parse_x509_certificate(leaf.der())
3559 .expect("generated leaf should have supported metadata");
3560 let key_info = KeyInfo {
3561 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
3562 subject_names: vec![leaf_metadata.subject_dn],
3563 ..X509DataInfo::default()
3564 })],
3565 };
3566 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3567 trusted_certs: vec![anchor.der().to_vec()],
3568 lookup_certs: vec![leaf.der().to_vec(), external_issuer.der().to_vec()],
3569 ..KeyResolverConfig::default()
3570 });
3571
3572 let resolved = resolver
3573 .resolve_with_policy(
3574 Some(&key_info),
3575 SignatureAlgorithm::EcdsaSha256,
3576 &verification_policy_with_trust(chain_policy()),
3577 )
3578 .expect("path construction must stop at the configured anchor");
3579
3580 assert!(resolved.is_some());
3581 }
3582
3583 #[test]
3584 fn selector_resolved_leaf_does_not_anchor_itself() {
3585 let certificate_der = certificate_der(RSA_4096_CERTIFICATE);
3588 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3589 lookup_certs: vec![certificate_der],
3590 ..KeyResolverConfig::default()
3591 });
3592 let error = super::super::VerifyContext::new()
3593 .policy(verification_policy_with_trust(chain_policy_at(
3594 fixture_certificate_time(),
3595 )))
3596 .key_resolver(&resolver)
3597 .verify(&x509_signature_with_leaf_subject())
3598 .expect_err("selector-resolved leaf must not trust itself");
3599
3600 assert!(matches!(
3601 error,
3602 DsigError::KeyResolution(KeyResolutionError::Chain(
3603 super::super::X509ChainError::UntrustedRoot
3604 ))
3605 ));
3606 }
3607
3608 #[test]
3609 fn selector_resolved_leaf_uses_separate_anchor() {
3610 let leaf = certificate_der(RSA_4096_CERTIFICATE);
3613 let issuer = certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem"));
3614 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3615 lookup_certs: vec![leaf],
3616 trusted_certs: vec![issuer],
3617 ..KeyResolverConfig::default()
3618 });
3619 let result = super::super::VerifyContext::new()
3620 .policy(verification_policy_with_trust(chain_policy_at(
3621 fixture_certificate_time(),
3622 )))
3623 .key_resolver(&resolver)
3624 .verify(&x509_signature_with_leaf_subject())
3625 .expect("selector-resolved leaf should chain to its configured issuer");
3626
3627 assert_eq!(result.status, super::super::DsigStatus::Valid);
3628 }
3629
3630 #[test]
3631 fn selector_resolved_leaf_uses_lookup_intermediate() {
3632 let mut root_params =
3635 rcgen::CertificateParams::new(Vec::new()).expect("empty root SAN list should be valid");
3636 root_params
3637 .distinguished_name
3638 .push(rcgen::DnType::CommonName, "lookup root");
3639 root_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
3640 root_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
3641 let root = rcgen::CertifiedIssuer::self_signed(
3642 root_params,
3643 rcgen::KeyPair::generate().expect("root key generation should succeed"),
3644 )
3645 .expect("root certificate should be self-signable");
3646
3647 let mut intermediate_params = rcgen::CertificateParams::new(Vec::new())
3648 .expect("empty intermediate SAN list should be valid");
3649 intermediate_params
3650 .distinguished_name
3651 .push(rcgen::DnType::CommonName, "lookup intermediate");
3652 intermediate_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
3653 intermediate_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
3654 let intermediate = rcgen::CertifiedIssuer::signed_by(
3655 intermediate_params,
3656 rcgen::KeyPair::generate().expect("intermediate key generation should succeed"),
3657 &root,
3658 )
3659 .expect("root should sign the intermediate certificate");
3660
3661 let mut leaf_params =
3662 rcgen::CertificateParams::new(Vec::new()).expect("empty leaf SAN list should be valid");
3663 leaf_params
3664 .distinguished_name
3665 .push(rcgen::DnType::CommonName, "lookup leaf");
3666 let leaf = leaf_params
3667 .signed_by(
3668 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3669 &intermediate,
3670 )
3671 .expect("intermediate should sign the leaf certificate");
3672 let key_info_xml = concat!(
3673 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
3674 "<X509Data><X509SubjectName>CN=lookup leaf</X509SubjectName></X509Data>",
3675 "</KeyInfo>"
3676 );
3677 let document = roxmltree::Document::parse(key_info_xml)
3678 .expect("static selector KeyInfo should parse as XML");
3679 let key_info = super::super::parse_key_info(document.root_element())
3680 .expect("static selector KeyInfo should satisfy XMLDSig structure");
3681 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3682 lookup_certs: vec![leaf.der().to_vec(), intermediate.der().to_vec()],
3683 trusted_certs: vec![root.der().to_vec()],
3684 ..KeyResolverConfig::default()
3685 });
3686
3687 let resolved = resolver
3688 .resolve_with_policy(
3689 Some(&key_info),
3690 SignatureAlgorithm::EcdsaSha256,
3691 &verification_policy_with_trust(chain_policy()),
3692 )
3693 .expect("selector-resolved leaf should chain through the lookup intermediate");
3694
3695 assert!(resolved.is_some());
3696 }
3697
3698 #[test]
3699 fn x509_path_signatures_use_the_operation_provider() {
3700 let root = rcgen::CertifiedIssuer::self_signed(
3704 generated_certificate_params("provider root", true),
3705 rcgen::KeyPair::generate().expect("root key generation should succeed"),
3706 )
3707 .expect("root should be self-signable");
3708 let leaf = generated_certificate_params("provider leaf", false)
3709 .signed_by(
3710 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3711 &root,
3712 )
3713 .expect("root should sign the leaf");
3714 let leaf_der = leaf.der().to_vec();
3715 let leaf_metadata =
3716 parse_x509_certificate(&leaf_der).expect("generated leaf metadata should parse");
3717 let policy = crate::policy::VerificationPolicy {
3718 key_trust: chain_policy(),
3719 ..crate::policy::VerificationPolicy::default()
3720 };
3721
3722 let cases = [
3723 (
3724 KeyInfo {
3725 sources: vec![KeyInfoSource::X509Data(x509_info(
3726 vec![leaf_der.clone()],
3727 0,
3728 ))],
3729 },
3730 Vec::new(),
3731 ),
3732 (
3733 KeyInfo {
3734 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
3735 subject_names: vec![leaf_metadata.subject_dn],
3736 ..X509DataInfo::default()
3737 })],
3738 },
3739 vec![leaf_der],
3740 ),
3741 ];
3742
3743 for (key_info, lookup_certs) in cases {
3744 let provider = RejectSecondSha512Provider {
3745 sha512_calls: AtomicUsize::new(0),
3746 verification_calls: AtomicUsize::new(0),
3747 reject_verification_call: Some(0),
3748 rejected_verification_data: None,
3749 };
3750 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3751 trusted_certs: vec![root.der().to_vec()],
3752 lookup_certs,
3753 ..KeyResolverConfig::default()
3754 });
3755 let error = match resolver.resolve_with_policy_and_provider(
3756 Some(&key_info),
3757 SignatureAlgorithm::EcdsaSha256,
3758 &policy,
3759 &provider,
3760 ) {
3761 Ok(_) => panic!("the operation provider must gate every X.509 path signature"),
3762 Err(error) => error,
3763 };
3764
3765 assert!(matches!(
3766 error,
3767 DsigError::KeyResolution(KeyResolutionError::Chain(
3768 super::super::X509ChainError::UnsupportedSignatureAlgorithm { ref oid }
3769 )) if oid == "1.2.840.10045.4.3.2"
3770 ));
3771 assert_eq!(provider.verification_calls.load(Ordering::Relaxed), 1);
3772 }
3773
3774 let provider = RejectSecondSha512Provider {
3777 sha512_calls: AtomicUsize::new(0),
3778 verification_calls: AtomicUsize::new(0),
3779 reject_verification_call: Some(1),
3780 rejected_verification_data: None,
3781 };
3782 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3783 trusted_certs: vec![root.der().to_vec()],
3784 ..KeyResolverConfig::default()
3785 });
3786 let key_info = KeyInfo {
3787 sources: vec![KeyInfoSource::X509Data(x509_info(
3788 vec![leaf.der().to_vec()],
3789 0,
3790 ))],
3791 };
3792 let error = match resolver.resolve_with_policy_and_provider(
3793 Some(&key_info),
3794 SignatureAlgorithm::EcdsaSha256,
3795 &policy,
3796 &provider,
3797 ) {
3798 Ok(_) => panic!("complete-path validation must retain the operation provider"),
3799 Err(error) => error,
3800 };
3801 assert!(matches!(
3802 error,
3803 DsigError::KeyResolution(KeyResolutionError::Chain(
3804 super::super::X509ChainError::Provider(_)
3805 ))
3806 ));
3807 assert_eq!(provider.verification_calls.load(Ordering::Relaxed), 2);
3808 }
3809
3810 #[test]
3811 fn path_resource_failure_overrides_an_earlier_semantic_rejection() {
3812 let root = rcgen::CertifiedIssuer::self_signed(
3815 generated_certificate_params("resource authority", true),
3816 rcgen::KeyPair::generate().expect("root key"),
3817 )
3818 .expect("root certificate");
3819 let intermediate_key = rcgen::KeyPair::generate().expect("intermediate key");
3820 let good_params = generated_certificate_params("resource intermediate", true);
3821 let good = good_params
3822 .signed_by(&intermediate_key, &root)
3823 .expect("good intermediate");
3824 let mut bad_params = good_params.clone();
3825 bad_params.extended_key_usages = vec![rcgen::ExtendedKeyUsagePurpose::ServerAuth];
3826 let bad = bad_params
3827 .signed_by(&intermediate_key, &root)
3828 .expect("purpose-restricted intermediate");
3829 let leaf = generated_certificate_params("resource signer", false)
3830 .signed_by(
3831 &rcgen::KeyPair::generate().expect("leaf key"),
3832 &rcgen::Issuer::from_params(&good_params, &intermediate_key),
3833 )
3834 .expect("leaf certificate");
3835 let mut available = x509_info(
3836 vec![
3837 root.der().to_vec(),
3838 good.der().to_vec(),
3839 bad.der().to_vec(),
3840 leaf.der().to_vec(),
3841 ],
3842 3,
3843 );
3844 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3845 trusted_certs: vec![root.der().to_vec()],
3846 ..KeyResolverConfig::default()
3847 });
3848 let mut trust = chain_policy();
3849 trust.allowed_extended_key_usages =
3850 std::collections::HashSet::from([crate::policy::ExtendedKeyPurpose::CodeSigning]);
3851 let measured =
3852 super::super::pkix::CertificateSession::new(&crate::policy::ResourcePolicy::default());
3853 let candidates = build_x509_certificate_paths_to_trusted_prefix(
3854 &available,
3855 3,
3856 1,
3857 super::super::parse::X509PathBounds {
3858 max_depth: trust.max_x509_chain_depth,
3859 max_candidate_paths: trust.max_x509_candidate_paths,
3860 },
3861 crate::provider::default_provider(),
3862 trust.certificate_signature_algorithms.as_ref(),
3863 &measured,
3864 )
3865 .expect("both cryptographic candidates");
3866 assert_eq!(candidates.len(), 2);
3867 assert_eq!(
3868 candidates[0],
3869 [3, 2, 0],
3870 "purpose-restricted path must be tried first"
3871 );
3872 available.certificate_chain = candidates[0].to_vec();
3873 let measured_budget = InspectedKeyCandidateBudget::with_ingestion(
3874 &crate::policy::VerificationPolicy::default(),
3875 &measured,
3876 None,
3877 );
3878 assert!(matches!(
3879 resolver.verify_x509_policy(
3880 &available,
3881 &trust,
3882 crate::provider::default_provider(),
3883 &measured_budget,
3884 ),
3885 Err(KeyResolutionError::Chain(
3886 super::super::X509ChainError::InvalidKeyUsage { position: 1, .. }
3887 ))
3888 ));
3889 let maximum = measured.memory().work_used() + 1;
3890 let resources = crate::policy::ResourcePolicy {
3891 max_x509_work: maximum,
3892 ..Default::default()
3893 };
3894 let bounded = super::super::pkix::CertificateSession::new(&resources);
3895 let bounded_budget = InspectedKeyCandidateBudget::with_ingestion(
3896 &crate::policy::VerificationPolicy {
3897 resources,
3898 ..Default::default()
3899 },
3900 &bounded,
3901 None,
3902 );
3903 let mut borrowed = BorrowedX509Pool::new(&available.crls, &bounded);
3904 for certificate in &available.certificates {
3905 borrowed
3906 .insert(certificate, &bounded)
3907 .expect("borrowed certificate pool");
3908 }
3909 let error = resolver
3910 .select_valid_x509_path(
3911 &mut borrowed,
3912 3,
3913 1,
3914 &trust,
3915 None,
3916 (crate::provider::default_provider(), &bounded_budget),
3917 )
3918 .expect_err("later path must exhaust the shared account");
3919 assert!(
3920 matches!(error,
3921 KeyResolutionError::Chain(super::super::X509ChainError::Policy(
3922 crate::policy::PolicyViolation::ResourceLimitExceeded {
3923 resource: crate::policy::resource_name::X509_WORK, maximum: actual,
3924 }
3925 )) if actual == maximum
3926 ),
3927 "semantic rejection masked the resource failure: {error:?}"
3928 );
3929 }
3930
3931 #[test]
3932 fn embedded_leaf_uses_lookup_intermediate_with_duplicate_anchor() {
3933 let trusted_root = rcgen::CertifiedIssuer::self_signed(
3936 generated_certificate_params("unrelated trusted root", true),
3937 rcgen::KeyPair::generate().expect("root key generation should succeed"),
3938 )
3939 .expect("root should be self-signable");
3940 let issuer_root = rcgen::CertifiedIssuer::self_signed(
3941 generated_certificate_params("untrusted issuer root", true),
3942 rcgen::KeyPair::generate().expect("issuer root key generation should succeed"),
3943 )
3944 .expect("issuer root should be self-signable");
3945 let intermediate = rcgen::CertifiedIssuer::signed_by(
3946 generated_certificate_params("embedded intermediate", true),
3947 rcgen::KeyPair::generate().expect("intermediate key generation should succeed"),
3948 &issuer_root,
3949 )
3950 .expect("issuer root should sign the intermediate");
3951 let leaf = generated_certificate_params("embedded leaf", false)
3952 .signed_by(
3953 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
3954 &intermediate,
3955 )
3956 .expect("intermediate should sign the leaf");
3957 let key_info = KeyInfo {
3958 sources: vec![KeyInfoSource::X509Data(x509_info(
3959 vec![leaf.der().to_vec()],
3960 0,
3961 ))],
3962 };
3963 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
3964 lookup_certs: vec![intermediate.der().to_vec()],
3965 trusted_certs: vec![trusted_root.der().to_vec(), trusted_root.der().to_vec()],
3966 ..KeyResolverConfig::default()
3967 });
3968
3969 let policy = verification_policy_with_trust(chain_policy());
3970 let error = match resolver.resolve_with_policy(
3971 Some(&key_info),
3972 SignatureAlgorithm::EcdsaSha256,
3973 &policy,
3974 ) {
3975 Ok(_) => panic!("an untrusted lookup intermediate must not become a trust anchor"),
3976 Err(error) => error,
3977 };
3978
3979 assert!(matches!(
3980 error,
3981 DsigError::KeyResolution(KeyResolutionError::Chain(
3982 super::super::X509ChainError::UntrustedRoot
3983 ))
3984 ));
3985 }
3986
3987 #[test]
3988 fn selector_resolved_leaf_chooses_unique_valid_same_key_path() {
3989 let trusted_root = rcgen::CertifiedIssuer::self_signed(
3993 generated_certificate_params("trusted cross-sign root", true),
3994 rcgen::KeyPair::generate().expect("trusted root key generation should succeed"),
3995 )
3996 .expect("trusted root should be self-signable");
3997 let untrusted_root = rcgen::CertifiedIssuer::self_signed(
3998 generated_certificate_params("untrusted cross-sign root", true),
3999 rcgen::KeyPair::generate().expect("untrusted root key generation should succeed"),
4000 )
4001 .expect("untrusted root should be self-signable");
4002 let shared_params = generated_certificate_params("shared cross-sign issuer", true);
4003 let shared_key =
4004 rcgen::KeyPair::generate().expect("shared issuer key generation should succeed");
4005 let trusted_intermediate = shared_params
4006 .signed_by(&shared_key, &trusted_root)
4007 .expect("trusted root should cross-sign the shared issuer key");
4008 let untrusted_intermediate = shared_params
4009 .signed_by(&shared_key, &untrusted_root)
4010 .expect("untrusted root should cross-sign the shared issuer key");
4011 let shared_issuer = rcgen::Issuer::from_params(&shared_params, &shared_key);
4012 let leaf = generated_certificate_params("cross-signed leaf", false)
4013 .signed_by(
4014 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
4015 &shared_issuer,
4016 )
4017 .expect("shared issuer key should sign the leaf");
4018 let leaf_metadata = parse_x509_certificate(leaf.der())
4019 .expect("generated leaf should have supported metadata");
4020 let key_info = KeyInfo {
4021 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
4022 subject_names: vec![leaf_metadata.subject_dn],
4023 ..X509DataInfo::default()
4024 })],
4025 };
4026 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4027 trusted_certs: vec![trusted_root.der().to_vec()],
4028 lookup_certs: vec![
4029 leaf.der().to_vec(),
4030 untrusted_intermediate.der().to_vec(),
4031 trusted_intermediate.der().to_vec(),
4032 untrusted_root.der().to_vec(),
4033 ],
4034 ..KeyResolverConfig::default()
4035 });
4036
4037 let resolved = resolver
4038 .resolve_with_policy(
4039 Some(&key_info),
4040 SignatureAlgorithm::EcdsaSha256,
4041 &verification_policy_with_trust(chain_policy()),
4042 )
4043 .expect("the sole path to a configured anchor should be selected");
4044
4045 assert!(resolved.is_some());
4046 }
4047
4048 #[test]
4049 fn self_issued_rollover_continues_to_same_name_trusted_signer() {
4050 let root = rcgen::CertifiedIssuer::self_signed(
4053 generated_certificate_params("rollover authority", true),
4054 rcgen::KeyPair::generate().expect("root key generation should succeed"),
4055 )
4056 .expect("root should be self-signable");
4057 let rollover_params = generated_certificate_params("rollover authority", true);
4058 let rollover_key =
4059 rcgen::KeyPair::generate().expect("rollover key generation should succeed");
4060 let rollover_certificate = rollover_params
4061 .signed_by(&rollover_key, &root)
4062 .expect("root should sign the same-name rollover certificate");
4063 let rollover_issuer = rcgen::Issuer::from_params(&rollover_params, &rollover_key);
4064 let leaf = generated_certificate_params("rollover leaf", false)
4065 .signed_by(
4066 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
4067 &rollover_issuer,
4068 )
4069 .expect("rollover key should sign the leaf");
4070 let leaf_metadata =
4071 parse_x509_certificate(leaf.der()).expect("generated leaf metadata should parse");
4072 let key_info = KeyInfo {
4073 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
4074 subject_names: vec![leaf_metadata.subject_dn],
4075 ..X509DataInfo::default()
4076 })],
4077 };
4078 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4079 trusted_certs: vec![root.der().to_vec()],
4080 lookup_certs: vec![leaf.der().to_vec(), rollover_certificate.der().to_vec()],
4081 ..KeyResolverConfig::default()
4082 });
4083
4084 let resolved = resolver
4085 .resolve_with_policy(
4086 Some(&key_info),
4087 SignatureAlgorithm::EcdsaSha256,
4088 &verification_policy_with_trust(chain_policy()),
4089 )
4090 .expect("same-name rollover path must reach its configured signer");
4091
4092 assert!(resolved.is_some());
4093 }
4094
4095 #[test]
4096 fn x509_candidate_limit_counts_generated_partial_paths() {
4097 let root = rcgen::CertifiedIssuer::self_signed(
4100 generated_certificate_params("candidate root", true),
4101 rcgen::KeyPair::generate().expect("root key generation should succeed"),
4102 )
4103 .expect("root should be self-signable");
4104 let intermediate = rcgen::CertifiedIssuer::signed_by(
4105 generated_certificate_params("candidate intermediate", true),
4106 rcgen::KeyPair::generate().expect("intermediate key generation should succeed"),
4107 &root,
4108 )
4109 .expect("root should sign the intermediate");
4110 let leaf = generated_certificate_params("candidate leaf", false)
4111 .signed_by(
4112 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
4113 &intermediate,
4114 )
4115 .expect("intermediate should sign the leaf");
4116 let info = x509_info(
4117 vec![
4118 root.der().to_vec(),
4119 intermediate.der().to_vec(),
4120 leaf.der().to_vec(),
4121 ],
4122 2,
4123 );
4124
4125 assert!(matches!(
4126 build_x509_certificate_paths_to_trusted_prefix(
4127 &info,
4128 2,
4129 1,
4130 super::super::parse::X509PathBounds {
4131 max_depth: 9,
4132 max_candidate_paths: 2
4133 },
4134 crate::provider::default_provider(),
4135 None,
4136 &super::super::pkix::CertificateSession::new(
4137 &crate::policy::ResourcePolicy::default()
4138 ),
4139 ),
4140 Err(X509ChainBuildError::AmbiguousIssuer)
4141 ));
4142 }
4143
4144 #[test]
4145 fn selector_resolved_leaf_disambiguates_same_subject_issuers_by_signature() {
4146 let mut root_params =
4150 rcgen::CertificateParams::new(Vec::new()).expect("empty root SAN list should be valid");
4151 root_params
4152 .distinguished_name
4153 .push(rcgen::DnType::CommonName, "shared-issuer root");
4154 root_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
4155 root_params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
4156 let root = rcgen::CertifiedIssuer::self_signed(
4157 root_params,
4158 rcgen::KeyPair::generate().expect("root key generation should succeed"),
4159 )
4160 .expect("root certificate should be self-signable");
4161
4162 let intermediate = |key: rcgen::KeyPair| {
4163 let mut params = rcgen::CertificateParams::new(Vec::new())
4164 .expect("empty intermediate SAN list should be valid");
4165 params
4166 .distinguished_name
4167 .push(rcgen::DnType::CommonName, "renewed intermediate");
4168 params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
4169 params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign];
4170 rcgen::CertifiedIssuer::signed_by(params, key, &root)
4171 .expect("root should sign the intermediate certificate")
4172 };
4173 let unrelated_intermediate = intermediate(
4174 rcgen::KeyPair::generate().expect("unrelated intermediate key generation should work"),
4175 );
4176 let signing_intermediate = intermediate(
4177 rcgen::KeyPair::generate().expect("signing intermediate key generation should work"),
4178 );
4179
4180 let mut leaf_params =
4181 rcgen::CertificateParams::new(Vec::new()).expect("empty leaf SAN list should be valid");
4182 leaf_params
4183 .distinguished_name
4184 .push(rcgen::DnType::CommonName, "same-subject leaf");
4185 let leaf = leaf_params
4186 .signed_by(
4187 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
4188 &signing_intermediate,
4189 )
4190 .expect("the selected intermediate should sign the leaf certificate");
4191 let key_info_xml = concat!(
4192 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">",
4193 "<X509Data><X509SubjectName>CN=same-subject leaf</X509SubjectName></X509Data>",
4194 "</KeyInfo>"
4195 );
4196 let document = roxmltree::Document::parse(key_info_xml)
4197 .expect("static selector KeyInfo should parse as XML");
4198 let key_info = super::super::parse_key_info(document.root_element())
4199 .expect("static selector KeyInfo should satisfy XMLDSig structure");
4200 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4201 lookup_certs: vec![
4202 leaf.der().to_vec(),
4203 unrelated_intermediate.der().to_vec(),
4204 signing_intermediate.der().to_vec(),
4205 ],
4206 trusted_certs: vec![root.der().to_vec()],
4207 ..KeyResolverConfig::default()
4208 });
4209
4210 let resolved = resolver
4211 .resolve_with_policy(
4212 Some(&key_info),
4213 SignatureAlgorithm::EcdsaSha256,
4214 &verification_policy_with_trust(chain_policy()),
4215 )
4216 .expect("the leaf signature should select its unique same-subject issuer");
4217
4218 assert!(resolved.is_some());
4219 }
4220
4221 #[test]
4222 fn x509_path_builder_skips_policy_rejected_alternatives() {
4223 use crate::provider::X509SignatureAlgorithm;
4224 use std::collections::HashSet;
4225 let root = rcgen::CertifiedIssuer::self_signed(
4228 generated_certificate_params("policy root", true),
4229 rcgen::KeyPair::generate().expect("root key"),
4230 )
4231 .expect("root certificate");
4232 let alternate_root = rcgen::CertifiedIssuer::self_signed(
4233 generated_certificate_params("policy alternate root", true),
4234 rcgen::KeyPair::generate_for(&rcgen::PKCS_ECDSA_P384_SHA384)
4235 .expect("alternate root key"),
4236 )
4237 .expect("alternate root certificate");
4238 let shared_params = generated_certificate_params("policy shared issuer", true);
4239 let shared_key = rcgen::KeyPair::generate().expect("issuer key");
4240 let rejected = shared_params
4241 .signed_by(&shared_key, &alternate_root)
4242 .expect("cross-signed issuer");
4243 let shared = rcgen::CertifiedIssuer::signed_by(shared_params, shared_key, &root)
4244 .expect("issuer certificate");
4245 let leaf = generated_certificate_params("policy leaf", false)
4246 .signed_by(&rcgen::KeyPair::generate().expect("leaf key"), &shared)
4247 .expect("leaf certificate");
4248 let rejected = rejected.der().to_vec();
4249 let allowed = crate::policy::CertificateSignatureAlgorithms::Allowlist(HashSet::from([
4250 X509SignatureAlgorithm::Ecdsa(super::super::DigestAlgorithm::Sha256),
4251 ]));
4252 for rejected_first in [true, false] {
4253 let mut alternatives = vec![shared.der().to_vec(), rejected.clone()];
4254 if rejected_first {
4255 alternatives.reverse();
4256 }
4257 let permitted_index = if rejected_first { 3 } else { 2 };
4258 let info = x509_info(
4259 vec![
4260 root.der().to_vec(),
4261 leaf.der().to_vec(),
4262 alternatives.remove(0),
4263 alternatives.remove(0),
4264 alternate_root.der().to_vec(),
4265 ],
4266 1,
4267 );
4268 assert_eq!(
4269 build_x509_certificate_paths_to_trusted_prefix(
4270 &info,
4271 1,
4272 1,
4273 super::super::parse::X509PathBounds {
4274 max_depth: 4,
4275 max_candidate_paths: 8
4276 },
4277 crate::provider::default_provider(),
4278 Some(&allowed),
4279 &super::super::pkix::CertificateSession::new(
4280 &crate::policy::ResourcePolicy::default()
4281 ),
4282 )
4283 .expect("forbidden alternative must not abort search")
4284 .into_iter()
4285 .map(|path| path.to_vec())
4286 .collect::<Vec<_>>(),
4287 vec![vec![1, permitted_index, 0]]
4288 );
4289 }
4290 let info = x509_info(
4291 vec![
4292 root.der().to_vec(),
4293 leaf.der().to_vec(),
4294 rejected,
4295 alternate_root.der().to_vec(),
4296 ],
4297 1,
4298 );
4299 assert!(matches!(
4300 build_x509_certificate_paths_to_trusted_prefix(
4301 &info,
4302 1,
4303 1,
4304 super::super::parse::X509PathBounds {
4305 max_depth: 4,
4306 max_candidate_paths: 8
4307 },
4308 crate::provider::default_provider(),
4309 Some(&allowed),
4310 &super::super::pkix::CertificateSession::new(
4311 &crate::policy::ResourcePolicy::default()
4312 ),
4313 ),
4314 Err(X509ChainBuildError::Policy(_))
4315 ));
4316 }
4317
4318 #[test]
4319 fn x509_path_builder_skips_branch_local_unsupported_algorithms() {
4320 let root = rcgen::CertifiedIssuer::self_signed(
4324 generated_certificate_params("unsupported-edge root", true),
4325 rcgen::KeyPair::generate().expect("root key generation should succeed"),
4326 )
4327 .expect("root certificate should be self-signable");
4328 let signing_intermediate = rcgen::CertifiedIssuer::signed_by(
4329 generated_certificate_params("shared unsupported-edge issuer", true),
4330 rcgen::KeyPair::generate().expect("signing issuer key generation should succeed"),
4331 &root,
4332 )
4333 .expect("root should sign the intermediate certificate");
4334 let key_unsupported_intermediate = rcgen::CertifiedIssuer::signed_by(
4335 generated_certificate_params("shared unsupported-edge issuer", true),
4336 rcgen::KeyPair::generate().expect("unsupported issuer key generation should succeed"),
4337 &root,
4338 )
4339 .expect("root should sign the alternate intermediate certificate");
4340 let leaf = generated_certificate_params("unsupported-edge leaf", false)
4341 .signed_by(
4342 &rcgen::KeyPair::generate().expect("leaf key generation should succeed"),
4343 &signing_intermediate,
4344 )
4345 .expect("signing intermediate should sign the leaf");
4346
4347 let ordered = x509_info(
4348 vec![
4349 leaf.der().to_vec(),
4350 key_unsupported_intermediate.der().to_vec(),
4351 signing_intermediate.der().to_vec(),
4352 root.der().to_vec(),
4353 ],
4354 0,
4355 );
4356 let key_selective_provider = RejectSecondSha512Provider {
4357 sha512_calls: AtomicUsize::new(0),
4358 verification_calls: AtomicUsize::new(0),
4359 reject_verification_call: Some(0),
4360 rejected_verification_data: None,
4361 };
4362 assert_eq!(
4363 super::super::parse::build_x509_certificate_chain_from(
4364 &ordered,
4365 0,
4366 &key_selective_provider,
4367 None,
4368 &super::super::pkix::CertificateSession::new(
4369 &crate::policy::ResourcePolicy::default()
4370 ),
4371 )
4372 .expect("one unsupported issuer key must not suppress a usable candidate"),
4373 vec![0, 2, 3]
4374 );
4375
4376 let anchored_same_edge = x509_info(
4377 vec![
4378 root.der().to_vec(),
4379 leaf.der().to_vec(),
4380 key_unsupported_intermediate.der().to_vec(),
4381 signing_intermediate.der().to_vec(),
4382 ],
4383 1,
4384 );
4385 let first_candidate_unsupported = RejectSecondSha512Provider {
4386 sha512_calls: AtomicUsize::new(0),
4387 verification_calls: AtomicUsize::new(0),
4388 reject_verification_call: Some(0),
4389 rejected_verification_data: None,
4390 };
4391 assert_eq!(
4392 build_x509_certificate_paths_to_trusted_prefix(
4393 &anchored_same_edge,
4394 1,
4395 1,
4396 super::super::parse::X509PathBounds {
4397 max_depth: 4,
4398 max_candidate_paths: 8
4399 },
4400 &first_candidate_unsupported,
4401 None,
4402 &super::super::pkix::CertificateSession::new(
4403 &crate::policy::ResourcePolicy::default()
4404 ),
4405 )
4406 .expect("a later same-DN issuer must survive an earlier provider capability miss")
4407 .into_iter()
4408 .map(|path| path.to_vec())
4409 .collect::<Vec<_>>(),
4410 vec![vec![1, 3, 0]]
4411 );
4412
4413 let mut unsupported_intermediate = signing_intermediate.der().to_vec();
4414 let ecdsa_sha256_oid = [0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02];
4415 let offsets = unsupported_intermediate
4416 .windows(ecdsa_sha256_oid.len())
4417 .enumerate()
4418 .filter_map(|(offset, window)| (window == ecdsa_sha256_oid).then_some(offset))
4419 .collect::<Vec<_>>();
4420 assert_eq!(
4421 offsets.len(),
4422 2,
4423 "certificate must repeat its signature OID"
4424 );
4425 for offset in offsets {
4426 unsupported_intermediate[offset + ecdsa_sha256_oid.len() - 1] = 0x05;
4427 }
4428
4429 let anchored = x509_info(
4430 vec![
4431 root.der().to_vec(),
4432 leaf.der().to_vec(),
4433 signing_intermediate.der().to_vec(),
4434 unsupported_intermediate,
4435 ],
4436 1,
4437 );
4438 assert_eq!(
4439 build_x509_certificate_paths_to_trusted_prefix(
4440 &anchored,
4441 1,
4442 1,
4443 super::super::parse::X509PathBounds {
4444 max_depth: 4,
4445 max_candidate_paths: 8
4446 },
4447 crate::provider::default_provider(),
4448 None,
4449 &super::super::pkix::CertificateSession::new(
4450 &crate::policy::ResourcePolicy::default()
4451 ),
4452 )
4453 .expect("a branch-local provider gap must not abort path enumeration")
4454 .into_iter()
4455 .map(|path| path.to_vec())
4456 .collect::<Vec<_>>(),
4457 vec![vec![1, 2, 0]]
4458 );
4459
4460 let unsupported_only = x509_info(
4461 vec![
4462 root.der().to_vec(),
4463 leaf.der().to_vec(),
4464 anchored.certificates[3].clone(),
4465 ],
4466 1,
4467 );
4468 assert!(matches!(
4469 build_x509_certificate_paths_to_trusted_prefix(
4470 &unsupported_only,
4471 1,
4472 1,
4473 super::super::parse::X509PathBounds { max_depth: 4, max_candidate_paths: 8 },
4474 crate::provider::default_provider(),
4475 None,
4476 &super::super::pkix::CertificateSession::new(&crate::policy::ResourcePolicy::default()),
4477 ),
4478 Err(X509ChainBuildError::UnsupportedSignatureAlgorithm { ref oid })
4479 if oid == "1.2.840.10045.4.3.5"
4480 ));
4481 }
4482
4483 #[test]
4484 fn selector_resolved_certificate_preserves_supplied_crls() {
4485 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>";
4486 let crl = crl_der(include_str!(
4487 "../../tests/fixtures/keys/rsa/rsa-2048-cert-revoked-crl.pem"
4488 ));
4489 let xml = replace_unprefixed_key_info(
4490 RSA_KEY_VALUE_SIGNATURE,
4491 &selector.replace("CRL_PLACEHOLDER", &STANDARD.encode(&crl)),
4492 );
4493 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4494 lookup_certs: vec![certificate_der(include_str!(
4495 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
4496 ))],
4497 trusted_certs: vec![
4498 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
4499 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
4500 ],
4501 ..KeyResolverConfig::default()
4502 });
4503 let policy = verification_policy_with_trust(crate::policy::KeyTrustPolicy {
4504 check_crls: true,
4505 max_x509_chain_depth: 3,
4506 ..chain_policy_at(
4507 SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_773_964_800),
4508 )
4509 });
4510
4511 let error = super::super::VerifyContext::new()
4512 .policy(policy.clone())
4513 .key_resolver(&resolver)
4514 .verify(&xml)
4515 .expect_err("selector lookup must retain and enforce the supplied CRL");
4516 assert!(matches!(
4520 error,
4521 DsigError::KeyResolution(KeyResolutionError::Chain(
4522 super::super::X509ChainError::InvalidKeyUsage {
4523 position: 1,
4524 required: "cRLSign"
4525 }
4526 ))
4527 ));
4528
4529 let (authorized, root) = authorized_revoked_chain();
4533 let session = super::super::pkix::CertificateSession::new(&policy.resources);
4534 let crl_signed_data = session
4535 .read_crl(&authorized.crls[0])
4536 .expect("authorized test CRL parses")
4537 .signed_bytes()
4538 .to_vec();
4539 let authorized_resolver = DefaultKeyResolver::new(KeyResolverConfig {
4540 lookup_certs: vec![authorized.certificates[1].clone()],
4541 trusted_certs: vec![root],
4542 ..KeyResolverConfig::default()
4543 });
4544 let info = KeyInfo {
4545 sources: vec![KeyInfoSource::X509Data(authorized)],
4546 };
4547 let mut budget = InspectedKeyCandidateBudget::new_with_utc_facts(
4548 &policy,
4549 super::super::pkix::test_utc_facts(),
4550 );
4551 let provider = RejectSecondSha512Provider {
4552 sha512_calls: AtomicUsize::new(0),
4553 verification_calls: AtomicUsize::new(0),
4554 reject_verification_call: None,
4555 rejected_verification_data: Some(crl_signed_data),
4556 };
4557 let error = match authorized_resolver.resolve_for_verification_with_budget(
4558 Some(&info),
4559 SignatureAlgorithm::EcdsaSha256,
4560 &policy,
4561 &provider,
4562 &mut budget,
4563 ) {
4564 Err(error) => error,
4565 Ok(_) => panic!("CRL authentication must retain the operation provider"),
4566 };
4567 assert!(matches!(
4568 error,
4569 DsigError::KeyResolution(KeyResolutionError::Chain(
4570 super::super::X509ChainError::Provider(_)
4571 ))
4572 ));
4573 }
4574
4575 #[test]
4576 fn resolver_rejects_revoked_leaf_with_authorized_crl_issuer() {
4577 let (mut info, root) = authorized_revoked_chain();
4580 let issuer = info.certificates[1].clone();
4581 info.certificates.truncate(1);
4582 info.parsed_certificates.truncate(1);
4583 let key_info = KeyInfo {
4584 sources: vec![KeyInfoSource::X509Data(info)],
4585 };
4586 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4587 lookup_certs: vec![issuer],
4588 trusted_certs: vec![root],
4589 ..KeyResolverConfig::default()
4590 });
4591 let policy = verification_policy_with_trust(crate::policy::KeyTrustPolicy {
4592 check_crls: true,
4593 max_x509_chain_depth: 3,
4594 ..chain_policy_at(
4595 SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_773_964_800),
4596 )
4597 });
4598
4599 let mut budget = InspectedKeyCandidateBudget::new_with_utc_facts(
4600 &policy,
4601 super::super::pkix::test_utc_facts(),
4602 );
4603 let error = match resolver.resolve_for_verification_with_budget(
4604 Some(&key_info),
4605 SignatureAlgorithm::EcdsaSha256,
4606 &policy,
4607 crate::provider::default_provider(),
4608 &mut budget,
4609 ) {
4610 Ok(_) => panic!("an authenticated CRL must reject its revoked leaf"),
4611 Err(error) => error,
4612 };
4613 assert!(matches!(
4614 error,
4615 DsigError::KeyResolution(KeyResolutionError::Chain(
4616 super::super::X509ChainError::Revoked(0)
4617 ))
4618 ));
4619 }
4620
4621 #[test]
4622 fn resolves_each_x509_selector_from_configured_certificates() {
4623 let selectors = [
4626 "<X509SubjectName>CN=Test Key rsa-2048,O=XML Security Library (http://www.aleksey.com/xmlsec),ST=California,C=US</X509SubjectName>",
4627 "<X509SubjectName>CN= test key rsa-2048 ,O=xml security library (HTTP://WWW.ALEKSEY.COM/XMLSEC),ST=california,C=us</X509SubjectName>",
4628 "<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>",
4629 "<X509SKI>bcOXN/nsVl8GatRbcKrPbzIbw0Y=</X509SKI>",
4630 ];
4631 let configured_certificate = certificate_der(include_str!(
4632 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
4633 ));
4634
4635 for selector in selectors {
4636 let key_info = format!("<KeyInfo><X509Data>{selector}</X509Data></KeyInfo>");
4637 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
4638 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4639 lookup_certs: vec![configured_certificate.clone()],
4640 ..KeyResolverConfig::default()
4641 });
4642 let result = super::super::VerifyContext::new()
4643 .policy(cryptographic_policy())
4644 .key_resolver(&resolver)
4645 .verify(&xml)
4646 .expect("X509 selector should resolve configured certificate");
4647
4648 assert_eq!(result.status, super::super::DsigStatus::Valid);
4649 }
4650 }
4651
4652 #[test]
4653 fn resolves_configured_chain_selectors_across_certificates() {
4654 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>"#;
4657 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
4658 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4659 lookup_certs: vec![
4660 certificate_der(include_str!(
4661 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
4662 )),
4663 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
4664 ],
4665 ..KeyResolverConfig::default()
4666 });
4667 let result = super::super::VerifyContext::new()
4668 .policy(cryptographic_policy())
4669 .key_resolver(&resolver)
4670 .verify(&xml)
4671 .expect("selectors across one configured chain should resolve its leaf");
4672
4673 assert_eq!(result.status, super::super::DsigStatus::Valid);
4674 }
4675
4676 #[test]
4677 fn selectors_must_all_match_the_selected_certificate_path() {
4678 let signing_certificate = certificate_der(include_str!(
4681 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
4682 ));
4683 let issuer_certificate =
4684 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem"));
4685 let unrelated = generated_certificate_params("unrelated selector certificate", false)
4686 .self_signed(
4687 &rcgen::KeyPair::generate().expect("unrelated key generation should succeed"),
4688 )
4689 .expect("unrelated certificate should be self-signable")
4690 .der()
4691 .to_vec();
4692 let digest = crate::provider::default_provider()
4693 .digest(super::super::DigestAlgorithm::Sha256, &unrelated)
4694 .expect("SHA-256 selector digest must be available");
4695 let key_info_xml = format!(
4696 "<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>",
4697 STANDARD.encode(digest)
4698 );
4699 let document = roxmltree::Document::parse(&key_info_xml)
4700 .expect("generated selector KeyInfo must be XML");
4701 let key_info = super::super::parse_key_info(document.root_element())
4702 .expect("generated selector KeyInfo must be structurally valid");
4703 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4704 lookup_certs: vec![signing_certificate, issuer_certificate, unrelated],
4705 ..KeyResolverConfig::default()
4706 });
4707
4708 assert!(
4709 resolver
4710 .resolve(Some(&key_info), SignatureAlgorithm::RsaSha256)
4711 .expect("disjoint selector matches are a key miss")
4712 .is_none()
4713 );
4714 }
4715
4716 #[test]
4717 fn unmatched_x509_selector_does_not_resolve() {
4718 let key_info = "<KeyInfo><X509Data><X509SubjectName>CN=not-the-signer</X509SubjectName></X509Data></KeyInfo>";
4720 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
4721 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4722 lookup_certs: vec![certificate_der(include_str!(
4723 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
4724 ))],
4725 ..KeyResolverConfig::default()
4726 });
4727 let result = super::super::VerifyContext::new()
4728 .key_resolver(&resolver)
4729 .verify(&xml)
4730 .expect("an unmatched selector is a key miss, not a parser failure");
4731
4732 assert!(matches!(
4733 result.status,
4734 super::super::DsigStatus::Invalid(super::super::FailureReason::KeyNotFound)
4735 ));
4736 }
4737
4738 #[test]
4739 fn overlapping_trusted_and_lookup_certificate_preserves_trust() {
4740 let certificate = certificate_der(RSA_4096_CERTIFICATE);
4743 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4744 trusted_certs: vec![certificate.clone()],
4745 lookup_certs: vec![certificate],
4746 ..KeyResolverConfig::default()
4747 });
4748 let result = super::super::VerifyContext::new()
4749 .policy(verification_policy_with_trust(chain_policy_at(
4750 fixture_certificate_time(),
4751 )))
4752 .key_resolver(&resolver)
4753 .verify(&x509_signature_with_leaf_subject())
4754 .expect("trusted/lookup overlap must resolve as one trusted candidate");
4755
4756 assert_eq!(result.status, super::super::DsigStatus::Valid);
4757 let super::super::KeyTrustEvidence::ValidatedX509(evidence) = result.key_trust else {
4758 panic!("successful path validation must retain typed evidence");
4759 };
4760 assert_eq!(evidence.verification_time(), fixture_certificate_time());
4761 assert!(!evidence.revocation_checked());
4762 assert_eq!(evidence.certificate_fingerprints().len(), 1);
4763 assert_eq!(
4764 evidence.anchor_fingerprint(),
4765 &evidence.certificate_fingerprints()[0]
4766 );
4767
4768 let document = crate::XmlDocument::parse(x509_signature_with_leaf_subject())
4771 .expect("signed certificate selector fixture must parse");
4772 let report = super::super::VerifyContext::new()
4773 .policy(verification_policy_with_trust(chain_policy_at(
4774 fixture_certificate_time(),
4775 )))
4776 .key_resolver(&resolver)
4777 .verify_all(&document)
4778 .expect("batch verification must preserve the validated path");
4779 assert!(
4780 report
4781 .accepted(&document)
4782 .expect("current document acceptance")
4783 );
4784 assert_eq!(
4785 report.signatures()[0]
4786 .result()
4787 .as_ref()
4788 .expect("the individually processed Signature must verify")
4789 .key_trust,
4790 super::super::KeyTrustEvidence::ValidatedX509(evidence)
4791 );
4792 }
4793
4794 #[test]
4795 fn distinct_x509_selector_matches_remain_ambiguous() {
4796 let certificate = || {
4799 generated_certificate_params("ambiguous selector", false)
4800 .self_signed(
4801 &rcgen::KeyPair::generate().expect("test key generation should succeed"),
4802 )
4803 .expect("test certificate should be self-signable")
4804 .der()
4805 .to_vec()
4806 };
4807 let xml = replace_unprefixed_key_info(
4808 X509_DIGEST_SIGNATURE,
4809 "<KeyInfo><X509Data><X509SubjectName>CN=ambiguous selector</X509SubjectName></X509Data></KeyInfo>",
4810 );
4811 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4812 lookup_certs: vec![certificate(), certificate()],
4813 ..KeyResolverConfig::default()
4814 });
4815 let error = super::super::VerifyContext::new()
4816 .key_resolver(&resolver)
4817 .verify(&xml)
4818 .expect_err("distinct selector matches must fail closed");
4819
4820 assert!(matches!(
4821 error,
4822 DsigError::KeyResolution(KeyResolutionError::AmbiguousCertificate)
4823 ));
4824 }
4825
4826 #[test]
4827 fn unsupported_x509_digest_selector_fails_closed() {
4828 let key_info = "<KeyInfo xmlns:dsig11=\"http://www.w3.org/2009/xmldsig11#\"><X509Data><dsig11:X509Digest Algorithm=\"urn:unsupported\">AQ==</dsig11:X509Digest></X509Data></KeyInfo>";
4831 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
4832 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4833 lookup_certs: vec![certificate_der(include_str!(
4834 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
4835 ))],
4836 ..KeyResolverConfig::default()
4837 });
4838 let error = super::super::VerifyContext::new()
4839 .key_resolver(&resolver)
4840 .verify(&xml)
4841 .expect_err("unsupported X509Digest algorithm must fail closed");
4842
4843 assert!(matches!(
4844 error,
4845 DsigError::KeyResolution(KeyResolutionError::UnsupportedDigestAlgorithm(uri))
4846 if uri == "urn:unsupported"
4847 ));
4848 }
4849
4850 #[test]
4851 fn x509_digest_selector_uses_operation_provider() {
4852 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
4855 lookup_certs: vec![certificate_der(RSA_4096_CERTIFICATE)],
4856 trusted_certs: vec![
4857 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
4858 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
4859 ],
4860 ..KeyResolverConfig::default()
4861 });
4862 let provider = RejectSecondSha512Provider {
4863 sha512_calls: AtomicUsize::new(0),
4864 verification_calls: AtomicUsize::new(0),
4865 reject_verification_call: None,
4866 rejected_verification_data: None,
4867 };
4868 let error = super::super::VerifyContext::new()
4869 .key_resolver(&resolver)
4870 .provider(&provider)
4871 .verify(X509_DIGEST_SIGNATURE)
4872 .expect_err("X509Digest selection must use the operation provider");
4873
4874 assert!(
4875 matches!(
4876 error,
4877 DsigError::Provider(crate::provider::ProviderError::Unsupported {
4878 operation: crate::provider::ProviderOperation::Digest,
4879 algorithm: Some(ref uri),
4880 }) if uri == super::super::DigestAlgorithm::Sha512.uri()
4881 ),
4882 "unexpected error: {error:?}"
4883 );
4884 }
4885
4886 #[test]
4887 fn resolves_named_key_end_to_end() {
4888 let xml = replace_key_info(
4890 SIGNED_SAML,
4891 "<ds:KeyInfo><ds:KeyName>idp-signing</ds:KeyName></ds:KeyInfo>",
4892 );
4893 let mut config = KeyResolverConfig::default();
4894 config.named_keys.insert(
4895 "idp-signing".into(),
4896 VerificationKey {
4897 algorithm: SignatureAlgorithm::EcdsaSha256,
4898 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
4899 certificate_der: None,
4900 name: Some("idp-signing".into()),
4901 },
4902 );
4903 let resolver = DefaultKeyResolver::new(config);
4904 let result = super::super::VerifyContext::new()
4905 .key_resolver(&resolver)
4906 .verify(&xml)
4907 .expect("named key should resolve");
4908
4909 assert_eq!(result.status, super::super::DsigStatus::Valid);
4910 }
4911
4912 #[test]
4913 fn resolves_der_encoded_key_end_to_end() {
4914 let encoded = STANDARD.encode(public_key_der(SAML_PUBLIC_KEY));
4916 let xml = replace_key_info(
4917 SIGNED_SAML,
4918 &format!(
4919 "<ds:KeyInfo><dsig11:DEREncodedKeyValue xmlns:dsig11=\"http://www.w3.org/2009/xmldsig11#\">{encoded}</dsig11:DEREncodedKeyValue></ds:KeyInfo>"
4920 ),
4921 );
4922 let resolver = DefaultKeyResolver::default();
4923 let result = super::super::VerifyContext::new()
4924 .policy(cryptographic_policy())
4925 .key_resolver(&resolver)
4926 .verify(&xml)
4927 .expect("DER key should resolve");
4928
4929 assert_eq!(result.status, super::super::DsigStatus::Valid);
4930 }
4931
4932 #[test]
4933 fn resolves_rsa_key_value_end_to_end() {
4934 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
4936 .expect("fixture must contain an RSA public key");
4937 let (modulus, exponent) = rsa_key_value_parts(&public_key);
4938 let key_info = format!(
4939 "<KeyInfo><KeyValue><RSAKeyValue><Modulus>{}</Modulus><Exponent>{}</Exponent></RSAKeyValue></KeyValue></KeyInfo>",
4940 modulus, exponent,
4941 );
4942 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
4943 let resolver = DefaultKeyResolver::default();
4944 let result = super::super::VerifyContext::new()
4945 .policy(cryptographic_policy())
4946 .key_resolver(&resolver)
4947 .verify(&xml)
4948 .expect("RSAKeyValue should resolve");
4949
4950 assert_eq!(result.status, super::super::DsigStatus::Valid);
4951 }
4952
4953 #[test]
4954 fn rsa_key_value_rejects_legacy_weak_modulus() {
4955 let resolver = DefaultKeyResolver::default();
4958 let error = super::super::VerifyContext::new()
4959 .key_resolver(&resolver)
4960 .verify(LEGACY_RSA_KEY_VALUE_SIGNATURE)
4961 .expect_err("context policy must override permissive resolver defaults");
4962
4963 assert!(matches!(
4964 error,
4965 DsigError::Policy(crate::policy::PolicyViolation::Algorithm {
4966 operation: "verification",
4967 ..
4968 })
4969 ));
4970 }
4971
4972 #[test]
4973 fn operation_policy_rejects_disabled_embedded_key_source() {
4974 let key_info = KeyInfo {
4977 sources: vec![KeyInfoSource::KeyValue(KeyValueInfo::Rsa {
4978 modulus: vec![0x80; 256],
4979 exponent: vec![1, 0, 1],
4980 })],
4981 };
4982 let mut policy = crate::policy::VerificationPolicy::default();
4983 policy.key_sources.key_value = false;
4984
4985 let error = match DefaultKeyResolver::default().resolve_with_policy(
4986 Some(&key_info),
4987 SignatureAlgorithm::RsaSha256,
4988 &policy,
4989 ) {
4990 Ok(_) => panic!("disabled KeyValue must fail before key construction"),
4991 Err(error) => error,
4992 };
4993
4994 assert!(matches!(
4995 error,
4996 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust {
4997 reason: "KeyValue key sources are disabled"
4998 })
4999 ));
5000 }
5001
5002 #[test]
5003 fn operation_policy_preflights_every_key_info_source_before_resolution() {
5004 let mut config = KeyResolverConfig::default();
5007 config.named_keys.insert(
5008 "idp-signing".into(),
5009 VerificationKey {
5010 algorithm: SignatureAlgorithm::EcdsaSha256,
5011 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
5012 certificate_der: None,
5013 name: Some("idp-signing".into()),
5014 },
5015 );
5016 let resolver = DefaultKeyResolver::new(config);
5017 let mut policy = crate::policy::VerificationPolicy::default();
5018 policy.key_sources.x509_data = false;
5019
5020 for sources in [
5021 vec![
5022 KeyInfoSource::KeyName("idp-signing".into()),
5023 KeyInfoSource::X509Data(X509DataInfo::default()),
5024 ],
5025 vec![
5026 KeyInfoSource::X509Data(X509DataInfo::default()),
5027 KeyInfoSource::KeyName("idp-signing".into()),
5028 ],
5029 ] {
5030 let error = match resolver.resolve_with_policy(
5031 Some(&KeyInfo { sources }),
5032 SignatureAlgorithm::EcdsaSha256,
5033 &policy,
5034 ) {
5035 Ok(_) => panic!("source order must not hide disabled X509Data"),
5036 Err(error) => error,
5037 };
5038
5039 assert!(matches!(
5040 error,
5041 DsigError::Policy(crate::policy::PolicyViolation::KeyTrust {
5042 reason: "X509Data key sources are disabled"
5043 })
5044 ));
5045 }
5046 }
5047
5048 #[test]
5049 fn operation_policy_bounds_ordered_key_info_candidates() {
5050 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 key_info = KeyInfo {
5064 sources: vec![
5065 KeyInfoSource::KeyValue(KeyValueInfo::Ec {
5066 curve_oid: "1.3.132.0.35".into(),
5067 public_key: vec![4],
5068 }),
5069 KeyInfoSource::KeyName("idp-signing".into()),
5070 ],
5071 };
5072
5073 for maximum in [0, 1] {
5074 let mut policy = crate::policy::VerificationPolicy::default();
5075 policy.resources.max_key_candidates = maximum;
5076 let error = match resolver.resolve_with_policy(
5077 Some(&key_info),
5078 SignatureAlgorithm::EcdsaSha256,
5079 &policy,
5080 ) {
5081 Ok(_) => panic!("candidate ceiling {maximum} must stop resolution"),
5082 Err(error) => error,
5083 };
5084 assert!(matches!(
5085 error,
5086 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
5087 resource: crate::policy::resource_name::KEY_CANDIDATES,
5088 maximum: observed,
5089 actual,
5090 }) if observed == maximum && actual == maximum + 1
5091 ));
5092 }
5093
5094 let mut policy = crate::policy::VerificationPolicy::default();
5095 policy.resources.max_key_candidates = 2;
5096 assert!(
5097 resolver
5098 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::EcdsaSha256, &policy,)
5099 .expect("two allowed attempts must reach the named key")
5100 .is_some()
5101 );
5102 }
5103
5104 #[test]
5105 fn operation_policy_bounds_configured_x509_selector_candidates() {
5106 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
5110 lookup_certs: vec![
5111 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
5112 certificate_der(RSA_4096_CERTIFICATE),
5113 ],
5114 ..KeyResolverConfig::default()
5115 });
5116 let mut policy = crate::policy::VerificationPolicy::default();
5117 policy.resources.max_key_candidates = 1;
5118
5119 let error = super::super::VerifyContext::new()
5120 .policy(policy)
5121 .key_resolver(&resolver)
5122 .verify(&x509_signature_with_leaf_subject())
5123 .expect_err("the second configured certificate must exceed the candidate budget");
5124
5125 assert!(matches!(
5126 error,
5127 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
5128 resource: crate::policy::resource_name::KEY_CANDIDATES,
5129 maximum: 1,
5130 actual: 2,
5131 })
5132 ));
5133 }
5134
5135 #[test]
5136 fn configured_crls_are_bounded_before_der_parsing() {
5137 let key_info = KeyInfo {
5139 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
5140 subject_names: vec!["CN=selected".into()],
5141 ..X509DataInfo::default()
5142 })],
5143 };
5144 let mut policy = crate::policy::VerificationPolicy::default();
5145 policy.key_trust.check_crls = true;
5146 policy.key_trust.verify_x509_chains = true;
5147 policy.resources.max_external_resource_bytes = 4;
5148 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
5149 crls: vec![vec![0; 5]],
5150 ..KeyResolverConfig::default()
5151 });
5152 let error = resolver
5153 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::RsaSha256, &policy)
5154 .err()
5155 .expect("oversized CRL must fail before DER parsing");
5156 assert!(
5157 matches!(
5158 error,
5159 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
5160 resource: crate::policy::resource_name::EXTERNAL_RESOURCE_BYTES,
5161 ..
5162 })
5163 ),
5164 "{error:?}"
5165 );
5166
5167 policy.resources.max_external_resource_bytes = 4;
5168 policy.resources.max_external_resource_total_bytes = 7;
5169 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
5170 crls: vec![vec![0; 4], vec![0; 4]],
5171 ..KeyResolverConfig::default()
5172 });
5173 let error = resolver
5174 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::RsaSha256, &policy)
5175 .err()
5176 .expect("aggregate CRL bytes must fail before DER parsing");
5177 assert!(matches!(
5178 error,
5179 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
5180 resource: crate::policy::resource_name::AGGREGATE_EXTERNAL_RESOURCE_BYTES,
5181 ..
5182 })
5183 ));
5184
5185 policy.resources.max_external_resource_total_bytes = 8;
5186 policy.resources.max_key_candidates = 1;
5187 let error = resolver
5188 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::RsaSha256, &policy)
5189 .err()
5190 .expect("CRL candidate count must fail before DER parsing");
5191 assert!(matches!(
5192 error,
5193 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
5194 resource: crate::policy::resource_name::KEY_CANDIDATES,
5195 ..
5196 })
5197 ));
5198 }
5199
5200 #[test]
5201 fn configured_certificates_and_crls_share_external_byte_budget() {
5202 let key_info = KeyInfo {
5206 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
5207 subject_names: vec!["CN=selected".into()],
5208 ..X509DataInfo::default()
5209 })],
5210 };
5211 let mut policy = crate::policy::VerificationPolicy::default();
5212 policy.key_trust.check_crls = true;
5213 policy.key_trust.verify_x509_chains = true;
5214 policy.resources.max_external_resource_bytes = 8;
5215 policy.resources.max_external_resource_total_bytes = 12;
5216 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
5217 trusted_certs: vec![vec![0; 8]],
5218 crls: vec![vec![0; 8]],
5219 ..KeyResolverConfig::default()
5220 });
5221 let error = resolver
5222 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::RsaSha256, &policy)
5223 .err()
5224 .expect("combined external material exceeds the operation limit");
5225 assert!(matches!(
5226 error,
5227 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
5228 resource: crate::policy::resource_name::AGGREGATE_EXTERNAL_RESOURCE_BYTES,
5229 ..
5230 })
5231 ));
5232 }
5233
5234 #[test]
5235 fn embedded_and_configured_x509_share_one_byte_budget() {
5236 let mut info = KeyInfo {
5239 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
5240 certificates: vec![vec![0; 8]],
5241 certificate_chain: vec![0],
5242 crls: vec![vec![0; 2]],
5243 ..X509DataInfo::default()
5244 })],
5245 };
5246 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
5247 crls: vec![vec![0; 8]],
5248 ..KeyResolverConfig::default()
5249 });
5250 let mut policy = crate::policy::VerificationPolicy::default();
5251 policy.key_trust.check_crls = true;
5252 policy.key_trust.verify_x509_chains = true;
5253 policy.resources.max_external_resource_total_bytes = 17;
5254 let error = resolver
5255 .resolve_with_policy(Some(&info), SignatureAlgorithm::RsaSha256, &policy)
5256 .err()
5257 .expect("combined material must be rejected");
5258 assert!(
5259 matches!(
5260 error,
5261 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
5262 resource: crate::policy::resource_name::AGGREGATE_EXTERNAL_RESOURCE_BYTES,
5263 actual: 18,
5264 ..
5265 })
5266 ),
5267 "{error:?}"
5268 );
5269 policy.resources.max_external_resource_total_bytes = 18;
5270 let error = resolver
5271 .resolve_with_policy(Some(&info), SignatureAlgorithm::RsaSha256, &policy)
5272 .err()
5273 .expect("exact byte allowance reaches DER parsing");
5274 assert!(
5275 matches!(
5276 error,
5277 DsigError::KeyResolution(KeyResolutionError::Chain(super::super::X509ChainError::Processing(ref error)))
5278 if error.code() == structured_pkix::ErrorCode::Encoding(structured_asn1::ErrorCode::MalformedEndOfContents)
5279 && error.field() == "certificate" && error.offset() == 0
5280 ),
5281 "{error:?}"
5282 );
5283 info.sources.insert(
5286 0,
5287 KeyInfoSource::X509Data(X509DataInfo {
5288 subject_names: vec!["CN=absent".into()],
5289 ..X509DataInfo::default()
5290 }),
5291 );
5292 policy.resources.max_external_resource_total_bytes = 17;
5293 policy.resources.max_key_candidates = 2;
5294 assert!(matches!(
5295 resolver.resolve_with_policy(Some(&info), SignatureAlgorithm::RsaSha256, &policy),
5296 Err(DsigError::Policy(
5297 crate::policy::PolicyViolation::ResourceLimit {
5298 resource: crate::policy::resource_name::AGGREGATE_EXTERNAL_RESOURCE_BYTES,
5299 actual: 18,
5300 ..
5301 }
5302 ))
5303 ));
5304 }
5305
5306 #[test]
5307 fn direct_certificate_does_not_charge_unused_configured_store() {
5308 let certificate = certificate_der(RSA_4096_CERTIFICATE);
5311 let key_info = KeyInfo {
5312 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
5313 certificates: vec![certificate],
5314 certificate_chain: vec![0],
5315 subject_names: vec!["CN=unused-selector".into()],
5316 ..X509DataInfo::default()
5317 })],
5318 };
5319 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
5320 lookup_certs: vec![vec![0; 4096]],
5321 trusted_certs: vec![vec![0; 4096]],
5322 ..KeyResolverConfig::default()
5323 });
5324 let mut policy = crate::policy::VerificationPolicy::default();
5325 policy.resources.max_external_resource_bytes = 1024;
5326 policy.resources.max_external_resource_total_bytes = 1024;
5327 assert!(
5328 resolver
5329 .resolve_with_policy(Some(&key_info), SignatureAlgorithm::RsaSha256, &policy)
5330 .expect("unused configured certificates are not charged")
5331 .is_some()
5332 );
5333 }
5334
5335 #[test]
5336 fn operation_policy_bounds_embedded_x509_certificate_candidates() {
5337 let key_info = KeyInfo {
5341 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
5342 certificates: vec![
5343 certificate_der(RSA_4096_CERTIFICATE),
5344 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
5345 ],
5346 certificate_chain: vec![0],
5347 ..X509DataInfo::default()
5348 })],
5349 };
5350 let mut policy = crate::policy::VerificationPolicy::default();
5351 policy.resources.max_key_candidates = 1;
5352
5353 let error = match DefaultKeyResolver::default().resolve_with_policy(
5354 Some(&key_info),
5355 SignatureAlgorithm::RsaSha256,
5356 &policy,
5357 ) {
5358 Ok(_) => panic!("the second embedded certificate must exceed the candidate budget"),
5359 Err(error) => error,
5360 };
5361
5362 assert!(matches!(
5363 error,
5364 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
5365 resource: crate::policy::resource_name::KEY_CANDIDATES,
5366 maximum: 1,
5367 actual: 2,
5368 })
5369 ));
5370 }
5371
5372 #[test]
5373 fn operation_policy_charges_duplicate_configured_x509_candidates() {
5374 let certificate = certificate_der(RSA_4096_CERTIFICATE);
5377 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
5378 lookup_certs: vec![certificate.clone(), certificate],
5379 ..KeyResolverConfig::default()
5380 });
5381 let mut policy = crate::policy::VerificationPolicy::default();
5382 policy.resources.max_key_candidates = 1;
5383
5384 let error = super::super::VerifyContext::new()
5385 .policy(policy)
5386 .key_resolver(&resolver)
5387 .verify(&x509_signature_with_leaf_subject())
5388 .expect_err("the duplicate configured entry must consume candidate work");
5389
5390 assert!(matches!(
5391 error,
5392 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
5393 resource: crate::policy::resource_name::KEY_CANDIDATES,
5394 maximum: 1,
5395 actual: 2,
5396 })
5397 ));
5398 }
5399
5400 #[test]
5401 fn operation_policy_charges_duplicate_embedded_x509_candidates() {
5402 let certificate = certificate_der(RSA_4096_CERTIFICATE);
5405 let key_info = KeyInfo {
5406 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
5407 certificates: vec![certificate.clone(), certificate],
5408 certificate_chain: vec![0],
5409 ..X509DataInfo::default()
5410 })],
5411 };
5412 let mut policy = crate::policy::VerificationPolicy::default();
5413 policy.resources.max_key_candidates = 1;
5414
5415 let error = match DefaultKeyResolver::default().resolve_with_policy(
5416 Some(&key_info),
5417 SignatureAlgorithm::RsaSha256,
5418 &policy,
5419 ) {
5420 Ok(_) => panic!("the duplicate embedded entry must consume candidate work"),
5421 Err(error) => error,
5422 };
5423
5424 assert!(matches!(
5425 error,
5426 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
5427 resource: crate::policy::resource_name::KEY_CANDIDATES,
5428 maximum: 1,
5429 actual: 2,
5430 })
5431 ));
5432 }
5433
5434 #[test]
5435 fn policy_aware_resolver_rejects_resources_above_hard_ceiling() {
5436 let mut policy = crate::policy::VerificationPolicy::default();
5439 policy.resources.max_key_candidates = usize::MAX;
5440
5441 let error = match DefaultKeyResolver::default().resolve_with_policy(
5442 None,
5443 SignatureAlgorithm::RsaSha256,
5444 &policy,
5445 ) {
5446 Ok(_) => panic!("invalid resource policy must fail before key resolution"),
5447 Err(error) => error,
5448 };
5449
5450 assert!(matches!(
5451 error,
5452 DsigError::Policy(crate::policy::PolicyViolation::ResourceLimit {
5453 resource: crate::policy::resource_name::KEY_CANDIDATES,
5454 actual: usize::MAX,
5455 ..
5456 })
5457 ));
5458 }
5459
5460 #[test]
5461 fn embedded_x509_digest_selection_uses_operation_provider() {
5462 let certificate = certificate_der(RSA_4096_CERTIFICATE);
5465 let digest =
5466 super::super::compute_digest(super::super::DigestAlgorithm::Sha512, &certificate);
5467 let xml = format!(
5468 "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><X509Data><X509Certificate>{}</X509Certificate><X509Digest xmlns=\"http://www.w3.org/2009/xmldsig11#\" Algorithm=\"{}\">{}</X509Digest></X509Data></KeyInfo>",
5469 STANDARD.encode(&certificate),
5470 super::super::DigestAlgorithm::Sha512.uri(),
5471 STANDARD.encode(digest),
5472 );
5473 let document = roxmltree::Document::parse(&xml).expect("generated KeyInfo must be XML");
5474 let provider = RejectSecondSha512Provider {
5475 sha512_calls: AtomicUsize::new(1),
5476 verification_calls: AtomicUsize::new(0),
5477 reject_verification_call: None,
5478 rejected_verification_data: None,
5479 };
5480
5481 let error =
5482 super::super::parse::parse_key_info_with_provider(document.root_element(), &provider)
5483 .expect_err("embedded X509Digest selection must use the operation provider");
5484
5485 assert!(
5486 matches!(
5487 error,
5488 ParseError::Provider(crate::provider::ProviderError::Unsupported {
5489 operation: crate::provider::ProviderOperation::Digest,
5490 algorithm: Some(ref uri),
5491 }) if uri == super::super::DigestAlgorithm::Sha512.uri()
5492 ),
5493 "unexpected error: {error:?}"
5494 );
5495 }
5496
5497 #[cfg(feature = "legacy-algorithms")]
5498 #[test]
5499 fn x509_digest_selectors_obey_operation_policy() {
5500 for algorithm in [
5503 super::super::DigestAlgorithm::Md5,
5504 super::super::DigestAlgorithm::Ripemd160,
5505 ] {
5506 let certificate = certificate_der(RSA_4096_CERTIFICATE);
5507 let digest = super::super::compute_digest(algorithm, &certificate);
5508 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
5509 lookup_certs: vec![certificate.clone()],
5510 trusted_certs: vec![
5511 certificate.clone(),
5512 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
5513 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
5514 ],
5515 ..KeyResolverConfig::default()
5516 });
5517 for embedded in [false, true] {
5518 let cert_xml = if embedded {
5519 format!(
5520 "<X509Certificate>{}</X509Certificate>",
5521 STANDARD.encode(&certificate)
5522 )
5523 } else {
5524 String::new()
5525 };
5526 let xml = replace_unprefixed_key_info(
5527 X509_DIGEST_SIGNATURE,
5528 &format!(
5529 "<KeyInfo><X509Data>{cert_xml}<X509Digest xmlns=\"http://www.w3.org/2009/xmldsig11#\" Algorithm=\"{}\">{}</X509Digest></X509Data></KeyInfo>",
5530 algorithm.uri(),
5531 STANDARD.encode(&digest)
5532 ),
5533 );
5534 let provider = RejectSecondSha512Provider {
5535 sha512_calls: AtomicUsize::new(0),
5536 verification_calls: AtomicUsize::new(0),
5537 reject_verification_call: None,
5538 rejected_verification_data: None,
5539 };
5540 assert!(
5541 matches!(super::super::VerifyContext::new().key_resolver(&resolver).provider(&provider).verify(&xml),
5542 Err(DsigError::Policy(crate::policy::PolicyViolation::Algorithm { algorithm: uri, .. })) if uri == algorithm.uri())
5543 );
5544 assert_eq!(provider.sha512_calls.load(Ordering::SeqCst), 0);
5545 assert_eq!(provider.verification_calls.load(Ordering::SeqCst), 0);
5546 let info = KeyInfo {
5548 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
5549 digests: vec![(algorithm.uri().into(), digest.clone())],
5550 ..X509DataInfo::default()
5551 })],
5552 };
5553 assert!(matches!(
5554 resolver.resolve_with_policy(
5555 Some(&info),
5556 SignatureAlgorithm::RsaSha512,
5557 &crate::policy::VerificationPolicy::default()
5558 ),
5559 Err(DsigError::Policy(_))
5560 ));
5561 let policy = crate::policy::VerificationPolicy {
5562 digest_algorithms: Some(
5563 [algorithm, super::super::DigestAlgorithm::Sha512].into(),
5564 ),
5565 ..crate::policy::VerificationPolicy::default()
5566 };
5567 assert_eq!(
5568 super::super::VerifyContext::new()
5569 .key_resolver(&resolver)
5570 .policy(policy.clone())
5571 .verify(&xml)
5572 .expect("explicitly permitted selector must verify")
5573 .status,
5574 super::super::DsigStatus::Valid
5575 );
5576 let start = xml.find("<KeyInfo>").expect("fixture has KeyInfo");
5579 let end =
5580 xml.find("</KeyInfo>").expect("fixture closes KeyInfo") + "</KeyInfo>".len();
5581 let target = &xml[start..end];
5582 let referenced = replace_unprefixed_key_info(
5583 &xml,
5584 &format!(
5585 "<KeyInfo><KeyInfoReference xmlns=\"http://www.w3.org/2009/xmldsig11#\" URI=\"#selector\"/></KeyInfo><Object>{}</Object>",
5586 target.replace("<KeyInfo>", "<KeyInfo Id=\"selector\">")
5587 ),
5588 );
5589 let retrieved = replace_unprefixed_key_info(
5590 &xml,
5591 &format!(
5592 "<KeyInfo><RetrievalMethod URI=\"#selector\" Type=\"http://www.w3.org/2000/09/xmldsig#X509Data\"/></KeyInfo><Object>{}</Object>",
5593 target
5594 .strip_prefix("<KeyInfo>")
5595 .expect("selected range starts at KeyInfo")
5596 .strip_suffix("</KeyInfo>")
5597 .expect("selected range ends at KeyInfo")
5598 .replace("<X509Data>", "<X509Data Id=\"selector\">")
5599 ),
5600 );
5601 for indirect in [referenced, retrieved] {
5602 assert!(
5603 matches!(super::super::VerifyContext::new().key_resolver(&resolver).verify(&indirect),
5604 Err(DsigError::Policy(crate::policy::PolicyViolation::Algorithm { algorithm: uri, .. })) if uri == algorithm.uri())
5605 );
5606 assert_eq!(
5607 super::super::VerifyContext::new()
5608 .key_resolver(&resolver)
5609 .policy(policy.clone())
5610 .verify(&indirect)
5611 .expect("permitted indirect selector must verify")
5612 .status,
5613 super::super::DsigStatus::Valid
5614 );
5615 }
5616 }
5617 }
5618 }
5619
5620 #[test]
5621 fn generic_key_resolution_keeps_legacy_capability_source_independent() {
5622 let certificate =
5623 include_bytes!("../../tests/fixtures/xmldsig/phaos-xmldsig-three/certs/rsa-cert.der")
5624 .to_vec();
5625 let (_, parsed_certificate) = X509Certificate::from_der(&certificate)
5626 .expect("the Phaos fixture is a DER certificate");
5627 let public_key = parsed_certificate.public_key().raw.to_vec();
5628 let rsa_public_key = rsa::RsaPublicKey::from_public_key_der(&public_key)
5629 .expect("the Phaos certificate contains an RSA public key");
5630 let certificate_metadata = parse_x509_certificate(&certificate)
5631 .expect("the Phaos fixture has supported X.509 metadata");
5632 let named_key = VerificationKey {
5633 algorithm: SignatureAlgorithm::RsaSha1,
5634 public_key_bytes: public_key.clone(),
5635 certificate_der: None,
5636 name: Some("legacy".into()),
5637 };
5638 let key_infos = [
5639 KeyInfo {
5640 sources: vec![KeyInfoSource::KeyName("legacy".into())],
5641 },
5642 KeyInfo {
5643 sources: vec![KeyInfoSource::DerEncodedKeyValue(public_key.clone())],
5644 },
5645 KeyInfo {
5646 sources: vec![KeyInfoSource::KeyValue(KeyValueInfo::Rsa {
5647 modulus: rsa_public_key.n().to_be_bytes_trimmed_vartime().to_vec(),
5648 exponent: rsa_public_key.e().to_be_bytes_trimmed_vartime().to_vec(),
5649 })],
5650 },
5651 KeyInfo {
5652 sources: vec![KeyInfoSource::X509Data(X509DataInfo {
5653 certificates: vec![certificate],
5654 parsed_certificates: vec![certificate_metadata],
5655 certificate_chain: vec![0],
5656 ..X509DataInfo::default()
5657 })],
5658 },
5659 ];
5660 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
5661 named_keys: HashMap::from([("legacy".into(), named_key.clone())]),
5662 ..KeyResolverConfig::default()
5663 });
5664 let mut policy = crate::policy::VerificationPolicy::default();
5665 policy.key_trust.rsa_keys.minimum_modulus_bits = 1024;
5666 policy
5667 .key_trust
5668 .allowed_legacy_signature_algorithms
5669 .insert(SignatureAlgorithm::RsaSha1);
5670
5671 for key_info in &key_infos {
5672 let key = resolver
5673 .resolve_with_policy(Some(key_info), SignatureAlgorithm::RsaSha1, &policy)
5674 .expect("the key source is valid")
5675 .expect("key resolution remains independent from operation policy");
5676 assert!(
5677 !key.verify(SignatureAlgorithm::RsaSha1, b"data", &[0; 128])
5678 .expect("the legacy RSA key is structurally valid")
5679 );
5680 }
5681 }
5682
5683 #[test]
5684 fn rsa_key_value_rejects_ecdsa_signature_method() {
5685 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
5687 .expect("fixture must contain an RSA public key");
5688 let (modulus, exponent) = rsa_key_value_parts(&public_key);
5689 let key_info = format!(
5690 "<ds:KeyInfo><ds:KeyValue><ds:RSAKeyValue><ds:Modulus>{}</ds:Modulus><ds:Exponent>{}</ds:Exponent></ds:RSAKeyValue></ds:KeyValue></ds:KeyInfo>",
5691 modulus, exponent,
5692 );
5693 let xml = replace_key_info(SIGNED_SAML, &key_info);
5694 let resolver = DefaultKeyResolver::default();
5695 let error = super::super::VerifyContext::new()
5696 .key_resolver(&resolver)
5697 .verify(&xml)
5698 .expect_err("RSAKeyValue must not resolve for ECDSA");
5699
5700 assert!(matches!(
5701 error,
5702 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
5703 ));
5704 }
5705
5706 #[test]
5707 fn resolves_ec_p256_key_value_end_to_end() {
5708 let resolver = DefaultKeyResolver::default();
5710 let result = super::super::VerifyContext::new()
5711 .policy(cryptographic_policy())
5712 .key_resolver(&resolver)
5713 .verify(EC_P256_KEY_VALUE_SIGNATURE)
5714 .expect("P-256 ECKeyValue should resolve");
5715
5716 assert_eq!(result.status, super::super::DsigStatus::Valid);
5717 }
5718
5719 #[test]
5720 fn resolves_ec_p384_key_value_end_to_end() {
5721 let resolver = DefaultKeyResolver::default();
5723 let result = super::super::VerifyContext::new()
5724 .policy(cryptographic_policy())
5725 .key_resolver(&resolver)
5726 .verify(EC_P384_KEY_VALUE_SIGNATURE)
5727 .expect("P-384 ECKeyValue should resolve");
5728
5729 assert_eq!(result.status, super::super::DsigStatus::Valid);
5730 }
5731
5732 #[test]
5733 fn ec_key_value_ignored_for_rsa_signature_method() {
5734 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>"#;
5736 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
5737 let resolver = DefaultKeyResolver::default();
5738 let result = super::super::VerifyContext::new()
5739 .key_resolver(&resolver)
5740 .verify(&xml)
5741 .expect("single incompatible ECKeyValue should be ignored");
5742
5743 assert_eq!(
5744 result.status,
5745 super::super::DsigStatus::Invalid(super::super::FailureReason::KeyNotFound)
5746 );
5747 }
5748
5749 #[test]
5750 fn incompatible_ec_key_value_falls_back_to_later_rsa_key_value() {
5751 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
5753 .expect("fixture must contain an RSA public key");
5754 let (modulus, exponent) = rsa_key_value_parts(&public_key);
5755 let key_info = format!(
5756 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>"#,
5757 modulus, exponent,
5758 );
5759 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
5760 let resolver = DefaultKeyResolver::default();
5761 let result = super::super::VerifyContext::new()
5762 .policy(cryptographic_policy())
5763 .key_resolver(&resolver)
5764 .verify(&xml)
5765 .expect("later RSAKeyValue should resolve");
5766
5767 assert_eq!(result.status, super::super::DsigStatus::Valid);
5768 }
5769
5770 #[test]
5771 fn unsupported_ec_key_value_falls_back_to_later_key_name() {
5772 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>"#;
5774 let xml = replace_key_info(SIGNED_SAML, key_info);
5775 let mut config = KeyResolverConfig::default();
5776 config.named_keys.insert(
5777 "idp-signing".into(),
5778 VerificationKey {
5779 algorithm: SignatureAlgorithm::EcdsaSha256,
5780 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
5781 certificate_der: None,
5782 name: Some("idp-signing".into()),
5783 },
5784 );
5785 let resolver = DefaultKeyResolver::new(config);
5786 let result = super::super::VerifyContext::new()
5787 .key_resolver(&resolver)
5788 .verify(&xml)
5789 .expect("later KeyName should resolve");
5790
5791 assert_eq!(result.status, super::super::DsigStatus::Valid);
5792 }
5793
5794 #[test]
5795 fn invalid_ec_key_value_falls_back_to_later_key_name() {
5796 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>"#;
5798 let xml = replace_key_info(SIGNED_SAML, key_info);
5799 let mut config = KeyResolverConfig::default();
5800 config.named_keys.insert(
5801 "idp-signing".into(),
5802 VerificationKey {
5803 algorithm: SignatureAlgorithm::EcdsaSha256,
5804 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
5805 certificate_der: None,
5806 name: Some("idp-signing".into()),
5807 },
5808 );
5809 let resolver = DefaultKeyResolver::new(config);
5810 let result = super::super::VerifyContext::new()
5811 .key_resolver(&resolver)
5812 .verify(&xml)
5813 .expect("later KeyName should resolve after invalid ECKeyValue");
5814
5815 assert_eq!(result.status, super::super::DsigStatus::Valid);
5816 }
5817
5818 #[test]
5819 fn malformed_ec_key_value_falls_back_to_later_key_name() {
5820 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>"#;
5822 let xml = replace_key_info(SIGNED_SAML, key_info);
5823 let mut config = KeyResolverConfig::default();
5824 config.named_keys.insert(
5825 "idp-signing".into(),
5826 VerificationKey {
5827 algorithm: SignatureAlgorithm::EcdsaSha256,
5828 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
5829 certificate_der: None,
5830 name: Some("idp-signing".into()),
5831 },
5832 );
5833 let resolver = DefaultKeyResolver::new(config);
5834 let result = super::super::VerifyContext::new()
5835 .key_resolver(&resolver)
5836 .verify(&xml)
5837 .expect("later KeyName should resolve after malformed ECKeyValue");
5838
5839 assert_eq!(result.status, super::super::DsigStatus::Valid);
5840 }
5841
5842 #[test]
5843 fn invalid_base64_ec_key_value_falls_back_to_later_key_name() {
5844 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>"#;
5847 let xml = replace_key_info(SIGNED_SAML, key_info);
5848 let mut config = KeyResolverConfig::default();
5849 config.named_keys.insert(
5850 "idp-signing".into(),
5851 VerificationKey {
5852 algorithm: SignatureAlgorithm::EcdsaSha256,
5853 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
5854 certificate_der: None,
5855 name: Some("idp-signing".into()),
5856 },
5857 );
5858 let resolver = DefaultKeyResolver::new(config);
5859 let result = super::super::VerifyContext::new()
5860 .key_resolver(&resolver)
5861 .verify(&xml)
5862 .expect("later KeyName should resolve after bad ECKeyValue base64");
5863
5864 assert_eq!(result.status, super::super::DsigStatus::Valid);
5865 }
5866
5867 #[test]
5868 fn missing_curve_uri_ec_key_value_falls_back_to_later_key_name() {
5869 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>"#;
5871 let xml = replace_key_info(SIGNED_SAML, key_info);
5872 let mut config = KeyResolverConfig::default();
5873 config.named_keys.insert(
5874 "idp-signing".into(),
5875 VerificationKey {
5876 algorithm: SignatureAlgorithm::EcdsaSha256,
5877 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
5878 certificate_der: None,
5879 name: Some("idp-signing".into()),
5880 },
5881 );
5882 let resolver = DefaultKeyResolver::new(config);
5883 let result = super::super::VerifyContext::new()
5884 .key_resolver(&resolver)
5885 .verify(&xml)
5886 .expect("later KeyName should resolve after missing EC curve URI");
5887
5888 assert_eq!(result.status, super::super::DsigStatus::Valid);
5889 }
5890
5891 #[test]
5892 fn malformed_ec_key_value_children_fall_back_to_later_key_name() {
5893 let malformed_ec_key_values = [
5896 r#"<dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/>"#,
5897 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"/>"#,
5898 r#"<dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/><dsig11:PublicKey>BA==</dsig11:PublicKey><dsig11:PublicKey>BA==</dsig11:PublicKey>"#,
5899 ];
5900
5901 for malformed_children in malformed_ec_key_values {
5902 let key_info = format!(
5903 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>"#
5904 );
5905 let xml = replace_key_info(SIGNED_SAML, &key_info);
5906 let mut config = KeyResolverConfig::default();
5907 config.named_keys.insert(
5908 "idp-signing".into(),
5909 VerificationKey {
5910 algorithm: SignatureAlgorithm::EcdsaSha256,
5911 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
5912 certificate_der: None,
5913 name: Some("idp-signing".into()),
5914 },
5915 );
5916 let resolver = DefaultKeyResolver::new(config);
5917 let result = super::super::VerifyContext::new()
5918 .key_resolver(&resolver)
5919 .verify(&xml)
5920 .expect("later KeyName should resolve after malformed EC child shape");
5921
5922 assert_eq!(result.status, super::super::DsigStatus::Valid);
5923 }
5924 }
5925
5926 #[test]
5927 fn supported_ec_curve_does_not_fall_back_to_later_key_name() {
5928 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>"#;
5932 let xml = replace_key_info(SIGNED_SAML, key_info);
5933 let mut config = KeyResolverConfig::default();
5934 config.named_keys.insert(
5935 "idp-signing".into(),
5936 VerificationKey {
5937 algorithm: SignatureAlgorithm::EcdsaSha256,
5938 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
5939 certificate_der: None,
5940 name: Some("idp-signing".into()),
5941 },
5942 );
5943 let resolver = DefaultKeyResolver::new(config);
5944 let error = super::super::VerifyContext::new()
5945 .policy(cryptographic_policy())
5946 .key_resolver(&resolver)
5947 .verify(&xml)
5948 .expect_err("a usable first key source must not fall through after verification");
5949
5950 assert!(matches!(
5951 error,
5952 DsigError::Crypto(super::super::SignatureVerificationError::InvalidSignatureFormat)
5953 ));
5954 }
5955
5956 #[test]
5957 fn lone_malformed_ec_key_value_reports_invalid_public_key() {
5958 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>"#;
5959 let xml = replace_key_info(SIGNED_SAML, key_info);
5960 let error = super::super::VerifyContext::new()
5961 .key_resolver(&DefaultKeyResolver::default())
5962 .verify(&xml)
5963 .expect_err("lone malformed ECKeyValue should surface typed key error");
5964
5965 assert!(matches!(
5966 error,
5967 DsigError::KeyResolution(KeyResolutionError::InvalidPublicKey)
5968 ));
5969 }
5970
5971 #[test]
5972 fn lone_supported_ec_curve_reaches_signature_verification() {
5973 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>"#;
5974 let xml = replace_key_info(SIGNED_SAML, key_info);
5975 let error = super::super::VerifyContext::new()
5976 .policy(cryptographic_policy())
5977 .key_resolver(&DefaultKeyResolver::default())
5978 .verify(&xml)
5979 .expect_err("a supported EC curve must reach signature verification");
5980
5981 assert!(matches!(
5982 error,
5983 DsigError::Crypto(super::super::SignatureVerificationError::InvalidSignatureFormat)
5984 ));
5985 }
5986
5987 #[test]
5988 fn chain_verification_rejects_untrusted_embedded_certificate() {
5989 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
5991 ..KeyResolverConfig::default()
5992 });
5993 let error = super::super::VerifyContext::new()
5994 .policy(verification_policy_with_trust(chain_policy()))
5995 .key_resolver(&resolver)
5996 .verify(SIGNED_SAML)
5997 .expect_err("untrusted certificate must fail chain validation");
5998
5999 assert!(matches!(
6000 error,
6001 DsigError::KeyResolution(KeyResolutionError::Chain(
6002 super::super::X509ChainError::UntrustedRoot
6003 ))
6004 ));
6005 }
6006
6007 #[test]
6008 fn named_key_algorithm_mismatch_fails_closed() {
6009 let xml = replace_key_info(
6011 SIGNED_SAML,
6012 "<ds:KeyInfo><ds:KeyName>wrong-algorithm</ds:KeyName></ds:KeyInfo>",
6013 );
6014 let mut config = KeyResolverConfig::default();
6015 config.named_keys.insert(
6016 "wrong-algorithm".into(),
6017 VerificationKey {
6018 algorithm: SignatureAlgorithm::RsaSha256,
6019 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
6020 certificate_der: None,
6021 name: Some("wrong-algorithm".into()),
6022 },
6023 );
6024 let resolver = DefaultKeyResolver::new(config);
6025 let error = super::super::VerifyContext::new()
6026 .key_resolver(&resolver)
6027 .verify(&xml)
6028 .expect_err("algorithm mismatch must fail closed");
6029
6030 assert!(matches!(
6031 error,
6032 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
6033 ));
6034 }
6035
6036 #[test]
6037 fn named_key_spki_type_mismatch_fails_during_resolution() {
6038 let xml = replace_key_info(
6040 SIGNED_SAML,
6041 "<ds:KeyInfo><ds:KeyName>mislabeled</ds:KeyName></ds:KeyInfo>",
6042 );
6043 let mut config = KeyResolverConfig::default();
6044 config.named_keys.insert(
6045 "mislabeled".into(),
6046 VerificationKey {
6047 algorithm: SignatureAlgorithm::EcdsaSha256,
6048 public_key_bytes: public_key_der(RSA_PUBLIC_KEY),
6049 certificate_der: None,
6050 name: Some("mislabeled".into()),
6051 },
6052 );
6053 let resolver = DefaultKeyResolver::new(config);
6054 let error = super::super::VerifyContext::new()
6055 .key_resolver(&resolver)
6056 .verify(&xml)
6057 .expect_err("mislabeled named key must fail during resolution");
6058
6059 assert!(matches!(
6060 error,
6061 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
6062 ));
6063 }
6064
6065 #[test]
6066 fn malformed_named_key_reports_public_key_error() {
6067 let xml = replace_key_info(
6069 SIGNED_SAML,
6070 "<ds:KeyInfo><ds:KeyName>malformed</ds:KeyName></ds:KeyInfo>",
6071 );
6072 let mut config = KeyResolverConfig::default();
6073 config.named_keys.insert(
6074 "malformed".into(),
6075 VerificationKey {
6076 algorithm: SignatureAlgorithm::EcdsaSha256,
6077 public_key_bytes: vec![1, 2, 3],
6078 certificate_der: None,
6079 name: Some("malformed".into()),
6080 },
6081 );
6082 let resolver = DefaultKeyResolver::new(config);
6083 let error = super::super::VerifyContext::new()
6084 .key_resolver(&resolver)
6085 .verify(&xml)
6086 .expect_err("malformed named key must fail during resolution");
6087
6088 assert!(matches!(
6089 error,
6090 DsigError::KeyResolution(KeyResolutionError::InvalidPublicKey)
6091 ));
6092 }
6093}