use async_trait::async_trait;
use openssl::ssl::{SniError, SslRef};
use pingora::listeners::TlsAccept;
use pingora_openssl::{ext, ssl::NameType};
use crate::stores::certificates::CertificateStore;
#[derive(Debug, Clone)]
pub struct CertStore {
store: CertificateStore,
}
impl CertStore {
pub fn new(store: CertificateStore) -> Self {
CertStore { store }
}
pub fn sni_callback(ssl_ref: &mut SslRef, store: &CertificateStore) -> Result<(), SniError> {
let servername = ssl_ref.servername(NameType::HOST_NAME).unwrap_or("");
tracing::debug!("Received SNI: {}", servername);
if store.get(servername).is_some() {
return Ok(());
}
Err(SniError::ALERT_FATAL)
}
}
#[async_trait]
impl TlsAccept for CertStore {
async fn certificate_callback(&self, ssl: &mut pingora::tls::ssl::SslRef) {
let host_name = ssl.servername(NameType::HOST_NAME).unwrap_or_default();
let Some(cert) = self.store.get(host_name) else {
tracing::debug!("No certificate found for host: {:?}", host_name);
return;
};
ext::ssl_use_certificate(ssl, &cert.certificate).unwrap();
ext::ssl_use_private_key(ssl, &cert.key).unwrap();
}
}