Skip to content

Commit

Permalink
Hidden rustls old module to users (#555)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrislearn authored Dec 13, 2023
1 parent e8016c4 commit 8ef8830
Show file tree
Hide file tree
Showing 12 changed files with 473 additions and 536 deletions.
229 changes: 152 additions & 77 deletions crates/core/src/conn/acme/listener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ use std::path::PathBuf;
use std::sync::{Arc, Weak};
use std::time::Duration;

use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer};
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_rustls::rustls::crypto::ring::sign::any_ecdsa_type;
use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer};
use tokio_rustls::rustls::server::ServerConfig;
use tokio_rustls::rustls::sign::CertifiedKey;
use tokio_rustls::server::TlsStream;
Expand All @@ -21,14 +21,21 @@ use super::config::{AcmeConfig, AcmeConfigBuilder};
use super::resolver::{ResolveServerCert, ACME_TLS_ALPN_NAME};
use super::{AcmeCache, AcmeClient, ChallengeType, Http01Handler, WELL_KNOWN_PATH};

// TODO: waiting quinn update
// cfg_feature! {
// #![feature = "quinn"]
// use crate::conn::quinn::QuinnAcceptor;
// use crate::conn::joined::JoinedAcceptor;
// use crate::conn::quinn::QuinnListener;
// use futures_util::stream::BoxStream;
// }
cfg_feature! {
#![feature = "quinn"]
use crate::conn::quinn::QuinnAcceptor;
use crate::conn::joined::JoinedAcceptor;
use crate::conn::quinn::QuinnListener;
use super::resolver::ResolveServerCertOld;
use futures_util::stream::BoxStream;
use tokio_rustls_old::rustls::{
server::{
ServerConfig as ServerConfigOld,
},
sign::{any_ecdsa_type as any_ecdsa_type_old, CertifiedKey as CertifiedKeyOld},
{Certificate as CertificateOld, PrivateKey as PrivateKeyOld},
};
}
/// A wrapper around an underlying listener which implements the ACME.
pub struct AcmeListener<T> {
inner: T,
Expand Down Expand Up @@ -131,35 +138,73 @@ impl<T> AcmeListener<T> {
}
}

