use {
crate::{
rfc3447::RsaPrivateKey, rfc5958::OneAsymmetricKey, EcdsaCurve, KeyAlgorithm,
SignatureAlgorithm, X509CertificateError as Error,
},
bcder::decode::Constructed,
bytes::Bytes,
der::SecretDocument,
ring::{
rand::SystemRandom,
signature::{self as ringsig, KeyPair},
},
signature::{SignatureEncoding as SignatureTrait, Signer},
zeroize::Zeroizing,
};
pub trait Sign {
#[deprecated(since = "0.13.0", note = "use the signature::Signer trait instead")]
fn sign(&self, message: &[u8]) -> Result<(Vec<u8>, SignatureAlgorithm), Error>;
fn key_algorithm(&self) -> Option<KeyAlgorithm>;
fn public_key_data(&self) -> Bytes;
fn signature_algorithm(&self) -> Result<SignatureAlgorithm, Error>;
fn private_key_data(&self) -> Option<Zeroizing<Vec<u8>>>;
fn rsa_primes(&self) -> Result<Option<(Zeroizing<Vec<u8>>, Zeroizing<Vec<u8>>)>, Error>;
}
pub trait KeyInfoSigner: Signer<Signature> + Sign {}
#[derive(Clone, Debug)]
pub struct Signature(Vec<u8>);
impl From<Vec<u8>> for Signature {
fn from(v: Vec<u8>) -> Self {
Self(v)
}
}
impl From<Signature> for Vec<u8> {
fn from(v: Signature) -> Vec<u8> {
v.0
}
}
impl From<Signature> for Bytes {
fn from(v: Signature) -> Self {
Self::copy_from_slice(&v.0)
}
}
impl AsRef<[u8]> for Signature {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl SignatureTrait for Signature {
type Repr = Vec<u8>;
}
impl TryFrom<&[u8]> for Signature {
type Error = ();
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
Ok(Self(value.to_vec()))
}
}
#[derive(Debug)]
pub struct EcdsaKeyPair {
pkcs8_der: SecretDocument,
ring_pair: ringsig::EcdsaKeyPair,
curve: EcdsaCurve,
private_key: Zeroizing<Vec<u8>>,
}
#[derive(Debug)]
pub struct Ed25519KeyPair {
pkcs8_der: SecretDocument,
ring_pair: ringsig::Ed25519KeyPair,
}
#[derive(Debug)]
pub struct RsaKeyPair {
pkcs8_der: SecretDocument,
ring_pair: ringsig::RsaKeyPair,
private_key: Zeroizing<Vec<u8>>,
}
#[derive(Debug)]
pub enum InMemorySigningKeyPair {
Ecdsa(Box<EcdsaKeyPair>),
Ed25519(Box<Ed25519KeyPair>),
Rsa(Box<RsaKeyPair>),
}
impl Signer<Signature> for InMemorySigningKeyPair {
fn try_sign(&self, msg: &[u8]) -> Result<Signature, signature::Error> {
match self {
Self::Rsa(kp) => {
let mut signature = vec![0; kp.ring_pair.public().modulus_len()];
kp.ring_pair
.sign(
&ringsig::RSA_PKCS1_SHA256,
&ring::rand::SystemRandom::new(),
msg,
&mut signature,
)
.map_err(|_| signature::Error::new())?;
Ok(signature.into())
}
Self::Ecdsa(kp) => {
let signature = kp
.ring_pair
.sign(&ring::rand::SystemRandom::new(), msg)
.map_err(|_| signature::Error::new())?;
Ok(Signature::from(signature.as_ref().to_vec()))
}
Self::Ed25519(kp) => {
let signature = kp.ring_pair.sign(msg);
Ok(Signature::from(signature.as_ref().to_vec()))
}
}
}
}
impl Sign for InMemorySigningKeyPair {
fn sign(&self, message: &[u8]) -> Result<(Vec<u8>, SignatureAlgorithm), Error> {
let algorithm = self.signature_algorithm()?;
Ok((self.try_sign(message)?.into(), algorithm))
}
fn key_algorithm(&self) -> Option<KeyAlgorithm> {
Some(match self {
Self::Rsa(_) => KeyAlgorithm::Rsa,
Self::Ed25519(_) => KeyAlgorithm::Ed25519,
Self::Ecdsa(kp) => KeyAlgorithm::Ecdsa(kp.curve),
})
}
fn public_key_data(&self) -> Bytes {
match self {
Self::Rsa(kp) => Bytes::copy_from_slice(kp.ring_pair.public_key().as_ref()),
Self::Ecdsa(kp) => Bytes::copy_from_slice(kp.ring_pair.public_key().as_ref()),
Self::Ed25519(kp) => Bytes::copy_from_slice(kp.ring_pair.public_key().as_ref()),
}
}
fn signature_algorithm(&self) -> Result<SignatureAlgorithm, Error> {
Ok(match self {
Self::Rsa(_) => SignatureAlgorithm::RsaSha256,
Self::Ecdsa(kp) => {
match kp.curve {
EcdsaCurve::Secp256r1 => SignatureAlgorithm::EcdsaSha256,
EcdsaCurve::Secp384r1 => SignatureAlgorithm::EcdsaSha384,
}
}
Self::Ed25519(_) => SignatureAlgorithm::Ed25519,
})
}
fn private_key_data(&self) -> Option<Zeroizing<Vec<u8>>> {
match self {
Self::Rsa(kp) => Some(kp.private_key.clone()),
Self::Ecdsa(kp) => Some(kp.private_key.clone()),
Self::Ed25519(_) => None,
}
}
fn rsa_primes(&self) -> Result<Option<(Zeroizing<Vec<u8>>, Zeroizing<Vec<u8>>)>, Error> {
match self {
Self::Rsa(kp) => {
let key = Constructed::decode(kp.private_key.as_ref(), bcder::Mode::Der, |cons| {
RsaPrivateKey::take_from(cons)
})?;
Ok(Some((
Zeroizing::new(key.p.as_slice().to_vec()),
Zeroizing::new(key.q.as_slice().to_vec()),
)))
}
Self::Ecdsa(_) => Ok(None),
Self::Ed25519(_) => Ok(None),
}
}
}
impl KeyInfoSigner for InMemorySigningKeyPair {}
impl InMemorySigningKeyPair {
pub fn from_pkcs8_der(data: impl AsRef<[u8]>) -> Result<Self, Error> {
let pkcs8_der = SecretDocument::try_from(data.as_ref())?;
let key = Constructed::decode(data.as_ref(), bcder::Mode::Der, |cons| {
OneAsymmetricKey::take_from(cons)
})?;
let algorithm = KeyAlgorithm::try_from(&key.private_key_algorithm)?;
match algorithm {
KeyAlgorithm::Rsa => {
let pair = ringsig::RsaKeyPair::from_pkcs8(data.as_ref())?;
Ok(Self::Rsa(Box::new(RsaKeyPair {
pkcs8_der,
ring_pair: pair,
private_key: Zeroizing::new(key.private_key.into_bytes().to_vec()),
})))
}
KeyAlgorithm::Ecdsa(curve) => {
let pair = ringsig::EcdsaKeyPair::from_pkcs8(
curve.into(),
data.as_ref(),
&SystemRandom::new(),
)?;
Ok(Self::Ecdsa(Box::new(EcdsaKeyPair {
pkcs8_der,
ring_pair: pair,
curve,
private_key: Zeroizing::new(data.as_ref().to_vec()),
})))
}
KeyAlgorithm::Ed25519 => Ok(Self::Ed25519(Box::new(Ed25519KeyPair {
pkcs8_der,
ring_pair: ringsig::Ed25519KeyPair::from_pkcs8(data.as_ref())?,
}))),
}
}
pub fn from_pkcs8_pem(data: impl AsRef<[u8]>) -> Result<Self, Error> {
let der = pem::parse(data.as_ref()).map_err(Error::PemDecode)?;
Self::from_pkcs8_der(der.contents())
}
pub fn generate_random(key_algorithm: KeyAlgorithm) -> Result<Self, Error> {
let rng = SystemRandom::new();
let document = match key_algorithm {
KeyAlgorithm::Ed25519 => ringsig::Ed25519KeyPair::generate_pkcs8(&rng)
.map_err(|_| Error::KeyPairGenerationError),
KeyAlgorithm::Ecdsa(curve) => ringsig::EcdsaKeyPair::generate_pkcs8(curve.into(), &rng)
.map_err(|_| Error::KeyPairGenerationError),
KeyAlgorithm::Rsa => Err(Error::RsaKeyGenerationNotSupported),
}?;
Self::from_pkcs8_der(document.as_ref())
}
pub fn verification_algorithm(
&self,
) -> Result<&'static dyn ringsig::VerificationAlgorithm, Error> {
Ok(self.signature_algorithm()?
.resolve_verification_algorithm(self.key_algorithm().expect("key algorithm should be known for InMemorySigningKeyPair")).expect(
"illegal combination of key algorithm in signature algorithm: this should not occur"
))
}
pub fn to_pkcs8_one_asymmetric_key_der(&self) -> Zeroizing<Vec<u8>> {
match self {
Self::Ecdsa(kp) => kp.pkcs8_der.to_bytes(),
Self::Ed25519(kp) => kp.pkcs8_der.to_bytes(),
Self::Rsa(kp) => kp.pkcs8_der.to_bytes(),
}
}
}
impl From<&InMemorySigningKeyPair> for KeyAlgorithm {
fn from(key: &InMemorySigningKeyPair) -> Self {
match key {
InMemorySigningKeyPair::Rsa(_) => KeyAlgorithm::Rsa,
InMemorySigningKeyPair::Ecdsa(kp) => KeyAlgorithm::Ecdsa(kp.curve),
InMemorySigningKeyPair::Ed25519(_) => KeyAlgorithm::Ed25519,
}
}
}
#[cfg(test)]
mod test {
use {super::*, crate::rfc5280, crate::testutil::*, ringsig::UnparsedPublicKey};
#[test]
fn generate_random_ecdsa() {
for curve in EcdsaCurve::all() {
InMemorySigningKeyPair::generate_random(KeyAlgorithm::Ecdsa(*curve)).unwrap();
}
}
#[test]
fn generate_random_ed25519() {
InMemorySigningKeyPair::generate_random(KeyAlgorithm::Ed25519).unwrap();
}
#[test]
fn generate_random_rsa() {
assert!(InMemorySigningKeyPair::generate_random(KeyAlgorithm::Rsa).is_err());
}
#[test]
fn signing_key_from_ecdsa_pkcs8() {
let rng = ring::rand::SystemRandom::new();
for alg in &[
&ringsig::ECDSA_P256_SHA256_ASN1_SIGNING,
&ringsig::ECDSA_P384_SHA384_ASN1_SIGNING,
] {
let doc = ringsig::EcdsaKeyPair::generate_pkcs8(alg, &rng).unwrap();
let signing_key = InMemorySigningKeyPair::from_pkcs8_der(doc.as_ref()).unwrap();
assert!(matches!(signing_key, InMemorySigningKeyPair::Ecdsa(_,)));
let pem_data = pem::Pem::new("PRIVATE KEY", doc.as_ref()).to_string();
let signing_key = InMemorySigningKeyPair::from_pkcs8_pem(pem_data.as_bytes()).unwrap();
assert!(matches!(signing_key, InMemorySigningKeyPair::Ecdsa(_)));
let key_pair_asn1 = Constructed::decode(doc.as_ref(), bcder::Mode::Der, |cons| {
OneAsymmetricKey::take_from(cons)
})
.unwrap();
assert_eq!(
key_pair_asn1.private_key_algorithm.algorithm,
KeyAlgorithm::Ecdsa(EcdsaCurve::Secp256r1).into()
);
let expected = if *alg == &ringsig::ECDSA_P256_SHA256_ASN1_SIGNING {
EcdsaCurve::Secp256r1
} else if *alg == &ringsig::ECDSA_P384_SHA384_ASN1_SIGNING {
EcdsaCurve::Secp384r1
} else {
panic!("unhandled test case");
};
assert!(key_pair_asn1.private_key_algorithm.parameters.is_some());
let oid = key_pair_asn1
.private_key_algorithm
.parameters
.unwrap()
.decode_oid()
.unwrap();
assert_eq!(EcdsaCurve::try_from(&oid).unwrap(), expected);
}
}
#[test]
fn signing_key_from_ed25519_pkcs8() {
let rng = ring::rand::SystemRandom::new();
let doc = ringsig::Ed25519KeyPair::generate_pkcs8(&rng).unwrap();
let signing_key = InMemorySigningKeyPair::from_pkcs8_der(doc.as_ref()).unwrap();
assert!(matches!(signing_key, InMemorySigningKeyPair::Ed25519(_)));
let pem_data = pem::Pem::new("PRIVATE KEY", doc.as_ref()).to_string();
let signing_key = InMemorySigningKeyPair::from_pkcs8_pem(pem_data.as_bytes()).unwrap();
assert!(matches!(signing_key, InMemorySigningKeyPair::Ed25519(_)));
let key_pair_asn1 = Constructed::decode(doc.as_ref(), bcder::Mode::Der, |cons| {
OneAsymmetricKey::take_from(cons)
})
.unwrap();
assert_eq!(
key_pair_asn1.private_key_algorithm.algorithm,
SignatureAlgorithm::Ed25519.into()
);
assert!(key_pair_asn1.private_key_algorithm.parameters.is_none());
}
#[test]
fn ecdsa_self_signed_certificate_verification() {
for curve in EcdsaCurve::all() {
let (cert, _) = self_signed_ecdsa_key_pair(Some(*curve));
cert.verify_signed_by_certificate(&cert).unwrap();
let raw: &rfc5280::Certificate = cert.as_ref();
let tbs_signature_algorithm =
SignatureAlgorithm::try_from(&raw.tbs_certificate.signature).unwrap();
let expected = match curve {
EcdsaCurve::Secp256r1 => SignatureAlgorithm::EcdsaSha256,
EcdsaCurve::Secp384r1 => SignatureAlgorithm::EcdsaSha384,
};
assert_eq!(tbs_signature_algorithm, expected);
let spki = &raw.tbs_certificate.subject_public_key_info;
assert_eq!(
spki.algorithm.algorithm,
crate::algorithm::OID_EC_PUBLIC_KEY
);
let expected = match curve {
EcdsaCurve::Secp256r1 => crate::algorithm::OID_EC_SECP256R1,
EcdsaCurve::Secp384r1 => crate::algorithm::OID_EC_SECP384R1,
};
assert!(spki.algorithm.parameters.is_some());
assert_eq!(
spki.algorithm
.parameters
.as_ref()
.unwrap()
.decode_oid()
.unwrap(),
expected
);
let cert_algorithm = SignatureAlgorithm::try_from(&raw.signature_algorithm).unwrap();
assert_eq!(cert_algorithm, tbs_signature_algorithm);
}
}
#[test]
fn ed25519_self_signed_certificate_verification() {
let (cert, _) = self_signed_ed25519_key_pair();
cert.verify_signed_by_certificate(&cert).unwrap();
}
#[test]
fn rsa_signing_roundtrip() {
let key = rsa_private_key();
let cert = rsa_cert();
let message = b"hello, world";
let signature = Signer::try_sign(&key, message).unwrap();
let public_key = UnparsedPublicKey::new(
key.verification_algorithm().unwrap(),
cert.public_key_data(),
);
public_key.verify(message, signature.as_ref()).unwrap();
}
}