1use std::{collections::HashMap, time::SystemTime};
4
5use crypto_bigint::BoxedUint;
6use p256::pkcs8::EncodePublicKey as P256EncodePublicKey;
7use x509_parser::{
8 prelude::{FromDer, X509Certificate},
9 public_key::PublicKey,
10 x509::SubjectPublicKeyInfo,
11};
12
13use super::{
14 DsigError, KeyInfo, KeyInfoSource, KeyResolver, KeyValueInfo, SignatureAlgorithm, VerifyingKey,
15 X509ChainOptions, X509DataInfo,
16 parse::{
17 EC_P256_OID, EC_P384_OID, ParseError, parse_x509_certificate,
18 x509_certificate_matches_any_selector, x509_data_has_lookup_identifiers,
19 x509_selector_categories_match_chain,
20 },
21 verify_ecdsa_signature_spki, verify_rsa_signature_spki, verify_x509_certificate_chain,
22};
23
24#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct VerificationKey {
27 pub algorithm: SignatureAlgorithm,
29 pub public_key_bytes: Vec<u8>,
31 pub certificate_der: Option<Vec<u8>>,
33 pub name: Option<String>,
35}
36
37impl VerifyingKey for VerificationKey {
38 fn verify(
39 &self,
40 algorithm: SignatureAlgorithm,
41 signed_data: &[u8],
42 signature_value: &[u8],
43 ) -> Result<bool, DsigError> {
44 if algorithm != self.algorithm {
45 return Err(KeyResolutionError::AlgorithmMismatch.into());
46 }
47 let result = match algorithm {
48 SignatureAlgorithm::RsaSha1
49 | SignatureAlgorithm::RsaSha256
50 | SignatureAlgorithm::RsaSha384
51 | SignatureAlgorithm::RsaSha512 => verify_rsa_signature_spki(
52 algorithm,
53 &self.public_key_bytes,
54 signed_data,
55 signature_value,
56 ),
57 SignatureAlgorithm::EcdsaP256Sha256 | SignatureAlgorithm::EcdsaP384Sha384 => {
58 verify_ecdsa_signature_spki(
59 algorithm,
60 &self.public_key_bytes,
61 signed_data,
62 signature_value,
63 )
64 }
65 };
66 result.map_err(DsigError::Crypto)
67 }
68}
69
70#[derive(Debug, thiserror::Error)]
72#[non_exhaustive]
73pub enum KeyResolutionError {
74 #[error("verification key does not match the signature algorithm")]
76 AlgorithmMismatch,
77 #[error("invalid embedded certificate DER")]
79 InvalidCertificate,
80 #[error("invalid public key DER")]
82 InvalidPublicKey,
83 #[error("X.509 lookup selectors match multiple configured certificates")]
85 AmbiguousCertificate,
86 #[error("unsupported X.509 digest algorithm: {0}")]
88 UnsupportedDigestAlgorithm(String),
89 #[error("certificate chain validation failed: {0}")]
91 Chain(#[from] super::X509ChainError),
92 #[error("system time is unavailable")]
94 SystemTime,
95}
96
97#[derive(Debug, Clone, PartialEq, Eq)]
103pub struct KeyResolverConfig {
104 pub trusted_certs: Vec<Vec<u8>>,
106 pub named_keys: HashMap<String, VerificationKey>,
108 pub verify_chains: bool,
110 pub verification_time: Option<SystemTime>,
112 pub max_chain_depth: usize,
114}
115
116impl Default for KeyResolverConfig {
117 fn default() -> Self {
118 Self {
119 trusted_certs: Vec::new(),
120 named_keys: HashMap::new(),
121 verify_chains: false,
122 verification_time: None,
123 max_chain_depth: 9,
124 }
125 }
126}
127
128#[derive(Debug, Clone, Default)]
130pub struct DefaultKeyResolver {
131 config: KeyResolverConfig,
132}
133
134impl DefaultKeyResolver {
135 #[must_use]
137 pub fn new(config: KeyResolverConfig) -> Self {
138 Self { config }
139 }
140
141 #[must_use]
143 pub fn config(&self) -> &KeyResolverConfig {
144 &self.config
145 }
146
147 fn resolve_x509(
148 &self,
149 info: &X509DataInfo,
150 algorithm: SignatureAlgorithm,
151 ) -> Result<Option<VerificationKey>, KeyResolutionError> {
152 let certificate_der = if let Some(&signing_index) = info.certificate_chain.first() {
153 let certificate_der = info
154 .certificates
155 .get(signing_index)
156 .ok_or(KeyResolutionError::InvalidCertificate)?;
157 if self.config.verify_chains {
158 self.verify_x509_policy(info, None)?;
159 }
160 certificate_der
161 } else {
162 let Some(certificate) = self.resolve_configured_x509(info)? else {
163 return Ok(None);
164 };
165 if self.config.verify_chains {
166 let parsed = parse_x509_certificate(certificate)
167 .map_err(|_| KeyResolutionError::InvalidCertificate)?;
168 let selected = X509DataInfo {
169 certificates: vec![certificate.clone()],
170 parsed_certificates: vec![parsed],
171 certificate_chain: vec![0],
172 ..X509DataInfo::default()
173 };
174 self.verify_x509_policy(&selected, None)?;
177 self.verify_x509_policy(&selected, Some(certificate))?;
178 }
179 certificate
180 };
181
182 let (rest, certificate) = X509Certificate::from_der(certificate_der)
183 .map_err(|_| KeyResolutionError::InvalidCertificate)?;
184 if !rest.is_empty() {
185 return Err(KeyResolutionError::InvalidCertificate);
186 }
187 let public_key_bytes = certificate.public_key().raw.to_vec();
188 validate_spki_algorithm(&public_key_bytes, algorithm)?;
189 Ok(Some(VerificationKey {
190 algorithm,
191 public_key_bytes,
192 certificate_der: Some(certificate_der.clone()),
193 name: None,
194 }))
195 }
196
197 fn verify_x509_policy(
198 &self,
199 info: &X509DataInfo,
200 selected_lookup_certificate: Option<&[u8]>,
201 ) -> Result<(), KeyResolutionError> {
202 let trusted_certs = self
203 .config
204 .trusted_certs
205 .iter()
206 .filter(|certificate| {
207 selected_lookup_certificate
208 .is_none_or(|selected| certificate.as_slice() != selected)
209 })
210 .cloned()
211 .collect::<Vec<_>>();
212 let options = X509ChainOptions {
213 trusted_certs: &trusted_certs,
214 verification_time: self
215 .config
216 .verification_time
217 .unwrap_or_else(SystemTime::now),
218 max_chain_depth: self.config.max_chain_depth,
219 check_crls: false,
220 };
221 verify_x509_certificate_chain(info, &options)?;
222 Ok(())
223 }
224
225 fn resolve_configured_x509<'a>(
226 &'a self,
227 info: &X509DataInfo,
228 ) -> Result<Option<&'a Vec<u8>>, KeyResolutionError> {
229 if !x509_data_has_lookup_identifiers(info) {
230 return Ok(None);
231 }
232
233 let mut matches = Vec::new();
234 for certificate_der in &self.config.trusted_certs {
235 let parsed = parse_x509_certificate(certificate_der)
236 .map_err(|_| KeyResolutionError::InvalidCertificate)?;
237 let is_match = x509_certificate_matches_any_selector(info, &parsed, certificate_der)
238 .map_err(|error| match error {
239 ParseError::UnsupportedAlgorithm { uri } => {
240 KeyResolutionError::UnsupportedDigestAlgorithm(uri)
241 }
242 _ => KeyResolutionError::InvalidCertificate,
243 })?;
244 if is_match {
245 matches.push((certificate_der, parsed));
246 }
247 }
248
249 let matched_chain = X509DataInfo {
250 certificates: matches
251 .iter()
252 .map(|(certificate, _)| (*certificate).clone())
253 .collect(),
254 parsed_certificates: matches.iter().map(|(_, parsed)| parsed.clone()).collect(),
255 ..X509DataInfo::default()
256 };
257 if !x509_selector_categories_match_chain(&X509DataInfo {
258 subject_names: info.subject_names.clone(),
259 issuer_serials: info.issuer_serials.clone(),
260 skis: info.skis.clone(),
261 digests: info.digests.clone(),
262 ..matched_chain
263 })
264 .map_err(|error| match error {
265 ParseError::UnsupportedAlgorithm { uri } => {
266 KeyResolutionError::UnsupportedDigestAlgorithm(uri)
267 }
268 _ => KeyResolutionError::InvalidCertificate,
269 })? {
270 return Ok(None);
271 }
272
273 match matches.as_slice() {
274 [] => Ok(None),
275 [(certificate, _)] => Ok(Some(certificate)),
276 _ => {
277 let leaves = matches
278 .iter()
279 .filter(|(_, candidate)| {
280 candidate.subject_dn != candidate.issuer_dn
281 && !matches
282 .iter()
283 .any(|(_, other)| other.issuer_dn == candidate.subject_dn)
284 })
285 .collect::<Vec<_>>();
286 match leaves.as_slice() {
287 [(certificate, _)] => Ok(Some(certificate)),
288 _ => Err(KeyResolutionError::AmbiguousCertificate),
289 }
290 }
291 }
292 }
293
294 fn resolve_key_value(
295 key_value: &KeyValueInfo,
296 algorithm: SignatureAlgorithm,
297 ) -> Result<Option<VerificationKey>, KeyResolutionError> {
298 let public_key_bytes = match key_value {
299 KeyValueInfo::Rsa { modulus, exponent } => {
300 if !matches!(
301 algorithm,
302 SignatureAlgorithm::RsaSha1
303 | SignatureAlgorithm::RsaSha256
304 | SignatureAlgorithm::RsaSha384
305 | SignatureAlgorithm::RsaSha512
306 ) {
307 return Err(KeyResolutionError::AlgorithmMismatch);
308 }
309 rsa_key_value_to_spki_der(modulus, exponent)?
310 }
311 KeyValueInfo::Ec {
312 curve_oid,
313 public_key,
314 } => {
315 if !matches!(
316 algorithm,
317 SignatureAlgorithm::EcdsaP256Sha256 | SignatureAlgorithm::EcdsaP384Sha384
318 ) {
319 return Ok(None);
320 }
321 ec_key_value_to_spki_der(curve_oid, public_key)?
322 }
323 KeyValueInfo::InvalidEcKeyValue => return Err(KeyResolutionError::InvalidPublicKey),
324 KeyValueInfo::Unsupported { .. } => return Ok(None),
325 };
326 validate_spki_algorithm(&public_key_bytes, algorithm)?;
327
328 Ok(Some(VerificationKey {
329 algorithm,
330 public_key_bytes,
331 certificate_der: None,
332 name: None,
333 }))
334 }
335}
336
337impl KeyResolver for DefaultKeyResolver {
338 fn resolve<'a>(
339 &'a self,
340 key_info: Option<&KeyInfo>,
341 algorithm: SignatureAlgorithm,
342 ) -> Result<Option<Box<dyn VerifyingKey + 'a>>, DsigError> {
343 let Some(key_info) = key_info else {
344 return Ok(None);
345 };
346 let mut deferred_key_value_error = None;
347 for source in &key_info.sources {
348 let resolved = match source {
349 KeyInfoSource::X509Data(info) => self.resolve_x509(info, algorithm)?,
350 KeyInfoSource::DerEncodedKeyValue(public_key_bytes) => {
351 validate_spki_algorithm(public_key_bytes, algorithm)?;
352 Some(VerificationKey {
353 algorithm,
354 public_key_bytes: public_key_bytes.clone(),
355 certificate_der: None,
356 name: None,
357 })
358 }
359 KeyInfoSource::KeyName(name) => self
360 .config
361 .named_keys
362 .get(name)
363 .map(|key| {
364 if key.algorithm != algorithm {
365 return Err(KeyResolutionError::AlgorithmMismatch);
366 }
367 validate_spki_algorithm(&key.public_key_bytes, algorithm)?;
368 Ok(key.clone())
369 })
370 .transpose()?,
371 KeyInfoSource::KeyValue(key_value) => {
372 match Self::resolve_key_value(key_value, algorithm) {
373 Ok(resolved) => resolved,
374 Err(error) if ec_key_value_error_allows_fallback(key_value, &error) => {
375 deferred_key_value_error.get_or_insert(error);
376 None
377 }
378 Err(error) => return Err(error.into()),
379 }
380 }
381 };
382 if let Some(key) = resolved {
383 return Ok(Some(Box::new(key)));
384 }
385 }
386 if let Some(error) = deferred_key_value_error {
387 return Err(error.into());
388 }
389 Ok(None)
390 }
391
392 fn consumes_document_key_info(&self) -> bool {
393 true
394 }
395}
396
397fn rsa_key_value_to_spki_der(
398 modulus: &[u8],
399 exponent: &[u8],
400) -> Result<Vec<u8>, KeyResolutionError> {
401 let key = rsa::RsaPublicKey::new(
402 BoxedUint::from_be_slice_vartime(modulus),
403 BoxedUint::from_be_slice_vartime(exponent),
404 )
405 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
406 key.to_public_key_der()
407 .map_err(|_| KeyResolutionError::InvalidPublicKey)
408 .map(|der| der.as_bytes().to_vec())
409}
410
411fn ec_key_value_to_spki_der(
412 curve_oid: &str,
413 public_key: &[u8],
414) -> Result<Vec<u8>, KeyResolutionError> {
415 match curve_oid {
416 EC_P256_OID => p256::PublicKey::from_sec1_bytes(public_key)
417 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
418 .to_public_key_der()
419 .map_err(|_| KeyResolutionError::InvalidPublicKey)
420 .map(|der| der.as_bytes().to_vec()),
421 EC_P384_OID => p384::PublicKey::from_sec1_bytes(public_key)
422 .map_err(|_| KeyResolutionError::InvalidPublicKey)?
423 .to_public_key_der()
424 .map_err(|_| KeyResolutionError::InvalidPublicKey)
425 .map(|der| der.as_bytes().to_vec()),
426 _ => Err(KeyResolutionError::InvalidPublicKey),
427 }
428}
429
430fn ec_key_value_error_allows_fallback(
431 key_value: &KeyValueInfo,
432 error: &KeyResolutionError,
433) -> bool {
434 matches!(
435 key_value,
436 KeyValueInfo::Ec { .. } | KeyValueInfo::InvalidEcKeyValue
437 ) && matches!(
438 error,
439 KeyResolutionError::InvalidPublicKey | KeyResolutionError::AlgorithmMismatch
440 )
441}
442
443fn validate_spki_algorithm(
444 public_key_bytes: &[u8],
445 algorithm: SignatureAlgorithm,
446) -> Result<(), KeyResolutionError> {
447 let (rest, spki) = SubjectPublicKeyInfo::from_der(public_key_bytes)
448 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
449 if !rest.is_empty() {
450 return Err(KeyResolutionError::InvalidPublicKey);
451 }
452 let parsed = spki
453 .parsed()
454 .map_err(|_| KeyResolutionError::InvalidPublicKey)?;
455 let curve_oid = spki
456 .algorithm
457 .parameters
458 .as_ref()
459 .and_then(|value| value.as_oid().ok())
460 .map(|oid| oid.to_id_string());
461 match (algorithm, parsed) {
462 (
463 SignatureAlgorithm::RsaSha1
464 | SignatureAlgorithm::RsaSha256
465 | SignatureAlgorithm::RsaSha384
466 | SignatureAlgorithm::RsaSha512,
467 PublicKey::RSA(_),
468 ) => Ok(()),
469 (SignatureAlgorithm::EcdsaP256Sha256, PublicKey::EC(_))
470 if curve_oid.as_deref() == Some("1.2.840.10045.3.1.7") =>
471 {
472 Ok(())
473 }
474 (SignatureAlgorithm::EcdsaP384Sha384, PublicKey::EC(_))
478 if matches!(curve_oid.as_deref(), Some("1.3.132.0.34" | "1.3.132.0.35")) =>
479 {
480 Ok(())
481 }
482 _ => Err(KeyResolutionError::AlgorithmMismatch),
483 }
484}
485
486#[cfg(test)]
487mod tests {
488 use base64::{Engine, engine::general_purpose::STANDARD};
489 use rsa::{pkcs8::DecodePublicKey, traits::PublicKeyParts};
490
491 use super::*;
492
493 const SIGNED_SAML: &str =
494 include_str!("../../tests/fixtures/saml/response_signed_by_idp_ecdsa.xml");
495 const SAML_PUBLIC_KEY: &str =
496 include_str!("../../tests/fixtures/keys/ec/saml-idp-ecdsa-pubkey.pem");
497 const RSA_PUBLIC_KEY: &str = include_str!("../../tests/fixtures/keys/rsa/rsa-2048-pubkey.pem");
498 const RSA_4096_CERTIFICATE: &str =
499 include_str!("../../tests/fixtures/keys/rsa/rsa-4096-cert.pem");
500 const X509_DIGEST_SIGNATURE: &str = include_str!(
501 "../../tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloped-x509-digest-sha512.xml"
502 );
503 const RSA_KEY_VALUE_SIGNATURE: &str = include_str!(
504 "../../tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloping-sha256-rsa-sha256.xml"
505 );
506 const LEGACY_RSA_KEY_VALUE_SIGNATURE: &str = include_str!(
507 "../../tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-rsa.xml"
508 );
509 const EC_P256_KEY_VALUE_SIGNATURE: &str = include_str!(
510 "../../tests/fixtures/xmldsig/xmldsig11-interop-2012/signature-enveloping-p256_sha256.xml"
511 );
512 const EC_P384_KEY_VALUE_SIGNATURE: &str = include_str!(
513 "../../tests/fixtures/xmldsig/xmldsig11-interop-2012/signature-enveloping-p384_sha384.xml"
514 );
515
516 fn replace_key_info(xml: &str, replacement: &str) -> String {
517 let start = xml.find("<ds:KeyInfo>").expect("fixture has KeyInfo");
518 let end = xml
519 .find("</ds:KeyInfo>")
520 .expect("fixture has closing KeyInfo")
521 + "</ds:KeyInfo>".len();
522 format!("{}{}{}", &xml[..start], replacement, &xml[end..])
523 }
524
525 fn replace_unprefixed_key_info(xml: &str, replacement: &str) -> String {
526 let start = xml.find("<KeyInfo>").expect("fixture has KeyInfo");
527 let end = xml.find("</KeyInfo>").expect("fixture has closing KeyInfo") + "</KeyInfo>".len();
528 format!("{}{}{}", &xml[..start], replacement, &xml[end..])
529 }
530
531 fn rsa_key_value_parts(public_key: &rsa::RsaPublicKey) -> (String, String) {
532 (
533 STANDARD.encode(public_key.n().to_be_bytes_trimmed_vartime()),
534 STANDARD.encode(public_key.e().to_be_bytes_trimmed_vartime()),
535 )
536 }
537
538 fn x509_signature_with_leaf_subject() -> String {
539 replace_unprefixed_key_info(
540 X509_DIGEST_SIGNATURE,
541 "<KeyInfo><X509Data><X509SubjectName>C=US, ST=California, O=XML Security Library (http://www.aleksey.com/xmlsec), CN=Test Key rsa-4096</X509SubjectName></X509Data></KeyInfo>",
542 )
543 }
544
545 fn fixture_certificate_time() -> SystemTime {
546 SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_800_000_000)
548 }
549
550 fn public_key_der(pem_text: &str) -> Vec<u8> {
551 let (rest, pem) = x509_parser::pem::parse_x509_pem(pem_text.as_bytes())
552 .expect("fixture public key is PEM");
553 assert!(rest.iter().all(|byte| byte.is_ascii_whitespace()));
554 assert_eq!(pem.label, "PUBLIC KEY");
555 pem.contents
556 }
557
558 fn certificate_der(pem_text: &str) -> Vec<u8> {
559 let (rest, pem) = x509_parser::pem::parse_x509_pem(pem_text.as_bytes())
560 .expect("fixture certificate is PEM");
561 assert!(rest.iter().all(|byte| byte.is_ascii_whitespace()));
562 assert_eq!(pem.label, "CERTIFICATE");
563 pem.contents
564 }
565
566 #[test]
567 fn defaults_match_key_resolution_policy() {
568 let config = KeyResolverConfig::default();
570
571 assert!(config.trusted_certs.is_empty());
572 assert!(config.named_keys.is_empty());
573 assert!(!config.verify_chains);
574 assert_eq!(config.verification_time, None);
575 assert_eq!(config.max_chain_depth, 9);
576 }
577
578 #[test]
579 fn stores_named_verification_key_metadata() {
580 let key = VerificationKey {
582 algorithm: SignatureAlgorithm::RsaSha256,
583 public_key_bytes: vec![1, 2, 3],
584 certificate_der: Some(vec![4, 5, 6]),
585 name: Some("idp-signing".into()),
586 };
587 let mut config = KeyResolverConfig::default();
588 config.named_keys.insert("idp-signing".into(), key.clone());
589
590 assert_eq!(config.named_keys.get("idp-signing"), Some(&key));
591 }
592
593 #[test]
594 fn resolves_embedded_certificate_end_to_end() {
595 let resolver = DefaultKeyResolver::default();
597 let result = super::super::VerifyContext::new()
598 .key_resolver(&resolver)
599 .verify(SIGNED_SAML)
600 .expect("embedded certificate should resolve");
601
602 assert_eq!(result.status, super::super::DsigStatus::Valid);
603 }
604
605 #[test]
606 fn resolves_x509_digest_from_configured_certificates() {
607 let leaf_certificate_der = certificate_der(RSA_4096_CERTIFICATE);
610 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
611 trusted_certs: vec![
612 leaf_certificate_der,
613 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
614 certificate_der(include_str!("../../tests/fixtures/keys/cacert.pem")),
615 ],
616 ..KeyResolverConfig::default()
617 });
618 let result = super::super::VerifyContext::new()
619 .key_resolver(&resolver)
620 .verify(X509_DIGEST_SIGNATURE)
621 .expect("X509Digest should resolve a configured certificate");
622
623 assert_eq!(result.status, super::super::DsigStatus::Valid);
624 }
625
626 #[test]
627 fn selector_resolved_certificate_obeys_chain_policy() {
628 let certificate_der = certificate_der(RSA_4096_CERTIFICATE);
631 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
632 trusted_certs: vec![certificate_der],
633 verify_chains: true,
634 verification_time: Some(SystemTime::UNIX_EPOCH),
635 ..KeyResolverConfig::default()
636 });
637 let error = super::super::VerifyContext::new()
638 .key_resolver(&resolver)
639 .verify(&x509_signature_with_leaf_subject())
640 .expect_err("selector-resolved certificate must satisfy chain policy");
641
642 assert!(matches!(
643 error,
644 DsigError::KeyResolution(KeyResolutionError::Chain(
645 super::super::X509ChainError::CertificateNotValid(_)
646 ))
647 ));
648 }
649
650 #[test]
651 fn selector_resolved_leaf_does_not_anchor_itself() {
652 let certificate_der = certificate_der(RSA_4096_CERTIFICATE);
655 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
656 trusted_certs: vec![certificate_der],
657 verify_chains: true,
658 verification_time: Some(fixture_certificate_time()),
659 ..KeyResolverConfig::default()
660 });
661 let error = super::super::VerifyContext::new()
662 .key_resolver(&resolver)
663 .verify(&x509_signature_with_leaf_subject())
664 .expect_err("selector-resolved leaf must not trust itself");
665
666 assert!(matches!(
667 error,
668 DsigError::KeyResolution(KeyResolutionError::Chain(
669 super::super::X509ChainError::UntrustedRoot
670 ))
671 ));
672 }
673
674 #[test]
675 fn selector_resolved_leaf_uses_separate_anchor() {
676 let leaf = certificate_der(RSA_4096_CERTIFICATE);
679 let issuer = certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem"));
680 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
681 trusted_certs: vec![leaf, issuer],
682 verify_chains: true,
683 verification_time: Some(fixture_certificate_time()),
684 ..KeyResolverConfig::default()
685 });
686 let result = super::super::VerifyContext::new()
687 .key_resolver(&resolver)
688 .verify(&x509_signature_with_leaf_subject())
689 .expect("selector-resolved leaf should chain to its configured issuer");
690
691 assert_eq!(result.status, super::super::DsigStatus::Valid);
692 }
693
694 #[test]
695 fn resolves_each_x509_selector_from_configured_certificates() {
696 let selectors = [
699 "<X509SubjectName>C=US, ST=California, O=XML Security Library (http://www.aleksey.com/xmlsec), CN=Test Key rsa-2048</X509SubjectName>",
700 "<X509IssuerSerial><X509IssuerName>C=US, ST=California, O=XML Security Library (http://www.aleksey.com/xmlsec), OU=Second level CA, CN=Aleksey Sanin, Email=xmlsec@aleksey.com</X509IssuerName><X509SerialNumber>680572598617295163017172295025714171905498632019</X509SerialNumber></X509IssuerSerial>",
701 "<X509SKI>bcOXN/nsVl8GatRbcKrPbzIbw0Y=</X509SKI>",
702 ];
703 let configured_certificate = certificate_der(include_str!(
704 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
705 ));
706
707 for selector in selectors {
708 let key_info = format!("<KeyInfo><X509Data>{selector}</X509Data></KeyInfo>");
709 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
710 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
711 trusted_certs: vec![configured_certificate.clone()],
712 ..KeyResolverConfig::default()
713 });
714 let result = super::super::VerifyContext::new()
715 .key_resolver(&resolver)
716 .verify(&xml)
717 .expect("X509 selector should resolve configured certificate");
718
719 assert_eq!(result.status, super::super::DsigStatus::Valid);
720 }
721 }
722
723 #[test]
724 fn resolves_configured_chain_selectors_across_certificates() {
725 let key_info = r#"<KeyInfo><X509Data><X509SubjectName>C=US, ST=California, O=XML Security Library (http://www.aleksey.com/xmlsec), CN=Test Key rsa-2048</X509SubjectName><X509SKI>0X0XrEVCio75sBcl1TxymJ2IOiU=</X509SKI></X509Data></KeyInfo>"#;
728 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
729 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
730 trusted_certs: vec![
731 certificate_der(include_str!(
732 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
733 )),
734 certificate_der(include_str!("../../tests/fixtures/keys/ca2cert.pem")),
735 ],
736 ..KeyResolverConfig::default()
737 });
738 let result = super::super::VerifyContext::new()
739 .key_resolver(&resolver)
740 .verify(&xml)
741 .expect("selectors across one configured chain should resolve its leaf");
742
743 assert_eq!(result.status, super::super::DsigStatus::Valid);
744 }
745
746 #[test]
747 fn unmatched_x509_selector_does_not_resolve() {
748 let key_info = "<KeyInfo><X509Data><X509SubjectName>CN=not-the-signer</X509SubjectName></X509Data></KeyInfo>";
750 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
751 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
752 trusted_certs: vec![certificate_der(include_str!(
753 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
754 ))],
755 ..KeyResolverConfig::default()
756 });
757 let result = super::super::VerifyContext::new()
758 .key_resolver(&resolver)
759 .verify(&xml)
760 .expect("an unmatched selector is a key miss, not a parser failure");
761
762 assert!(matches!(
763 result.status,
764 super::super::DsigStatus::Invalid(super::super::FailureReason::KeyNotFound)
765 ));
766 }
767
768 #[test]
769 fn ambiguous_x509_selector_fails_closed() {
770 let certificate = certificate_der(RSA_4096_CERTIFICATE);
772 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
773 trusted_certs: vec![certificate.clone(), certificate],
774 ..KeyResolverConfig::default()
775 });
776 let error = super::super::VerifyContext::new()
777 .key_resolver(&resolver)
778 .verify(&x509_signature_with_leaf_subject())
779 .expect_err("ambiguous X509 selector lookup must fail closed");
780
781 assert!(matches!(
782 error,
783 DsigError::KeyResolution(KeyResolutionError::AmbiguousCertificate)
784 ));
785 }
786
787 #[test]
788 fn unsupported_x509_digest_selector_fails_closed() {
789 let key_info = "<KeyInfo xmlns:dsig11=\"http://www.w3.org/2009/xmldsig11#\"><X509Data><dsig11:X509Digest Algorithm=\"urn:unsupported\">AQ==</dsig11:X509Digest></X509Data></KeyInfo>";
792 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
793 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
794 trusted_certs: vec![certificate_der(include_str!(
795 "../../tests/fixtures/keys/rsa/rsa-2048-cert.pem"
796 ))],
797 ..KeyResolverConfig::default()
798 });
799 let error = super::super::VerifyContext::new()
800 .key_resolver(&resolver)
801 .verify(&xml)
802 .expect_err("unsupported X509Digest algorithm must fail closed");
803
804 assert!(matches!(
805 error,
806 DsigError::KeyResolution(KeyResolutionError::UnsupportedDigestAlgorithm(uri))
807 if uri == "urn:unsupported"
808 ));
809 }
810
811 #[test]
812 fn resolves_named_key_end_to_end() {
813 let xml = replace_key_info(
815 SIGNED_SAML,
816 "<ds:KeyInfo><ds:KeyName>idp-signing</ds:KeyName></ds:KeyInfo>",
817 );
818 let mut config = KeyResolverConfig::default();
819 config.named_keys.insert(
820 "idp-signing".into(),
821 VerificationKey {
822 algorithm: SignatureAlgorithm::EcdsaP256Sha256,
823 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
824 certificate_der: None,
825 name: Some("idp-signing".into()),
826 },
827 );
828 let resolver = DefaultKeyResolver::new(config);
829 let result = super::super::VerifyContext::new()
830 .key_resolver(&resolver)
831 .verify(&xml)
832 .expect("named key should resolve");
833
834 assert_eq!(result.status, super::super::DsigStatus::Valid);
835 }
836
837 #[test]
838 fn resolves_der_encoded_key_end_to_end() {
839 let encoded = STANDARD.encode(public_key_der(SAML_PUBLIC_KEY));
841 let xml = replace_key_info(
842 SIGNED_SAML,
843 &format!(
844 "<ds:KeyInfo><dsig11:DEREncodedKeyValue xmlns:dsig11=\"http://www.w3.org/2009/xmldsig11#\">{encoded}</dsig11:DEREncodedKeyValue></ds:KeyInfo>"
845 ),
846 );
847 let resolver = DefaultKeyResolver::default();
848 let result = super::super::VerifyContext::new()
849 .key_resolver(&resolver)
850 .verify(&xml)
851 .expect("DER key should resolve");
852
853 assert_eq!(result.status, super::super::DsigStatus::Valid);
854 }
855
856 #[test]
857 fn resolves_rsa_key_value_end_to_end() {
858 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
860 .expect("fixture must contain an RSA public key");
861 let (modulus, exponent) = rsa_key_value_parts(&public_key);
862 let key_info = format!(
863 "<KeyInfo><KeyValue><RSAKeyValue><Modulus>{}</Modulus><Exponent>{}</Exponent></RSAKeyValue></KeyValue></KeyInfo>",
864 modulus, exponent,
865 );
866 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
867 let resolver = DefaultKeyResolver::default();
868 let result = super::super::VerifyContext::new()
869 .key_resolver(&resolver)
870 .verify(&xml)
871 .expect("RSAKeyValue should resolve");
872
873 assert_eq!(result.status, super::super::DsigStatus::Valid);
874 }
875
876 #[test]
877 fn rsa_key_value_rejects_legacy_weak_modulus() {
878 let resolver = DefaultKeyResolver::default();
880 let error = super::super::VerifyContext::new()
881 .key_resolver(&resolver)
882 .verify(LEGACY_RSA_KEY_VALUE_SIGNATURE)
883 .expect_err("1024-bit RSAKeyValue must fail closed");
884
885 assert!(matches!(
886 error,
887 DsigError::Crypto(super::super::SignatureVerificationError::InvalidKeyDer)
888 ));
889 }
890
891 #[test]
892 fn rsa_key_value_rejects_ecdsa_signature_method() {
893 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
895 .expect("fixture must contain an RSA public key");
896 let (modulus, exponent) = rsa_key_value_parts(&public_key);
897 let key_info = format!(
898 "<ds:KeyInfo><ds:KeyValue><ds:RSAKeyValue><ds:Modulus>{}</ds:Modulus><ds:Exponent>{}</ds:Exponent></ds:RSAKeyValue></ds:KeyValue></ds:KeyInfo>",
899 modulus, exponent,
900 );
901 let xml = replace_key_info(SIGNED_SAML, &key_info);
902 let resolver = DefaultKeyResolver::default();
903 let error = super::super::VerifyContext::new()
904 .key_resolver(&resolver)
905 .verify(&xml)
906 .expect_err("RSAKeyValue must not resolve for ECDSA");
907
908 assert!(matches!(
909 error,
910 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
911 ));
912 }
913
914 #[test]
915 fn resolves_ec_p256_key_value_end_to_end() {
916 let resolver = DefaultKeyResolver::default();
918 let result = super::super::VerifyContext::new()
919 .key_resolver(&resolver)
920 .verify(EC_P256_KEY_VALUE_SIGNATURE)
921 .expect("P-256 ECKeyValue should resolve");
922
923 assert_eq!(result.status, super::super::DsigStatus::Valid);
924 }
925
926 #[test]
927 fn resolves_ec_p384_key_value_end_to_end() {
928 let resolver = DefaultKeyResolver::default();
930 let result = super::super::VerifyContext::new()
931 .key_resolver(&resolver)
932 .verify(EC_P384_KEY_VALUE_SIGNATURE)
933 .expect("P-384 ECKeyValue should resolve");
934
935 assert_eq!(result.status, super::super::DsigStatus::Valid);
936 }
937
938 #[test]
939 fn ec_key_value_ignored_for_rsa_signature_method() {
940 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>"#;
942 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, key_info);
943 let resolver = DefaultKeyResolver::default();
944 let result = super::super::VerifyContext::new()
945 .key_resolver(&resolver)
946 .verify(&xml)
947 .expect("single incompatible ECKeyValue should be ignored");
948
949 assert_eq!(
950 result.status,
951 super::super::DsigStatus::Invalid(super::super::FailureReason::KeyNotFound)
952 );
953 }
954
955 #[test]
956 fn incompatible_ec_key_value_falls_back_to_later_rsa_key_value() {
957 let public_key = rsa::RsaPublicKey::from_public_key_pem(RSA_PUBLIC_KEY)
959 .expect("fixture must contain an RSA public key");
960 let (modulus, exponent) = rsa_key_value_parts(&public_key);
961 let key_info = format!(
962 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>"#,
963 modulus, exponent,
964 );
965 let xml = replace_unprefixed_key_info(RSA_KEY_VALUE_SIGNATURE, &key_info);
966 let resolver = DefaultKeyResolver::default();
967 let result = super::super::VerifyContext::new()
968 .key_resolver(&resolver)
969 .verify(&xml)
970 .expect("later RSAKeyValue should resolve");
971
972 assert_eq!(result.status, super::super::DsigStatus::Valid);
973 }
974
975 #[test]
976 fn unsupported_ec_key_value_falls_back_to_later_key_name() {
977 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>"#;
979 let xml = replace_key_info(SIGNED_SAML, key_info);
980 let mut config = KeyResolverConfig::default();
981 config.named_keys.insert(
982 "idp-signing".into(),
983 VerificationKey {
984 algorithm: SignatureAlgorithm::EcdsaP256Sha256,
985 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
986 certificate_der: None,
987 name: Some("idp-signing".into()),
988 },
989 );
990 let resolver = DefaultKeyResolver::new(config);
991 let result = super::super::VerifyContext::new()
992 .key_resolver(&resolver)
993 .verify(&xml)
994 .expect("later KeyName should resolve");
995
996 assert_eq!(result.status, super::super::DsigStatus::Valid);
997 }
998
999 #[test]
1000 fn invalid_ec_key_value_falls_back_to_later_key_name() {
1001 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>"#;
1003 let xml = replace_key_info(SIGNED_SAML, key_info);
1004 let mut config = KeyResolverConfig::default();
1005 config.named_keys.insert(
1006 "idp-signing".into(),
1007 VerificationKey {
1008 algorithm: SignatureAlgorithm::EcdsaP256Sha256,
1009 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
1010 certificate_der: None,
1011 name: Some("idp-signing".into()),
1012 },
1013 );
1014 let resolver = DefaultKeyResolver::new(config);
1015 let result = super::super::VerifyContext::new()
1016 .key_resolver(&resolver)
1017 .verify(&xml)
1018 .expect("later KeyName should resolve after invalid ECKeyValue");
1019
1020 assert_eq!(result.status, super::super::DsigStatus::Valid);
1021 }
1022
1023 #[test]
1024 fn malformed_ec_key_value_falls_back_to_later_key_name() {
1025 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>"#;
1027 let xml = replace_key_info(SIGNED_SAML, key_info);
1028 let mut config = KeyResolverConfig::default();
1029 config.named_keys.insert(
1030 "idp-signing".into(),
1031 VerificationKey {
1032 algorithm: SignatureAlgorithm::EcdsaP256Sha256,
1033 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
1034 certificate_der: None,
1035 name: Some("idp-signing".into()),
1036 },
1037 );
1038 let resolver = DefaultKeyResolver::new(config);
1039 let result = super::super::VerifyContext::new()
1040 .key_resolver(&resolver)
1041 .verify(&xml)
1042 .expect("later KeyName should resolve after malformed ECKeyValue");
1043
1044 assert_eq!(result.status, super::super::DsigStatus::Valid);
1045 }
1046
1047 #[test]
1048 fn invalid_base64_ec_key_value_falls_back_to_later_key_name() {
1049 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>"#;
1052 let xml = replace_key_info(SIGNED_SAML, key_info);
1053 let mut config = KeyResolverConfig::default();
1054 config.named_keys.insert(
1055 "idp-signing".into(),
1056 VerificationKey {
1057 algorithm: SignatureAlgorithm::EcdsaP256Sha256,
1058 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
1059 certificate_der: None,
1060 name: Some("idp-signing".into()),
1061 },
1062 );
1063 let resolver = DefaultKeyResolver::new(config);
1064 let result = super::super::VerifyContext::new()
1065 .key_resolver(&resolver)
1066 .verify(&xml)
1067 .expect("later KeyName should resolve after bad ECKeyValue base64");
1068
1069 assert_eq!(result.status, super::super::DsigStatus::Valid);
1070 }
1071
1072 #[test]
1073 fn missing_curve_uri_ec_key_value_falls_back_to_later_key_name() {
1074 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>"#;
1076 let xml = replace_key_info(SIGNED_SAML, key_info);
1077 let mut config = KeyResolverConfig::default();
1078 config.named_keys.insert(
1079 "idp-signing".into(),
1080 VerificationKey {
1081 algorithm: SignatureAlgorithm::EcdsaP256Sha256,
1082 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
1083 certificate_der: None,
1084 name: Some("idp-signing".into()),
1085 },
1086 );
1087 let resolver = DefaultKeyResolver::new(config);
1088 let result = super::super::VerifyContext::new()
1089 .key_resolver(&resolver)
1090 .verify(&xml)
1091 .expect("later KeyName should resolve after missing EC curve URI");
1092
1093 assert_eq!(result.status, super::super::DsigStatus::Valid);
1094 }
1095
1096 #[test]
1097 fn malformed_ec_key_value_children_fall_back_to_later_key_name() {
1098 let malformed_ec_key_values = [
1101 r#"<dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/>"#,
1102 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"/>"#,
1103 r#"<dsig11:NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/><dsig11:PublicKey>BA==</dsig11:PublicKey><dsig11:PublicKey>BA==</dsig11:PublicKey>"#,
1104 ];
1105
1106 for malformed_children in malformed_ec_key_values {
1107 let key_info = format!(
1108 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>"#
1109 );
1110 let xml = replace_key_info(SIGNED_SAML, &key_info);
1111 let mut config = KeyResolverConfig::default();
1112 config.named_keys.insert(
1113 "idp-signing".into(),
1114 VerificationKey {
1115 algorithm: SignatureAlgorithm::EcdsaP256Sha256,
1116 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
1117 certificate_der: None,
1118 name: Some("idp-signing".into()),
1119 },
1120 );
1121 let resolver = DefaultKeyResolver::new(config);
1122 let result = super::super::VerifyContext::new()
1123 .key_resolver(&resolver)
1124 .verify(&xml)
1125 .expect("later KeyName should resolve after malformed EC child shape");
1126
1127 assert_eq!(result.status, super::super::DsigStatus::Valid);
1128 }
1129 }
1130
1131 #[test]
1132 fn mismatched_ec_curve_falls_back_to_later_key_name() {
1133 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>"#;
1136 let xml = replace_key_info(SIGNED_SAML, key_info);
1137 let mut config = KeyResolverConfig::default();
1138 config.named_keys.insert(
1139 "idp-signing".into(),
1140 VerificationKey {
1141 algorithm: SignatureAlgorithm::EcdsaP256Sha256,
1142 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
1143 certificate_der: None,
1144 name: Some("idp-signing".into()),
1145 },
1146 );
1147 let resolver = DefaultKeyResolver::new(config);
1148 let result = super::super::VerifyContext::new()
1149 .key_resolver(&resolver)
1150 .verify(&xml)
1151 .expect("later KeyName should resolve after mismatched ECKeyValue");
1152
1153 assert_eq!(result.status, super::super::DsigStatus::Valid);
1154 }
1155
1156 #[test]
1157 fn lone_malformed_ec_key_value_reports_invalid_public_key() {
1158 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>"#;
1159 let xml = replace_key_info(SIGNED_SAML, key_info);
1160 let error = super::super::VerifyContext::new()
1161 .key_resolver(&DefaultKeyResolver::default())
1162 .verify(&xml)
1163 .expect_err("lone malformed ECKeyValue should surface typed key error");
1164
1165 assert!(matches!(
1166 error,
1167 DsigError::KeyResolution(KeyResolutionError::InvalidPublicKey)
1168 ));
1169 }
1170
1171 #[test]
1172 fn lone_mismatched_ec_curve_reports_algorithm_mismatch() {
1173 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>"#;
1174 let xml = replace_key_info(SIGNED_SAML, key_info);
1175 let error = super::super::VerifyContext::new()
1176 .key_resolver(&DefaultKeyResolver::default())
1177 .verify(&xml)
1178 .expect_err("lone mismatched ECKeyValue should surface typed key error");
1179
1180 assert!(matches!(
1181 error,
1182 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
1183 ));
1184 }
1185
1186 #[test]
1187 fn chain_verification_rejects_untrusted_embedded_certificate() {
1188 let resolver = DefaultKeyResolver::new(KeyResolverConfig {
1190 verify_chains: true,
1191 ..KeyResolverConfig::default()
1192 });
1193 let error = super::super::VerifyContext::new()
1194 .key_resolver(&resolver)
1195 .verify(SIGNED_SAML)
1196 .expect_err("untrusted certificate must fail chain validation");
1197
1198 assert!(matches!(
1199 error,
1200 DsigError::KeyResolution(KeyResolutionError::Chain(
1201 super::super::X509ChainError::UntrustedRoot
1202 ))
1203 ));
1204 }
1205
1206 #[test]
1207 fn named_key_algorithm_mismatch_fails_closed() {
1208 let xml = replace_key_info(
1210 SIGNED_SAML,
1211 "<ds:KeyInfo><ds:KeyName>wrong-algorithm</ds:KeyName></ds:KeyInfo>",
1212 );
1213 let mut config = KeyResolverConfig::default();
1214 config.named_keys.insert(
1215 "wrong-algorithm".into(),
1216 VerificationKey {
1217 algorithm: SignatureAlgorithm::RsaSha256,
1218 public_key_bytes: public_key_der(SAML_PUBLIC_KEY),
1219 certificate_der: None,
1220 name: Some("wrong-algorithm".into()),
1221 },
1222 );
1223 let resolver = DefaultKeyResolver::new(config);
1224 let error = super::super::VerifyContext::new()
1225 .key_resolver(&resolver)
1226 .verify(&xml)
1227 .expect_err("algorithm mismatch must fail closed");
1228
1229 assert!(matches!(
1230 error,
1231 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
1232 ));
1233 }
1234
1235 #[test]
1236 fn named_key_spki_type_mismatch_fails_during_resolution() {
1237 let xml = replace_key_info(
1239 SIGNED_SAML,
1240 "<ds:KeyInfo><ds:KeyName>mislabeled</ds:KeyName></ds:KeyInfo>",
1241 );
1242 let mut config = KeyResolverConfig::default();
1243 config.named_keys.insert(
1244 "mislabeled".into(),
1245 VerificationKey {
1246 algorithm: SignatureAlgorithm::EcdsaP256Sha256,
1247 public_key_bytes: public_key_der(RSA_PUBLIC_KEY),
1248 certificate_der: None,
1249 name: Some("mislabeled".into()),
1250 },
1251 );
1252 let resolver = DefaultKeyResolver::new(config);
1253 let error = super::super::VerifyContext::new()
1254 .key_resolver(&resolver)
1255 .verify(&xml)
1256 .expect_err("mislabeled named key must fail during resolution");
1257
1258 assert!(matches!(
1259 error,
1260 DsigError::KeyResolution(KeyResolutionError::AlgorithmMismatch)
1261 ));
1262 }
1263
1264 #[test]
1265 fn malformed_named_key_reports_public_key_error() {
1266 let xml = replace_key_info(
1268 SIGNED_SAML,
1269 "<ds:KeyInfo><ds:KeyName>malformed</ds:KeyName></ds:KeyInfo>",
1270 );
1271 let mut config = KeyResolverConfig::default();
1272 config.named_keys.insert(
1273 "malformed".into(),
1274 VerificationKey {
1275 algorithm: SignatureAlgorithm::EcdsaP256Sha256,
1276 public_key_bytes: vec![1, 2, 3],
1277 certificate_der: None,
1278 name: Some("malformed".into()),
1279 },
1280 );
1281 let resolver = DefaultKeyResolver::new(config);
1282 let error = super::super::VerifyContext::new()
1283 .key_resolver(&resolver)
1284 .verify(&xml)
1285 .expect_err("malformed named key must fail during resolution");
1286
1287 assert!(matches!(
1288 error,
1289 DsigError::KeyResolution(KeyResolutionError::InvalidPublicKey)
1290 ));
1291 }
1292}