use solti_tls::{ServerTlsConfig, TlsError};
use tonic::transport::{Certificate, Identity, ServerTlsConfig as TonicServerTls};
pub fn to_tonic_server_tls(cfg: ServerTlsConfig) -> Result<TonicServerTls, TlsError> {
let loaded = cfg.load()?;
let identity = loaded.identity();
let mut tls = TonicServerTls::new().identity(Identity::from_pem(
identity.certificate_chain_pem(),
identity.expose_private_key_pem(),
));
if let Some(roots) = loaded.client_auth_roots_pem() {
tls = tls.client_ca_root(Certificate::from_pem(roots));
}
Ok(tls)
}
#[cfg(test)]
mod tests {
use super::*;
use solti_tls::{PemRole, ServerTlsConfig, TlsIdentity, TrustRoots};
fn rcgen_self_signed() -> (Vec<u8>, Vec<u8>) {
let b = rcgen::generate_simple_self_signed(vec!["example.com".into()]).unwrap();
(
b.cert.pem().into_bytes(),
b.signing_key.serialize_pem().into_bytes(),
)
}
#[test]
fn to_tonic_server_tls_succeeds_with_cert_and_key() {
let (cert, key) = rcgen_self_signed();
let cfg = ServerTlsConfig::new(TlsIdentity::from_pem_bytes(cert, key));
let _tls = to_tonic_server_tls(cfg).unwrap();
}
#[test]
fn to_tonic_server_tls_includes_client_ca_for_mtls() {
let (cert, key) = rcgen_self_signed();
let (ca, _) = rcgen_self_signed();
let cfg = ServerTlsConfig::new(TlsIdentity::from_pem_bytes(cert, key))
.require_client_auth(TrustRoots::from_pem_bytes(ca));
let _tls = to_tonic_server_tls(cfg).unwrap();
}
#[test]
fn to_tonic_server_tls_propagates_io_error_for_missing_cert_path() {
let cfg = ServerTlsConfig::new(TlsIdentity::from_pem_files(
"/nonexistent/server.crt",
"/nonexistent/server.key",
));
let err = to_tonic_server_tls(cfg).unwrap_err();
assert!(matches!(
err,
TlsError::ReadPem {
role: PemRole::ServerCertificate,
..
}
));
}
}