use crate::cms::envelope::CmsError;
use crate::cms::signed_data::SignedData;
#[derive(Debug, Clone, Default)]
pub struct VerificationResult {
pub all_verified: bool,
pub per_signer: Vec<SignerVerification>,
}
#[derive(Debug, Clone)]
pub struct SignerVerification {
pub signer_index: usize,
pub verified: bool,
pub error: Option<String>,
}
pub fn verify_signed_data<F>(
signed_data: &SignedData,
payload: &[u8],
verifier: F,
) -> Result<VerificationResult, CmsError>
where
F: Fn(usize, &[u8], &[u8], &[u8]) -> Result<(), String>,
{
let mut all_verified = true;
let mut per_signer = Vec::new();
for (i, signer) in signed_data.signer_infos.iter().enumerate() {
let cert_der = signed_data
.certificates
.first()
.cloned()
.unwrap_or_default();
let pubkey = cert_der.as_slice();
let signed_bytes = if signed_data.encap_content_info.content.is_some() {
signed_data.encap_content_info.content.clone().unwrap_or_default()
} else {
payload.to_vec()
};
match verifier(i, pubkey, &signed_bytes, &signer.signature) {
Ok(()) => per_signer.push(SignerVerification {
signer_index: i,
verified: true,
error: None,
}),
Err(e) => {
all_verified = false;
per_signer.push(SignerVerification {
signer_index: i,
verified: false,
error: Some(e),
});
}
}
}
Ok(VerificationResult {
all_verified,
per_signer,
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cms::envelope::build_detached_signature;
#[test]
fn verify_with_accepting_callback_passes() {
let sd = build_detached_signature(
vec![0u8; 32],
"1.2.840.113549.1.1.11",
vec![0u8; 256],
vec![vec![0u8; 100]],
)
.unwrap();
let result = verify_signed_data(&sd, b"hello", |_, _, _, _| Ok(())).unwrap();
assert!(result.all_verified);
assert_eq!(result.per_signer.len(), 1);
}
#[test]
fn verify_with_rejecting_callback_fails() {
let sd = build_detached_signature(
vec![0u8; 32],
"1.2.840.113549.1.1.11",
vec![0u8; 256],
vec![vec![0u8; 100]],
)
.unwrap();
let result = verify_signed_data(&sd, b"hello", |_, _, _, _| Err("bad".into())).unwrap();
assert!(!result.all_verified);
assert_eq!(result.per_signer[0].error.as_deref(), Some("bad"));
}
}