diff --git a/src/xmldsig/mod.rs b/src/xmldsig/mod.rs index 18eb695..21ce853 100644 --- a/src/xmldsig/mod.rs +++ b/src/xmldsig/mod.rs @@ -30,7 +30,7 @@ pub use transforms::{ }; pub use types::{NodeSet, TransformData, TransformError}; pub use verify::{ - DsigStatus, FailureReason, KeyResolver, ReferenceProcessingError, ReferenceResult, - ReferencesResult, SignatureVerificationPipelineError, UriTypeSet, VerifyContext, VerifyResult, - VerifyingKey, process_all_references, process_reference, verify_signature_with_pem_key, + DsigError, DsigStatus, FailureReason, KeyResolver, ReferenceProcessingError, ReferenceResult, + ReferencesResult, UriTypeSet, VerifyContext, VerifyResult, VerifyingKey, + process_all_references, process_reference, verify_signature_with_pem_key, }; diff --git a/src/xmldsig/transforms.rs b/src/xmldsig/transforms.rs index 6fce8de..92cb8ca 100644 --- a/src/xmldsig/transforms.rs +++ b/src/xmldsig/transforms.rs @@ -106,8 +106,7 @@ pub(crate) fn apply_transform<'a>( let nodes = input.into_node_set()?; let mut output = Vec::new(); let predicate = |node: Node| nodes.contains(node); - c14n::canonicalize(nodes.document(), Some(&predicate), algo, &mut output) - .map_err(|e| TransformError::C14n(e.to_string()))?; + c14n::canonicalize(nodes.document(), Some(&predicate), algo, &mut output)?; Ok(TransformData::Binary(output)) } } @@ -142,8 +141,7 @@ pub fn execute_transforms<'a>( .expect("default C14N algorithm URI must be supported by C14nAlgorithm::from_uri"); let mut output = Vec::new(); let predicate = |node: Node| nodes.contains(node); - c14n::canonicalize(nodes.document(), Some(&predicate), &algo, &mut output) - .map_err(|e| TransformError::C14n(e.to_string()))?; + c14n::canonicalize(nodes.document(), Some(&predicate), &algo, &mut output)?; Ok(output) } } diff --git a/src/xmldsig/types.rs b/src/xmldsig/types.rs index 27314e6..51d6727 100644 --- a/src/xmldsig/types.rs +++ b/src/xmldsig/types.rs @@ -226,7 +226,7 @@ pub enum TransformError { /// Canonicalization error during transform. #[error("C14N error: {0}")] - C14n(String), + C14n(#[from] crate::c14n::C14nError), /// The Signature node passed to the enveloped transform belongs to a /// different `Document` than the input `NodeSet`. diff --git a/src/xmldsig/verify.rs b/src/xmldsig/verify.rs index 24d5186..8feaa3a 100644 --- a/src/xmldsig/verify.rs +++ b/src/xmldsig/verify.rs @@ -41,7 +41,7 @@ pub trait VerifyingKey { algorithm: SignatureAlgorithm, signed_data: &[u8], signature_value: &[u8], - ) -> Result; + ) -> Result; } /// Key resolver hook used by [`VerifyContext`] when no pre-set key is provided. @@ -55,10 +55,7 @@ pub trait KeyResolver { /// key material (for example, missing `` candidates). `VerifyContext` /// maps `Ok(None)` to `DsigStatus::Invalid(FailureReason::KeyNotFound)`; /// reserve `Err(...)` for resolver failures. - fn resolve<'a>( - &'a self, - xml: &str, - ) -> Result>, SignatureVerificationPipelineError>; + fn resolve<'a>(&'a self, xml: &str) -> Result>, DsigError>; } /// Allowed URI classes for ``. @@ -212,7 +209,7 @@ impl<'a> VerifyContext<'a> { /// Returns `Ok(VerifyResult)` for both valid and invalid signatures; inspect /// `VerifyResult::status` for the verification outcome. `Err(...)` is /// reserved for pipeline failures. - pub fn verify(&self, xml: &str) -> Result { + pub fn verify(&self, xml: &str) -> Result { verify_signature_with_context(xml, self) } } @@ -394,11 +391,11 @@ pub enum ReferenceProcessingError { /// URI dereference failed. #[error("URI dereference failed: {0}")] - UriDereference(super::types::TransformError), + UriDereference(#[source] super::types::TransformError), /// Transform execution failed. #[error("transform failed: {0}")] - Transform(super::types::TransformError), + Transform(#[source] super::types::TransformError), } /// End-to-end XMLDSig verification result for one ``. @@ -422,7 +419,7 @@ pub struct VerifyResult { /// Errors while running end-to-end XMLDSig verification. #[derive(Debug, thiserror::Error)] #[non_exhaustive] -pub enum SignatureVerificationPipelineError { +pub enum DsigError { /// XML parsing failed. #[error("XML parse error: {0}")] XmlParse(#[from] roxmltree::Error), @@ -480,6 +477,8 @@ pub enum SignatureVerificationPipelineError { ManifestProcessingUnsupported, } +type SignatureVerificationPipelineError = DsigError; + /// Verify one XMLDSig `` end-to-end with a PEM public key. /// /// Pipeline: @@ -501,7 +500,7 @@ pub fn verify_signature_with_pem_key( xml: &str, public_key_pem: &str, store_pre_digest: bool, -) -> Result { +) -> Result { struct PemVerifyingKey<'a> { public_key_pem: &'a str, } @@ -512,7 +511,7 @@ pub fn verify_signature_with_pem_key( algorithm: SignatureAlgorithm, signed_data: &[u8], signature_value: &[u8], - ) -> Result { + ) -> Result { verify_with_algorithm(algorithm, self.public_key_pem, signed_data, signature_value) } } diff --git a/tests/signature_pipeline_integration.rs b/tests/signature_pipeline_integration.rs index 0151b69..f8de186 100644 --- a/tests/signature_pipeline_integration.rs +++ b/tests/signature_pipeline_integration.rs @@ -5,9 +5,7 @@ use std::path::Path; -use xml_sec::xmldsig::{ - DsigStatus, FailureReason, SignatureVerificationPipelineError, verify_signature_with_pem_key, -}; +use xml_sec::xmldsig::{DsigError, DsigStatus, FailureReason, verify_signature_with_pem_key}; fn read_fixture(path: &Path) -> String { std::fs::read_to_string(path) @@ -93,12 +91,9 @@ fn strip_xml_declaration(xml: &str) -> &str { xml } -fn assert_invalid_structure_reason( - err: SignatureVerificationPipelineError, - expected_reason: &'static str, -) { +fn assert_invalid_structure_reason(err: DsigError, expected_reason: &'static str) { match err { - SignatureVerificationPipelineError::InvalidStructure { reason } => { + DsigError::InvalidStructure { reason } => { assert_eq!(reason, expected_reason); } other => panic!("expected InvalidStructure error, got: {other:?}"), @@ -411,10 +406,7 @@ fn malformed_signature_value_base64_returns_decode_error() { let err = verify_signature_with_pem_key(&tampered_xml, &public_key_pem, false) .expect_err("malformed SignatureValue base64 must fail decode stage"); - assert!(matches!( - err, - SignatureVerificationPipelineError::SignatureValueBase64(_) - )); + assert!(matches!(err, DsigError::SignatureValueBase64(_))); } #[test] @@ -428,10 +420,7 @@ fn signature_value_with_non_ascii_whitespace_is_rejected() { let err = verify_signature_with_pem_key(&tampered_xml, &public_key_pem, false) .expect_err("non-XML whitespace in SignatureValue must fail base64 decode"); - assert!(matches!( - err, - SignatureVerificationPipelineError::SignatureValueBase64(_) - )); + assert!(matches!(err, DsigError::SignatureValueBase64(_))); } #[test] @@ -494,7 +483,7 @@ fn missing_signed_info_is_reported_as_missing_element() { .expect_err("missing SignedInfo must be rejected as missing element"); assert!(matches!( err, - SignatureVerificationPipelineError::MissingElement { + DsigError::MissingElement { element: "SignedInfo" } )); @@ -512,7 +501,7 @@ fn non_empty_signature_without_signed_info_is_reported_as_missing_element() { .expect_err("non-empty Signature without SignedInfo must be rejected as missing element"); assert!(matches!( err, - SignatureVerificationPipelineError::MissingElement { + DsigError::MissingElement { element: "SignedInfo" } )); @@ -531,7 +520,7 @@ fn signature_value_only_without_signed_info_reports_missing_element() { .expect_err("Signature without SignedInfo must report missing SignedInfo"); assert!(matches!( err, - SignatureVerificationPipelineError::MissingElement { + DsigError::MissingElement { element: "SignedInfo" } )); @@ -552,7 +541,7 @@ fn multiple_signature_elements_are_rejected() { .expect_err("documents with multiple Signature elements must be rejected"); assert!(matches!( err, - SignatureVerificationPipelineError::InvalidStructure { + DsigError::InvalidStructure { reason: "Signature must appear exactly once in document", } ));