use openssl::{
hash::MessageDigest,
pkey::PKey,
rsa::{Padding, Rsa},
sign::{RsaPssSaltlen, Verifier},
};
use crate::{RawSignatureValidationError, RawSignatureValidator, openssl::OpenSslMutex};
pub(crate) enum RsaValidator {
Ps256,
Ps384,
Ps512,
}
impl RawSignatureValidator for RsaValidator {
fn validate(
&self,
sig: &[u8],
data: &[u8],
public_key: &[u8],
) -> Result<(), RawSignatureValidationError> {
let _openssl = OpenSslMutex::acquire()?;
let rsa = Rsa::public_key_from_der(public_key)?;
let n = rsa.n().to_owned()?;
let e = rsa.e().to_owned()?;
let new_rsa = Rsa::from_public_components(n, e)?;
let public_key = PKey::from_rsa(new_rsa)?;
let mut verifier = match self {
Self::Ps256 => {
let mut verifier = Verifier::new(MessageDigest::sha256(), &public_key)?;
verifier.set_rsa_padding(Padding::PKCS1_PSS)?;
verifier.set_rsa_mgf1_md(MessageDigest::sha256())?;
verifier.set_rsa_pss_saltlen(RsaPssSaltlen::DIGEST_LENGTH)?;
verifier
}
Self::Ps384 => {
let mut verifier = Verifier::new(MessageDigest::sha384(), &public_key)?;
verifier.set_rsa_padding(Padding::PKCS1_PSS)?;
verifier.set_rsa_mgf1_md(MessageDigest::sha384())?;
verifier.set_rsa_pss_saltlen(RsaPssSaltlen::DIGEST_LENGTH)?;
verifier
}
Self::Ps512 => {
let mut verifier = Verifier::new(MessageDigest::sha512(), &public_key)?;
verifier.set_rsa_padding(Padding::PKCS1_PSS)?;
verifier.set_rsa_mgf1_md(MessageDigest::sha512())?;
verifier.set_rsa_pss_saltlen(RsaPssSaltlen::DIGEST_LENGTH)?;
verifier
}
};
if verifier.verify_oneshot(sig, data)? {
Ok(())
} else {
Err(RawSignatureValidationError::SignatureMismatch)
}
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
const SAMPLE_DATA: &[u8] = b"some sample content to sign";
#[test]
fn unparseable_public_key_is_crypto_error() {
let sig = include_bytes!("../../../tests/fixtures/raw_signature/ps256.raw_sig");
let err = RsaValidator::Ps256
.validate(sig, SAMPLE_DATA, &[0x00, 0x01, 0x02])
.unwrap_err();
assert!(matches!(
err,
RawSignatureValidationError::CryptoLibraryError(_)
));
}
}