use std::io;
use std::sync::Arc;
use tokio::net::TcpStream;
use tokio_rustls::TlsAcceptor;
use tokio_rustls::rustls::ServerConfig;
use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer, pem::PemObject};
use tokio_rustls::server::TlsStream;
pub struct TlsConfig {
cert_chain: Vec<CertificateDer<'static>>,
private_key: PrivateKeyDer<'static>,
}
impl TlsConfig {
pub fn from_pem(cert_pem: &[u8], key_pem: &[u8]) -> io::Result<Self> {
let cert_chain: Vec<CertificateDer<'static>> = CertificateDer::pem_slice_iter(cert_pem)
.collect::<Result<Vec<_>, _>>()
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;
if cert_chain.is_empty() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"no certificates found in PEM data",
));
}
let private_key = PrivateKeyDer::from_pem_slice(key_pem)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;
Ok(Self {
cert_chain,
private_key,
})
}
pub(crate) fn into_acceptor(self) -> io::Result<Acceptor> {
self.into_acceptor_inner().map(|(acceptor, _, _)| acceptor)
}
pub(crate) fn into_acceptor_and_h3_material(
self,
) -> io::Result<(
Acceptor,
Vec<CertificateDer<'static>>,
PrivateKeyDer<'static>,
)> {
self.into_acceptor_inner()
}
fn into_acceptor_inner(
self,
) -> io::Result<(
Acceptor,
Vec<CertificateDer<'static>>,
PrivateKeyDer<'static>,
)> {
let h3_cert_chain = self.cert_chain.clone();
let h3_private_key = self.private_key.clone_key();
let provider = Arc::new(aes256_chacha20_only_provider());
let mut config = ServerConfig::builder_with_provider(provider)
.with_safe_default_protocol_versions()
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?
.with_no_client_auth()
.with_single_cert(self.cert_chain, self.private_key)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;
config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
Ok((
Acceptor {
inner: TlsAcceptor::from(Arc::new(config)),
},
h3_cert_chain,
h3_private_key,
))
}
}
fn aes256_chacha20_only_provider() -> tokio_rustls::rustls::crypto::CryptoProvider {
let mut provider = tokio_rustls::rustls::crypto::aws_lc_rs::default_provider();
provider
.cipher_suites
.retain(|suite| !format!("{:?}", suite.suite()).contains("AES_128"));
provider
}
pub(crate) struct Acceptor {
inner: TlsAcceptor,
}
impl Acceptor {
pub(crate) async fn accept(&self, stream: TcpStream) -> io::Result<TlsStream<TcpStream>> {
self.inner.accept(stream).await
}
}