athene 2.0.4

A simple and lightweight rust web framework based on hyper
Documentation
use crate::error::Error;
use tokio_rustls::rustls::{
    server::{AllowAnyAnonymousOrAuthenticatedClient, AllowAnyAuthenticatedClient, NoClientAuth},
    Certificate, PrivateKey, RootCertStore, ServerConfig,
};

/// Tls client authentication configuration.
#[derive(Debug)]
pub enum ClientAuth {
    /// No client auth.
    Off,
    /// Allow any anonymous or authenticated client. 允许任何匿名或经过身份验证的客户端。
    Optional(Vec<u8>),
    /// Allow any authenticated client. 允许任何经过身份验证的客户端。
    Required(Vec<u8>),
}

/// `rustls`'s config.
#[derive(Debug)]
pub struct TlsConfig {
    pub cert: Vec<u8>,
    pub key: Vec<u8>,
    pub ocsp: Vec<u8>,
    pub client_auth: ClientAuth,
}

impl Default for TlsConfig {
    fn default() -> Self {
        Self::new()
    }
}

impl TlsConfig {
    /// Create a new Tls config
    #[must_use]
    pub fn new() -> Self {
        Self {
            cert: Vec::new(),
            key: Vec::new(),
            client_auth: ClientAuth::Off,
            ocsp: Vec::new(),
        }
    }

    /// sets the Tls certificate
    #[must_use]
    pub fn cert(mut self, cert: Vec<u8>) -> Self {
        self.cert = cert;
        self
    }

    /// sets the Tls key
    #[must_use]
    pub fn key(mut self, key: Vec<u8>) -> Self {
        self.key = key;
        self
    }

    /// Sets the trust anchor for optional Tls client authentication
    #[must_use]
    pub fn client_auth_optional(mut self, trust_anchor: Vec<u8>) -> Self {
        self.client_auth = ClientAuth::Optional(trust_anchor);
        self
    }

    /// Sets the trust anchor for required Tls client authentication
    #[must_use]
    pub fn client_auth_required(mut self, trust_anchor: Vec<u8>) -> Self {
        self.client_auth = ClientAuth::Required(trust_anchor);
        self
    }

    /// sets the DER-encoded OCSP response
    #[must_use]
    pub fn ocsp(mut self, ocsp: Vec<u8>) -> Self {
        self.ocsp = ocsp;
        self
    }

    /// builds the Tls `ServerConfig`
    pub(crate) fn build(self) -> Result<ServerConfig, Error> {
        fn read_trust_anchor(trust_anchor: &Certificate) -> Result<RootCertStore, Error> {
            let mut store = RootCertStore::empty();
            store
                .add(trust_anchor)
                .map_err(|e| Error::Custom(Box::new(e)))?;
            Ok(store)
        }

        let certs = rustls_pemfile::certs(&mut self.cert.as_slice())
            .map(|mut certs| certs.drain(..).map(Certificate).collect())
            .map_err(|e| Error::Custom(Box::new(e)))?;

        let keys = {
            let mut pkcs8: Vec<PrivateKey> =
                rustls_pemfile::pkcs8_private_keys(&mut self.key.as_slice())
                    .map(|mut keys| keys.drain(..).map(PrivateKey).collect())
                    .map_err(|e| Error::Custom(Box::new(e)))?;
            if pkcs8.is_empty() {
                let mut rsa: Vec<PrivateKey> =
                    rustls_pemfile::rsa_private_keys(&mut self.key.as_slice())
                        .map(|mut keys| keys.drain(..).map(PrivateKey).collect())
                        .map_err(|e| Error::Custom(Box::new(e)))?;

                if rsa.is_empty() {
                    return Err(Error::Custom(Box::new(std::io::Error::new(
                        std::io::ErrorKind::InvalidData,
                        "failed to parse tls private keys",
                    ))));
                }
                rsa.remove(0)
            } else {
                pkcs8.remove(0)
            }
        };

        let client_auth = match self.client_auth {
            ClientAuth::Off => NoClientAuth::boxed(),
            ClientAuth::Optional(trust_anchor) => AllowAnyAnonymousOrAuthenticatedClient::new(
                read_trust_anchor(&Certificate(trust_anchor))?,
            )
            .boxed(),
            ClientAuth::Required(trust_anchor) => {
                AllowAnyAuthenticatedClient::new(read_trust_anchor(&Certificate(trust_anchor))?)
                    .boxed()
            }
        };

        ServerConfig::builder()
            .with_safe_defaults()
            .with_client_cert_verifier(client_auth)
            .with_single_cert_with_ocsp_and_sct(certs, keys, self.ocsp, Vec::new())
            .map_err(|e| Error::Custom(Box::new(e)))
    }
}