flexible_hyper_server_tls/
rustls_helpers.rs

1//! Provides a couple of functions that assist in getting a `TlsAcceptor` from certificate and key data.
2//!
3//! These functions use safe defaults from rustls to generate the `TlsAcceptor`, but it is not necessary to use them.
4
5use std::path::Path;
6use std::sync::Arc;
7
8use rustls_pki_types::pem::PemObject;
9use rustls_pki_types::{CertificateDer, PrivateKeyDer};
10use thiserror::Error;
11use tokio_rustls::rustls;
12
13/// Error when creating a `TlsAcceptor`
14#[derive(Error, Debug)]
15pub enum TlsAcceptorError {
16    /// PEM data was invalid
17    #[error("invalid pem data")]
18    InvalidPem(#[from] rustls_pki_types::pem::Error),
19    /// Rustls failed to create the `ServerConfig`
20    #[error("failed to create ServerConfig")]
21    ServerConfig(#[from] rustls::Error),
22    /// Failed to read a file
23    #[error("failed to read file")]
24    FileRead(#[source] std::io::Error),
25}
26
27// Only HTTP/1 is supported at the moment
28
29// /// The HTTP protocol to use when clients are connecting.
30// ///
31// /// This should match the version(s) of HTTP used to serve your application in Hyper.
32// /// Using `Both` will prefer HTTP/2 over HTTP/1.1
33// #[derive(Debug, Clone, Copy)]
34// pub enum HttpProtocol {
35//     Http1,
36//     Http2,
37//     Both,
38// }
39
40/// Get a `TlsAcceptor` from PEM-encoded certificate and key files
41///
42/// # Errors
43/// Errors if the files cannot be read, if there is no valid certificate/key data given, or if rustls fails to create
44/// the [`ServerConfig`](rustls::ServerConfig)
45pub async fn get_tlsacceptor_from_files(
46    cert_path: impl AsRef<Path> + Send,
47    key_path: impl AsRef<Path> + Send,
48) -> Result<tokio_rustls::TlsAcceptor, TlsAcceptorError> {
49    let cert_data = tokio::fs::read(cert_path)
50        .await
51        .map_err(TlsAcceptorError::FileRead)?;
52    let key_data = tokio::fs::read(key_path)
53        .await
54        .map_err(TlsAcceptorError::FileRead)?;
55
56    get_tlsacceptor_from_pem_data(&cert_data, &key_data)
57}
58
59/// Get a `TlsAcceptor` from PEM certificate and key data
60///
61/// # Errors
62/// Errors if there is no valid certificate/key data given or if rustls fails to create the [`ServerConfig`](rustls::ServerConfig)
63pub fn get_tlsacceptor_from_pem_data(
64    cert_data: &[u8],
65    key_data: &[u8],
66) -> Result<tokio_rustls::TlsAcceptor, TlsAcceptorError> {
67    let certs: Vec<_> = CertificateDer::pem_slice_iter(cert_data).collect::<Result<_, _>>()?;
68
69    let key = PrivateKeyDer::from_pem_slice(key_data)?;
70
71    let mut cfg = rustls::server::ServerConfig::builder()
72        .with_no_client_auth()
73        .with_single_cert(certs, key)?;
74
75    cfg.alpn_protocols = vec![b"http/1.1".to_vec(), b"http/1.0".to_vec()];
76
77    let acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(cfg));
78
79    Ok(acceptor)
80}