refactor
This commit is contained in:
parent
fa9c1ecb2c
commit
c7677bdb70
@ -3,7 +3,7 @@ use anyhow::{anyhow, Context, Result};
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
use crate::common::{is_file_exist, read_file, write_file, AppConfig, OpenSSLProviderArg, VarsMap};
|
||||
use crate::crypto::{ICryptoProvider, OpenSSLBinProvider, OpenSSLLibProvider};
|
||||
use crate::crypto::{ICryptoProvider, OpenSSLExternalProvider, OpenSSLInternalProvider};
|
||||
|
||||
pub(crate) struct Certs<T>
|
||||
where
|
||||
@ -93,14 +93,14 @@ pub async fn build_client_config(config: &AppConfig, vars: VarsMap) -> Result<()
|
||||
let created: bool;
|
||||
|
||||
if let OpenSSLProviderArg::ExternalBin(_) = config.openssl {
|
||||
let certs = Certs::new(config, OpenSSLBinProvider::from_cfg(config, vars));
|
||||
let certs = Certs::new(config, OpenSSLExternalProvider::from_cfg(config, vars));
|
||||
created = certs
|
||||
.build_client_config()
|
||||
.await
|
||||
.context("external openssl error")?;
|
||||
result_file = certs.config_file;
|
||||
} else {
|
||||
let certs = Certs::new(config, OpenSSLLibProvider::from_cfg(config, vars));
|
||||
let certs = Certs::new(config, OpenSSLInternalProvider::from_cfg(config, vars));
|
||||
created = certs
|
||||
.build_client_config()
|
||||
.await
|
||||
|
170
src/crypto.rs
170
src/crypto.rs
@ -8,10 +8,10 @@ use openssl::{
|
||||
stack::Stack,
|
||||
x509::{
|
||||
extension::{ExtendedKeyUsage, KeyUsage, SubjectAlternativeName},
|
||||
X509Name, X509NameBuilder, X509Req, X509ReqBuilder, X509,
|
||||
X509Extension, X509Name, X509NameBuilder, X509Req, X509ReqBuilder, X509,
|
||||
},
|
||||
};
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use tokio::{fs, process::Command};
|
||||
|
||||
@ -35,6 +35,42 @@ lazy_static! {
|
||||
};
|
||||
}
|
||||
|
||||
trait ToPemX {
|
||||
fn to_pem_x(&self) -> Result<Vec<u8>>;
|
||||
}
|
||||
|
||||
impl ToPemX for X509 {
|
||||
fn to_pem_x(&self) -> Result<Vec<u8>> {
|
||||
Ok(self.to_pem()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToPemX for X509Req {
|
||||
fn to_pem_x(&self) -> Result<Vec<u8>> {
|
||||
Ok(self.to_pem()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToPemX for PKey<Private> {
|
||||
fn to_pem_x(&self) -> Result<Vec<u8>> {
|
||||
Ok(self.private_key_to_pem_pkcs8()?)
|
||||
}
|
||||
}
|
||||
|
||||
struct Pem<'a, T: ToPemX>(&'a T);
|
||||
|
||||
trait WritePem {
|
||||
async fn write<T: AsRef<Path>>(&self, path: T) -> Result<()>;
|
||||
}
|
||||
|
||||
impl<'a, P: ToPemX> WritePem for Pem<'a, P> {
|
||||
async fn write<T: AsRef<Path>>(&self, path: T) -> Result<()> {
|
||||
let pem = self.0.to_pem_x().context("to_pem()")?;
|
||||
fs::write(path, pem).await.context("write pem")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_time_str_x509(days: u32) -> Result<String> {
|
||||
let dt = Utc::now();
|
||||
let dt = dt
|
||||
@ -57,7 +93,7 @@ pub(crate) trait ICryptoProvider {
|
||||
async fn sign(&self) -> Result<()>;
|
||||
}
|
||||
|
||||
pub(crate) struct OpenSSLBinProvider {
|
||||
pub(crate) struct OpenSSLExternalProvider {
|
||||
vars: VarsMap,
|
||||
base_dir: PathBuf,
|
||||
openssl_cnf: PathBuf,
|
||||
@ -69,7 +105,7 @@ pub(crate) struct OpenSSLBinProvider {
|
||||
req_days: u32,
|
||||
}
|
||||
|
||||
impl OpenSSLBinProvider {
|
||||
impl OpenSSLExternalProvider {
|
||||
async fn is_ca_exists(&self) -> bool {
|
||||
is_file_exist(&self.ca_file).await
|
||||
}
|
||||
@ -114,7 +150,7 @@ impl OpenSSLBinProvider {
|
||||
}
|
||||
}
|
||||
|
||||
impl ICryptoProvider for OpenSSLBinProvider {
|
||||
impl ICryptoProvider for OpenSSLExternalProvider {
|
||||
async fn request(&self) -> Result<()> {
|
||||
if self.is_req_exists().await {
|
||||
return Ok(());
|
||||
@ -188,7 +224,7 @@ impl ICryptoProvider for OpenSSLBinProvider {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct OpenSSLLibProvider {
|
||||
pub(crate) struct OpenSSLInternalProvider {
|
||||
vars: VarsMap,
|
||||
#[allow(unused)]
|
||||
base_dir: PathBuf,
|
||||
@ -204,7 +240,7 @@ pub(crate) struct OpenSSLLibProvider {
|
||||
encoding: String,
|
||||
}
|
||||
|
||||
impl OpenSSLLibProvider {
|
||||
impl OpenSSLInternalProvider {
|
||||
async fn is_ca_exists(&self) -> bool {
|
||||
is_file_exist(&self.ca_file).await
|
||||
}
|
||||
@ -268,9 +304,9 @@ impl OpenSSLLibProvider {
|
||||
Ok(X509::from_pem(text.as_bytes())?)
|
||||
}
|
||||
|
||||
async fn get_ca_key(&self) -> Result<Rsa<Private>> {
|
||||
async fn get_ca_key(&self) -> Result<PKey<Private>> {
|
||||
let text = read_file(self.ca_key_file.clone(), &self.encoding).await?;
|
||||
Ok(Rsa::private_key_from_pem(text.as_bytes())?)
|
||||
Ok(PKey::from_rsa(Rsa::private_key_from_pem(text.as_bytes())?)?)
|
||||
}
|
||||
|
||||
async fn get_key(&self) -> Result<(Rsa<Private>, PKey<Private>)> {
|
||||
@ -290,8 +326,10 @@ impl OpenSSLLibProvider {
|
||||
self.get_key().await
|
||||
} else {
|
||||
let (rsa, pkey) = self.generate_key_pair()?;
|
||||
let key_data = pkey.private_key_to_pem_pkcs8()?;
|
||||
tokio::fs::write(self.key_file.as_path(), key_data).await?;
|
||||
Pem(&pkey)
|
||||
.write(&self.key_file)
|
||||
.await
|
||||
.context("key write pem")?;
|
||||
Ok((rsa, pkey))
|
||||
}
|
||||
}
|
||||
@ -308,9 +346,42 @@ impl OpenSSLLibProvider {
|
||||
}
|
||||
Ok(name_builder.build())
|
||||
}
|
||||
|
||||
fn gen_x509_extensions(
|
||||
context: &openssl::x509::X509v3Context,
|
||||
vars: &VarsMap,
|
||||
) -> Result<Vec<X509Extension>> {
|
||||
let key_usage = KeyUsage::new()
|
||||
.key_agreement()
|
||||
.digital_signature()
|
||||
.build()?;
|
||||
let key_extended_ext = ExtendedKeyUsage::new().client_auth().build()?;
|
||||
|
||||
let mut san_extension = SubjectAlternativeName::new();
|
||||
if let Some(name) = vars.get("KEY_NAME") {
|
||||
san_extension.dns(name);
|
||||
}
|
||||
if let Some(email) = vars.get("KEY_EMAIL") {
|
||||
san_extension.email(email);
|
||||
}
|
||||
let san_ext = san_extension.build(context).context("build san")?;
|
||||
|
||||
Ok(vec![san_ext, key_usage, key_extended_ext])
|
||||
}
|
||||
|
||||
fn gen_x509_extensions_stack(
|
||||
context: &openssl::x509::X509v3Context,
|
||||
vars: &VarsMap,
|
||||
) -> Result<Stack<X509Extension>> {
|
||||
let mut stack = Stack::new()?;
|
||||
for extension in Self::gen_x509_extensions(context, vars)?.into_iter() {
|
||||
stack.push(extension).context("push ext")?;
|
||||
}
|
||||
Ok(stack)
|
||||
}
|
||||
}
|
||||
|
||||
impl ICryptoProvider for OpenSSLLibProvider {
|
||||
impl ICryptoProvider for OpenSSLInternalProvider {
|
||||
async fn request(&self) -> Result<()> {
|
||||
if self.is_req_exists().await {
|
||||
return Ok(());
|
||||
@ -326,44 +397,25 @@ impl ICryptoProvider for OpenSSLLibProvider {
|
||||
let (_, pkey) = self.ensure_key().await?;
|
||||
|
||||
let name = self.build_x509_name()?;
|
||||
let key_usage = KeyUsage::new()
|
||||
.key_agreement()
|
||||
.digital_signature()
|
||||
.build()?;
|
||||
let key_extended_ext = ExtendedKeyUsage::new().client_auth().build()?;
|
||||
let mut st = Stack::new()?;
|
||||
st.push(key_usage).context("push key usage")?;
|
||||
st.push(key_extended_ext).context("push key_extended_ext")?;
|
||||
|
||||
let conf = Conf::new(ConfMethod::default()).context("conf new")?;
|
||||
|
||||
// Create certificate signing request (CSR)
|
||||
let mut csr_builder = X509ReqBuilder::new()?;
|
||||
csr_builder.set_pubkey(&pkey).context("set pubkey")?;
|
||||
csr_builder.set_version(2).context("set version")?;
|
||||
|
||||
let context = csr_builder.x509v3_context(Some(&conf));
|
||||
|
||||
let mut san_extension = SubjectAlternativeName::new();
|
||||
if let Some(name) = self.vars.get("KEY_NAME") {
|
||||
san_extension.dns(name);
|
||||
}
|
||||
if let Some(email) = self.vars.get("KEY_EMAIL") {
|
||||
san_extension.email(email);
|
||||
}
|
||||
let san_ext = san_extension.build(&context).context("build san")?;
|
||||
|
||||
st.push(san_ext).context("push san")?;
|
||||
|
||||
csr_builder.set_pubkey(&pkey).context("set pubkey")?;
|
||||
csr_builder
|
||||
.set_subject_name(&name)
|
||||
.context("set subject name")?;
|
||||
csr_builder.add_extensions(&st)?;
|
||||
let context = csr_builder.x509v3_context(Some(&conf));
|
||||
let extensions = Self::gen_x509_extensions_stack(&context, &self.vars)?;
|
||||
csr_builder.add_extensions(&extensions)?;
|
||||
csr_builder.sign(&pkey, MessageDigest::sha512())?;
|
||||
let csr = csr_builder.build();
|
||||
let pem = csr.to_pem()?;
|
||||
fs::write(self.req_file.as_path(), pem).await?;
|
||||
|
||||
Pem(&csr)
|
||||
.write(&self.req_file)
|
||||
.await
|
||||
.context("req write pem")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -388,22 +440,11 @@ impl ICryptoProvider for OpenSSLLibProvider {
|
||||
|
||||
let ca_key = self.get_ca_key().await?;
|
||||
let ca_cert = self.get_ca_cert().await?;
|
||||
let ca_pkey = PKey::from_rsa(ca_key.clone())?;
|
||||
|
||||
let req = self.get_req().await?;
|
||||
let pub_key = req.public_key()?;
|
||||
let subject_name = req.subject_name();
|
||||
|
||||
let key_usage = KeyUsage::new()
|
||||
.key_agreement()
|
||||
.digital_signature()
|
||||
.build()
|
||||
.context("new key_usage")?;
|
||||
let key_extended_ext = ExtendedKeyUsage::new()
|
||||
.client_auth()
|
||||
.build()
|
||||
.context("new key_extended_ext")?;
|
||||
|
||||
let mut builder = openssl::x509::X509Builder::new().context("new builder")?;
|
||||
let not_before = Asn1Time::days_from_now(0).context("days_from_now 0")?;
|
||||
let na_s = get_time_str_x509(self.req_days).context("na_s get_time_str_x509")?;
|
||||
@ -423,36 +464,19 @@ impl ICryptoProvider for OpenSSLLibProvider {
|
||||
.context("set_subject_name")?;
|
||||
|
||||
let context = builder.x509v3_context(Some(&ca_cert), None);
|
||||
|
||||
let mut san_extension = SubjectAlternativeName::new();
|
||||
if let Some(name) = self.vars.get("KEY_NAME") {
|
||||
san_extension.dns(name);
|
||||
for extension in Self::gen_x509_extensions(&context, &self.vars)? {
|
||||
builder.append_extension(extension).context("append ext")?;
|
||||
}
|
||||
if let Some(email) = self.vars.get("KEY_EMAIL") {
|
||||
san_extension.email(email);
|
||||
}
|
||||
let san_ext = san_extension.build(&context).context("build san")?;
|
||||
|
||||
builder
|
||||
.append_extension(san_ext)
|
||||
.context("append san ext")?;
|
||||
builder
|
||||
.append_extension(key_usage)
|
||||
.context("append key_usage ext")?;
|
||||
builder
|
||||
.append_extension(key_extended_ext)
|
||||
.context("append key_extended_ext ext")?;
|
||||
|
||||
builder
|
||||
.sign(&ca_pkey, MessageDigest::sha512())
|
||||
.sign(&ca_key, MessageDigest::sha512())
|
||||
.context("builder.sign")?;
|
||||
let cert = builder.build();
|
||||
|
||||
let pem = cert.to_pem().context("cert.to_pem()")?;
|
||||
fs::write(self.cert_file.as_path(), pem)
|
||||
Pem(&cert)
|
||||
.write(&self.cert_file)
|
||||
.await
|
||||
.context("fs::write")?;
|
||||
|
||||
.context("cert.to_pem()")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user