Build a `ServerConfig` from certificate, key, and optional client CA files.
(
cert_path: &Path,
key_path: &Path,
client_ca_path: Option<&Path>,
require_client_auth: bool,
)
| 246 | |
| 247 | /// Build a `ServerConfig` from certificate, key, and optional client CA files. |
| 248 | fn build_server_config( |
| 249 | cert_path: &Path, |
| 250 | key_path: &Path, |
| 251 | client_ca_path: Option<&Path>, |
| 252 | require_client_auth: bool, |
| 253 | ) -> Result<Arc<ServerConfig>> { |
| 254 | let certs = load_certs(cert_path)?; |
| 255 | let key = load_key(key_path)?; |
| 256 | |
| 257 | // Validate the key type early — rustls defers this to handshake time, |
| 258 | // which produces a cryptic error. A bad key type surfaces clearly here. |
| 259 | sign::any_supported_type(&key) |
| 260 | .map_err(|e| Error::tls(format!("unsupported private key type: {e}")))?; |
| 261 | |
| 262 | let mut config = if let Some(ca_path) = client_ca_path { |
| 263 | let ca_certs = load_certs(ca_path)?; |
| 264 | let mut root_store = rustls::RootCertStore::empty(); |
| 265 | for cert in ca_certs { |
| 266 | root_store |
| 267 | .add(cert) |
| 268 | .map_err(|e| Error::tls(format!("failed to add CA certificate: {e}")))?; |
| 269 | } |
| 270 | |
| 271 | let verifier_builder = WebPkiClientVerifier::builder(Arc::new(root_store)); |
| 272 | let verifier = if require_client_auth { |
| 273 | verifier_builder |
| 274 | } else { |
| 275 | verifier_builder.allow_unauthenticated() |
| 276 | } |
| 277 | .build() |
| 278 | .map_err(|e| Error::tls(format!("failed to build client verifier: {e}")))?; |
| 279 | |
| 280 | ServerConfig::builder() |
| 281 | .with_client_cert_verifier(verifier) |
| 282 | .with_single_cert(certs, key) |
| 283 | .map_err(|e| Error::tls(format!("failed to create TLS config: {e}")))? |
| 284 | } else { |
| 285 | ServerConfig::builder() |
| 286 | .with_no_client_auth() |
| 287 | .with_single_cert(certs, key) |
| 288 | .map_err(|e| Error::tls(format!("failed to create TLS config: {e}")))? |
| 289 | }; |
| 290 | |
| 291 | config |
| 292 | .alpn_protocols |
| 293 | .extend([b"h2".to_vec(), b"http/1.1".to_vec()]); |
| 294 | |
| 295 | Ok(Arc::new(config)) |
| 296 | } |
| 297 | |
| 298 | /// Load certificates from a PEM file. |
| 299 | fn load_certs(path: &Path) -> Result<Vec<CertificateDer<'static>>> { |