use crate::der::{Reader, parse_oid};
use crate::ec::{
BoxedEcdsaPublicKey, BoxedEcdsaSignature, CurveId, Ed25519PublicKey, Ed25519Signature,
};
use crate::hash::{Sha256, Sha384, Sha512};
use crate::signature_registry::SignatureAlgorithm;
use crate::x509::{Error, oid};
fn parse_ecdsa_spki(spki: &[u8]) -> Result<(CurveId, BoxedEcdsaPublicKey), Error> {
let mut reader = Reader::new(spki);
let mut outer = reader.read_sequence()?;
let mut algid = outer.read_sequence()?;
let alg = parse_oid(algid.read_oid()?)?;
if alg.as_slice() != oid::EC_PUBLIC_KEY {
return Err(Error::UnsupportedAlgorithm);
}
let curve_arcs = parse_oid(algid.read_oid()?)?;
let curve = if curve_arcs.as_slice() == oid::PRIME256V1 {
CurveId::P256
} else if curve_arcs.as_slice() == oid::SECP384R1 {
CurveId::P384
} else if curve_arcs.as_slice() == oid::SECP521R1 {
CurveId::P521
} else if curve_arcs.as_slice() == oid::SECP256K1 {
CurveId::Secp256k1
} else {
return Err(Error::UnsupportedAlgorithm);
};
let key_bits = outer.read_bit_string()?;
let key = BoxedEcdsaPublicKey::from_sec1(curve, key_bits).map_err(|_| Error::Malformed)?;
Ok((curve, key))
}
fn parse_ed25519_spki(spki: &[u8]) -> Result<Ed25519PublicKey, Error> {
let mut reader = Reader::new(spki);
let mut outer = reader.read_sequence()?;
let mut algid = outer.read_sequence()?;
let alg = parse_oid(algid.read_oid()?)?;
if alg.as_slice() != oid::ID_ED25519 {
return Err(Error::UnsupportedAlgorithm);
}
let key_bits = outer.read_bit_string()?;
let bytes: [u8; 32] = key_bits.try_into().map_err(|_| Error::Malformed)?;
Ok(Ed25519PublicKey::from_bytes(bytes))
}
fn verify_ecdsa_strict<D: crate::hash::Digest>(
spki: &[u8],
message: &[u8],
signature: &[u8],
expected_curve: CurveId,
) -> Result<(), Error> {
let (curve, key) = parse_ecdsa_spki(spki)?;
if curve != expected_curve {
return Err(Error::UnsupportedAlgorithm);
}
let sig = BoxedEcdsaSignature::from_der(signature).map_err(|_| Error::Malformed)?;
key.verify::<D>(message, &sig)
.map_err(|_| Error::Verification)
}
fn verify_ecdsa_any_curve<D: crate::hash::Digest>(
spki: &[u8],
message: &[u8],
signature: &[u8],
) -> Result<(), Error> {
let (_curve, key) = parse_ecdsa_spki(spki)?;
let sig = BoxedEcdsaSignature::from_der(signature).map_err(|_| Error::Malformed)?;
key.verify::<D>(message, &sig)
.map_err(|_| Error::Verification)
}
pub(crate) struct EcdsaSha256AnyCurve;
impl SignatureAlgorithm for EcdsaSha256AnyCurve {
fn id(&self) -> &'static str {
"ecdsa-with-sha256"
}
fn x509_oids(&self) -> &'static [&'static [u64]] {
&[oid::ECDSA_WITH_SHA256]
}
fn tls_schemes(&self) -> &'static [u16] {
&[]
}
fn verify(&self, spki: &[u8], message: &[u8], signature: &[u8]) -> Result<(), Error> {
verify_ecdsa_any_curve::<Sha256>(spki, message, signature)
}
}
pub(crate) struct EcdsaSha384AnyCurve;
impl SignatureAlgorithm for EcdsaSha384AnyCurve {
fn id(&self) -> &'static str {
"ecdsa-with-sha384"
}
fn x509_oids(&self) -> &'static [&'static [u64]] {
&[oid::ECDSA_WITH_SHA384]
}
fn tls_schemes(&self) -> &'static [u16] {
&[]
}
fn verify(&self, spki: &[u8], message: &[u8], signature: &[u8]) -> Result<(), Error> {
verify_ecdsa_any_curve::<Sha384>(spki, message, signature)
}
}
pub(crate) struct EcdsaSha512AnyCurve;
impl SignatureAlgorithm for EcdsaSha512AnyCurve {
fn id(&self) -> &'static str {
"ecdsa-with-sha512"
}
fn x509_oids(&self) -> &'static [&'static [u64]] {
&[oid::ECDSA_WITH_SHA512]
}
fn tls_schemes(&self) -> &'static [u16] {
&[]
}
fn verify(&self, spki: &[u8], message: &[u8], signature: &[u8]) -> Result<(), Error> {
verify_ecdsa_any_curve::<Sha512>(spki, message, signature)
}
}
macro_rules! strict_ecdsa_entry {
(
$(#[$m:meta])*
$name:ident, $id:expr, $curve:expr, $digest:ty, $tls_schemes:expr
) => {
$(#[$m])*
pub(crate) struct $name;
impl SignatureAlgorithm for $name {
fn id(&self) -> &'static str { $id }
fn x509_oids(&self) -> &'static [&'static [u64]] { &[] }
fn tls_schemes(&self) -> &'static [u16] { $tls_schemes }
fn verify(&self, spki: &[u8], message: &[u8], signature: &[u8]) -> Result<(), Error> {
verify_ecdsa_strict::<$digest>(spki, message, signature, $curve)
}
}
};
}
strict_ecdsa_entry!(
EcdsaP256Sha256, "ecdsa-secp256r1-sha256", CurveId::P256, Sha256, &[0x0403]
);
strict_ecdsa_entry!(
EcdsaP384Sha384, "ecdsa-secp384r1-sha384", CurveId::P384, Sha384, &[0x0503]
);
strict_ecdsa_entry!(
EcdsaP521Sha512, "ecdsa-secp521r1-sha512", CurveId::P521, Sha512, &[0x0603]
);
strict_ecdsa_entry!(
EcdsaP256Sha384, "ecdsa-secp256r1-sha384", CurveId::P256, Sha384, &[]
);
strict_ecdsa_entry!(
EcdsaP256Sha512, "ecdsa-secp256r1-sha512", CurveId::P256, Sha512, &[]
);
strict_ecdsa_entry!(
EcdsaP384Sha256, "ecdsa-secp384r1-sha256", CurveId::P384, Sha256, &[]
);
strict_ecdsa_entry!(
EcdsaP384Sha512, "ecdsa-secp384r1-sha512", CurveId::P384, Sha512, &[]
);
strict_ecdsa_entry!(
EcdsaP521Sha256, "ecdsa-secp521r1-sha256", CurveId::P521, Sha256, &[]
);
strict_ecdsa_entry!(
EcdsaP521Sha384, "ecdsa-secp521r1-sha384", CurveId::P521, Sha384, &[]
);
strict_ecdsa_entry!(
EcdsaSecp256k1Sha256, "ecdsa-secp256k1-sha256", CurveId::Secp256k1, Sha256, &[]
);
strict_ecdsa_entry!(
EcdsaSecp256k1Sha384, "ecdsa-secp256k1-sha384", CurveId::Secp256k1, Sha384, &[]
);
strict_ecdsa_entry!(
EcdsaSecp256k1Sha512, "ecdsa-secp256k1-sha512", CurveId::Secp256k1, Sha512, &[]
);
pub(crate) struct Ed25519;
impl SignatureAlgorithm for Ed25519 {
fn id(&self) -> &'static str {
"ed25519"
}
fn x509_oids(&self) -> &'static [&'static [u64]] {
&[oid::ID_ED25519]
}
fn tls_schemes(&self) -> &'static [u16] {
&[0x0807]
}
fn verify(&self, spki: &[u8], message: &[u8], signature: &[u8]) -> Result<(), Error> {
let key = parse_ed25519_spki(spki)?;
let bytes: [u8; 64] = signature.try_into().map_err(|_| Error::Malformed)?;
key.verify(message, &Ed25519Signature::from_bytes(bytes))
.map_err(|_| Error::Verification)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ec::BoxedEcdsaPrivateKey;
use crate::rng::HmacDrbg;
use crate::signature_registry::{find_by_id, find_by_oid, find_by_tls_scheme};
use crate::x509::AnyPublicKey;
#[test]
fn ecdsa_p256_sha256_verify_via_registry() {
let mut rng = HmacDrbg::<Sha256>::new(b"reg-ec-p256", b"n", &[]);
let sk = BoxedEcdsaPrivateKey::generate(CurveId::P256, &mut rng);
let pk = AnyPublicKey::Ecdsa(sk.public_key());
let spki = pk.to_spki_der();
let sig = sk.sign::<Sha256>(b"hi").unwrap().to_der(CurveId::P256);
let algo = find_by_id("ecdsa-secp256r1-sha256").unwrap();
algo.verify(&spki, b"hi", &sig).unwrap();
assert!(algo.verify(&spki, b"other", &sig).is_err());
let by_oid = find_by_oid(oid::ECDSA_WITH_SHA256).unwrap();
assert_eq!(by_oid.id(), "ecdsa-with-sha256");
let by_scheme = find_by_tls_scheme(0x0403).unwrap();
assert_eq!(by_scheme.id(), "ecdsa-secp256r1-sha256");
}
#[test]
fn ecdsa_p384_curve_mismatch_rejected() {
let mut rng = HmacDrbg::<Sha256>::new(b"reg-ec-p256-2", b"n", &[]);
let sk = BoxedEcdsaPrivateKey::generate(CurveId::P256, &mut rng);
let pk = AnyPublicKey::Ecdsa(sk.public_key());
let spki = pk.to_spki_der();
let sig = sk.sign::<Sha256>(b"hi").unwrap().to_der(CurveId::P256);
let algo = find_by_id("ecdsa-secp384r1-sha384").unwrap();
assert!(algo.verify(&spki, b"hi", &sig).is_err());
}
#[test]
fn secp256k1_verify_via_registry() {
let mut rng = HmacDrbg::<Sha256>::new(b"reg-ec-k1", b"n", &[]);
let sk = BoxedEcdsaPrivateKey::generate(CurveId::Secp256k1, &mut rng);
let pk = AnyPublicKey::Ecdsa(sk.public_key());
let spki = pk.to_spki_der();
let sig = sk.sign::<Sha256>(b"hi").unwrap().to_der(CurveId::Secp256k1);
let algo = find_by_id("ecdsa-secp256k1-sha256").unwrap();
algo.verify(&spki, b"hi", &sig).unwrap();
let any = find_by_id("ecdsa-with-sha256").unwrap();
any.verify(&spki, b"hi", &sig).unwrap();
}
#[test]
fn ed25519_verify_via_registry() {
use crate::ec::Ed25519PrivateKey;
let mut rng = HmacDrbg::<Sha256>::new(b"reg-ed25519", b"n", &[]);
let sk = Ed25519PrivateKey::generate(&mut rng);
let pk = AnyPublicKey::Ed25519(sk.public_key());
let spki = pk.to_spki_der();
let sig = sk.sign(b"hi").to_bytes().to_vec();
let algo = find_by_id("ed25519").unwrap();
algo.verify(&spki, b"hi", &sig).unwrap();
assert!(algo.verify(&spki, b"other", &sig).is_err());
}
}