#![allow(clippy::expect_used)]
use rcgen::{
BasicConstraints, CertificateParams, DistinguishedName, DnType, IsCa, Issuer, KeyPair, SanType,
};
#[derive(Debug)]
pub struct Ca {
pem: String,
issuer: Issuer<'static, KeyPair>,
}
impl Ca {
#[must_use]
pub fn new() -> Self {
Self::named("sipx test CA")
}
#[must_use]
pub fn named(common_name: &str) -> Self {
let key = KeyPair::generate().expect("a key");
let mut params = CertificateParams::new(Vec::new()).expect("params");
params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
let mut name = DistinguishedName::new();
name.push(DnType::CommonName, common_name);
params.distinguished_name = name;
let certificate = params.clone().self_signed(&key).expect("a CA certificate");
Self {
pem: certificate.pem(),
issuer: Issuer::new(params, key),
}
}
#[must_use]
pub fn pem(&self) -> String {
self.pem.clone()
}
#[must_use]
pub fn issue(&self, sans: &[SanType], common_name: &str) -> (String, String) {
let key = KeyPair::generate().expect("a key");
let mut params = CertificateParams::new(Vec::new()).expect("params");
params.subject_alt_names = sans.to_vec();
let mut name = DistinguishedName::new();
name.push(DnType::CommonName, common_name);
params.distinguished_name = name;
let signed = params
.signed_by(&key, &self.issuer)
.expect("a leaf certificate");
(signed.pem(), key.serialize_pem())
}
#[must_use]
pub fn issue_for(&self, host: &str) -> (String, String) {
self.issue(&[dns(host)], host)
}
}
impl Default for Ca {
fn default() -> Self {
Self::new()
}
}
#[must_use]
pub fn dns(name: &str) -> SanType {
SanType::DnsName(name.try_into().expect("a DNS name"))
}