use anyhow::Error;
use rcgen::{CertificateParams, DistinguishedName, DnType, IsCa, KeyIdMethod, SanType, PKCS_ECDSA_P256_SHA256};
use rustls_pki_types::{CertificateDer, PrivateKeyDer};
use time::{ext::NumericalDuration, OffsetDateTime};
use std::path::PathBuf;
use crate::{ServerCertHash, WebServerDestination};
pub fn generate_self_signed_certificate(
params: CertificateParams,
) -> Result<(CertificateDer<'static>, PrivateKeyDer<'static>), rcgen::Error> {
let keypair = rcgen::KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256)?;
let rc_certificate = params.self_signed(&keypair)?;
let certificate = rc_certificate.der().clone();
let privkey = PrivateKeyDer::Pkcs8(keypair.serialize_der().into());
Ok((certificate, privkey))
}
pub fn generate_self_signed_certificate_opinionated<T: Into<WebServerDestination>>(
subject_alt_names: impl IntoIterator<Item = T>,
) -> Result<(CertificateDer<'static>, PrivateKeyDer<'static>), rcgen::Error> {
let not_before = OffsetDateTime::now_utc().saturating_sub(1.hours()); let not_after = not_before.saturating_add(2.weeks());
let mut distinguished_name = DistinguishedName::new();
distinguished_name.push(DnType::CommonName, "renet2 self signed cert");
let mut subject_alt_names_collected: Vec<SanType> = vec![];
for dest in subject_alt_names.into_iter() {
let san_type = match dest.into() {
WebServerDestination::Addr(addr) => SanType::IpAddress(addr.ip()),
WebServerDestination::Url(url) => match url.domain() {
Some(domain) => SanType::DnsName(domain.try_into()?),
None => SanType::URI(String::from(url).try_into()?),
},
};
subject_alt_names_collected.push(san_type);
}
let mut params = CertificateParams::default(); params.not_before = not_before;
params.not_after = not_after;
params.serial_number = None;
params.subject_alt_names = subject_alt_names_collected;
params.distinguished_name = distinguished_name;
params.is_ca = IsCa::NoCa;
params.key_usages = Vec::new();
params.extended_key_usages = Vec::new();
params.name_constraints = None;
params.crl_distribution_points = Vec::new();
params.custom_extensions = Vec::new();
params.use_authority_key_identifier_extension = false;
params.key_identifier_method = KeyIdMethod::Sha256;
generate_self_signed_certificate(params)
}
pub fn get_certificate_and_key_from_files(cert: PathBuf, key: PathBuf) -> Result<(CertificateDer<'static>, PrivateKeyDer<'static>), Error> {
let cert = CertificateDer::from(std::fs::read(cert)?);
let key = PrivateKeyDer::Pkcs8(std::fs::read(key)?.into());
Ok((cert, key))
}
pub fn get_server_cert_hash(cert: &CertificateDer<'_>) -> ServerCertHash {
let hash = hmac_sha256::Hash::hash(cert.as_ref());
ServerCertHash { hash }
}