From 63e35712fe2c3316bb2d59e9525e0c367428df62 Mon Sep 17 00:00:00 2001 From: Rodolphe Breard Date: Fri, 7 Jun 2019 19:22:26 +0200 Subject: [PATCH] Create an abstraction around public and private keys Since it is planned to add a "standalone" feature that will replace OpenSSL by crates not linking to any external library, it is required to abstract all the OpenSSL specific types. This is a huge work and therefore is divided in several steps. This first one is dedicated to public and private keys. rel #2 --- acme_common/src/crypto.rs | 3 + acme_common/src/crypto/openssl_keys.rs | 223 ++++++++++++++++++ acme_common/src/gen.rs | 45 ---- acme_common/src/lib.rs | 2 +- acmed/src/acme_proto/account.rs | 16 +- acmed/src/acme_proto/certificate.rs | 37 +-- acmed/src/acme_proto/jws.rs | 48 +--- acmed/src/acme_proto/jws/algorithms.rs | 80 +------ acmed/src/acme_proto/structs/authorization.rs | 10 +- acmed/src/storage.rs | 31 +-- tacd/src/certificate.rs | 17 +- tacd/src/server.rs | 10 +- 12 files changed, 309 insertions(+), 213 deletions(-) create mode 100644 acme_common/src/crypto.rs create mode 100644 acme_common/src/crypto/openssl_keys.rs delete mode 100644 acme_common/src/gen.rs diff --git a/acme_common/src/crypto.rs b/acme_common/src/crypto.rs new file mode 100644 index 0000000..6833708 --- /dev/null +++ b/acme_common/src/crypto.rs @@ -0,0 +1,3 @@ +mod openssl_keys; +pub use openssl_keys::{gen_keypair, KeyType, PrivateKey, PublicKey}; +pub const DEFAULT_ALGO: &str = "rsa2048"; diff --git a/acme_common/src/crypto/openssl_keys.rs b/acme_common/src/crypto/openssl_keys.rs new file mode 100644 index 0000000..e9c6a29 --- /dev/null +++ b/acme_common/src/crypto/openssl_keys.rs @@ -0,0 +1,223 @@ +use crate::b64_encode; +use crate::error::Error; +use openssl::bn::{BigNum, BigNumContext}; +use openssl::ec::{EcGroup, EcKey}; +use openssl::ecdsa::EcdsaSig; +use openssl::nid::Nid; +use openssl::pkey::{Id, PKey, Private, Public}; +use openssl::rsa::Rsa; +use serde_json::json; +use std::fmt; +use std::str::FromStr; + +macro_rules! get_key_type { + ($key: expr) => { + match $key.id() { + Id::RSA => match $key.rsa()?.size() { + 2048 => KeyType::Rsa2048, + 4096 => KeyType::Rsa4096, + s => { + return Err(format!("{}: unsupported RSA key size", s).into()); + } + }, + Id::EC => match $key.ec_key()?.group().curve_name() { + Some(Nid::X9_62_PRIME256V1) => KeyType::EcdsaP256, + Some(Nid::SECP384R1) => KeyType::EcdsaP384, + _ => { + return Err("Unsupported EC key".into()); + } + }, + _ => { + return Err("Unsupported key type".into()); + } + } + }; +} + +#[derive(Clone, Copy, Debug)] +pub enum KeyType { + Rsa2048, + Rsa4096, + EcdsaP256, + EcdsaP384, +} + +impl FromStr for KeyType { + type Err = Error; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "rsa2048" => Ok(KeyType::Rsa2048), + "rsa4096" => Ok(KeyType::Rsa4096), + "ecdsa_p256" => Ok(KeyType::EcdsaP256), + "ecdsa_p384" => Ok(KeyType::EcdsaP384), + _ => Err(format!("{}: unknown algorithm.", s).into()), + } + } +} + +impl fmt::Display for KeyType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match self { + KeyType::Rsa2048 => "rsa2048", + KeyType::Rsa4096 => "rsa4096", + KeyType::EcdsaP256 => "ecdsa-p256", + KeyType::EcdsaP384 => "ecdsa-p384", + }; + write!(f, "{}", s) + } +} + +pub struct PublicKey { + pub key_type: KeyType, + pub inner_key: PKey, +} + +impl PublicKey { + pub fn from_pem(pem_data: &[u8]) -> Result { + let inner_key = PKey::public_key_from_pem(pem_data)?; + let key_type = get_key_type!(inner_key); + Ok(PublicKey { + key_type, + inner_key, + }) + } + + pub fn to_pem(&self) -> Result, Error> { + self.inner_key + .public_key_to_pem() + .map_err(|e| Error::from(e)) + } +} + +pub struct PrivateKey { + pub key_type: KeyType, + pub inner_key: PKey, +} + +impl PrivateKey { + 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(PrivateKey { + key_type, + inner_key, + }) + } + + pub fn to_pem(&self) -> Result, Error> { + self.inner_key + .private_key_to_pem_pkcs8() + .map_err(|e| Error::from(e)) + } + + pub fn sign(&self, data: &[u8]) -> Result, Error> { + match self.key_type { + KeyType::Rsa2048 | KeyType::Rsa4096 => { + // TODO: implement RSA signatures + Err("RSA signatures are not implemented yet".into()) + } + KeyType::EcdsaP256 | KeyType::EcdsaP384 => { + let signature = EcdsaSig::sign(data, 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) + } + } + } + + pub fn get_jwk_thumbprint(&self) -> Result { + match self.key_type { + KeyType::EcdsaP256 | KeyType::EcdsaP384 => self.get_nist_ec_jwk(), + // TODO: implement RSA JWK thumbprint + KeyType::Rsa2048 | KeyType::Rsa4096 => { + Err("RSA jwk thumbprint are not implemented yet".into()) + } + } + } + + fn get_nist_ec_jwk(&self) -> Result { + let (x, y) = self.get_nist_ec_coordinates()?; + let crv = match self.key_type { + KeyType::EcdsaP256 => "P-256", + KeyType::EcdsaP384 => "P-384", + _ => { + return Err("Not a NIST elliptic curve.".into()); + } + }; + let jwk = json!({ + "crv": crv, + "kty": "EC", + "x": x, + "y": y, + }); + Ok(jwk.to_string()) + } + + pub fn get_nist_ec_coordinates(&self) -> Result<(String, String), Error> { + let curve = match self.key_type { + KeyType::EcdsaP256 => Nid::X9_62_PRIME256V1, + KeyType::EcdsaP384 => Nid::SECP384R1, + _ => { + return Err("Not a NIST 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()); + Ok((x, y)) + } +} + +fn gen_rsa_pair(nb_bits: u32) -> Result<(PKey, PKey), Error> { + let priv_key = Rsa::generate(nb_bits).unwrap(); + let pub_key = Rsa::from_public_components( + priv_key.n().to_owned().unwrap(), + priv_key.e().to_owned().unwrap(), + ) + .unwrap(); + Ok(( + PKey::from_rsa(pub_key).unwrap(), + PKey::from_rsa(priv_key).unwrap(), + )) +} + +fn gen_ec_pair(nid: Nid) -> Result<(PKey, PKey), Error> { + let group = EcGroup::from_curve_name(nid).unwrap(); + let ec_priv_key = EcKey::generate(&group).unwrap(); + let public_key_point = ec_priv_key.public_key(); + let ec_pub_key = EcKey::from_public_key(&group, public_key_point).unwrap(); + Ok(( + PKey::from_ec_key(ec_pub_key).unwrap(), + PKey::from_ec_key(ec_priv_key).unwrap(), + )) +} + +pub fn gen_keypair(key_type: KeyType) -> Result<(PublicKey, PrivateKey), Error> { + let (pub_key, 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), + } + .map_err(|_| Error::from(format!("Unable to generate a {} key pair.", key_type)))?; + let pub_key = PublicKey { + key_type, + inner_key: pub_key, + }; + let priv_key = PrivateKey { + key_type, + inner_key: priv_key, + }; + Ok((pub_key, priv_key)) +} diff --git a/acme_common/src/gen.rs b/acme_common/src/gen.rs deleted file mode 100644 index 58b389a..0000000 --- a/acme_common/src/gen.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::error::Error; -use openssl::ec::{EcGroup, EcKey}; -use openssl::nid::Nid; -use openssl::pkey::{PKey, Private, Public}; -use openssl::rsa::Rsa; - -fn gen_ec_pair(nid: Nid) -> Result<(PKey, PKey), Error> { - let group = EcGroup::from_curve_name(nid).unwrap(); - let ec_priv_key = EcKey::generate(&group).unwrap(); - let public_key_point = ec_priv_key.public_key(); - let ec_pub_key = EcKey::from_public_key(&group, public_key_point).unwrap(); - Ok(( - PKey::from_ec_key(ec_priv_key).unwrap(), - PKey::from_ec_key(ec_pub_key).unwrap(), - )) -} - -pub fn p256() -> Result<(PKey, PKey), Error> { - gen_ec_pair(Nid::X9_62_PRIME256V1) -} - -pub fn p384() -> Result<(PKey, PKey), Error> { - gen_ec_pair(Nid::SECP384R1) -} - -fn gen_rsa_pair(nb_bits: u32) -> Result<(PKey, PKey), Error> { - let priv_key = Rsa::generate(nb_bits).unwrap(); - let pub_key = Rsa::from_public_components( - priv_key.n().to_owned().unwrap(), - priv_key.e().to_owned().unwrap(), - ) - .unwrap(); - Ok(( - PKey::from_rsa(priv_key).unwrap(), - PKey::from_rsa(pub_key).unwrap(), - )) -} - -pub fn rsa2048() -> Result<(PKey, PKey), Error> { - gen_rsa_pair(2048) -} - -pub fn rsa4096() -> Result<(PKey, PKey), Error> { - gen_rsa_pair(4096) -} diff --git a/acme_common/src/lib.rs b/acme_common/src/lib.rs index dd6fad2..62d38f7 100644 --- a/acme_common/src/lib.rs +++ b/acme_common/src/lib.rs @@ -1,7 +1,7 @@ use daemonize::Daemonize; +pub mod crypto; pub mod error; -pub mod gen; pub mod logs; pub fn b64_encode>(input: &T) -> String { diff --git a/acmed/src/acme_proto/account.rs b/acmed/src/acme_proto/account.rs index d280975..009daff 100644 --- a/acmed/src/acme_proto/account.rs +++ b/acmed/src/acme_proto/account.rs @@ -4,13 +4,13 @@ use crate::acme_proto::jws::encode_jwk; use crate::acme_proto::structs::{Account, AccountResponse, Directory}; use crate::certificate::Certificate; use crate::storage; +use acme_common::crypto::{PrivateKey, PublicKey}; use acme_common::error::Error; -use openssl::pkey::{PKey, Private, Public}; use std::str::FromStr; pub struct AccountManager { - pub priv_key: PKey, - pub pub_key: PKey, + pub pub_key: PublicKey, + pub priv_key: PrivateKey, pub account_url: String, pub orders_url: String, } @@ -23,20 +23,20 @@ impl AccountManager { root_certs: &[String], ) -> Result<(Self, String), Error> { // TODO: store the key id (account url) - let (priv_key, pub_key) = if storage::account_files_exists(cert) { + let (pub_key, priv_key) = if storage::account_files_exists(cert) { // TODO: check if the keys are suitable for the specified signature algorithm // and, if not, initiate a key rollover. ( - storage::get_account_priv_key(cert)?, storage::get_account_pub_key(cert)?, + storage::get_account_priv_key(cert)?, ) } else { // TODO: allow to change the signature algo let sign_alg = SignatureAlgorithm::from_str(crate::DEFAULT_JWS_SIGN_ALGO)?; - let (priv_key, pub_key) = sign_alg.gen_key_pair()?; + let (pub_key, priv_key) = sign_alg.gen_key_pair()?; storage::set_account_priv_key(cert, &priv_key)?; storage::set_account_pub_key(cert, &pub_key)?; - (priv_key, pub_key) + (pub_key, priv_key) }; let account = Account::new(cert); let account = serde_json::to_string(&account)?; @@ -50,8 +50,8 @@ impl AccountManager { &nonce, )?; let ac = AccountManager { - priv_key, pub_key, + priv_key, account_url, orders_url: acc_rep.orders.unwrap_or_default(), }; diff --git a/acmed/src/acme_proto/certificate.rs b/acmed/src/acme_proto/certificate.rs index 197354f..fd874fa 100644 --- a/acmed/src/acme_proto/certificate.rs +++ b/acmed/src/acme_proto/certificate.rs @@ -1,32 +1,33 @@ use crate::certificate::{Algorithm, Certificate}; use crate::storage; +use acme_common::b64_encode; +use acme_common::crypto::{gen_keypair, KeyType, PrivateKey, PublicKey}; use acme_common::error::Error; -use acme_common::{b64_encode, gen}; use openssl::hash::MessageDigest; -use openssl::pkey::{PKey, Private, Public}; use openssl::stack::Stack; use openssl::x509::extension::SubjectAlternativeName; use openssl::x509::X509ReqBuilder; use serde_json::json; -fn gen_key_pair(cert: &Certificate) -> Result<(PKey, PKey), Error> { - let (priv_key, pub_key) = match cert.algo { - Algorithm::Rsa2048 => gen::rsa2048(), - Algorithm::Rsa4096 => gen::rsa4096(), - Algorithm::EcdsaP256 => gen::p256(), - Algorithm::EcdsaP384 => gen::p384(), - }?; +fn gen_key_pair(cert: &Certificate) -> Result<(PublicKey, PrivateKey), Error> { + let key_type = match cert.algo { + Algorithm::Rsa2048 => KeyType::Rsa2048, + Algorithm::Rsa4096 => KeyType::Rsa4096, + Algorithm::EcdsaP256 => KeyType::EcdsaP256, + Algorithm::EcdsaP384 => KeyType::EcdsaP384, + }; + let (pub_key, priv_key) = gen_keypair(key_type)?; storage::set_priv_key(cert, &priv_key)?; - Ok((priv_key, pub_key)) + Ok((pub_key, priv_key)) } -fn read_key_pair(cert: &Certificate) -> Result<(PKey, PKey), Error> { - let priv_key = storage::get_priv_key(cert)?; +fn read_key_pair(cert: &Certificate) -> Result<(PublicKey, PrivateKey), Error> { let pub_key = storage::get_pub_key(cert)?; - Ok((priv_key, pub_key)) + let priv_key = storage::get_priv_key(cert)?; + Ok((pub_key, priv_key)) } -pub fn get_key_pair(cert: &Certificate) -> Result<(PKey, PKey), Error> { +pub fn get_key_pair(cert: &Certificate) -> Result<(PublicKey, PrivateKey), Error> { if cert.kp_reuse { match read_key_pair(cert) { Ok((priv_key, pub_key)) => Ok((priv_key, pub_key)), @@ -39,11 +40,11 @@ pub fn get_key_pair(cert: &Certificate) -> Result<(PKey, PKey), pub fn generate_csr( cert: &Certificate, - priv_key: &PKey, - pub_key: &PKey, + pub_key: &PublicKey, + priv_key: &PrivateKey, ) -> Result { let mut builder = X509ReqBuilder::new()?; - builder.set_pubkey(pub_key)?; + builder.set_pubkey(&pub_key.inner_key)?; let ctx = builder.x509v3_context(None); let mut san = SubjectAlternativeName::new(); for c in cert.domains.iter() { @@ -53,7 +54,7 @@ pub fn generate_csr( let mut ext_stack = Stack::new()?; ext_stack.push(san)?; builder.add_extensions(&ext_stack)?; - builder.sign(priv_key, MessageDigest::sha256())?; + builder.sign(&priv_key.inner_key, MessageDigest::sha256())?; let csr = builder.build(); let csr = csr.to_der()?; let csr = b64_encode(&csr); diff --git a/acmed/src/acme_proto/jws.rs b/acmed/src/acme_proto/jws.rs index a86ee7d..b601262 100644 --- a/acmed/src/acme_proto/jws.rs +++ b/acmed/src/acme_proto/jws.rs @@ -1,8 +1,7 @@ use crate::acme_proto::jws::algorithms::{EdDsaVariant, SignatureAlgorithm}; use acme_common::b64_encode; +use acme_common::crypto::PrivateKey; use acme_common::error::Error; -use openssl::ecdsa::EcdsaSig; -use openssl::pkey::{PKey, Private}; use openssl::sha::sha256; use serde::Serialize; @@ -32,37 +31,13 @@ struct JwsProtectedHeaderKid { url: String, } -fn es256_sign(data: &[u8], private_key: &PKey) -> Result { - let signature = EcdsaSig::sign(data, private_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); - let signature = b64_encode(&signature); - Ok(signature) -} - -fn eddsa_ed25519_sign(_data: &[u8], _private_key: &PKey) -> Result { - // TODO: implement eddsa_ed25519_sign - Err("EdDSA not implemented.".into()) -} - -fn get_data( - private_key: &PKey, - protected: &str, - payload: &[u8], - sign_alg: SignatureAlgorithm, -) -> Result { +fn get_data(private_key: &PrivateKey, protected: &str, payload: &[u8]) -> Result { let protected = b64_encode(protected); let payload = b64_encode(payload); let signing_input = format!("{}.{}", protected, payload); let fingerprint = sha256(signing_input.as_bytes()); - let signature = match sign_alg { - SignatureAlgorithm::Es256 => es256_sign(&fingerprint, private_key)?, - SignatureAlgorithm::EdDsa(variant) => match variant { - EdDsaVariant::Ed25519 => eddsa_ed25519_sign(&fingerprint, private_key)?, - }, - }; + let signature = private_key.sign(&fingerprint)?; + let signature = b64_encode(&signature); let data = JwsData { protected, payload, @@ -73,7 +48,7 @@ fn get_data( } pub fn encode_jwk( - private_key: &PKey, + private_key: &PrivateKey, payload: &[u8], url: &str, nonce: &str, @@ -86,11 +61,11 @@ pub fn encode_jwk( url: url.into(), }; let protected = serde_json::to_string(&protected)?; - get_data(private_key, &protected, payload, sign_alg) + get_data(private_key, &protected, payload) } pub fn encode_kid( - private_key: &PKey, + private_key: &PrivateKey, key_id: &str, payload: &[u8], url: &str, @@ -104,16 +79,17 @@ pub fn encode_kid( url: url.into(), }; let protected = serde_json::to_string(&protected)?; - get_data(private_key, &protected, payload, sign_alg) + get_data(private_key, &protected, payload) } #[cfg(test)] mod tests { use super::{encode_jwk, encode_kid}; + use acme_common::crypto::{gen_keypair, KeyType}; #[test] fn test_default_jwk() { - let (priv_key, _) = acme_common::gen::p256().unwrap(); + let (_, priv_key) = gen_keypair(KeyType::EcdsaP256).unwrap(); let payload = "Dummy payload 1"; let payload_b64 = "RHVtbXkgcGF5bG9hZCAx"; let s = encode_jwk(&priv_key, payload.as_bytes(), "", ""); @@ -127,7 +103,7 @@ mod tests { #[test] fn test_default_nopad_jwk() { - let (priv_key, _) = acme_common::gen::p256().unwrap(); + let (_, priv_key) = gen_keypair(KeyType::EcdsaP256).unwrap(); let payload = "Dummy payload"; let payload_b64 = "RHVtbXkgcGF5bG9hZA"; let payload_b64_pad = "RHVtbXkgcGF5bG9hZA=="; @@ -143,7 +119,7 @@ mod tests { #[test] fn test_default_kid() { - let (priv_key, _) = acme_common::gen::p256().unwrap(); + let (_, priv_key) = gen_keypair(KeyType::EcdsaP256).unwrap(); let payload = "Dummy payload 1"; let payload_b64 = "RHVtbXkgcGF5bG9hZCAx"; let key_id = "0x2a"; diff --git a/acmed/src/acme_proto/jws/algorithms.rs b/acmed/src/acme_proto/jws/algorithms.rs index 48d4a73..c8039f3 100644 --- a/acmed/src/acme_proto/jws/algorithms.rs +++ b/acmed/src/acme_proto/jws/algorithms.rs @@ -1,11 +1,6 @@ use super::jwk::{EdDsaEd25519Jwk, Es256Jwk, Jwk}; +use acme_common::crypto::{gen_keypair, KeyType, PrivateKey, PublicKey}; use acme_common::error::Error; -use acme_common::{b64_encode, gen}; -use openssl::bn::{BigNum, BigNumContext}; -use openssl::ec::EcGroup; -use openssl::nid::Nid; -use openssl::pkey::{Id, PKey, Private, Public}; -use serde_json::json; use std::fmt; use std::str::FromStr; @@ -52,71 +47,22 @@ impl FromStr for SignatureAlgorithm { } impl SignatureAlgorithm { - pub fn from_pkey(private_key: &PKey) -> Result { - match private_key.id() { - Id::EC => match private_key.ec_key()?.group().curve_name() { - Some(nid) => { - if nid == Nid::X9_62_PRIME256V1 { - Ok(SignatureAlgorithm::Es256) - // TODO: add support for Ed25519 keys - } else { - Err(format!("{}: unsupported EC key type", nid.as_raw()).into()) - } - } - None => Err("EC curve: name not found".into()), - }, - _ => Err(format!("{}: unsupported key id", private_key.id().as_raw()).into()), + pub fn from_pkey(private_key: &PrivateKey) -> Result { + match private_key.key_type { + KeyType::EcdsaP256 => Ok(SignatureAlgorithm::Es256), + t => Err(format!("{}: unsupported key type", t).into()), } } - fn get_p256_coordinates(private_key: &PKey) -> Result<(String, String), Error> { - let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); - let mut ctx = BigNumContext::new().unwrap(); - let mut x = BigNum::new().unwrap(); - let mut y = BigNum::new().unwrap(); - private_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()); - Ok((x, y)) - } - - pub fn get_jwk_thumbprint(&self, private_key: &PKey) -> Result { - let jwk = match self { - SignatureAlgorithm::Es256 => { - let (x, y) = SignatureAlgorithm::get_p256_coordinates(private_key)?; - json!({ - "crv": "P-256", - "kty": "EC", - "x": x, - "y": y, - }) - } - SignatureAlgorithm::EdDsa(_crv) => json!({ - // TODO: implement EdDsa - }), - }; - Ok(jwk.to_string()) - } - - pub fn get_jwk(&self, private_key: &PKey) -> Result { - let jwk = match self { - SignatureAlgorithm::Es256 => { - let (x, y) = SignatureAlgorithm::get_p256_coordinates(private_key)?; - Jwk::Es256(Es256Jwk::new(&x, &y)) - } - // TODO: implement EdDsa - SignatureAlgorithm::EdDsa(_crv) => Jwk::EdDsaEd25519(EdDsaEd25519Jwk::new()), - }; + pub fn get_jwk(&self, private_key: &PrivateKey) -> Result { + let (x, y) = private_key.get_nist_ec_coordinates()?; + let jwk = Jwk::Es256(Es256Jwk::new(&x, &y)); Ok(jwk) } - pub fn gen_key_pair(&self) -> Result<(PKey, PKey), Error> { + pub fn gen_key_pair(&self) -> Result<(PublicKey, PrivateKey), Error> { match self { - SignatureAlgorithm::Es256 => gen::p256(), + SignatureAlgorithm::Es256 => gen_keypair(KeyType::EcdsaP256), SignatureAlgorithm::EdDsa(EdDsaVariant::Ed25519) => Err("Not implemented".into()), } } @@ -125,8 +71,7 @@ impl SignatureAlgorithm { #[cfg(test)] mod tests { use super::{EdDsaVariant, SignatureAlgorithm}; - use openssl::ec::EcKey; - use openssl::pkey::PKey; + use acme_common::crypto::PrivateKey; use std::str::FromStr; #[test] @@ -170,8 +115,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg6To1BW8qTehGhPca 0eMcW8iQU4yA02dvtKkuqfny4HChRANCAAQwxx+j3wYGzD5LSFNBTLlT7J+7rWrq 4BGdR8705iwpBeOQgMpLj+9vuFutlVtmoYpJSYa9+49Hxz8aCe1AQeWt -----END PRIVATE KEY-----"; - let ek = EcKey::private_key_from_pem(pem).unwrap(); - let k = PKey::from_ec_key(ek).unwrap(); + let k = PrivateKey::from_pem(pem).unwrap(); let s = SignatureAlgorithm::from_pkey(&k); assert!(s.is_ok()); let s = s.unwrap(); diff --git a/acmed/src/acme_proto/structs/authorization.rs b/acmed/src/acme_proto/structs/authorization.rs index 8415bc2..b84c88a 100644 --- a/acmed/src/acme_proto/structs/authorization.rs +++ b/acmed/src/acme_proto/structs/authorization.rs @@ -1,8 +1,7 @@ -use crate::acme_proto::jws::algorithms::SignatureAlgorithm; use crate::acme_proto::structs::{ApiError, HttpApiError, Identifier}; use acme_common::b64_encode; +use acme_common::crypto::PrivateKey; use acme_common::error::Error; -use openssl::pkey::{PKey, Private}; use openssl::sha::sha256; use serde::Deserialize; use std::fmt; @@ -94,7 +93,7 @@ impl Challenge { } } - pub fn get_proof(&self, private_key: &PKey) -> Result { + pub fn get_proof(&self, private_key: &PrivateKey) -> Result { match self { Challenge::Http01(tc) => tc.key_authorization(private_key), Challenge::Dns01(tc) => { @@ -156,9 +155,8 @@ pub struct TokenChallenge { } impl TokenChallenge { - fn key_authorization(&self, private_key: &PKey) -> Result { - let sa = SignatureAlgorithm::from_pkey(private_key)?; - let thumbprint = sa.get_jwk_thumbprint(private_key)?; + fn key_authorization(&self, private_key: &PrivateKey) -> Result { + let thumbprint = private_key.get_jwk_thumbprint()?; let thumbprint = sha256(thumbprint.as_bytes()); let thumbprint = b64_encode(&thumbprint); let auth = format!("{}.{}", self.token, thumbprint); diff --git a/acmed/src/storage.rs b/acmed/src/storage.rs index 966161a..09787dc 100644 --- a/acmed/src/storage.rs +++ b/acmed/src/storage.rs @@ -2,8 +2,8 @@ use crate::certificate::Certificate; use crate::config::HookType; use crate::hooks::{self, FileStorageHookData, HookEnvData}; use acme_common::b64_encode; +use acme_common::crypto::{PrivateKey, PublicKey}; use acme_common::error::Error; -use openssl::pkey::{PKey, Private, Public}; use openssl::x509::X509; use std::collections::HashMap; use std::fmt; @@ -175,44 +175,45 @@ fn write_file(cert: &Certificate, file_type: FileType, data: &[u8]) -> Result<() Ok(()) } -pub fn get_account_priv_key(cert: &Certificate) -> Result, Error> { +pub fn get_account_priv_key(cert: &Certificate) -> Result { let path = get_file_path(cert, FileType::AccountPrivateKey)?; let raw_key = read_file(cert, &path)?; - let key = PKey::private_key_from_pem(&raw_key)?; + let key = PrivateKey::from_pem(&raw_key)?; Ok(key) } -pub fn set_account_priv_key(cert: &Certificate, key: &PKey) -> Result<(), Error> { - let data = key.private_key_to_pem_pkcs8()?; +pub fn set_account_priv_key(cert: &Certificate, key: &PrivateKey) -> Result<(), Error> { + let data = key.to_pem()?; write_file(cert, FileType::AccountPrivateKey, &data) } -pub fn get_account_pub_key(cert: &Certificate) -> Result, Error> { +pub fn get_account_pub_key(cert: &Certificate) -> Result { let path = get_file_path(cert, FileType::AccountPublicKey)?; let raw_key = read_file(cert, &path)?; - let key = PKey::public_key_from_pem(&raw_key)?; + let key = PublicKey::from_pem(&raw_key)?; Ok(key) } -pub fn set_account_pub_key(cert: &Certificate, key: &PKey) -> Result<(), Error> { - let data = key.public_key_to_pem()?; +pub fn set_account_pub_key(cert: &Certificate, key: &PublicKey) -> Result<(), Error> { + let data = key.to_pem()?; write_file(cert, FileType::AccountPublicKey, &data) } -pub fn get_priv_key(cert: &Certificate) -> Result, Error> { +pub fn get_priv_key(cert: &Certificate) -> Result { let path = get_file_path(cert, FileType::PrivateKey)?; let raw_key = read_file(cert, &path)?; - let key = PKey::private_key_from_pem(&raw_key)?; + let key = PrivateKey::from_pem(&raw_key)?; Ok(key) } -pub fn set_priv_key(cert: &Certificate, key: &PKey) -> Result<(), Error> { - let data = key.private_key_to_pem_pkcs8()?; +pub fn set_priv_key(cert: &Certificate, key: &PrivateKey) -> Result<(), Error> { + let data = key.to_pem()?; write_file(cert, FileType::PrivateKey, &data) } -pub fn get_pub_key(cert: &Certificate) -> Result, Error> { - let pub_key = get_certificate(cert)?.public_key()?; +pub fn get_pub_key(cert: &Certificate) -> Result { + let raw_key = get_certificate(cert)?.public_key()?.public_key_to_pem()?; + let pub_key = PublicKey::from_pem(&raw_key)?; Ok(pub_key) } diff --git a/tacd/src/certificate.rs b/tacd/src/certificate.rs index 47db759..b74b36e 100644 --- a/tacd/src/certificate.rs +++ b/tacd/src/certificate.rs @@ -1,9 +1,8 @@ +use acme_common::crypto::{gen_keypair, KeyType, PrivateKey, PublicKey}; use acme_common::error::Error; -use acme_common::gen; use openssl::asn1::Asn1Time; use openssl::bn::{BigNum, MsbOption}; use openssl::hash::MessageDigest; -use openssl::pkey::{PKey, Private, Public}; use openssl::x509::extension::{BasicConstraints, SubjectAlternativeName}; use openssl::x509::{X509Builder, X509Extension, X509NameBuilder, X509}; @@ -14,8 +13,8 @@ const INVALID_EXT_MSG: &str = "Invalid acmeIdentifier extension."; fn get_certificate( domain: &str, - private_key: &PKey, - public_key: &PKey, + public_key: &PublicKey, + private_key: &PrivateKey, acme_ext: &str, ) -> Result { let mut x509_name = X509NameBuilder::new()?; @@ -34,7 +33,7 @@ fn get_certificate( builder.set_serial_number(&serial_number)?; builder.set_subject_name(&x509_name)?; builder.set_issuer_name(&x509_name)?; - builder.set_pubkey(public_key)?; + builder.set_pubkey(&public_key.inner_key)?; let not_before = Asn1Time::days_from_now(0)?; builder.set_not_before(¬_before)?; let not_after = Asn1Time::days_from_now(CRT_NB_DAYS_VALIDITY)?; @@ -57,13 +56,13 @@ fn get_certificate( builder .append_extension(acme_ext) .map_err(|_| Error::from(INVALID_EXT_MSG))?; - builder.sign(private_key, MessageDigest::sha256())?; + builder.sign(&private_key.inner_key, MessageDigest::sha256())?; let cert = builder.build(); Ok(cert) } -pub fn gen_certificate(domain: &str, acme_ext: &str) -> Result<(PKey, X509), Error> { - let (priv_key, pub_key) = gen::p256()?; - let cert = get_certificate(domain, &priv_key, &pub_key, acme_ext)?; +pub fn gen_certificate(domain: &str, acme_ext: &str) -> Result<(PrivateKey, X509), Error> { + let (pub_key, priv_key) = gen_keypair(KeyType::EcdsaP256)?; + let cert = get_certificate(domain, &pub_key, &priv_key, acme_ext)?; Ok((priv_key, cert)) } diff --git a/tacd/src/server.rs b/tacd/src/server.rs index 4e613fa..174cebe 100644 --- a/tacd/src/server.rs +++ b/tacd/src/server.rs @@ -1,6 +1,6 @@ +use acme_common::crypto::PrivateKey; use acme_common::error::Error; use log::debug; -use openssl::pkey::{PKey, Private}; use openssl::ssl::{self, AlpnError, SslAcceptor, SslMethod}; use openssl::x509::X509; use std::net::TcpListener; @@ -30,17 +30,13 @@ macro_rules! listen_and_accept { }; } -pub fn start( - listen_addr: &str, - certificate: &X509, - private_key: &PKey, -) -> Result<(), Error> { +pub fn start(listen_addr: &str, certificate: &X509, private_key: &PrivateKey) -> Result<(), Error> { let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls())?; acceptor.set_alpn_select_callback(|_, client| { debug!("ALPN negociation"); ssl::select_next_proto(crate::ALPN_ACME_PROTO_NAME, client).ok_or(ALPN_ERROR) }); - acceptor.set_private_key(private_key)?; + acceptor.set_private_key(&private_key.inner_key)?; acceptor.set_certificate(certificate)?; acceptor.check_private_key()?; let acceptor = Arc::new(acceptor.build());