Compare commits
5 Commits
8c1add6ff1
...
internal_o
| Author | SHA1 | Date | |
|---|---|---|---|
|
cdac6d2aa5
|
|||
|
f5e207654c
|
|||
|
232ad335fa
|
|||
|
c7677bdb70
|
|||
|
fa9c1ecb2c
|
12
Cargo.lock
generated
12
Cargo.lock
generated
@@ -153,9 +153,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.7.2"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
|
checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
@@ -690,9 +690,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.79"
|
version = "2.0.82"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
|
checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -701,9 +701,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.40.0"
|
version = "1.41.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
|
checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ futures-util = "0.3.31"
|
|||||||
lazy_static = "1.5.0"
|
lazy_static = "1.5.0"
|
||||||
openssl = { version="0.10.68" }
|
openssl = { version="0.10.68" }
|
||||||
regex = "1.11.0"
|
regex = "1.11.0"
|
||||||
tokio = { version = "1.40.0", features = ["fs", "rt", "process", "macros", "io-util"] }
|
tokio = { version = "1.41.0", features = ["fs", "rt", "process", "macros", "io-util"] }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
FROM lukemathwalker/cargo-chef:latest-rust-1 AS chef
|
FROM lukemathwalker/cargo-chef:latest-rust-1 AS chef
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
RUN apt --no-install-recommends update && apt install -y libssl-dev
|
||||||
|
|
||||||
FROM chef AS planner
|
FROM chef AS planner
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ use anyhow::{anyhow, Context, Result};
|
|||||||
use std::{path::PathBuf, sync::Arc};
|
use std::{path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
use crate::common::{is_file_exist, read_file, write_file, AppConfig, OpenSSLProviderArg, VarsMap};
|
use crate::common::{is_file_exist, read_file, write_file, AppConfig, OpenSSLProviderArg, VarsMap};
|
||||||
use crate::crypto::{ICryptoProvider, OpenSSLBinProvider, OpenSSLLibProvider};
|
use crate::crypto_provider::ICryptoProvider;
|
||||||
|
use crate::openssl::{external::OpenSSLExternalProvider, internal::OpenSSLInternalProvider};
|
||||||
|
|
||||||
pub(crate) struct Certs<T>
|
pub(crate) struct Certs<T>
|
||||||
where
|
where
|
||||||
@@ -93,14 +94,14 @@ pub async fn build_client_config(config: &AppConfig, vars: VarsMap) -> Result<()
|
|||||||
let created: bool;
|
let created: bool;
|
||||||
|
|
||||||
if let OpenSSLProviderArg::ExternalBin(_) = config.openssl {
|
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
|
created = certs
|
||||||
.build_client_config()
|
.build_client_config()
|
||||||
.await
|
.await
|
||||||
.context("external openssl error")?;
|
.context("external openssl error")?;
|
||||||
result_file = certs.config_file;
|
result_file = certs.config_file;
|
||||||
} else {
|
} else {
|
||||||
let certs = Certs::new(config, OpenSSLLibProvider::from_cfg(config, vars));
|
let certs = Certs::new(config, OpenSSLInternalProvider::from_cfg(config, vars));
|
||||||
created = certs
|
created = certs
|
||||||
.build_client_config()
|
.build_client_config()
|
||||||
.await
|
.await
|
||||||
|
|||||||
6
src/crypto_provider.rs
Normal file
6
src/crypto_provider.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
pub(crate) trait ICryptoProvider {
|
||||||
|
async fn request(&self) -> Result<()>;
|
||||||
|
async fn sign(&self) -> Result<()>;
|
||||||
|
}
|
||||||
@@ -3,7 +3,8 @@ use clap::Parser;
|
|||||||
|
|
||||||
mod certs;
|
mod certs;
|
||||||
mod common;
|
mod common;
|
||||||
mod crypto;
|
mod crypto_provider;
|
||||||
|
mod openssl;
|
||||||
mod vars;
|
mod vars;
|
||||||
|
|
||||||
use crate::certs::build_client_config;
|
use crate::certs::build_client_config;
|
||||||
|
|||||||
138
src/openssl/external.rs
Normal file
138
src/openssl/external.rs
Normal file
@@ -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")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,14 +8,17 @@ use openssl::{
|
|||||||
stack::Stack,
|
stack::Stack,
|
||||||
x509::{
|
x509::{
|
||||||
extension::{ExtendedKeyUsage, KeyUsage, SubjectAlternativeName},
|
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};
|
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 lazy_static::lazy_static;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -35,6 +38,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> {
|
fn get_time_str_x509(days: u32) -> Result<String> {
|
||||||
let dt = Utc::now();
|
let dt = Utc::now();
|
||||||
let dt = dt
|
let dt = dt
|
||||||
@@ -52,143 +91,7 @@ fn get_time_str_x509(days: u32) -> Result<String> {
|
|||||||
Ok(s)
|
Ok(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait ICryptoProvider {
|
pub(crate) struct OpenSSLInternalProvider {
|
||||||
async fn request(&self) -> Result<()>;
|
|
||||||
async fn sign(&self) -> Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct OpenSSLBinProvider {
|
|
||||||
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 OpenSSLBinProvider {
|
|
||||||
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 OpenSSLBinProvider {
|
|
||||||
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 OpenSSLLibProvider {
|
|
||||||
vars: VarsMap,
|
vars: VarsMap,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
base_dir: PathBuf,
|
base_dir: PathBuf,
|
||||||
@@ -204,7 +107,7 @@ pub(crate) struct OpenSSLLibProvider {
|
|||||||
encoding: String,
|
encoding: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OpenSSLLibProvider {
|
impl OpenSSLInternalProvider {
|
||||||
async fn is_ca_exists(&self) -> bool {
|
async fn is_ca_exists(&self) -> bool {
|
||||||
is_file_exist(&self.ca_file).await
|
is_file_exist(&self.ca_file).await
|
||||||
}
|
}
|
||||||
@@ -268,9 +171,9 @@ impl OpenSSLLibProvider {
|
|||||||
Ok(X509::from_pem(text.as_bytes())?)
|
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?;
|
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>)> {
|
async fn get_key(&self) -> Result<(Rsa<Private>, PKey<Private>)> {
|
||||||
@@ -290,8 +193,10 @@ impl OpenSSLLibProvider {
|
|||||||
self.get_key().await
|
self.get_key().await
|
||||||
} else {
|
} else {
|
||||||
let (rsa, pkey) = self.generate_key_pair()?;
|
let (rsa, pkey) = self.generate_key_pair()?;
|
||||||
let key_data = pkey.private_key_to_pem_pkcs8()?;
|
Pem(&pkey)
|
||||||
tokio::fs::write(self.key_file.as_path(), key_data).await?;
|
.write(&self.key_file)
|
||||||
|
.await
|
||||||
|
.context("key write pem")?;
|
||||||
Ok((rsa, pkey))
|
Ok((rsa, pkey))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -308,9 +213,42 @@ impl OpenSSLLibProvider {
|
|||||||
}
|
}
|
||||||
Ok(name_builder.build())
|
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])
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ICryptoProvider for OpenSSLLibProvider {
|
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 OpenSSLInternalProvider {
|
||||||
async fn request(&self) -> Result<()> {
|
async fn request(&self) -> Result<()> {
|
||||||
if self.is_req_exists().await {
|
if self.is_req_exists().await {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -326,37 +264,25 @@ impl ICryptoProvider for OpenSSLLibProvider {
|
|||||||
let (_, pkey) = self.ensure_key().await?;
|
let (_, pkey) = self.ensure_key().await?;
|
||||||
|
|
||||||
let name = self.build_x509_name()?;
|
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")?;
|
let conf = Conf::new(ConfMethod::default()).context("conf new")?;
|
||||||
|
|
||||||
// Create certificate signing request (CSR)
|
// Create certificate signing request (CSR)
|
||||||
let mut csr_builder = X509ReqBuilder::new()?;
|
let mut csr_builder = X509ReqBuilder::new()?;
|
||||||
csr_builder.set_pubkey(&pkey).context("set pubkey")?;
|
|
||||||
csr_builder.set_version(2).context("set version")?;
|
csr_builder.set_version(2).context("set version")?;
|
||||||
|
csr_builder.set_pubkey(&pkey).context("set pubkey")?;
|
||||||
let context = csr_builder.x509v3_context(Some(&conf));
|
|
||||||
let mut san_extension = SubjectAlternativeName::new();
|
|
||||||
san_extension.dns(self.vars.get("KEY_NAME").unwrap());
|
|
||||||
let san_ext = san_extension.build(&context).context("build san")?;
|
|
||||||
st.push(san_ext).context("push san")?;
|
|
||||||
|
|
||||||
csr_builder
|
csr_builder
|
||||||
.set_subject_name(&name)
|
.set_subject_name(&name)
|
||||||
.context("set subject 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())?;
|
csr_builder.sign(&pkey, MessageDigest::sha512())?;
|
||||||
let csr = csr_builder.build();
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,22 +307,11 @@ impl ICryptoProvider for OpenSSLLibProvider {
|
|||||||
|
|
||||||
let ca_key = self.get_ca_key().await?;
|
let ca_key = self.get_ca_key().await?;
|
||||||
let ca_cert = self.get_ca_cert().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 req = self.get_req().await?;
|
||||||
let pub_key = req.public_key()?;
|
let pub_key = req.public_key()?;
|
||||||
let subject_name = req.subject_name();
|
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 mut builder = openssl::x509::X509Builder::new().context("new builder")?;
|
||||||
let not_before = Asn1Time::days_from_now(0).context("days_from_now 0")?;
|
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")?;
|
let na_s = get_time_str_x509(self.req_days).context("na_s get_time_str_x509")?;
|
||||||
@@ -416,29 +331,19 @@ impl ICryptoProvider for OpenSSLLibProvider {
|
|||||||
.context("set_subject_name")?;
|
.context("set_subject_name")?;
|
||||||
|
|
||||||
let context = builder.x509v3_context(Some(&ca_cert), None);
|
let context = builder.x509v3_context(Some(&ca_cert), None);
|
||||||
let mut san_extension = SubjectAlternativeName::new();
|
for extension in Self::gen_x509_extensions(&context, &self.vars)? {
|
||||||
san_extension.dns(self.vars.get("KEY_NAME").unwrap());
|
builder.append_extension(extension).context("append ext")?;
|
||||||
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
|
builder
|
||||||
.sign(&ca_pkey, MessageDigest::sha512())
|
.sign(&ca_key, MessageDigest::sha512())
|
||||||
.context("builder.sign")?;
|
.context("builder.sign")?;
|
||||||
let cert = builder.build();
|
let cert = builder.build();
|
||||||
|
|
||||||
let pem = cert.to_pem().context("cert.to_pem()")?;
|
Pem(&cert)
|
||||||
fs::write(self.cert_file.as_path(), pem)
|
.write(&self.cert_file)
|
||||||
.await
|
.await
|
||||||
.context("fs::write")?;
|
.context("cert.to_pem()")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
2
src/openssl/mod.rs
Normal file
2
src/openssl/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
pub(crate) mod external;
|
||||||
|
pub(crate) mod internal;
|
||||||
Reference in New Issue
Block a user