use crate::b64_encode; use crate::crypto::{HashFunction, JwsSignatureAlgorithm, KeyType}; use crate::error::Error; use openssl::bn::{BigNum, BigNumContext}; use openssl::ec::{Asn1Flag, EcGroup, EcKey}; use openssl::ecdsa::EcdsaSig; use openssl::hash::MessageDigest; use openssl::nid::Nid; use openssl::pkey::{Id, PKey, Private}; use openssl::rsa::Rsa; use openssl::sign::Signer; use serde_json::json; use serde_json::value::Value; macro_rules! get_key_type { ($key: expr) => { match $key.id() { Id::RSA => match $key.rsa()?.size() { 256 => KeyType::Rsa2048, 512 => KeyType::Rsa4096, s => { return Err(format!("{}: unsupported RSA key size", s * 8).into()); } }, Id::EC => match $key.ec_key()?.group().curve_name() { Some(Nid::X9_62_PRIME256V1) => KeyType::EcdsaP256, Some(Nid::SECP384R1) => KeyType::EcdsaP384, Some(nid) => { return Err(format!("{:?}: unsupported EC key", nid).into()); } None => { return Err("unsupported EC key".into()); } }, #[cfg(ed25519)] Id::ED25519 => KeyType::Ed25519, #[cfg(ed448)] Id::ED448 => KeyType::Ed448, _ => { return Err("unsupported key type".into()); } } }; } #[derive(Clone, Debug)] pub struct KeyPair { pub key_type: KeyType, pub inner_key: PKey, } impl KeyPair { pub fn from_der(der_data: &[u8]) -> Result { let inner_key = PKey::private_key_from_der(der_data)?; let key_type = get_key_type!(inner_key); Ok(KeyPair { key_type, inner_key, }) } pub fn from_pem(pem_data: &[u8]) -> Result { let inner_key = PKey::private_key_from_pem(pem_data)?; let key_type = get_key_type!(inner_key); Ok(KeyPair { key_type, inner_key, }) } pub fn private_key_to_der(&self) -> Result, Error> { self.inner_key.private_key_to_der().map_err(Error::from) } pub fn private_key_to_pem(&self) -> Result, Error> { self.inner_key .private_key_to_pem_pkcs8() .map_err(Error::from) } pub fn public_key_to_pem(&self) -> Result, Error> { self.inner_key.public_key_to_pem().map_err(Error::from) } pub fn sign(&self, alg: &JwsSignatureAlgorithm, data: &[u8]) -> Result, Error> { let _ = self.key_type.check_alg_compatibility(alg)?; match alg { JwsSignatureAlgorithm::Rs256 => self.sign_rsa(&MessageDigest::sha256(), data), JwsSignatureAlgorithm::Es256 => self.sign_ecdsa(&HashFunction::Sha256, data), JwsSignatureAlgorithm::Es384 => self.sign_ecdsa(&HashFunction::Sha384, data), #[cfg(ed25519)] JwsSignatureAlgorithm::Ed25519 => self.sign_eddsa(data), #[cfg(ed448)] JwsSignatureAlgorithm::Ed448 => self.sign_eddsa(data), } } fn sign_rsa(&self, hash_func: &MessageDigest, data: &[u8]) -> Result, Error> { let mut signer = Signer::new(*hash_func, &self.inner_key)?; signer.update(data)?; let signature = signer.sign_to_vec()?; Ok(signature) } fn sign_ecdsa(&self, hash_func: &HashFunction, data: &[u8]) -> Result, Error> { let fingerprint = hash_func.hash(data); let signature = EcdsaSig::sign(&fingerprint, self.inner_key.ec_key()?.as_ref())?; let r = signature.r().to_vec(); let mut s = signature.s().to_vec(); let mut signature = r; signature.append(&mut s); Ok(signature) } #[cfg(any(ed25519, ed448))] fn sign_eddsa(&self, data: &[u8]) -> Result, Error> { let mut signer = Signer::new_without_digest(&self.inner_key)?; let signature = signer.sign_oneshot_to_vec(data)?; Ok(signature) } pub fn jwk_public_key(&self) -> Result { self.get_jwk_public_key(false) } pub fn jwk_public_key_thumbprint(&self) -> Result { self.get_jwk_public_key(true) } fn get_jwk_public_key(&self, thumbprint: bool) -> Result { match self.key_type { KeyType::Rsa2048 | KeyType::Rsa4096 => self.get_rsa_jwk(thumbprint), KeyType::EcdsaP256 | KeyType::EcdsaP384 => self.get_ecdsa_jwk(thumbprint), #[cfg(ed25519)] KeyType::Ed25519 => self.get_eddsa_jwk(thumbprint), #[cfg(ed448)] KeyType::Ed448 => self.get_eddsa_jwk(thumbprint), } } fn get_rsa_jwk(&self, thumbprint: bool) -> Result { let rsa = self.inner_key.rsa().unwrap(); let e = rsa.e(); let n = rsa.n(); let e = b64_encode(&e.to_vec()); let n = b64_encode(&n.to_vec()); let jwk = if thumbprint { json!({ "kty": "RSA", "e": e, "n": n, }) } else { json!({ "alg": "RS256", "kty": "RSA", "use": "sig", "e": e, "n": n, }) }; Ok(jwk) } fn get_ecdsa_jwk(&self, thumbprint: bool) -> Result { let (crv, alg, curve) = match self.key_type { KeyType::EcdsaP256 => ("P-256", "ES256", Nid::X9_62_PRIME256V1), KeyType::EcdsaP384 => ("P-384", "ES384", Nid::SECP384R1), _ => { return Err("not an ECDSA elliptic curve".into()); } }; let group = EcGroup::from_curve_name(curve).unwrap(); let mut ctx = BigNumContext::new().unwrap(); let mut x = BigNum::new().unwrap(); let mut y = BigNum::new().unwrap(); self.inner_key .ec_key() .unwrap() .public_key() .affine_coordinates_gfp(&group, &mut x, &mut y, &mut ctx)?; let x = b64_encode(&x.to_vec()); let y = b64_encode(&y.to_vec()); let jwk = if thumbprint { json!({ "crv": crv, "kty": "EC", "x": x, "y": y, }) } else { json!({ "alg": alg, "crv": crv, "kty": "EC", "use": "sig", "x": x, "y": y, }) }; Ok(jwk) } #[cfg(any(ed25519, ed448))] fn get_eddsa_jwk(&self, thumbprint: bool) -> Result { let crv = match self.key_type { #[cfg(ed25519)] KeyType::Ed25519 => "Ed25519", #[cfg(ed448)] KeyType::Ed448 => "Ed448", _ => { return Err("not an EdDSA elliptic curve".into()); } }; let x = ""; let jwk = if thumbprint { json!({ "crv": crv, "kty": "OKP", "x": x, }) } else { json!({ "alg": "EdDSA", "crv": crv, "kty": "OKP", "use": "sig", "x": x, }) }; //Ok(jwk) Err("TODO: implement get_eddsa_jwk (require binding to EVP_PKEY_get1_ED25519, which requires OpenSSL 3.0)".into()) } } fn gen_rsa_pair(nb_bits: u32) -> Result, Error> { let priv_key = Rsa::generate(nb_bits)?; let pk = PKey::from_rsa(priv_key).map_err(|_| Error::from(""))?; Ok(pk) } fn gen_ec_pair(nid: Nid) -> Result, Error> { let mut group = EcGroup::from_curve_name(nid)?; // Use NAMED_CURVE format; OpenSSL 1.0.1 and 1.0.2 default to EXPLICIT_CURVE which won't work (see #9) group.set_asn1_flag(Asn1Flag::NAMED_CURVE); let ec_priv_key = EcKey::generate(&group).map_err(|_| Error::from(""))?; let pk = PKey::from_ec_key(ec_priv_key).map_err(|_| Error::from(""))?; Ok(pk) } #[cfg(ed25519)] fn gen_ed25519_pair() -> Result, Error> { let pk = PKey::generate_ed25519().map_err(|_| Error::from(""))?; Ok(pk) } #[cfg(ed448)] fn gen_ed448_pair() -> Result, Error> { let pk = PKey::generate_ed448().map_err(|_| Error::from(""))?; Ok(pk) } pub fn gen_keypair(key_type: KeyType) -> Result { let priv_key = match key_type { KeyType::Rsa2048 => gen_rsa_pair(2048), KeyType::Rsa4096 => gen_rsa_pair(4096), KeyType::EcdsaP256 => gen_ec_pair(Nid::X9_62_PRIME256V1), KeyType::EcdsaP384 => gen_ec_pair(Nid::SECP384R1), #[cfg(ed25519)] KeyType::Ed25519 => gen_ed25519_pair(), #[cfg(ed448)] KeyType::Ed448 => gen_ed448_pair(), } .map_err(|_| Error::from(format!("unable to generate a {} key pair", key_type)))?; let key_pair = KeyPair { key_type, inner_key: priv_key, }; Ok(key_pair) }