pub mod future;
use std::{io, io::Error, path::Path, sync::Arc, time::Duration};
use rustls_pemfile::Item;
use rustls_pki_types::{CertificateDer, PrivateKeyDer};
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_rustls::{rustls::ServerConfig, server::TlsStream};
use self::future::RustlsAcceptorFuture;
use super::accept::{Accept, DefaultAcceptor};
#[derive(Clone)]
pub struct RustlsAcceptor<A = DefaultAcceptor> {
inner: A,
config: RustlsConfig,
handshake_timeout: Duration,
}
impl RustlsAcceptor {
pub fn new(config: RustlsConfig, handshake_timeout: Duration) -> Self {
let inner = DefaultAcceptor::new();
Self {
inner,
config,
handshake_timeout,
}
}
}
impl<A, I> Accept<I> for RustlsAcceptor<A>
where
A: Accept<I>,
A::Stream: AsyncRead + AsyncWrite + Unpin,
{
type Stream = TlsStream<A::Stream>;
type Future = RustlsAcceptorFuture<A::Future, A::Stream>;
fn accept(&self, stream: I) -> Self::Future {
let inner_future = self.inner.accept(stream);
let config = self.config.clone();
RustlsAcceptorFuture::new(inner_future, config, self.handshake_timeout)
}
}
#[derive(Clone)]
pub struct RustlsConfig {
inner: Arc<ServerConfig>,
}
impl RustlsConfig {
pub fn get_inner(&self) -> Arc<ServerConfig> {
self.inner.clone()
}
pub fn from_pem(cert: Vec<u8>, key: Vec<u8>) -> io::Result<Self> {
let server_config = config_from_pem(cert, key)?;
let inner = Arc::new(server_config);
Ok(Self { inner })
}
pub fn from_pem_chain_file(chain: impl AsRef<Path>, key: impl AsRef<Path>) -> io::Result<Self> {
let server_config = config_from_pem_chain_file(chain, key)?;
let inner = Arc::new(server_config);
Ok(Self { inner })
}
}
fn config_from_der(cert: Vec<Vec<u8>>, key: Vec<u8>) -> io::Result<ServerConfig> {
let cert = cert.into_iter().map(CertificateDer::from).collect();
let key = PrivateKeyDer::try_from(key).map_err(Error::other)?;
let mut config = ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(cert, key)
.map_err(Error::other)?;
config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
Ok(config)
}
fn config_from_pem(cert: Vec<u8>, key: Vec<u8>) -> io::Result<ServerConfig> {
let cert = rustls_pemfile::certs(&mut cert.as_ref())
.map(|it| it.map(|it| it.to_vec()))
.collect::<Result<Vec<_>, _>>()?;
let mut key_vec: Vec<Vec<u8>> = rustls_pemfile::read_all(&mut key.as_ref())
.filter_map(|i| match i.ok()? {
Item::Sec1Key(key) => Some(key.secret_sec1_der().to_vec()),
Item::Pkcs1Key(key) => Some(key.secret_pkcs1_der().to_vec()),
Item::Pkcs8Key(key) => Some(key.secret_pkcs8_der().to_vec()),
_ => None,
})
.collect();
if key_vec.len() != 1 {
return Err(Error::other("private key format not supported"));
}
config_from_der(cert, key_vec.pop().unwrap())
}
fn config_from_pem_chain_file(
cert: impl AsRef<Path>,
chain: impl AsRef<Path>,
) -> io::Result<ServerConfig> {
let cert = std::fs::read(cert.as_ref())?;
let cert = rustls_pemfile::certs(&mut cert.as_ref())
.map(|it| it.map(|it| CertificateDer::from(it.to_vec())))
.collect::<Result<Vec<_>, _>>()?;
let key = std::fs::read(chain.as_ref())?;
let key_cert: PrivateKeyDer = match rustls_pemfile::read_one(&mut key.as_ref())?
.ok_or_else(|| Error::other("could not parse pem file"))?
{
Item::Pkcs8Key(key) => Ok(key.into()),
Item::Sec1Key(key) => Ok(key.into()),
Item::Pkcs1Key(key) => Ok(key.into()),
x => Err(Error::other(format!(
"invalid certificate format, received: {x:?}"
))),
}?;
ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(cert, key_cert)
.map_err(|_| Error::other("invalid certificate"))
}