Skip to content

Support both rustls and native-tls #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jobs:
strategy:
matrix:
rust: [stable, beta, nightly]
tls: [rustls, native-tls]
features:
- hyper-h1,hyper-h2
continue-on-error: ${{ matrix.rust == 'nightly' }}
Expand All @@ -25,10 +26,10 @@ jobs:
profile: minimal
components: rustfmt, clippy
- name: Build
run: cargo build --verbose --examples --features ${{ matrix.features }}
run: cargo build --verbose --examples --features ${{ matrix.tls }},${{ matrix.features }}
- name: Test
run: cargo test --verbose
run: cargo test --verbose --features ${{ matrix.tls }},${{ matrix.features }}
- name: Lint
run: cargo clippy --examples --features ${{ matrix.features }}
run: cargo clippy --examples --features ${{ matrix.tls }},${{ matrix.features }}
- name: Format check
run: cargo fmt -- --check
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/target
**/*.rs.bk
Cargo.lock
.idea/
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Changelog

## 0.4.0 - 2022-02-22

### Added

- Support for [`native-tls`](https://github.com/sfackler/rust-native-tls).

### Changed

- Either one of the `rustls` or `native-tls` features must now be enabled.
- The `TlsListener` stream now returns a `tls_listener::Error` instead of `std::io::Error` type.
- Signatures of `TcpListener::new()` and `builder()` have changed to now take an argument `T: Into<TlsAcceptor>`.
When passing a `rustls::ServerConfig` it should therefore be wrapped in an `Arc` first.

### Fixed

- Crate will now compile when linked against a target that doesn't explicitly enable the `tokio/time` and `hyper/tcp`
features.
21 changes: 10 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,33 +1,32 @@
[package]
name = "tls-listener"
description = "wrap incoming Stream of connections in TLS"
version = "0.3.0"
version = "0.4.0"
authors = ["Thayne McCombs <[email protected]>"]
repository = "https://github.com/tmccombs/tls-listener"
edition = "2018"
license = "Apache-2.0"

[features]
default = ["tokio-net"]
rustls = ["tokio-rustls"]
native-tls = ["tokio-native-tls"]
Comment on lines 10 to +13
Copy link
Contributor Author

@jacob-pro jacob-pro Feb 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if you would like rustls to be in the defaults instead? I think this way is more consistent with the rust ecosystem from what I have seen of other libraries


tokio-net = ["tokio/net"]
hyper-h1 = ["hyper", "hyper/http1"]
hyper-h2 = ["hyper", "hyper/http2"]

[dependencies]
futures-util = "0.3.8"
tokio = "1.0"
tokio-rustls = "0.23.0"
hyper = { version = "0.14.1", features = ["server", "tcp"], optional = true }
pin-project-lite = "0.2.8"
#tokio-native-tls = "0.3.0"

[dependencies.hyper]
version = "0.14.1"
features = ["server"]
optional = true
thiserror = "1.0.30"
tokio = { version = "1.0", features = ["time"] }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a bug here such that if you try to use this crate in another project that doesn't itself also import tokio/time, then it will fail to compile.
You wouldn't have noticed this in the tests because of the weird way Cargo works, where it combines all the feature flag from different targets (i.e. the library + dev dependencies in this case) (something like this rust-lang/cargo#3620 )

tokio-native-tls = { version = "0.3.0", optional = true }
tokio-rustls = { version = "0.23.0", optional = true }

[dev-dependencies]
hyper = { version = "0.14.1", features = ["server", "http1", "tcp", "stream"] }
hyper = { version = "0.14.1", features = ["http1", "stream"] }
tokio = { version = "1.0", features = ["rt", "macros", "net", "io-util"] }

[[example]]
Expand All @@ -51,5 +50,5 @@ path = "examples/http-low-level.rs"
required-features = ["hyper-h1"]

[package.metadata.docs.rs]
all-features = true
features = ["rustls", "hyper-h1", "hyper-h2"]
rustdoc-args = ["--cfg", "docsrs"]
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ This library is intended to automatically initiate a TLS connection
as for each new connection in a source of new streams (such as a listening
TCP or unix domain socket).

In particular, the `TlsListener` can be used as the `incoming` argument to `hyper::server::Server::builder`.
In particular, the `TlsListener` can be used as the `incoming` argument to `hyper::server::Server::builder` (requires
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.
9 changes: 7 additions & 2 deletions examples/echo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ use std::net::SocketAddr;
use tls_listener::TlsListener;
use tokio::io::{copy, split};
use tokio::net::{TcpListener, TcpStream};
#[cfg(feature = "native-tls")]
use tokio_native_tls::TlsStream;
#[cfg(feature = "rustls")]
use tokio_rustls::server::TlsStream;

mod tls_config;
use tls_config::tls_config;
use tls_config::tls_acceptor;

#[inline]
async fn handle_stream(stream: TlsStream<TcpStream>) {
Expand All @@ -17,13 +20,15 @@ async fn handle_stream(stream: TlsStream<TcpStream>) {
};
}

/// For example try opening and closing a connection with:
/// `echo "Q" | openssl s_client -connect host:port`
#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr: SocketAddr = ([127, 0, 0, 1], 3000).into();

let listener = TcpListener::bind(&addr).await?;

TlsListener::new(tls_config(), listener)
TlsListener::new(tls_acceptor(), listener)
.for_each_concurrent(None, |s| async {
match s {
Ok(stream) => {
Expand Down
4 changes: 2 additions & 2 deletions examples/http-low-level.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ use hyper::{Body, Response};
use std::convert::Infallible;

mod tls_config;
use tls_config::tls_config;
use tls_config::tls_acceptor;

#[tokio::main(flavor = "current_thread")]
async fn main() {
let addr = ([127, 0, 0, 1], 3000).into();
let listener = tls_listener::builder(tls_config())
let listener = tls_listener::builder(tls_acceptor())
.max_handshakes(10)
.listen(AddrIncoming::bind(&addr).unwrap());

Expand Down
4 changes: 2 additions & 2 deletions examples/http-stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::future::ready;
use tls_listener::TlsListener;

mod tls_config;
use tls_config::tls_config;
use tls_config::tls_acceptor;

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
Expand All @@ -22,7 +22,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
});

// This uses a filter to handle errors with connecting
let incoming = TlsListener::new(tls_config(), AddrIncoming::bind(&addr)?).filter(|conn| {
let incoming = TlsListener::new(tls_acceptor(), AddrIncoming::bind(&addr)?).filter(|conn| {
if let Err(err) = conn {
eprintln!("Error: {:?}", err);
ready(false)
Expand Down
4 changes: 2 additions & 2 deletions examples/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::convert::Infallible;
use tls_listener::TlsListener;

mod tls_config;
use tls_config::tls_config;
use tls_config::tls_acceptor;

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
Expand All @@ -21,7 +21,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// This could be handled by adding a filter to the stream to filter out
// unwanted errors (and possibly log them), then use `hyper::server::accept::from_stream`,
// or by doing something similar to the http-low-level.rs example.
let incoming = TlsListener::new(tls_config(), AddrIncoming::bind(&addr)?);
let incoming = TlsListener::new(tls_acceptor(), AddrIncoming::bind(&addr)?);

let server = Server::builder(incoming).serve(new_svc);
server.await?;
Expand Down
Binary file added examples/tls_config/local.pfx
Binary file not shown.
39 changes: 28 additions & 11 deletions examples/tls_config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
use tokio_rustls::rustls::{Certificate, PrivateKey, ServerConfig};
#[cfg(feature = "rustls")]
mod cert {
pub const CERT: &[u8] = include_bytes!("local.cert");
pub const PKEY: &[u8] = include_bytes!("local.key");
}
#[cfg(feature = "native-tls")]
const PFX: &[u8] = include_bytes!("local.pfx");

#[cfg(feature = "rustls")]
pub fn tls_acceptor() -> std::sync::Arc<tokio_rustls::rustls::ServerConfig> {
use std::sync::Arc;
use tokio_rustls::rustls::{Certificate, PrivateKey, ServerConfig};

const CERT: &[u8] = include_bytes!("local.cert");
const PKEY: &[u8] = include_bytes!("local.key");
let key = PrivateKey(cert::PKEY.into());
let cert = Certificate(cert::CERT.into());

Arc::new(
ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth()
.with_single_cert(vec![cert], key)
.unwrap(),
)
}

pub fn tls_config() -> ServerConfig {
let key = PrivateKey(PKEY.into());
let cert = Certificate(CERT.into());
#[cfg(feature = "native-tls")]
pub fn tls_acceptor() -> tokio_native_tls::native_tls::TlsAcceptor {
use tokio_native_tls::native_tls::{Identity, TlsAcceptor};

ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth()
.with_single_cert(vec![cert], key)
.unwrap()
let identity = Identity::from_pkcs12(PFX, "").unwrap();
TlsAcceptor::builder(identity).build().unwrap()
}
Loading