use crate::metadata::error::MetadataError;
pub struct MetadataSigningProfile;
impl MetadataSigningProfile {
pub fn validate_signature_profile(
signature_xml: &str,
expected_id: &str,
) -> Result<(), MetadataError> {
if signature_xml.contains("<ds:Object") || signature_xml.contains("<Object") {
return Err(MetadataError::SignatureInvalid(
"Signature contains ds:Object element (rejected per E91)".to_string(),
));
}
let expected_uri = format!("#{}", expected_id);
if !signature_xml.contains(&expected_uri) {
return Err(MetadataError::SignatureInvalid(format!(
"Signature Reference URI does not match expected ID '{}'",
expected_id
)));
}
Ok(())
}
pub fn has_ds_object(signature_xml: &str) -> bool {
signature_xml.contains("<ds:Object") || signature_xml.contains("<Object")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_reject_ds_object() {
let sig_with_object = r##"<ds:Signature>
<ds:SignedInfo>
<ds:Reference URI="#_entity1"/>
</ds:SignedInfo>
<ds:Object>malicious data</ds:Object>
</ds:Signature>"##;
let result =
MetadataSigningProfile::validate_signature_profile(sig_with_object, "_entity1");
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("ds:Object"));
}
#[test]
fn test_valid_signature_profile() {
let sig = r##"<ds:Signature>
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:Reference URI="#_entity1">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
</ds:Reference>
</ds:SignedInfo>
</ds:Signature>"##;
let result = MetadataSigningProfile::validate_signature_profile(sig, "_entity1");
assert!(result.is_ok());
}
#[test]
fn test_mismatched_reference_uri() {
let sig = r##"<ds:Signature>
<ds:SignedInfo>
<ds:Reference URI="#_wrong_id"/>
</ds:SignedInfo>
</ds:Signature>"##;
let result = MetadataSigningProfile::validate_signature_profile(sig, "_entity1");
assert!(result.is_err());
}
#[test]
fn test_has_ds_object_with_prefix() {
let xml = "<ds:Object>data</ds:Object>";
let result = MetadataSigningProfile::has_ds_object(xml);
assert!(result);
}
#[test]
fn test_has_ds_object_without_prefix() {
let xml = "<Object>data</Object>";
let result = MetadataSigningProfile::has_ds_object(xml);
assert!(result);
}
#[test]
fn test_no_ds_object() {
let xml = "ds:SignedInfo content";
let result = MetadataSigningProfile::has_ds_object(xml);
assert!(!result);
}
}