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