use crate::crypto::algorithm::{
OID_ECDSA_WITH_SHA1, OID_ED25519, OID_MD5_WITH_RSA, OID_RSASSA_PSS, OID_SHA1_WITH_RSA,
OID_SHA224_WITH_RSA,
};
use crate::error::TrustError;
pub fn verify_signature_by_oid(
tbs_bytes: &[u8],
signature_bytes: &[u8],
spki_der: &[u8],
sig_alg_oid: &const_oid::ObjectIdentifier,
) -> Result<(), TrustError> {
use const_oid::db;
if *sig_alg_oid == OID_MD5_WITH_RSA {
verify_rsa_signature::<md5::Md5>(tbs_bytes, signature_bytes, spki_der)
} else if *sig_alg_oid == OID_SHA1_WITH_RSA {
verify_rsa_signature::<sha1::Sha1>(tbs_bytes, signature_bytes, spki_der)
} else if *sig_alg_oid == OID_SHA224_WITH_RSA {
verify_rsa_signature::<sha2::Sha224>(tbs_bytes, signature_bytes, spki_der)
}
else if *sig_alg_oid == db::rfc5912::SHA_256_WITH_RSA_ENCRYPTION {
verify_rsa_signature::<sha2::Sha256>(tbs_bytes, signature_bytes, spki_der)
} else if *sig_alg_oid == db::rfc5912::SHA_384_WITH_RSA_ENCRYPTION {
verify_rsa_signature::<sha2::Sha384>(tbs_bytes, signature_bytes, spki_der)
} else if *sig_alg_oid == db::rfc5912::SHA_512_WITH_RSA_ENCRYPTION {
verify_rsa_signature::<sha2::Sha512>(tbs_bytes, signature_bytes, spki_der)
} else if *sig_alg_oid == OID_RSASSA_PSS {
verify_rsa_pss_signature::<sha2::Sha256>(tbs_bytes, signature_bytes, spki_der)
.or_else(|_| {
verify_rsa_pss_signature::<sha2::Sha384>(tbs_bytes, signature_bytes, spki_der)
})
.or_else(|_| {
verify_rsa_pss_signature::<sha2::Sha512>(tbs_bytes, signature_bytes, spki_der)
})
}
else if *sig_alg_oid == OID_ECDSA_WITH_SHA1 {
verify_ecdsa_p256_sha1_signature(tbs_bytes, signature_bytes, spki_der)
.or_else(|_| verify_ecdsa_p384_sha1_signature(tbs_bytes, signature_bytes, spki_der))
}
else if *sig_alg_oid == db::rfc5912::ECDSA_WITH_SHA_256 {
verify_ecdsa_p256_signature(tbs_bytes, signature_bytes, spki_der)
.or_else(|_| verify_ecdsa_p384_signature(tbs_bytes, signature_bytes, spki_der))
.or_else(|_| verify_ecdsa_p521_sha256_signature(tbs_bytes, signature_bytes, spki_der))
} else if *sig_alg_oid == db::rfc5912::ECDSA_WITH_SHA_384 {
verify_ecdsa_p384_signature(tbs_bytes, signature_bytes, spki_der)
.or_else(|_| verify_ecdsa_p256_signature(tbs_bytes, signature_bytes, spki_der))
.or_else(|_| verify_ecdsa_p521_sha384_signature(tbs_bytes, signature_bytes, spki_der))
} else if *sig_alg_oid == db::rfc5912::ECDSA_WITH_SHA_512 {
verify_ecdsa_p521_signature(tbs_bytes, signature_bytes, spki_der)
.or_else(|_| verify_ecdsa_p384_signature(tbs_bytes, signature_bytes, spki_der))
} else if *sig_alg_oid == OID_ED25519 {
verify_ed25519_signature(tbs_bytes, signature_bytes, spki_der)
} else {
Err(TrustError::UnsupportedAlgorithm(format!(
"signature algorithm OID: {sig_alg_oid}"
)))
}
}
pub fn verify_certificate_signature(
cert: &x509_cert::Certificate,
issuer: &x509_cert::Certificate,
) -> Result<(), TrustError> {
use der::Encode;
let issuer_spki = &issuer.tbs_certificate.subject_public_key_info;
let tbs_bytes = cert
.tbs_certificate
.to_der()
.map_err(|e| TrustError::SignatureVerification(format!("TBS encoding failed: {e}")))?;
let signature_bytes = cert.signature.raw_bytes();
let sig_alg_oid = &cert.signature_algorithm.oid;
let spki_der = issuer_spki
.to_der()
.map_err(|e| TrustError::SignatureVerification(format!("SPKI encoding failed: {e}")))?;
verify_signature_by_oid(&tbs_bytes, signature_bytes, &spki_der, sig_alg_oid)
}
pub fn verify_rsa_signature<D: digest::Digest + const_oid::AssociatedOid>(
tbs: &[u8],
sig: &[u8],
spki_der: &[u8],
) -> Result<(), TrustError> {
use der::Decode;
use rsa::pkcs1v15::Pkcs1v15Sign;
use rsa::RsaPublicKey;
use spki::SubjectPublicKeyInfoRef;
let spki = SubjectPublicKeyInfoRef::from_der(spki_der)
.map_err(|e| TrustError::SignatureVerification(format!("SPKI decode failed: {e}")))?;
let pub_key = RsaPublicKey::try_from(spki)
.map_err(|e| TrustError::SignatureVerification(format!("RSA key decode failed: {e}")))?;
let hash = D::digest(tbs);
let scheme = Pkcs1v15Sign::new::<D>();
pub_key
.verify(scheme, &hash, sig)
.map_err(|e| TrustError::SignatureVerification(format!("RSA signature invalid: {e}")))
}
pub fn verify_rsa_pss_signature<
D: digest::Digest + digest::FixedOutputReset + Default + Clone + Send + Sync + 'static,
>(
tbs: &[u8],
sig: &[u8],
spki_der: &[u8],
) -> Result<(), TrustError> {
use der::Decode;
use rsa::pss::Pss;
use rsa::RsaPublicKey;
use spki::SubjectPublicKeyInfoRef;
let spki = SubjectPublicKeyInfoRef::from_der(spki_der)
.map_err(|e| TrustError::SignatureVerification(format!("SPKI decode failed: {e}")))?;
let pub_key = RsaPublicKey::try_from(spki)
.map_err(|e| TrustError::SignatureVerification(format!("RSA key decode failed: {e}")))?;
let hash = D::digest(tbs);
let scheme = Pss::new::<D>();
pub_key
.verify(scheme, &hash, sig)
.map_err(|e| TrustError::SignatureVerification(format!("RSA-PSS signature invalid: {e}")))
}
pub fn verify_ecdsa_p256_signature(
tbs: &[u8],
sig: &[u8],
spki_der: &[u8],
) -> Result<(), TrustError> {
use der::Decode;
use p256::ecdsa::{signature::Verifier, Signature, VerifyingKey};
use spki::SubjectPublicKeyInfoRef;
let spki = SubjectPublicKeyInfoRef::from_der(spki_der)
.map_err(|e| TrustError::SignatureVerification(format!("SPKI decode failed: {e}")))?;
let vk = VerifyingKey::try_from(spki)
.map_err(|e| TrustError::SignatureVerification(format!("P-256 key decode failed: {e}")))?;
let signature = Signature::from_der(sig)
.map_err(|e| TrustError::SignatureVerification(format!("P-256 sig decode failed: {e}")))?;
vk.verify(tbs, &signature)
.map_err(|e| TrustError::SignatureVerification(format!("ECDSA P-256 invalid: {e}")))
}
pub fn verify_ecdsa_p384_signature(
tbs: &[u8],
sig: &[u8],
spki_der: &[u8],
) -> Result<(), TrustError> {
use der::Decode;
use p384::ecdsa::{signature::Verifier, Signature, VerifyingKey};
use spki::SubjectPublicKeyInfoRef;
let spki = SubjectPublicKeyInfoRef::from_der(spki_der)
.map_err(|e| TrustError::SignatureVerification(format!("SPKI decode failed: {e}")))?;
let vk = VerifyingKey::try_from(spki)
.map_err(|e| TrustError::SignatureVerification(format!("P-384 key decode failed: {e}")))?;
let signature = Signature::from_der(sig)
.map_err(|e| TrustError::SignatureVerification(format!("P-384 sig decode failed: {e}")))?;
vk.verify(tbs, &signature)
.map_err(|e| TrustError::SignatureVerification(format!("ECDSA P-384 invalid: {e}")))
}
pub fn verify_ecdsa_p521_signature(
tbs: &[u8],
sig: &[u8],
spki_der: &[u8],
) -> Result<(), TrustError> {
use der::Decode;
use ecdsa::signature::hazmat::PrehashVerifier;
use sha2::Digest as _;
use spki::SubjectPublicKeyInfoRef;
let spki = SubjectPublicKeyInfoRef::from_der(spki_der)
.map_err(|e| TrustError::SignatureVerification(format!("SPKI decode failed: {e}")))?;
let vk = ecdsa::VerifyingKey::<p521::NistP521>::try_from(spki)
.map_err(|e| TrustError::SignatureVerification(format!("P-521 key decode failed: {e}")))?;
let signature = ecdsa::Signature::<p521::NistP521>::from_der(sig)
.map_err(|e| TrustError::SignatureVerification(format!("P-521 sig decode failed: {e}")))?;
let hash = sha2::Sha512::digest(tbs);
vk.verify_prehash(&hash, &signature)
.map_err(|e| TrustError::SignatureVerification(format!("ECDSA P-521 invalid: {e}")))
}
pub fn verify_ecdsa_p521_sha256_signature(
tbs: &[u8],
sig: &[u8],
spki_der: &[u8],
) -> Result<(), TrustError> {
use der::Decode;
use ecdsa::signature::hazmat::PrehashVerifier;
use sha2::Digest as _;
use spki::SubjectPublicKeyInfoRef;
let spki = SubjectPublicKeyInfoRef::from_der(spki_der)
.map_err(|e| TrustError::SignatureVerification(format!("SPKI decode failed: {e}")))?;
let vk = ecdsa::VerifyingKey::<p521::NistP521>::try_from(spki)
.map_err(|e| TrustError::SignatureVerification(format!("P-521 key decode failed: {e}")))?;
let signature = ecdsa::Signature::<p521::NistP521>::from_der(sig)
.map_err(|e| TrustError::SignatureVerification(format!("P-521 sig decode failed: {e}")))?;
let hash = sha2::Sha256::digest(tbs);
let mut padded = vec![0u8; 66];
padded[66 - 32..].copy_from_slice(&hash);
vk.verify_prehash(&padded, &signature)
.map_err(|e| TrustError::SignatureVerification(format!("ECDSA P-521/SHA-256 invalid: {e}")))
}
pub fn verify_ecdsa_p521_sha384_signature(
tbs: &[u8],
sig: &[u8],
spki_der: &[u8],
) -> Result<(), TrustError> {
use der::Decode;
use ecdsa::signature::hazmat::PrehashVerifier;
use sha2::Digest as _;
use spki::SubjectPublicKeyInfoRef;
let spki = SubjectPublicKeyInfoRef::from_der(spki_der)
.map_err(|e| TrustError::SignatureVerification(format!("SPKI decode failed: {e}")))?;
let vk = ecdsa::VerifyingKey::<p521::NistP521>::try_from(spki)
.map_err(|e| TrustError::SignatureVerification(format!("P-521 key decode failed: {e}")))?;
let signature = ecdsa::Signature::<p521::NistP521>::from_der(sig)
.map_err(|e| TrustError::SignatureVerification(format!("P-521 sig decode failed: {e}")))?;
let hash = sha2::Sha384::digest(tbs);
vk.verify_prehash(&hash, &signature)
.map_err(|e| TrustError::SignatureVerification(format!("ECDSA P-521/SHA-384 invalid: {e}")))
}
pub fn verify_ecdsa_p256_sha1_signature(
tbs: &[u8],
sig: &[u8],
spki_der: &[u8],
) -> Result<(), TrustError> {
use der::Decode;
use ecdsa::signature::hazmat::PrehashVerifier;
use sha1::Digest as _;
use spki::SubjectPublicKeyInfoRef;
let spki = SubjectPublicKeyInfoRef::from_der(spki_der)
.map_err(|e| TrustError::SignatureVerification(format!("SPKI decode failed: {e}")))?;
let vk = p256::ecdsa::VerifyingKey::try_from(spki)
.map_err(|e| TrustError::SignatureVerification(format!("P-256 key decode failed: {e}")))?;
let signature = p256::ecdsa::Signature::from_der(sig)
.map_err(|e| TrustError::SignatureVerification(format!("P-256 sig decode failed: {e}")))?;
let hash = sha1::Sha1::digest(tbs);
vk.verify_prehash(&hash, &signature)
.map_err(|e| TrustError::SignatureVerification(format!("ECDSA P-256/SHA-1 invalid: {e}")))
}
pub fn verify_ecdsa_p384_sha1_signature(
tbs: &[u8],
sig: &[u8],
spki_der: &[u8],
) -> Result<(), TrustError> {
use der::Decode;
use ecdsa::signature::hazmat::PrehashVerifier;
use sha1::Digest as _;
use spki::SubjectPublicKeyInfoRef;
let spki = SubjectPublicKeyInfoRef::from_der(spki_der)
.map_err(|e| TrustError::SignatureVerification(format!("SPKI decode failed: {e}")))?;
let vk = p384::ecdsa::VerifyingKey::try_from(spki)
.map_err(|e| TrustError::SignatureVerification(format!("P-384 key decode failed: {e}")))?;
let signature = p384::ecdsa::Signature::from_der(sig)
.map_err(|e| TrustError::SignatureVerification(format!("P-384 sig decode failed: {e}")))?;
let hash = sha1::Sha1::digest(tbs);
vk.verify_prehash(&hash, &signature)
.map_err(|e| TrustError::SignatureVerification(format!("ECDSA P-384/SHA-1 invalid: {e}")))
}
pub fn verify_ed25519_signature(tbs: &[u8], sig: &[u8], spki_der: &[u8]) -> Result<(), TrustError> {
use der::Decode;
use ed25519_dalek::{Signature, Verifier, VerifyingKey};
let spki = spki::SubjectPublicKeyInfoRef::from_der(spki_der)
.map_err(|e| TrustError::SignatureVerification(format!("SPKI decode failed: {e}")))?;
let key_bytes = spki.subject_public_key.raw_bytes();
let vk = VerifyingKey::try_from(key_bytes)
.map_err(|e| TrustError::SignatureVerification(format!("Ed25519 key decode: {e}")))?;
let signature = Signature::from_slice(sig)
.map_err(|e| TrustError::SignatureVerification(format!("Ed25519 sig decode: {e}")))?;
vk.verify(tbs, &signature)
.map_err(|e| TrustError::SignatureVerification(format!("Ed25519 invalid: {e}")))
}
#[cfg(test)]
mod tests {
use super::*;
use der::Decode;
use x509_cert::Certificate;
fn load_test_cert(pem_str: &str) -> Certificate {
let (_, der) = pem_rfc7468::decode_vec(pem_str.as_bytes()).unwrap();
Certificate::from_der(&der).unwrap()
}
#[test]
fn test_verify_certificate_signature_ca_self_signed() {
let ca_pem = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/fixtures/ca_cert.pem"
));
let ca = load_test_cert(ca_pem);
let result = verify_certificate_signature(&ca, &ca);
assert!(
result.is_ok(),
"CA self-signature should verify: {result:?}"
);
}
#[test]
fn test_verify_certificate_signature_chain() {
let ca_pem = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/fixtures/ca_cert.pem"
));
let intermediate_pem = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/fixtures/intermediate_ca_cert.pem"
));
let signer_pem = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/fixtures/signer_cert.pem"
));
let ca = load_test_cert(ca_pem);
let intermediate = load_test_cert(intermediate_pem);
let signer = load_test_cert(signer_pem);
let result = verify_certificate_signature(&signer, &intermediate);
assert!(
result.is_ok(),
"signer cert should verify against intermediate: {result:?}"
);
let result = verify_certificate_signature(&intermediate, &ca);
assert!(
result.is_ok(),
"intermediate cert should verify against CA: {result:?}"
);
}
#[test]
fn test_verify_certificate_signature_wrong_issuer() {
let signer_pem = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/fixtures/signer_cert.pem"
));
let signer = load_test_cert(signer_pem);
let result = verify_certificate_signature(&signer, &signer);
assert!(result.is_err(), "wrong issuer should fail verification");
}
#[test]
fn test_unsupported_algorithm_oid() {
let fake_oid = const_oid::ObjectIdentifier::new_unwrap("1.2.3.4.5.6.7.8.9");
let result = verify_signature_by_oid(b"tbs", b"sig", b"spki", &fake_oid);
assert!(result.is_err());
let err_msg = format!("{}", result.unwrap_err());
assert!(
err_msg.contains("unsupported"),
"error should mention unsupported: {err_msg}"
);
}
#[test]
fn test_rsassa_pss_oid_dispatches() {
let pss_oid = OID_RSASSA_PSS;
let result = verify_signature_by_oid(b"tbs", b"sig", b"bad_spki", &pss_oid);
assert!(result.is_err());
let err_msg = format!("{}", result.unwrap_err());
assert!(
!err_msg.contains("unsupported"),
"RSA-PSS should be dispatched, not unsupported: {err_msg}"
);
}
#[test]
fn test_ed25519_oid_dispatches() {
let ed_oid = OID_ED25519;
let result = verify_signature_by_oid(b"tbs", b"sig", b"bad_spki", &ed_oid);
assert!(result.is_err());
let err_msg = format!("{}", result.unwrap_err());
assert!(
!err_msg.contains("unsupported"),
"Ed25519 should be dispatched, not unsupported: {err_msg}"
);
}
}