kumo_server_common/
tls_helpers.rs1use anyhow::Context;
2use data_loader::KeySource;
3use rustls::pki_types::pem::PemObject;
4use rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer};
5use rustls::server::WebPkiClientVerifier;
6use rustls::{RootCertStore, ServerConfig};
7use std::sync::Arc;
8
9fn read_trust_anchor(trust_anchor: &[u8]) -> anyhow::Result<RootCertStore> {
10 let mut store = RootCertStore::empty();
11 let mut added = 0;
12 for cert in CertificateDer::pem_slice_iter(trust_anchor) {
13 store.add(cert?)?;
14 added += 1;
15 }
16
17 if added == 0 {
18 anyhow::bail!("failed to parse certs");
19 }
20
21 Ok(store)
22}
23
24pub async fn make_server_config(
25 hostname: &str,
26 tls_private_key: &Option<KeySource>,
27 tls_certificate: &Option<KeySource>,
28 required_client_ca: &Option<KeySource>,
29) -> anyhow::Result<Arc<ServerConfig>> {
30 let mut certificates = vec![];
31 let private_key = match tls_private_key {
32 Some(key) => PrivateKeyDer::from_pem_slice(&key.get().await?)
33 .with_context(|| format!("loading private key from {key:?}"))?,
34 None => {
35 let key = rcgen::generate_simple_self_signed(vec![hostname.to_string()])?;
36 certificates.push(CertificateDer::from_slice(key.cert.der()).into_owned());
37 PrivateKeyDer::from(PrivatePkcs8KeyDer::from(key.key_pair.serialize_der()))
38 }
39 };
40
41 if let Some(cert_file) = tls_certificate {
42 let data = cert_file.get().await?;
43 certificates = CertificateDer::pem_slice_iter(&data)
44 .collect::<Result<Vec<_>, _>>()
45 .with_context(|| format!("loading certificates from {cert_file:?}"))?;
46 }
47
48 let config = ServerConfig::builder();
49 let config = match required_client_ca {
50 Some(client_ca) => {
51 let ca = client_ca.get().await?;
52 let verifier = WebPkiClientVerifier::builder(read_trust_anchor(&ca)?.into()).build()?;
53 config.with_client_cert_verifier(verifier)
54 }
55 None => config.with_no_client_auth(),
56 };
57 let config = config.with_single_cert(certificates, private_key)?;
58
59 Ok(Arc::new(config))
60}