Open dayday2019 opened 1 year ago
Thank you for your reply! Will you implement this in a near future? I am looking forward to it
You can try out @carl-wallace's crate which implements certificate verification:
https://github.com/carl-wallace/rust-pki/tree/main/certval
Hopefully we can get such work upstream soon
@dayday2019 a very limited implementation. Hope it can be helpful. License: Apache-2 + MIT
Note: it doesn't perform path validation, etc. Just signature checks.
pub fn verify_signature(
cert: &Certificate,
signed_data: &[u8],
signature: &[u8],
algo: &AlgorithmIdentifierOwned,
) -> Result<(), Box<dyn Error>> {
let spki = cert.tbs_certificate.subject_public_key_info.owned_to_ref();
match algo.oid {
OIDdb::rfc5912::SHA_1_WITH_RSA_ENCRYPTION => {
println!("PKCS#1 v1.5 / SHA1 signature");
rsa::pkcs1v15::VerifyingKey::<Sha1>::new(RsaPublicKey::try_from(spki)?)
.verify(signed_data, &signature.try_into()?)?;
}
OIDdb::rfc5912::SHA_256_WITH_RSA_ENCRYPTION => {
println!("PKCS#1 v1.5 / SHA256 signature");
rsa::pkcs1v15::VerifyingKey::<Sha256>::new(RsaPublicKey::try_from(spki)?)
.verify(signed_data, &signature.try_into()?)?;
}
OIDdb::rfc5912::ID_RSASSA_PSS => {
let params = algo
.parameters
.as_ref()
.ok_or("Empty PSS parameters")?
.decode_as::<RsaPssParams>()?;
match params.hash.oid {
OIDdb::rfc5912::ID_SHA_256 => {
println!("PSS / SHA256 signature");
rsa::pss::VerifyingKey::<Sha256>::new(RsaPublicKey::try_from(spki)?)
.verify(signed_data, &signature.try_into()?)?
}
OIDdb::rfc5912::ID_SHA_1 => {
println!("PSS / SHA1 signature");
rsa::pss::VerifyingKey::<Sha1>::new(RsaPublicKey::try_from(spki)?)
.verify(signed_data, &signature.try_into()?)?
}
_ => return Err(format!("Unknown PSS hash algo {}", params.hash.oid).into()),
}
}
OIDdb::rfc5912::ECDSA_WITH_SHA_256 => {
println!("ECDSA P256 signature");
let signature = p256::ecdsa::DerSignature::try_from(signature)?;
p256::ecdsa::VerifyingKey::try_from(spki)?.verify(signed_data, &signature)?;
}
OIDdb::rfc5912::ECDSA_WITH_SHA_384 => {
println!("ECDSA P384 signature");
let signature = p384::ecdsa::DerSignature::try_from(signature)?;
p384::ecdsa::VerifyingKey::try_from(spki)?.verify(signed_data, &signature)?;
}
_ => {
return Err(format!(
"Unknown signature algo {}",
cert.tbs_certificate.signature.oid
)
.into())
}
}
Ok(())
}
pub fn verify_cert_signature(
cert: &Certificate,
signed: &Certificate,
) -> Result<(), Box<dyn Error>> {
if cert.tbs_certificate.subject != signed.tbs_certificate.issuer {
return Err("Certificate issuer does not match".into());
}
let signed_data = signed.tbs_certificate.to_der()?;
let signature = signed
.signature
.as_bytes()
.ok_or("Could not get cert signature")?;
verify_signature(cert, &signed_data, signature, &signed.signature_algorithm)
}
Tying a few related threads together: PyCA Cryptography (i.e. pip install cryptography
) recently merged a pure-Rust X.509 path validator, which we've tested pretty extensively against both other implementations and well-known pathological cases.
The code of that implementation is 100% pure Rust (with a trait abstraction for any backend to provide the crypto), but is tied to PyCA Cryptography's own ASN.1/DER and X.509 libraries. Still, the core approach may be instructive/valuable/reusable for any other Rust implementation ๐
The code is here: https://github.com/pyca/cryptography/tree/main/src/rust/cryptography-x509-verification/src, and can be followed top-down from verify
in lib.rs
.
(I'm happy to answer questions about the implementation as well! Feel free to ping me here or on the RustCrypto Zulip ๐)
@woodruffw x509-limbo
seems interesting for testing!
We donโt implement this yet, sorry. The
x509-cert
crate is still a work in progress