refactor
This commit is contained in:
		@@ -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(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user