use rcgen::{
BasicConstraints, CertificateParams, DistinguishedName, DnType, IsCa, KeyPair, KeyUsagePurpose,
SanType, date_time_ymd,
};
pub fn get_self_signed_cert() -> crate::Result<(Vec<u8>, Vec<u8>)> {
let temp_dir = std::env::temp_dir().join(env!("CARGO_PKG_NAME"));
if !temp_dir.exists() {
tracing::info!("Creating temp cert directory: {}", temp_dir.display());
std::fs::create_dir_all(&temp_dir)?;
}
let cert_path = temp_dir.join("cert.pem");
let key_path = temp_dir.join("key.pem");
if cert_path.exists() && key_path.exists() {
let cert = std::fs::read_to_string(cert_path)?;
let key = std::fs::read(key_path)?;
tracing::trace!("Using existing self-signed certificate: \n{}", cert);
return Ok((cert.into_bytes(), key));
}
let (cert, key) = generate_self_signed()?;
std::fs::write(cert_path, &cert)?;
std::fs::write(key_path, &key)?;
Ok((cert, key))
}
fn generate_self_signed() -> crate::Result<(Vec<u8>, Vec<u8>)> {
let mut params = CertificateParams::default();
params.not_before = date_time_ymd(1975, 1, 1);
params.not_after = date_time_ymd(4096, 1, 1);
let mut distinguished_name = DistinguishedName::new();
distinguished_name.push(DnType::CommonName, env!("CARGO_PKG_NAME"));
distinguished_name.push(DnType::OrganizationName, env!("CARGO_PKG_NAME"));
params.distinguished_name = distinguished_name;
params.key_usages = vec![
KeyUsagePurpose::DigitalSignature,
KeyUsagePurpose::KeyCertSign,
KeyUsagePurpose::CrlSign,
KeyUsagePurpose::KeyEncipherment,
];
params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
params.subject_alt_names = vec![SanType::DnsName("localhost".try_into()?)];
let key_pair = KeyPair::generate()?;
let cert = params.self_signed(&key_pair)?;
let cert = cert.pem();
tracing::trace!("Generating self-signed certificate:\n{}", cert);
Ok((cert.into_bytes(), key_pair.serialize_pem().into_bytes()))
}