// TODO: waiting quinn update
// cfg_feature! {
// #![feature = "quinn"]
// /// Enable Http3 using quinn.
// pub fn quinn<A>(self, local_addr: A) -> AcmeQuinnListener<T, A>
// where
// A: std::net::ToSocketAddrs + Send,
// {
// AcmeQuinnListener::new(self, local_addr)
// }
// }
}
cfg_feature! {
#![feature = "quinn"]
/// Enable Http3 using quinn.
pub fn quinn<A>(self, local_addr: A) -> AcmeQuinnListener<T, A>
where
A: std::net::ToSocketAddrs + Send,
{
AcmeQuinnListener::new(self, local_addr)
}

#[async_trait]
impl<T> Listener for AcmeListener<T>
where
T: Listener + Send,
T::Acceptor: Send + 'static,
{
type Acceptor = AcmeAcceptor<T::Acceptor>;
async fn build_server_config_old(acme_config: &AcmeConfig) -> crate::Result<ServerConfigOld> {
let mut cached_key = None;
let mut cached_cert = None;
if let Some(cache_path) = &acme_config.cache_path {
let key_data = cache_path
.read_key(&acme_config.directory_name, &acme_config.domains)
.await?;
if let Some(key_data) = key_data {
tracing::debug!("load private key from cache");
match rustls_pemfile_old::pkcs8_private_keys(&mut key_data.as_slice()) {
Ok(key) => cached_key = key.into_iter().next(),
Err(e) => {
tracing::warn!(error = ?e, "parse cached private key failed")
}
};
}
let cert_data = cache_path
.read_cert(&acme_config.directory_name, &acme_config.domains)
.await?;
if let Some(cert_data) = cert_data {
tracing::debug!("load certificate from cache");
match rustls_pemfile_old::certs(&mut cert_data.as_slice()) {
Ok(cert) => cached_cert = Some(cert),
Err(e) => {
tracing::warn!(error = ?e, "parse cached tls certificates failed")
}
};
}
};

async fn try_bind(mut self) -> crate::Result<Self::Acceptor> {
let Self {
inner,
config_builder,
check_duration,
..
} = self;
let acme_config = config_builder.build()?;
let cert_resolver = Arc::new(ResolveServerCertOld::default());
if let (Some(cached_cert), Some(cached_key)) = (cached_cert, cached_key) {
let certs = cached_cert
.into_iter()
.map(CertificateOld)
.collect::<Vec<_>>();
tracing::debug!("using cached tls certificates");
*cert_resolver.cert.write() = Some(Arc::new(CertifiedKeyOld::new(
certs,
any_ecdsa_type_old(&PrivateKeyOld(cached_key)).unwrap(),
)));
}

let mut server_config = ServerConfigOld::builder()
.with_safe_defaults()
.with_no_client_auth()
.with_cert_resolver(cert_resolver.clone());

server_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];

if acme_config.challenge_type == ChallengeType::TlsAlpn01 {
server_config.alpn_protocols.push(ACME_TLS_ALPN_NAME.to_vec());
}
Ok(server_config)
}
}
async fn build_server_config(acme_config: &AcmeConfig) -> crate::Result<(ServerConfig, Arc<ResolveServerCert>)> {
let mut cached_key = None;
let mut cached_certs = None;
if let Some(cache_path) = &acme_config.cache_path {
Expand Down Expand Up @@ -216,13 +261,38 @@ where
if acme_config.challenge_type == ChallengeType::TlsAlpn01 {
server_config.alpn_protocols.push(ACME_TLS_ALPN_NAME.to_vec());
}
let server_config = Arc::new(server_config);
Ok((server_config, cert_resolver))
}
}

#[async_trait]
impl<T> Listener for AcmeListener<T>
where
T: Listener + Send,
T::Acceptor: Send + 'static,
{
type Acceptor = AcmeAcceptor<T::Acceptor>;

async fn try_bind(mut self) -> crate::Result<Self::Acceptor> {
let Self {
inner,
config_builder,
check_duration,
..
} = self;
let acme_config = config_builder.build()?;

let (server_config, cert_resolver) = Self::build_server_config(&acme_config).await?;
let server_config = Arc::new(server_config);
let tls_acceptor = TlsAcceptor::from(server_config.clone());
let inner = inner.try_bind().await?;
#[cfg(feature = "quinn")]
let server_config_old = Self::build_server_config_old(&acme_config).await?;
let acceptor = AcmeAcceptor::new(
acme_config,
server_config,
#[cfg(feature = "quinn")]
server_config_old,
cert_resolver,
inner,
tls_acceptor,
Expand All @@ -232,51 +302,53 @@ where
Ok(acceptor)
}
}
// TODO: waiting quinn update
// cfg_feature! {
// #![feature = "quinn"]
// /// A wrapper around an underlying listener which implements the ACME and Quinn.
// pub struct AcmeQuinnListener<T, A> {
// acme: AcmeListener<T>,
// local_addr: A,
// }

// impl <T, A> AcmeQuinnListener<T, A>
// where
// A: std::net::ToSocketAddrs + Send,
// {
// pub(crate) fn new(acme: AcmeListener<T>, local_addr: A) -> Self {
// Self { acme, local_addr }
// }
// }

// #[async_trait]
// impl<T, A> Listener for AcmeQuinnListener<T, A>
// where
// T: Listener + Send,
// T::Acceptor: Send + Unpin + 'static,
// A: std::net::ToSocketAddrs + Send,
// {
// type Acceptor = JoinedAcceptor<AcmeAcceptor<T::Acceptor>, QuinnAcceptor<BoxStream<'static, crate::conn::quinn::ServerConfig>, crate::conn::quinn::ServerConfig, std::convert::Infallible>>;

// async fn try_bind(self) -> crate::Result<Self::Acceptor> {
// let Self { acme, local_addr } = self;
// let a = acme.try_bind().await?;

// let mut crypto = a.server_config.as_ref().clone();
// crypto.alpn_protocols = vec![b"h3-29".to_vec(), b"h3-28".to_vec(), b"h3-27".to_vec(), b"h3".to_vec()];
// let config = crate::conn::quinn::ServerConfig::with_crypto(Arc::new(crypto));
// let b = QuinnListener::new(futures_util::stream::once(async {config}), local_addr).try_bind().await?;
// let holdings = a.holdings().iter().chain(b.holdings().iter()).cloned().collect();
// Ok(JoinedAcceptor::new(a, b, holdings))
// }
// }
// }

cfg_feature! {
#![feature = "quinn"]
/// A wrapper around an underlying listener which implements the ACME and Quinn.
pub struct AcmeQuinnListener<T, A> {
acme: AcmeListener<T>,
local_addr: A,
}

impl <T, A> AcmeQuinnListener<T, A>
where
A: std::net::ToSocketAddrs + Send,
{
pub(crate) fn new(acme: AcmeListener<T>, local_addr: A) -> Self {
Self { acme, local_addr }
}
}

#[async_trait]
impl<T, A> Listener for AcmeQuinnListener<T, A>
where
T: Listener + Send,
T::Acceptor: Send + Unpin + 'static,
A: std::net::ToSocketAddrs + Send,
{
type Acceptor = JoinedAcceptor<AcmeAcceptor<T::Acceptor>, QuinnAcceptor<BoxStream<'static, crate::conn::quinn::ServerConfig>, crate::conn::quinn::ServerConfig, std::convert::Infallible>>;

async fn try_bind(self) -> crate::Result<Self::Acceptor> {
let Self { acme, local_addr } = self;
let a = acme.try_bind().await?;

let mut crypto = a.server_config_old.as_ref().clone();
crypto.alpn_protocols = vec![b"h3-29".to_vec(), b"h3-28".to_vec(), b"h3-27".to_vec(), b"h3".to_vec()];
let config = crate::conn::quinn::ServerConfig::with_crypto(Arc::new(crypto));
let b = QuinnListener::new(futures_util::stream::once(async {config}), local_addr).try_bind().await?;
let holdings = a.holdings().iter().chain(b.holdings().iter()).cloned().collect();
Ok(JoinedAcceptor::new(a, b, holdings))
}
}
}

/// AcmeAcceptor
pub struct AcmeAcceptor<T> {
config: Arc<AcmeConfig>,
server_config: Arc<ServerConfig>,
#[cfg(feature = "quinn")]
server_config_old: Arc<ServerConfigOld>,
inner: T,
holdings: Vec<Holding>,
tls_acceptor: tokio_rustls::TlsAcceptor,
Expand All @@ -289,6 +361,7 @@ where
pub(crate) async fn new(
config: impl Into<Arc<AcmeConfig>> + Send,
server_config: impl Into<Arc<ServerConfig>> + Send,
#[cfg(feature = "quinn")] server_config_old: impl Into<Arc<ServerConfigOld>> + Send,
cert_resolver: Arc<ResolveServerCert>,
inner: T,
tls_acceptor: TlsAcceptor,
Expand Down Expand Up @@ -321,6 +394,8 @@ where
let acceptor = AcmeAcceptor {
config: config.into(),
server_config: server_config.into(),
#[cfg(feature = "quinn")]
server_config_old: server_config_old.into(),
inner,
holdings,
tls_acceptor,
Expand Down
46 changes: 45 additions & 1 deletion crates/core/src/conn/acme/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ use tokio_rustls::rustls::server::{ClientHello, ResolvesServerCert};
use tokio_rustls::rustls::sign::CertifiedKey;
use x509_parser::prelude::{FromDer, X509Certificate};

cfg_feature! {
#![feature = "quinn"]
use tokio_rustls_old::rustls::{
server::{
ClientHello as OldClientHello,
ResolvesServerCert as OldResolvesServerCert,
},
sign::{CertifiedKey as CertifiedKeyOld},
};
}

pub(crate) const ACME_TLS_ALPN_NAME: &[u8] = b"acme-tls/1";

#[derive(Default, Debug)]
Expand Down Expand Up @@ -59,4 +70,37 @@ impl ResolvesServerCert for ResolveServerCert {

self.cert.read().as_ref().cloned()
}
}
}

#[cfg(feature = "quinn")]
#[derive(Default)]
pub(crate) struct ResolveServerCertOld {
pub(crate) cert: RwLock<Option<Arc<CertifiedKeyOld>>>,
pub(crate) acme_keys: RwLock<HashMap<String, Arc<CertifiedKeyOld>>>,
}
impl OldResolvesServerCert for ResolveServerCertOld {
#[inline]
fn resolve(&self, client_hello: OldClientHello) -> Option<Arc<CertifiedKeyOld>> {
if client_hello
.alpn()
.and_then(|mut iter| iter.find(|alpn| *alpn == ACME_TLS_ALPN_NAME))
.is_some()
{
return match client_hello.server_name() {
None => None,
Some(domain) => {
tracing::debug!(domain = domain, "load acme key");
match self.acme_keys.read().get(domain).cloned() {
Some(cert) => Some(cert),
None => {
tracing::error!(domain = domain, "acme key not found");
None
}
}
}
};
};

self.cert.read().as_ref().cloned()
}
}
2 changes: 1 addition & 1 deletion crates/core/src/conn/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ cfg_feature! {
cfg_feature! {
#![feature = "quinn"]
pub mod quinn;
pub mod rustls_old;
pub(crate) mod rustls_old;
pub use self::quinn::{QuinnListener, H3Connection};
}
cfg_feature! {
Expand Down
4 changes: 2 additions & 2 deletions crates/core/src/conn/quinn/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub use salvo_http3::http3_quinn::ServerConfig;
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};

use crate::async_trait;
use crate::conn::rustls_old::RustlsConfig;
use crate::conn::rustls::RustlsConfig;
use crate::conn::{HttpBuilder, IntoConfigStream};
use crate::http::HttpConnection;
use crate::service::HyperHandler;
Expand All @@ -26,7 +26,7 @@ pub use listener::{QuinnAcceptor, QuinnListener};
impl TryInto<ServerConfig> for RustlsConfig {
type Error = IoError;
fn try_into(self) -> IoResult<ServerConfig> {
let mut crypto = self.build_server_config()?;
let mut crypto = self.build_server_config_old()?;
crypto.alpn_protocols = vec![b"h3-29".to_vec(), b"h3-28".to_vec(), b"h3-27".to_vec(), b"h3".to_vec()];
Ok(ServerConfig::with_crypto(Arc::new(crypto)))
}
Expand Down
Loading

0 comments on commit 8ef8830

Please sign in to comment.