use crate::mitm::certificate_authority::{CertificateAuthority, CACHE_TTL, NOT_BEFORE_OFFSET, TTL_SECS};
use product_os_http::uri::Authority;
use moka::future::Cache;
use rand::{thread_rng, Rng};
use rcgen::{
Certificate, CertificateParams, DistinguishedName, DnType, Ia5String, KeyPair, SanType,
};
use std::sync::Arc;
use time::{Duration, OffsetDateTime};
use tokio_rustls::rustls::{
pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer},
ServerConfig,
};
use tracing::debug;
pub struct RcgenAuthority {
key_pair: KeyPair,
ca_cert: Certificate,
private_key: PrivateKeyDer<'static>,
cache: Cache<Authority, Arc<ServerConfig>>,
}
impl RcgenAuthority {
pub fn new(key_pair: KeyPair, ca_cert: Certificate, cache_size: u64) -> Self {
let private_key = PrivateKeyDer::from(PrivatePkcs8KeyDer::from(key_pair.serialize_der()));
Self {
key_pair,
ca_cert,
private_key,
cache: Cache::builder()
.max_capacity(cache_size)
.time_to_live(std::time::Duration::from_secs(CACHE_TTL))
.build(),
}
}
fn gen_cert(&self, authority: &Authority) -> CertificateDer<'static> {
let mut params = CertificateParams::default();
params.serial_number = Some(thread_rng().gen::<u64>().into());
let not_before = OffsetDateTime::now_utc() - Duration::seconds(NOT_BEFORE_OFFSET);
params.not_before = not_before;
params.not_after = not_before + Duration::seconds(TTL_SECS);
let mut distinguished_name = DistinguishedName::new();
distinguished_name.push(DnType::CommonName, authority.host());
params.distinguished_name = distinguished_name;
params.subject_alt_names.push(SanType::DnsName(
Ia5String::try_from(authority.host()).expect("Failed to create Ia5String"),
));
params
.signed_by(&self.key_pair, &self.ca_cert, &self.key_pair)
.expect("Failed to sign certificate")
.into()
}
}
impl CertificateAuthority for RcgenAuthority {
async fn gen_server_config(&self, authority: &Authority) -> Arc<ServerConfig> {
if let Some(server_cfg) = self.cache.get(authority).await {
debug!("Using cached server config");
return server_cfg;
}
debug!("Generating server config");
let certs = vec![self.gen_cert(authority)];
let mut server_cfg = ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(certs, self.private_key.clone_key())
.expect("Failed to build ServerConfig");
server_cfg.alpn_protocols = vec![
b"h2".to_vec(),
b"http/1.1".to_vec(),
];
let server_cfg = Arc::new(server_cfg);
self.cache
.insert(authority.clone(), Arc::clone(&server_cfg))
.await;
server_cfg
}
}