use rcgen::{CertificateParams, IsCa, KeyPair, KeyUsagePurpose};
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
use crate::Error;
pub struct CertificateAuthority {
pub(crate) cert: rcgen::Certificate,
pub(crate) key: KeyPair,
}
impl CertificateAuthority {
pub fn from_pem(cert_pem: &str, key_pem: &str) -> Result<Self, Error> {
let key = KeyPair::from_pem(key_pem)?;
let params = CertificateParams::from_ca_cert_pem(cert_pem)?;
let cert = params.self_signed(&key)?;
Ok(Self { cert, key })
}
pub fn from_pem_files(
cert_path: impl AsRef<std::path::Path>,
key_path: impl AsRef<std::path::Path>,
) -> Result<Self, Error> {
let cert_pem = std::fs::read_to_string(cert_path)?;
let key_pem = std::fs::read_to_string(key_path)?;
Self::from_pem(&cert_pem, &key_pem)
}
pub fn generate() -> Result<Self, Error> {
Self::generate_with_cn("MITM CA")
}
pub fn generate_with_cn(cn: &str) -> Result<Self, Error> {
let mut params = CertificateParams::default();
params.is_ca = IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
params
.distinguished_name
.push(rcgen::DnType::CommonName, cn);
params.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign];
let key = KeyPair::generate()?;
let cert = params.self_signed(&key)?;
Ok(Self { cert, key })
}
pub fn to_pem_files(
&self,
cert_path: impl AsRef<std::path::Path>,
key_path: impl AsRef<std::path::Path>,
) -> Result<(), Error> {
std::fs::write(cert_path, self.cert.pem())?;
std::fs::write(key_path, self.key.serialize_pem())?;
Ok(())
}
pub fn cert_pem(&self) -> String {
self.cert.pem()
}
pub fn key_pem(&self) -> String {
self.key.serialize_pem()
}
pub fn generate_cert(
&self,
hostname: &str,
) -> Result<(CertificateDer<'static>, PrivateKeyDer<'static>), Error> {
let mut params = CertificateParams::new(vec![hostname.to_string()])?;
params.is_ca = IsCa::NoCa;
params.key_usages = vec![KeyUsagePurpose::DigitalSignature];
params
.distinguished_name
.push(rcgen::DnType::CommonName, hostname);
let key_pair = KeyPair::generate()?;
let key_der = PrivateKeyDer::Pkcs8(key_pair.serialized_der().to_vec().into());
let cert = params.signed_by(&key_pair, &self.cert, &self.key)?;
let cert_der = cert.der().clone();
Ok((cert_der, key_der))
}
}