use super::{Jwk, JwsAlgorithm, VerificationError};
pub trait JwsVerifier: Send + Sync {
fn verify(
&self,
alg: JwsAlgorithm,
signing_input: &[u8],
signature: &[u8],
key: &Jwk,
) -> Result<(), VerificationError>;
}
impl<T: JwsVerifier + ?Sized> JwsVerifier for &T {
fn verify(
&self,
alg: JwsAlgorithm,
signing_input: &[u8],
signature: &[u8],
key: &Jwk,
) -> Result<(), VerificationError> {
(**self).verify(alg, signing_input, signature, key)
}
}
impl<T: JwsVerifier + ?Sized> JwsVerifier for Box<T> {
fn verify(
&self,
alg: JwsAlgorithm,
signing_input: &[u8],
signature: &[u8],
key: &Jwk,
) -> Result<(), VerificationError> {
(**self).verify(alg, signing_input, signature, key)
}
}
impl<T: JwsVerifier + ?Sized> JwsVerifier for std::sync::Arc<T> {
fn verify(
&self,
alg: JwsAlgorithm,
signing_input: &[u8],
signature: &[u8],
key: &Jwk,
) -> Result<(), VerificationError> {
(**self).verify(alg, signing_input, signature, key)
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct DefaultVerifier;
impl JwsVerifier for DefaultVerifier {
fn verify(
&self,
alg: JwsAlgorithm,
signing_input: &[u8],
signature: &[u8],
key: &Jwk,
) -> Result<(), VerificationError> {
check_key_restrictions(alg, key)?;
match alg {
JwsAlgorithm::EdDSA => {
let verifying_key = key.ed25519_verifying_key()?;
let signature = ed25519_dalek::Signature::from_bytes(fixed_size::<64>(signature)?);
verifying_key
.verify_strict(signing_input, &signature)
.map_err(|_| VerificationError::InvalidSignature)
}
JwsAlgorithm::ES256 => {
use p256::ecdsa::signature::Verifier as _;
let verifying_key = p256::ecdsa::VerifyingKey::from(&key.p256_public_key()?);
let signature = p256::ecdsa::Signature::from_slice(ecdsa_raw::<64>(signature)?)
.map_err(|_| VerificationError::InvalidSignature)?;
verifying_key
.verify(signing_input, &signature)
.map_err(|_| VerificationError::InvalidSignature)
}
#[cfg(feature = "secp256k1")]
JwsAlgorithm::ES256K => {
use k256::ecdsa::signature::Verifier as _;
let verifying_key = k256::ecdsa::VerifyingKey::from(&key.secp256k1_public_key()?);
let signature = k256::ecdsa::Signature::from_slice(ecdsa_raw::<64>(signature)?)
.map_err(|_| VerificationError::InvalidSignature)?;
verifying_key
.verify(signing_input, &signature)
.map_err(|_| VerificationError::InvalidSignature)
}
#[cfg(feature = "rsa")]
JwsAlgorithm::RS256 => {
use rsa::signature::Verifier as _;
let public_key = key.rsa_public_key()?;
let signature =
rsa::pkcs1v15::Signature::try_from(rsa_sized(&public_key, signature)?)
.map_err(|_| VerificationError::InvalidSignature)?;
rsa::pkcs1v15::VerifyingKey::<sha2::Sha256>::new(public_key)
.verify(signing_input, &signature)
.map_err(|_| VerificationError::InvalidSignature)
}
#[cfg(feature = "rsa")]
JwsAlgorithm::PS256 => {
use rsa::signature::Verifier as _;
let public_key = key.rsa_public_key()?;
let signature = rsa::pss::Signature::try_from(rsa_sized(&public_key, signature)?)
.map_err(|_| VerificationError::InvalidSignature)?;
rsa::pss::VerifyingKey::<sha2::Sha256>::new(public_key)
.verify(signing_input, &signature)
.map_err(|_| VerificationError::InvalidSignature)
}
other => Err(VerificationError::UnsupportedAlgorithm(other)),
}
}
}
fn check_key_restrictions(alg: JwsAlgorithm, key: &Jwk) -> Result<(), VerificationError> {
match key.alg() {
Some(key_alg) if key_alg != alg.as_str() => {
return Err(VerificationError::AlgorithmMismatch {
alg,
key_alg: key_alg.to_owned(),
});
}
_ => {}
}
if key.key_use().is_some_and(|key_use| key_use != "sig") {
return Err(VerificationError::KeyUse("`use` is not `sig`"));
}
if key
.key_ops()
.is_some_and(|key_ops| !key_ops.iter().any(|op| op == "verify"))
{
return Err(VerificationError::KeyUse("`key_ops` lacks `verify`"));
}
Ok(())
}
fn fixed_size<const N: usize>(signature: &[u8]) -> Result<&[u8; N], VerificationError> {
signature
.try_into()
.map_err(|_| VerificationError::InvalidSignatureLength {
expected: N,
actual: signature.len(),
})
}
#[cfg(feature = "rsa")]
fn rsa_sized<'a>(
key: &rsa::RsaPublicKey,
signature: &'a [u8],
) -> Result<&'a [u8], VerificationError> {
use rsa::traits::PublicKeyParts as _;
let expected = key.size();
if signature.len() != expected {
return Err(VerificationError::InvalidSignatureLength {
expected,
actual: signature.len(),
});
}
Ok(signature)
}
fn ecdsa_raw<const N: usize>(signature: &[u8]) -> Result<&[u8; N], VerificationError> {
if signature.len() != N && signature.first() == Some(&0x30) {
return Err(VerificationError::DerEncodedSignature);
}
fixed_size::<N>(signature)
}