Compare commits
2 Commits
8c1add6ff1
...
c7677bdb70
Author | SHA1 | Date | |
---|---|---|---|
c7677bdb70 | |||
fa9c1ecb2c |
@ -3,7 +3,7 @@ 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::{ICryptoProvider, OpenSSLExternalProvider, OpenSSLInternalProvider};
|
||||||
|
|
||||||
pub(crate) struct Certs<T>
|
pub(crate) struct Certs<T>
|
||||||
where
|
where
|
||||||
@ -93,14 +93,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
|
||||||
|
158
src/crypto.rs
158
src/crypto.rs
@ -8,10 +8,10 @@ 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, 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> {
|
fn get_time_str_x509(days: u32) -> Result<String> {
|
||||||
let dt = Utc::now();
|
let dt = Utc::now();
|
||||||
let dt = dt
|
let dt = dt
|
||||||
@ -57,7 +93,7 @@ pub(crate) trait ICryptoProvider {
|
|||||||
async fn sign(&self) -> Result<()>;
|
async fn sign(&self) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct OpenSSLBinProvider {
|
pub(crate) struct OpenSSLExternalProvider {
|
||||||
vars: VarsMap,
|
vars: VarsMap,
|
||||||
base_dir: PathBuf,
|
base_dir: PathBuf,
|
||||||
openssl_cnf: PathBuf,
|
openssl_cnf: PathBuf,
|
||||||
@ -69,7 +105,7 @@ pub(crate) struct OpenSSLBinProvider {
|
|||||||
req_days: u32,
|
req_days: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OpenSSLBinProvider {
|
impl OpenSSLExternalProvider {
|
||||||
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
|
||||||
}
|
}
|
||||||
@ -114,7 +150,7 @@ impl OpenSSLBinProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ICryptoProvider for OpenSSLBinProvider {
|
impl ICryptoProvider for OpenSSLExternalProvider {
|
||||||
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(());
|
||||||
@ -188,7 +224,7 @@ impl ICryptoProvider for OpenSSLBinProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct OpenSSLLibProvider {
|
pub(crate) struct OpenSSLInternalProvider {
|
||||||
vars: VarsMap,
|
vars: VarsMap,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
base_dir: PathBuf,
|
base_dir: PathBuf,
|
||||||
@ -204,7 +240,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 +304,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 +326,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 +346,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])
|
||||||
|
}
|
||||||
|
|
||||||
|
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<()> {
|
async fn request(&self) -> Result<()> {
|
||||||
if self.is_req_exists().await {
|
if self.is_req_exists().await {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -326,37 +397,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 +440,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 +464,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(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user