/* * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ use crate::{ KV_ACME, Server, network::acme::{SerializedCert, StaticResolver, directory::ACME_TLS_ALPN_NAME}, }; use rustls::{ ServerConfig, crypto::aws_lc_rs::sign::any_ecdsa_type, server::{ClientHello, ResolvesServerCert}, sign::CertifiedKey, }; use rustls_pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}; use std::sync::Arc; use store::{ dispatch::lookup::KeyValue, write::{AlignedBytes, Archive}, }; use trc::AcmeEvent; impl Server { pub(crate) async fn build_acme_certificate(&self, domain: &str) -> Option> { match self .in_memory_store() .key_get::>(KeyValue::<()>::build_key(KV_ACME, domain)) .await { Ok(Some(cert_)) => match cert_.unarchive::() { Ok(cert) => { match any_ecdsa_type(&PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( cert.private_key.as_ref(), ))) { Ok(key) => Some(Arc::new(CertifiedKey::new( vec![CertificateDer::from(cert.certificate.to_vec())], key, ))), Err(err) => { trc::event!( Acme(AcmeEvent::Error), Domain = domain.to_string(), Reason = err.to_string(), Details = "Failed to parse private key" ); None } } } Err(err) => { trc::event!( Acme(AcmeEvent::Error), Domain = domain.to_string(), CausedBy = err, Details = "Failed to unarchive certificate" ); None } }, Err(err) => { trc::event!( Acme(AcmeEvent::Error), Domain = domain.to_string(), CausedBy = err ); None } Ok(None) => { trc::event!(Acme(AcmeEvent::TokenNotFound), Domain = domain.to_string()); None } } } #[inline(always)] pub fn has_acme_tls_providers(&self) -> bool { self.core.network.has_acme_tls_challenge } #[inline(always)] pub fn has_acme_http_providers(&self) -> bool { self.core.network.has_acme_http_challenge } } impl ResolvesServerCert for StaticResolver { fn resolve(&self, _: ClientHello) -> Option> { self.key.clone() } } pub(crate) fn build_acme_static_resolver(key: Option>) -> Arc { let mut challenge = ServerConfig::builder() .with_no_client_auth() .with_cert_resolver(Arc::new(StaticResolver { key })); challenge.alpn_protocols.push(ACME_TLS_ALPN_NAME.to_vec()); Arc::new(challenge) } pub trait IsTlsAlpnChallenge { fn is_tls_alpn_challenge(&self) -> bool; } impl IsTlsAlpnChallenge for ClientHello<'_> { fn is_tls_alpn_challenge(&self) -> bool { self.alpn().into_iter().flatten().eq([ACME_TLS_ALPN_NAME]) } }