use bergshamra_dsig::{verify::verify, DsigContext, VerifyResult};
use bergshamra_keys::{KeyUsage, KeysManager};
use crate::crypto::error::CryptoError;
pub struct SamlVerifier {
keys_manager: KeysManager,
reject_ds_object: bool,
trusted_keys_only: bool,
strict_verification: bool,
skip_time_checks: bool,
hmac_min_out_len: usize,
}
impl SamlVerifier {
pub fn new(keys_manager: KeysManager) -> Self {
Self {
keys_manager,
reject_ds_object: true,
trusted_keys_only: true,
strict_verification: true,
skip_time_checks: false,
hmac_min_out_len: 128,
}
}
pub fn with_ds_object_rejection(keys_manager: KeysManager, reject_ds_object: bool) -> Self {
Self {
keys_manager,
reject_ds_object,
trusted_keys_only: true,
strict_verification: true,
skip_time_checks: false,
hmac_min_out_len: 128,
}
}
pub fn set_skip_time_checks(&mut self, skip: bool) {
self.skip_time_checks = skip;
}
pub fn set_trusted_keys_only(&mut self, trusted: bool) {
self.trusted_keys_only = trusted;
}
pub fn set_strict_verification(&mut self, strict: bool) {
self.strict_verification = strict;
}
pub fn set_hmac_min_out_len(&mut self, bits: usize) {
self.hmac_min_out_len = bits;
}
pub fn verify_enveloped(&self, signed_xml: &str) -> Result<VerifyResult, CryptoError> {
if self.reject_ds_object && signed_xml.contains("<ds:Object") {
return Err(CryptoError::SignatureContainsDsObject);
}
let mut ctx = DsigContext::new(self.keys_manager.clone());
ctx.trusted_keys_only = self.trusted_keys_only;
ctx.strict_verification = self.strict_verification;
ctx.skip_time_checks = self.skip_time_checks;
ctx.hmac_min_out_len = self.hmac_min_out_len;
let result = verify(&ctx, signed_xml)?;
Ok(result)
}
pub fn verify_redirect_query(
&self,
query_string: &[u8],
signature: &[u8],
algorithm_uri: &str,
) -> Result<bool, CryptoError> {
let sig_alg = bergshamra_crypto::sign::from_uri(algorithm_uri)
.map_err(CryptoError::BergshamraError)?;
let key = self
.keys_manager
.find_by_usage(KeyUsage::Verify)
.ok_or_else(|| CryptoError::KeyNotFound("No verification key found".to_string()))?;
let signing_key = key.to_signing_key().ok_or_else(|| {
CryptoError::KeyNotFound("Key cannot be used for verification".to_string())
})?;
let valid = sig_alg
.verify(&signing_key, query_string, signature)
.map_err(CryptoError::BergshamraError)?;
Ok(valid)
}
pub fn keys_manager(&self) -> &KeysManager {
&self.keys_manager
}
}