diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ab07649..30b5275 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,10 +39,11 @@ jobs: - tokio-net - rustls - native-tls + - openssl - rt - hyper-h1 - hyper-h2 - - rustls,native-tls + - rustls,native-tls,openssl - tokio-net,rt,rustls - tokio-net,native-tls steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index b7f1338..cfafa02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,15 @@ ## Upcoming 0.5.1 +### Added + +- Support for [`openssl`](https://github.com/sfackler/rust-openssl) + ### Fixed - Fixed compilation on non-unix environments, where tokio-net doesn't include unix sockets - `SpawningHandshakes` will abort the tasks for pending connections when the linked futures are dropped. This should allow timeouts to cause the connectionto be closed. - ## 0.5.0 - 2022-03-20 ### Added @@ -29,7 +32,7 @@ ### Added -- Added [TlsListener::replace_acceptor()] function to allow replacing the listener certificate at runtime. +- Added `TlsListener::replace_acceptor()` function to allow replacing the listener certificate at runtime. ## 0.4.1 - 2022-03-09 diff --git a/Cargo.toml b/Cargo.toml index 3356157..4abe0ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tls-listener" description = "wrap incoming Stream of connections in TLS" -version = "0.5.0" +version = "0.5.1" authors = ["Thayne McCombs "] repository = "https://github.com/tmccombs/tls-listener" edition = "2018" @@ -11,6 +11,7 @@ license = "Apache-2.0" default = ["tokio-net"] rustls = ["tokio-rustls"] native-tls = ["tokio-native-tls"] +openssl = ["tokio-openssl", "openssl_impl"] rt = ["tokio/rt"] tokio-net = ["tokio/net"] @@ -25,6 +26,8 @@ thiserror = "1.0.30" tokio = { version = "1.0", features = ["time"] } tokio-native-tls = { version = "0.3.0", optional = true } tokio-rustls = { version = "0.23.0", optional = true } +tokio-openssl = { version = "0.6.3", optional = true } +openssl_impl = { package = "openssl", version = "0.10.32", optional = true } [dev-dependencies] hyper = { version = "0.14.1", features = ["http1", "stream"] } @@ -56,5 +59,5 @@ path = "examples/http-low-level.rs" required-features = ["hyper-h1"] [package.metadata.docs.rs] -features = ["rustls", "native-tls", "hyper-h1", "hyper-h2"] +features = ["rustls", "native-tls", "openssl", "hyper-h1", "hyper-h2", "rt"] rustdoc-args = ["--cfg", "docsrs"] diff --git a/README.md b/README.md index aaaef51..d47ac82 100644 --- a/README.md +++ b/README.md @@ -14,5 +14,5 @@ one of the `hyper-h1` or `hyper-h2` features). See examples for examples of usage. -You must enable either one of the `rustls` or `native-tls` features depending on which implementation you would -like to use. +You must enable either one of the `rustls`, `native-tls`, or `openssl` features depending on which implementation you +would like to use. diff --git a/examples/echo.rs b/examples/echo.rs index fd9a836..373fb98 100644 --- a/examples/echo.rs +++ b/examples/echo.rs @@ -4,8 +4,17 @@ use tls_listener::{AsyncAccept, TlsListener}; use tokio::io::{copy, split}; use tokio::net::{TcpListener, TcpStream}; use tokio::signal::ctrl_c; -#[cfg(all(feature = "native-tls", not(feature = "rustls")))] + +#[cfg(all( + feature = "native-tls", + not(any(feature = "rustls", feature = "openssl")) +))] use tokio_native_tls::TlsStream; +#[cfg(all( + feature = "openssl", + not(any(feature = "rustls", feature = "native-tls")) +))] +use tokio_openssl::SslStream as TlsStream; #[cfg(feature = "rustls")] use tokio_rustls::server::TlsStream; @@ -22,7 +31,7 @@ async fn handle_stream(stream: TlsStream) { } /// For example try opening and closing a connection with: -/// `echo "Q" | openssl s_client -connect host:port` +/// `echo "Q" | openssl s_client -connect localhost:3000` #[tokio::main(flavor = "current_thread")] async fn main() -> Result<(), Box> { let addr: SocketAddr = ([127, 0, 0, 1], 3000).into(); diff --git a/examples/http-low-level.rs b/examples/http-low-level.rs index 4f6dd07..678486e 100644 --- a/examples/http-low-level.rs +++ b/examples/http-low-level.rs @@ -11,6 +11,8 @@ use std::convert::Infallible; mod tls_config; use tls_config::tls_acceptor; +/// For example try: +/// `curl https://localhost:3000 -k` #[tokio::main(flavor = "current_thread")] async fn main() { let addr = ([127, 0, 0, 1], 3000).into(); diff --git a/examples/tls_config/mod.rs b/examples/tls_config/mod.rs index 7a707c8..bd99b33 100644 --- a/examples/tls_config/mod.rs +++ b/examples/tls_config/mod.rs @@ -3,7 +3,7 @@ mod cert { pub const CERT: &[u8] = include_bytes!("local.cert"); pub const PKEY: &[u8] = include_bytes!("local.key"); } -#[cfg(feature = "native-tls")] +#[cfg(all(feature = "native-tls", not(feature = "rustls")))] const PFX: &[u8] = include_bytes!("local.pfx"); #[cfg(feature = "rustls")] @@ -24,10 +24,29 @@ pub fn tls_acceptor() -> tokio_rustls::TlsAcceptor { .into() } -#[cfg(all(feature = "native-tls", not(feature = "rustls")))] +#[cfg(all( + feature = "native-tls", + not(any(feature = "rustls", feature = "openssl")) +))] pub fn tls_acceptor() -> tokio_native_tls::TlsAcceptor { use tokio_native_tls::native_tls::{Identity, TlsAcceptor}; let identity = Identity::from_pkcs12(PFX, "").unwrap(); TlsAcceptor::builder(identity).build().unwrap().into() } + +#[cfg(all( + feature = "openssl", + not(any(feature = "rustls", feature = "native-tls")) +))] +pub fn tls_acceptor() -> openssl_impl::ssl::SslContext { + use openssl_impl::ssl::{SslContext, SslFiletype, SslMethod}; + let mut builder = SslContext::builder(SslMethod::tls_server()).unwrap(); + builder + .set_certificate_file("./examples/tls_config/local.cert", SslFiletype::ASN1) + .unwrap(); + builder + .set_private_key_file("./examples/tls_config/local.key", SslFiletype::ASN1) + .unwrap(); + builder.build() +} diff --git a/src/lib.rs b/src/lib.rs index bf45431..66c0ab0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -253,6 +253,35 @@ where } } +#[cfg(feature = "openssl")] +impl AsyncTls for openssl_impl::ssl::SslContext +where + C: AsyncRead + AsyncWrite + Unpin + Send + 'static, +{ + type Stream = tokio_openssl::SslStream; + type Error = openssl_impl::ssl::Error; + type AcceptFuture = Pin> + Send>>; + + fn accept(&self, conn: C) -> Self::AcceptFuture { + let ssl = match openssl_impl::ssl::Ssl::new(self) { + Ok(s) => s, + Err(e) => { + return Box::pin(futures_util::future::err(e.into())); + } + }; + let mut stream = match tokio_openssl::SslStream::new(ssl, conn) { + Ok(s) => s, + Err(e) => { + return Box::pin(futures_util::future::err(e.into())); + } + }; + Box::pin(async move { + Pin::new(&mut stream).accept().await?; + Ok(stream) + }) + } +} + impl Builder { /// Set the maximum number of concurrent handshakes. ///