vetis-compio 0.1.1

Very Tiny Server with compio runtime
use std::sync::Arc;

use crate::{host::HostImpl, VetisHosts};

use rustls::{
    pki_types::{CertificateDer, PrivateKeyDer},
    server::ResolvesServerCertUsingSni,
    sign::CertifiedKey,
    ServerConfig,
};
use vetis::{
    errors::{StartError, VetisError},
    host::Host,
};

pub struct TlsFactory {}

impl TlsFactory {
    pub async fn create_tls_config(
        hosts: VetisHosts<HostImpl>,
        alpn_protocols: Vec<Vec<u8>>,
    ) -> Result<Option<ServerConfig>, VetisError> {
        let hosts = hosts.clone();
        #[cfg(feature = "__rustls_awc_lc_rs")]
        let provider = rustls::crypto::aws_lc_rs::default_provider();
        #[cfg(feature = "__rustls_ring")]
        let provider = rustls::crypto::ring::default_provider();
        let mut resolver = ResolvesServerCertUsingSni::new();
        let hosts = hosts.read().await;
        for (hostname, host) in hosts.iter() {
            if let Some(security) = host
                .config()
                .security()
            {
                let cert = security.cert();
                let key = security.key();

                let cert = CertificateDer::from(cert.to_vec());
                let mut chain = vec![cert];
                if let Some(ca_cert) = security.ca_cert() {
                    let ca_cert = CertificateDer::from(ca_cert.to_vec());
                    chain.push(ca_cert);
                }

                let key = PrivateKeyDer::try_from(key.to_vec())
                    .map_err(|_| VetisError::Tls("Failed to parse private key".to_string()))?;
                let certified_key = CertifiedKey::from_der(chain, key, &provider).map_err(|e| {
                    VetisError::Tls(format!("Failed to create certified key: {}", e))
                })?;

                let hostname = hostname.clone();

                resolver
                    .add(&hostname, certified_key)
                    .map_err(|e| VetisError::Tls(e.to_string()))?;
            }
        }

        let builder = rustls::ServerConfig::builder_with_provider(Arc::new(provider))
            .with_protocol_versions(rustls::ALL_VERSIONS)
            .map_err(|e| VetisError::Start(StartError::Tls(e.to_string())))?;

        let mut tls_config = builder
            .with_no_client_auth()
            .with_cert_resolver(Arc::new(resolver));

        tls_config.max_early_data_size = u32::MAX;
        tls_config.alpn_protocols = alpn_protocols;

        Ok(Some(tls_config))
    }
}