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 cert_bytes = cfg.cert.read()?;
let key_bytes = cfg.key.read()?;
let mut tls = TonicServerTls::new().identity(Identity::from_pem(cert_bytes, key_bytes));
if let Some(ca_src) = &cfg.client_ca {
let ca_bytes = ca_src.read()?;
tls = tls.client_ca_root(Certificate::from_pem(ca_bytes));
}
Ok(tls)
}
#[cfg(test)]
mod tests {
use super::*;
use solti_tls::ServerTlsConfig;
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::builder()
.cert_pem_bytes(cert)
.key_pem_bytes(key)
.build()
.unwrap();
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::builder()
.cert_pem_bytes(cert)
.key_pem_bytes(key)
.require_client_ca_pem_bytes(ca)
.build()
.unwrap();
let _tls = to_tonic_server_tls(&cfg).unwrap();
}
#[test]
fn to_tonic_server_tls_propagates_io_error_for_missing_cert_path() {
let cfg = ServerTlsConfig::builder()
.cert_pem_file("/nonexistent/server.crt")
.key_pem_file("/nonexistent/server.key")
.build()
.unwrap();
let err = to_tonic_server_tls(&cfg).unwrap_err();
assert!(matches!(err, TlsError::Io(_)));
}
}