diff --git a/src/certs.rs b/src/certs.rs index b7ba444..d70bb9f 100644 --- a/src/certs.rs +++ b/src/certs.rs @@ -3,7 +3,8 @@ 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, OpenSSLExternalProvider, OpenSSLInternalProvider}; +use crate::crypto_provider::ICryptoProvider; +use crate::openssl::{external::OpenSSLExternalProvider, internal::OpenSSLInternalProvider}; pub(crate) struct Certs where diff --git a/src/crypto_provider.rs b/src/crypto_provider.rs new file mode 100644 index 0000000..afb2a96 --- /dev/null +++ b/src/crypto_provider.rs @@ -0,0 +1,6 @@ +use anyhow::Result; + +pub(crate) trait ICryptoProvider { + async fn request(&self) -> Result<()>; + async fn sign(&self) -> Result<()>; +} diff --git a/src/main.rs b/src/main.rs index 9d621b2..2c135bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,8 @@ use clap::Parser; mod certs; mod common; -mod crypto; +mod crypto_provider; +mod openssl; mod vars; use crate::certs::build_client_config; diff --git a/src/openssl/external.rs b/src/openssl/external.rs new file mode 100644 index 0000000..b54da1b --- /dev/null +++ b/src/openssl/external.rs @@ -0,0 +1,138 @@ +use anyhow::{anyhow, Result}; +use std::path::PathBuf; + +use tokio::process::Command; + +use crate::common::{is_file_exist, AppConfig, VarsMap}; +use crate::crypto_provider::ICryptoProvider; + +pub(crate) struct OpenSSLExternalProvider { + vars: VarsMap, + base_dir: PathBuf, + openssl_cnf: PathBuf, + openssl: String, + ca_file: PathBuf, + req_file: PathBuf, + key_file: PathBuf, + cert_file: PathBuf, + req_days: u32, +} + +impl OpenSSLExternalProvider { + async fn is_ca_exists(&self) -> bool { + is_file_exist(&self.ca_file).await + } + + async fn is_cert_exists(&self) -> bool { + is_file_exist(&self.cert_file).await + } + + async fn is_req_exists(&self) -> bool { + is_file_exist(&self.req_file).await + } + + pub(crate) fn from_cfg(cfg: &AppConfig, vars: VarsMap) -> Self { + let base_dir = PathBuf::from(&cfg.base_directory); + let keys_dir = base_dir.clone().join(cfg.keys_subdir.clone()); + let name = cfg.name.clone(); + let mut vars = vars; + + vars.insert("KEY_CN".into(), name.clone()); + vars.insert("KEY_NAME".into(), name.clone()); + vars.insert("KEY_EMAIL".into(), cfg.email.clone()); + + let ca_file = keys_dir.join(cfg.ca_filename.clone()); + let req_file = keys_dir.join(format!("{}.csr", &name)); + let key_file = keys_dir.join(format!("{}.key", &name)); + let cert_file = keys_dir.join(format!("{}.crt", &name)); + let openssl_cnf = base_dir.clone().join( + std::env::var(cfg.openssl_cnf_env.clone()).unwrap_or(cfg.openssl_default_cnf.clone()), + ); + + Self { + vars, + base_dir, + openssl_cnf, + openssl: cfg.openssl.to_string(), + ca_file, + req_file, + key_file, + cert_file, + req_days: cfg.req_days, + } + } +} + +impl ICryptoProvider for OpenSSLExternalProvider { + async fn request(&self) -> Result<()> { + if self.is_req_exists().await { + return Ok(()); + } + + if !self.is_ca_exists().await { + return Err(anyhow!( + "ca file not found: {}", + &self.ca_file.to_str().unwrap() + )); + } + + let status = Command::new(&self.openssl) + .args([ + "req", + "-nodes", + "-new", + "-keyout", + self.key_file.to_str().unwrap(), + "-out", + self.req_file.to_str().unwrap(), + "-config", + self.openssl_cnf.to_str().unwrap(), + "-batch", + ]) + .current_dir(&self.base_dir) + .envs(&self.vars) + .status() + .await?; + + match status.success() { + true => Ok(()), + false => Err(anyhow!("openssl req execution failed")), + } + } + + async fn sign(&self) -> Result<()> { + if self.is_cert_exists().await { + return Ok(()); + } + + if !self.is_ca_exists().await { + return Err(anyhow!( + "ca file not found: {}", + &self.ca_file.to_str().unwrap() + )); + } + + let status = Command::new(&self.openssl) + .args([ + "ca", + "-days", + format!("{}", self.req_days).as_str(), + "-out", + self.cert_file.to_str().unwrap(), + "-in", + self.req_file.to_str().unwrap(), + "-config", + self.openssl_cnf.to_str().unwrap(), + "-batch", + ]) + .current_dir(&self.base_dir) + .envs(&self.vars) + .status() + .await?; + + match status.success() { + true => Ok(()), + false => Err(anyhow!("ssl ca execution failed")), + } + } +} diff --git a/src/crypto.rs b/src/openssl/internal.rs similarity index 73% rename from src/crypto.rs rename to src/openssl/internal.rs index 2e6174a..02f2418 100644 --- a/src/crypto.rs +++ b/src/openssl/internal.rs @@ -13,9 +13,12 @@ use openssl::{ }; use std::path::{Path, PathBuf}; -use tokio::{fs, process::Command}; +use tokio::fs; -use crate::common::{is_file_exist, read_file, AppConfig, VarsMap}; +use crate::{ + common::{is_file_exist, read_file, AppConfig, VarsMap}, + crypto_provider::ICryptoProvider, +}; use lazy_static::lazy_static; use std::collections::HashMap; @@ -88,142 +91,6 @@ fn get_time_str_x509(days: u32) -> Result { Ok(s) } -pub(crate) trait ICryptoProvider { - async fn request(&self) -> Result<()>; - async fn sign(&self) -> Result<()>; -} - -pub(crate) struct OpenSSLExternalProvider { - vars: VarsMap, - base_dir: PathBuf, - openssl_cnf: PathBuf, - openssl: String, - ca_file: PathBuf, - req_file: PathBuf, - key_file: PathBuf, - cert_file: PathBuf, - req_days: u32, -} - -impl OpenSSLExternalProvider { - async fn is_ca_exists(&self) -> bool { - is_file_exist(&self.ca_file).await - } - - async fn is_cert_exists(&self) -> bool { - is_file_exist(&self.cert_file).await - } - - async fn is_req_exists(&self) -> bool { - is_file_exist(&self.req_file).await - } - - pub(crate) fn from_cfg(cfg: &AppConfig, vars: VarsMap) -> Self { - let base_dir = PathBuf::from(&cfg.base_directory); - let keys_dir = base_dir.clone().join(cfg.keys_subdir.clone()); - let name = cfg.name.clone(); - let mut vars = vars; - - vars.insert("KEY_CN".into(), name.clone()); - vars.insert("KEY_NAME".into(), name.clone()); - vars.insert("KEY_EMAIL".into(), cfg.email.clone()); - - let ca_file = keys_dir.join(cfg.ca_filename.clone()); - let req_file = keys_dir.join(format!("{}.csr", &name)); - let key_file = keys_dir.join(format!("{}.key", &name)); - let cert_file = keys_dir.join(format!("{}.crt", &name)); - let openssl_cnf = base_dir.clone().join( - std::env::var(cfg.openssl_cnf_env.clone()).unwrap_or(cfg.openssl_default_cnf.clone()), - ); - - Self { - vars, - base_dir, - openssl_cnf, - openssl: cfg.openssl.to_string(), - ca_file, - req_file, - key_file, - cert_file, - req_days: cfg.req_days, - } - } -} - -impl ICryptoProvider for OpenSSLExternalProvider { - async fn request(&self) -> Result<()> { - if self.is_req_exists().await { - return Ok(()); - } - - if !self.is_ca_exists().await { - return Err(anyhow!( - "ca file not found: {}", - &self.ca_file.to_str().unwrap() - )); - } - - let status = Command::new(&self.openssl) - .args([ - "req", - "-nodes", - "-new", - "-keyout", - self.key_file.to_str().unwrap(), - "-out", - self.req_file.to_str().unwrap(), - "-config", - self.openssl_cnf.to_str().unwrap(), - "-batch", - ]) - .current_dir(&self.base_dir) - .envs(&self.vars) - .status() - .await?; - - match status.success() { - true => Ok(()), - false => Err(anyhow!("openssl req execution failed")), - } - } - - async fn sign(&self) -> Result<()> { - if self.is_cert_exists().await { - return Ok(()); - } - - if !self.is_ca_exists().await { - return Err(anyhow!( - "ca file not found: {}", - &self.ca_file.to_str().unwrap() - )); - } - - let status = Command::new(&self.openssl) - .args([ - "ca", - "-days", - format!("{}", self.req_days).as_str(), - "-out", - self.cert_file.to_str().unwrap(), - "-in", - self.req_file.to_str().unwrap(), - "-config", - self.openssl_cnf.to_str().unwrap(), - "-batch", - ]) - .current_dir(&self.base_dir) - .envs(&self.vars) - .status() - .await?; - - match status.success() { - true => Ok(()), - false => Err(anyhow!("ssl ca execution failed")), - } - } -} - pub(crate) struct OpenSSLInternalProvider { vars: VarsMap, #[allow(unused)] diff --git a/src/openssl/mod.rs b/src/openssl/mod.rs new file mode 100644 index 0000000..d29baed --- /dev/null +++ b/src/openssl/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod external; +pub(crate) mod internal;