From 641a4a46ed1e3f2a5149c25fca406161977e6588 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Sun, 10 Nov 2019 23:10:37 +0100 Subject: [PATCH 01/36] feat(client): implement get_ref and get_mut for TlsStream --- src/client.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/client.rs b/src/client.rs index f1b401e..de394dc 100644 --- a/src/client.rs +++ b/src/client.rs @@ -28,6 +28,18 @@ pub(crate) enum MidHandshake { End, } +impl TlsStream { + /// Returns a reference to the underlying IO stream. + pub fn get_ref(&self) -> &IO { + &self.io + } + + /// Returns a mutuable reference to the underlying IO stream. + pub fn get_mut(&mut self) -> &mut IO { + &mut self.io + } +} + impl Future for MidHandshake where IO: AsyncRead + AsyncWrite + Unpin, From 04d43a03f79e3ef7a48b4bf42519f81c8f5887dc Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Mon, 11 Nov 2019 18:31:30 +0100 Subject: [PATCH 02/36] no more feature gate in the example --- src/connector.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/connector.rs b/src/connector.rs index 8cda808..90781a3 100644 --- a/src/connector.rs +++ b/src/connector.rs @@ -25,8 +25,6 @@ use webpki::DNSNameRef; /// ## Example /// /// ```rust -/// #![feature(async_await)] -/// /// use async_tls::TlsConnector; /// /// async_std::task::block_on(async { From c0909fc96bc081a22c6f8646141ee0c7318d9426 Mon Sep 17 00:00:00 2001 From: Friedel Ziegelmayer Date: Mon, 11 Nov 2019 18:45:40 +0100 Subject: [PATCH 03/36] docs(readme): nicer header --- README.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index fa6625f..82262d5 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,52 @@ -# async-tls -[![license](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/async-std/async-tls/blob/master/LICENSE-MIT) -[![license](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/async-std/async-tls/blob/master/LICENSE-APACHE) -[![docs.rs](https://docs.rs/async-tls/badge.svg)](https://docs.rs/async-tls/) - -Asynchronous TLS/SSL streams using [Rustls](https://github.com/ctz/rustls). +

async-tls

+
+ + Async TLS/SSL streams using Rustls. + +
+ +
+ +
+ + + Crates.io version + + + + Download + + + + docs.rs docs + + + + chat + +
+ + + +
### Simple Client @@ -36,7 +79,7 @@ See [examples/server](examples/server/src/main.rs). You can run it with: ```sh cd examples/server -cargo run -- 127.0.0.1:8080 --cert ../../tests/end.cert --key ../../tests/end.rsa +cargo run -- 127.0.0.1:8080 --cert ../../tests/end.cert --key ../../tests/end.rsa ``` and point the client at it with: From 120e379b5b0af0dbaa775e6986d504c132fd31c4 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Mon, 11 Nov 2019 18:47:28 +0100 Subject: [PATCH 04/36] (cargo-release) version 0.6.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 88ef8c5..de36aa1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-tls" -version = "0.5.0" +version = "0.6.0" authors = ["The async-rs developers", "Florian Gilcher ", "dignifiedquire ", "quininer kel "] license = "MIT/Apache-2.0" repository = "https://github.com/async-std/async-tls" From 9b6b1b9b8325e104a67f367cf160e994d1189bc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 14 Nov 2019 15:55:10 +0100 Subject: [PATCH 05/36] feat: make connect return a Future directly Don't return a io::Result> from Connector::connect() but only a plain future. `let conn = connector.connect(...)?.await?` is a bit awkward to use because of the double ?-operator. Instead always return a future now that in case of domain format errors immediately resolves to the error. Closes #10 --- README.md | 3 +-- examples/client/src/main.rs | 5 +--- src/connector.rs | 47 +++++++++++++++++++++++-------------- src/test_0rtt.rs | 2 +- tests/google.rs | 2 +- tests/test.rs | 2 +- 6 files changed, 34 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 82262d5..6b81178 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,7 @@ use async_std::net::TcpStream; let tcp_stream = TcpStream::connect("rust-lang.org:443").await?; let connector = TlsConnector::default(); -let handshake = connector.connect("www.rust-lang.org", tcp_stream)?; -let mut tls_stream = handshake.await?; +let mut tls_stream = connector.connect("www.rust-lang.org", tcp_stream).await?; // ... ``` diff --git a/examples/client/src/main.rs b/examples/client/src/main.rs index 81b3a32..5e04678 100644 --- a/examples/client/src/main.rs +++ b/examples/client/src/main.rs @@ -63,13 +63,10 @@ fn main() -> io::Result<()> { let tcp_stream = TcpStream::connect(&addr).await?; // Use the connector to start the handshake process. - // This might fail early if you pass an invalid domain, - // which is why we use `?`. // This consumes the TCP stream to ensure you are not reusing it. - let handshake = connector.connect(&domain, tcp_stream)?; // Awaiting the handshake gives you an encrypted // stream back which you can use like any other. - let mut tls_stream = handshake.await?; + let mut tls_stream = connector.connect(&domain, tcp_stream).await?; // We write our crafted HTTP request to it tls_stream.write_all(http_request.as_bytes()).await?; diff --git a/src/connector.rs b/src/connector.rs index 90781a3..cd5b9d6 100644 --- a/src/connector.rs +++ b/src/connector.rs @@ -30,8 +30,7 @@ use webpki::DNSNameRef; /// async_std::task::block_on(async { /// let connector = TlsConnector::default(); /// let tcp_stream = async_std::net::TcpStream::connect("example.com").await?; -/// let handshake = connector.connect("example.com", tcp_stream)?; -/// let encrypted_stream = handshake.await?; +/// let encrypted_stream = connector.connect("example.com", tcp_stream).await?; /// /// Ok(()) as async_std::io::Result<()> /// }); @@ -83,11 +82,10 @@ impl TlsConnector { /// Connect to a server. `stream` can be any type implementing `AsyncRead` and `AsyncWrite`, /// such as TcpStreams or Unix domain sockets. /// - /// The function will return an error if the domain is not of valid format. - /// Otherwise, it will return a `Connect` Future, representing the connecting part of a - /// Tls handshake. It will resolve when the handshake is over. + /// The function will return a `Connect` Future, representing the connecting part of a Tls + /// handshake. It will resolve when the handshake is over. #[inline] - pub fn connect<'a, IO>(&self, domain: impl AsRef, stream: IO) -> io::Result> + pub fn connect<'a, IO>(&self, domain: impl AsRef, stream: IO) -> Connect where IO: AsyncRead + AsyncWrite + Unpin, { @@ -96,24 +94,27 @@ impl TlsConnector { // NOTE: Currently private, exposing ClientSession exposes rusttls // Early data should be exposed differently - fn connect_with<'a, IO, F>( - &self, - domain: impl AsRef, - stream: IO, - f: F, - ) -> io::Result> + fn connect_with<'a, IO, F>(&self, domain: impl AsRef, stream: IO, f: F) -> Connect where IO: AsyncRead + AsyncWrite + Unpin, F: FnOnce(&mut ClientSession), { - let domain = DNSNameRef::try_from_ascii_str(domain.as_ref()) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid domain"))?; + let domain = match DNSNameRef::try_from_ascii_str(domain.as_ref()) { + Ok(domain) => domain, + Err(_) => { + return Connect(ConnectInner::Error(Some(io::Error::new( + io::ErrorKind::InvalidInput, + "invalid domain", + )))) + } + }; + let mut session = ClientSession::new(&self.inner, domain); f(&mut session); #[cfg(not(feature = "early-data"))] { - Ok(Connect(client::MidHandshake::Handshaking( + Connect(ConnectInner::Handshake(client::MidHandshake::Handshaking( client::TlsStream { session, io: stream, @@ -124,7 +125,7 @@ impl TlsConnector { #[cfg(feature = "early-data")] { - Ok(Connect(if self.early_data { + Connect(ConnectInner::Handshake(if self.early_data { client::MidHandshake::EarlyData(client::TlsStream { session, io: stream, @@ -145,13 +146,23 @@ impl TlsConnector { /// Future returned from `TlsConnector::connect` which will resolve /// once the connection handshake has finished. -pub struct Connect(client::MidHandshake); +pub struct Connect(ConnectInner); + +enum ConnectInner { + Error(Option), + Handshake(client::MidHandshake), +} impl Future for Connect { type Output = io::Result>; #[inline] fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Pin::new(&mut self.0).poll(cx) + match self.0 { + ConnectInner::Error(ref mut err) => { + Poll::Ready(Err(err.take().expect("Polled twice after being Ready"))) + } + ConnectInner::Handshake(ref mut handshake) => Pin::new(handshake).poll(cx), + } } } diff --git a/src/test_0rtt.rs b/src/test_0rtt.rs index ceeb943..83414b7 100644 --- a/src/test_0rtt.rs +++ b/src/test_0rtt.rs @@ -19,7 +19,7 @@ async fn get( let mut buf = Vec::new(); let stream = TcpStream::connect(&addr).await?; - let mut stream = connector.connect(domain, stream)?.await?; + let mut stream = connector.connect(domain, stream).await?; stream.write_all(input.as_bytes()).await?; stream.read_to_end(&mut buf).await?; diff --git a/tests/google.rs b/tests/google.rs index 4f78b40..627106e 100644 --- a/tests/google.rs +++ b/tests/google.rs @@ -9,7 +9,7 @@ fn fetch_google() -> std::io::Result<()> { let connector = TlsConnector::default(); let stream = TcpStream::connect("google.com:443").await?; - let mut stream = connector.connect("google.com", stream)?.await?; + let mut stream = connector.connect("google.com", stream).await?; stream.write_all(b"GET / HTTP/1.0\r\n\r\n").await?; let mut res = vec![]; diff --git a/tests/test.rs b/tests/test.rs index c678cd4..d7871ba 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -67,7 +67,7 @@ async fn start_client(addr: SocketAddr, domain: &str, config: Arc) let mut buf = vec![0; FILE.len()]; let stream = TcpStream::connect(&addr).await?; - let mut stream = config.connect(domain, stream)?.await?; + let mut stream = config.connect(domain, stream).await?; stream.write_all(FILE).await?; stream.read_exact(&mut buf).await?; From c5051eb0ab0550d3f4eee2dfa7f4b2039104180d Mon Sep 17 00:00:00 2001 From: "Demi M. Obenour" Date: Tue, 25 Feb 2020 14:43:48 -0500 Subject: [PATCH 06/36] Upgrade dependencies This bumps all dependencies to the latest versions. If preferred, I could bump only `rustls` and `webpki-roots`. --- Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index de36aa1..c7d183d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,10 +16,10 @@ travis-ci = { repository = "async-std/async-tls" } appveyor = { repository = "async-std/async-tls" } [dependencies] -futures = "0.3" -rustls = "0.16" -webpki = "0.21" -webpki-roots = "0.17" +futures = "0.3.4" +rustls = "0.17.0" +webpki = "0.21.2" +webpki-roots = "0.19.0" [features] early-data = [] From 5cb4e1546e0ab4ad826003f65d299cabe646c2ca Mon Sep 17 00:00:00 2001 From: "Demi M. Obenour" Date: Tue, 25 Feb 2020 15:08:20 -0500 Subject: [PATCH 07/36] Bump dependencies of examples --- examples/client/Cargo.toml | 6 +++--- examples/server/Cargo.toml | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/client/Cargo.toml b/examples/client/Cargo.toml index a0420eb..b12fb76 100644 --- a/examples/client/Cargo.toml +++ b/examples/client/Cargo.toml @@ -5,7 +5,7 @@ authors = ["The async-rs authors", "quininer "] edition = "2018" [dependencies] -structopt = "0.2" -rustls = "0.16" -async-std = "0.99" +structopt = "0.3.9" +rustls = "0.17.0" +async-std = "1.5.0" async-tls = { path = "../.." } diff --git a/examples/server/Cargo.toml b/examples/server/Cargo.toml index 082f1e4..3e1ce31 100644 --- a/examples/server/Cargo.toml +++ b/examples/server/Cargo.toml @@ -5,8 +5,8 @@ authors = ["The async-rs developers", "quininer "] edition = "2018" [dependencies] -structopt = "0.2" -async-std = "0.99" +structopt = "0.3.9" +async-std = "1.5.0" async-tls = { path = "../.." } -rustls = "0.16" -webpki = "0.21" +rustls = "0.17.0" +webpki = "0.21.2" From d07f09a611b8d55390b548821d243c2558f2f7e4 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Tue, 25 Feb 2020 21:15:49 +0100 Subject: [PATCH 08/36] fix: expose intermediate future types Signed-off-by: Yoshua Wuyts --- src/client.rs | 2 ++ src/lib.rs | 4 ++-- src/server.rs | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/client.rs b/src/client.rs index de394dc..1848c18 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,3 +1,5 @@ +//! The client end of a TLS connection. + use crate::common::tls_state::TlsState; use crate::rusttls::stream::Stream; use futures::io::{AsyncRead, AsyncWrite}; diff --git a/src/lib.rs b/src/lib.rs index 8f612d2..d45f668 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,8 +9,8 @@ mod connector; mod rusttls; pub mod server; -pub use acceptor::TlsAcceptor; -pub use connector::TlsConnector; +pub use acceptor::{Accept, TlsAcceptor}; +pub use connector::{Connect, TlsConnector}; #[cfg(feature = "early-data")] #[cfg(test)] diff --git a/src/server.rs b/src/server.rs index a81bbd0..3f4a7e2 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,3 +1,5 @@ +//! The server end of a TLS connection. + use crate::common::tls_state::TlsState; use crate::rusttls::stream::Stream; From 7535f8e5045adee37853ab69046b515a5d7913c5 Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Mon, 30 Mar 2020 21:26:17 +0200 Subject: [PATCH 09/36] (cargo-release) version 0.7.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c7d183d..d306d88 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-tls" -version = "0.6.0" +version = "0.7.0" authors = ["The async-rs developers", "Florian Gilcher ", "dignifiedquire ", "quininer kel "] license = "MIT/Apache-2.0" repository = "https://github.com/async-std/async-tls" From 644b9067657ad57e7b4f956956c52cd022d5a826 Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Mon, 30 Mar 2020 21:26:44 +0200 Subject: [PATCH 10/36] (cargo-release) start next development iteration 0.7.1-alpha.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d306d88..fa59f8d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-tls" -version = "0.7.0" +version = "0.7.1-alpha.0" authors = ["The async-rs developers", "Florian Gilcher ", "dignifiedquire ", "quininer kel "] license = "MIT/Apache-2.0" repository = "https://github.com/async-std/async-tls" From ad27db7eada13d35ddba6dee17d9026ec12c2d89 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Sun, 24 May 2020 10:49:12 -0700 Subject: [PATCH 11/36] Add cargo features "client" and "server" Since many consumers of this library do not need both client and server features, this allows them to shrink their dependencies somewhat. --- .travis.yml | 2 ++ Cargo.toml | 15 +++++++++++++-- src/lib.rs | 9 +++++++-- src/rusttls/stream.rs | 2 +- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9efee9d..fd79657 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,8 @@ matrix: script: - cargo test - cargo test --features early-data + - cargo test ---no-default-features --features client + - cargo test ---no-default-features --features server - cd examples/server - cargo check - cd ../../examples/client diff --git a/Cargo.toml b/Cargo.toml index fa59f8d..4cc74d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,13 +18,24 @@ appveyor = { repository = "async-std/async-tls" } [dependencies] futures = "0.3.4" rustls = "0.17.0" -webpki = "0.21.2" -webpki-roots = "0.19.0" +webpki = { version = "0.21.2", optional = true } +webpki-roots = { version = "0.19.0", optional = true } [features] +default = ["client", "server"] +client = ["webpki", "webpki-roots"] early-data = [] +server = [] [dev-dependencies] lazy_static = "1" futures-util = "0.3" async-std = { version = "1.0", features = ["unstable"] } + +[[test]] +name = "test" +required-features = ["client", "server"] + +[[test]] +name = "google" +required-features = ["client"] diff --git a/src/lib.rs b/src/lib.rs index d45f668..23f0208 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,16 +2,21 @@ #![deny(unsafe_code)] +#[cfg(feature = "server")] mod acceptor; +#[cfg(feature = "client")] pub mod client; mod common; +#[cfg(feature = "client")] mod connector; mod rusttls; +#[cfg(feature = "server")] pub mod server; +#[cfg(feature = "server")] pub use acceptor::{Accept, TlsAcceptor}; +#[cfg(feature = "client")] pub use connector::{Connect, TlsConnector}; -#[cfg(feature = "early-data")] -#[cfg(test)] +#[cfg(all(test, feature = "client", feature = "early-data"))] mod test_0rtt; diff --git a/src/rusttls/stream.rs b/src/rusttls/stream.rs index bbb47ac..b36ac62 100644 --- a/src/rusttls/stream.rs +++ b/src/rusttls/stream.rs @@ -257,6 +257,6 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> AsyncWrite for Stream<' } } -#[cfg(test)] +#[cfg(all(test, feature = "client"))] #[path = "test_stream.rs"] mod test_stream; From ca812819ea6f6fe1b34fc33cbd9397c2110951a7 Mon Sep 17 00:00:00 2001 From: Jason Mobarak Date: Mon, 6 Jul 2020 11:48:01 -0700 Subject: [PATCH 12/36] Bump to rusttls 0.18.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index fa59f8d..e305f77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ appveyor = { repository = "async-std/async-tls" } [dependencies] futures = "0.3.4" -rustls = "0.17.0" +rustls = "0.18.0" webpki = "0.21.2" webpki-roots = "0.19.0" From 425636d909012bc4025d48b00bec7da83324ab69 Mon Sep 17 00:00:00 2001 From: Jason Mobarak Date: Mon, 6 Jul 2020 11:51:01 -0700 Subject: [PATCH 13/36] Update example rusttls versions --- examples/client/Cargo.toml | 2 +- examples/server/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/client/Cargo.toml b/examples/client/Cargo.toml index b12fb76..78e95c9 100644 --- a/examples/client/Cargo.toml +++ b/examples/client/Cargo.toml @@ -6,6 +6,6 @@ edition = "2018" [dependencies] structopt = "0.3.9" -rustls = "0.17.0" +rustls = "0.18.0" async-std = "1.5.0" async-tls = { path = "../.." } diff --git a/examples/server/Cargo.toml b/examples/server/Cargo.toml index 3e1ce31..8c29d81 100644 --- a/examples/server/Cargo.toml +++ b/examples/server/Cargo.toml @@ -8,5 +8,5 @@ edition = "2018" structopt = "0.3.9" async-std = "1.5.0" async-tls = { path = "../.." } -rustls = "0.17.0" +rustls = "0.18.0" webpki = "0.21.2" From 281d3f3bb362f63b3a451af5191901be6293ad55 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Wed, 8 Jul 2020 15:25:05 +0200 Subject: [PATCH 14/36] v0.7.1 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e305f77..cf9eadf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-tls" -version = "0.7.1-alpha.0" +version = "0.7.1" authors = ["The async-rs developers", "Florian Gilcher ", "dignifiedquire ", "quininer kel "] license = "MIT/Apache-2.0" repository = "https://github.com/async-std/async-tls" From 321ee87ef040e5540032da1562b12018802c842b Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Thu, 9 Jul 2020 10:43:22 +0200 Subject: [PATCH 15/36] v0.8.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cf9eadf..60af7c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-tls" -version = "0.7.1" +version = "0.8.0" authors = ["The async-rs developers", "Florian Gilcher ", "dignifiedquire ", "quininer kel "] license = "MIT/Apache-2.0" repository = "https://github.com/async-std/async-tls" From 5d0ed9eb2ebc96cac36485d15d754b12918e8aa7 Mon Sep 17 00:00:00 2001 From: Atul Bhosale Date: Sun, 12 Jul 2020 22:17:00 +0530 Subject: [PATCH 16/36] Add cargo fmt to travis build config --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index 9efee9d..1acf8cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,12 @@ matrix: os: osx script: + - | + if [[ "$TRAVIS_RUST_VERSION" == stable ]] + then + rustup component add rustfmt + cargo fmt --all -- --check + fi - cargo test - cargo test --features early-data - cd examples/server From 6b2d3bdb2b33317ab1fb395a5dbfadd4db12ba1e Mon Sep 17 00:00:00 2001 From: Atul Bhosale Date: Mon, 13 Jul 2020 18:29:24 +0530 Subject: [PATCH 17/36] Format code using 'cargo fmt' --- tests/test.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/test.rs b/tests/test.rs index d7871ba..d0f4ffa 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,14 +1,14 @@ -use async_std::net::{TcpListener, TcpStream}; -use async_std::task; use async_std::io; -use async_std::sync::channel; +use async_std::net::{TcpListener, TcpStream}; use async_std::prelude::*; +use async_std::sync::channel; +use async_std::task; use async_tls::{TlsAcceptor, TlsConnector}; use lazy_static::lazy_static; use rustls::internal::pemfile::{certs, rsa_private_keys}; use rustls::{ClientConfig, ServerConfig}; -use std::net::SocketAddr; use std::io::{BufReader, Cursor}; +use std::net::SocketAddr; use std::sync::Arc; const CERT: &str = include_str!("end.cert"); @@ -49,9 +49,7 @@ lazy_static! { Ok(()) as io::Result<()> }); - let addr = task::block_on(async move { - recv.recv().await.unwrap() - }); + let addr = task::block_on(async move { recv.recv().await.unwrap() }); (addr, "localhost", CHAIN) }; } From c85b62bbdb42745b4f6a116cca78770fdaf5b05d Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Wed, 15 Jul 2020 22:07:53 +0200 Subject: [PATCH 18/36] Bump webpki-roots to 0.20 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a5c68ae..08a38b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ appveyor = { repository = "async-std/async-tls" } futures = "0.3.4" rustls = "0.18.0" webpki = { version = "0.21.2", optional = true } -webpki-roots = { version = "0.19.0", optional = true } +webpki-roots = { version = "0.20.0", optional = true } [features] default = ["client", "server"] From f88ff3479539afc0fd46415ab3b67a34d581a393 Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Wed, 15 Jul 2020 22:08:17 +0200 Subject: [PATCH 19/36] Bump version to 0.9.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 08a38b3..5680f92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-tls" -version = "0.8.0" +version = "0.9.0" authors = ["The async-rs developers", "Florian Gilcher ", "dignifiedquire ", "quininer kel "] license = "MIT/Apache-2.0" repository = "https://github.com/async-std/async-tls" From 331ac2fade96af00b7f5f992ad5b02f7e8587052 Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Wed, 15 Jul 2020 22:29:30 +0200 Subject: [PATCH 20/36] Allow construting from bare Server/ClientConfigs --- src/acceptor.rs | 6 ++++++ src/connector.rs | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/acceptor.rs b/src/acceptor.rs index 9fc3d3b..b47e7ca 100644 --- a/src/acceptor.rs +++ b/src/acceptor.rs @@ -74,3 +74,9 @@ impl From> for TlsAcceptor { TlsAcceptor { inner } } } + +impl From for TlsAcceptor { + fn from(inner: ServerConfig) -> TlsAcceptor { + TlsAcceptor { inner: Arc::new(inner) } + } +} diff --git a/src/connector.rs b/src/connector.rs index cd5b9d6..a90368b 100644 --- a/src/connector.rs +++ b/src/connector.rs @@ -52,6 +52,16 @@ impl From> for TlsConnector { } } +impl From for TlsConnector { + fn from(inner: ClientConfig) -> TlsConnector { + TlsConnector { + inner: Arc::new(inner), + #[cfg(feature = "early-data")] + early_data: false, + } + } +} + impl Default for TlsConnector { fn default() -> Self { let mut config = ClientConfig::new(); From 2a0afaac4c5cf29dfbf36ce80982dddff85c3f56 Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Wed, 15 Jul 2020 22:36:27 +0200 Subject: [PATCH 21/36] Make rustfmt happy --- src/acceptor.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/acceptor.rs b/src/acceptor.rs index b47e7ca..9a6c86b 100644 --- a/src/acceptor.rs +++ b/src/acceptor.rs @@ -77,6 +77,8 @@ impl From> for TlsAcceptor { impl From for TlsAcceptor { fn from(inner: ServerConfig) -> TlsAcceptor { - TlsAcceptor { inner: Arc::new(inner) } + TlsAcceptor { + inner: Arc::new(inner), + } } } From 5df4a09a0c37a9e231c4db0f82e6aba33b78b3aa Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Wed, 22 Jul 2020 08:49:59 -0700 Subject: [PATCH 22/36] Use finer-grained dependencies on futures crates --- Cargo.toml | 6 ++++-- src/acceptor.rs | 2 +- src/client.rs | 17 ++++++++--------- src/connector.rs | 2 +- src/rusttls/stream.rs | 7 ++++--- src/rusttls/test_stream.rs | 23 ++++++++++++----------- src/server.rs | 7 ++++--- src/test_0rtt.rs | 8 ++++---- tests/google.rs | 2 +- 9 files changed, 39 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5680f92..85ff152 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,8 @@ travis-ci = { repository = "async-std/async-tls" } appveyor = { repository = "async-std/async-tls" } [dependencies] -futures = "0.3.4" +futures-io = "0.3.5" +futures-core = "0.3.5" rustls = "0.18.0" webpki = { version = "0.21.2", optional = true } webpki-roots = { version = "0.20.0", optional = true } @@ -29,7 +30,8 @@ server = [] [dev-dependencies] lazy_static = "1" -futures-util = "0.3" +futures-executor = "0.3.5" +futures-util = { version = "0.3.5", features = ["io"] } async-std = { version = "1.0", features = ["unstable"] } [[test]] diff --git a/src/acceptor.rs b/src/acceptor.rs index 9a6c86b..2563f8b 100644 --- a/src/acceptor.rs +++ b/src/acceptor.rs @@ -1,7 +1,7 @@ use crate::common::tls_state::TlsState; use crate::server; -use futures::io::{AsyncRead, AsyncWrite}; +use futures_io::{AsyncRead, AsyncWrite}; use rustls::{ServerConfig, ServerSession}; use std::future::Future; use std::io; diff --git a/src/client.rs b/src/client.rs index 1848c18..890e210 100644 --- a/src/client.rs +++ b/src/client.rs @@ -2,7 +2,8 @@ use crate::common::tls_state::TlsState; use crate::rusttls::stream::Stream; -use futures::io::{AsyncRead, AsyncWrite}; +use futures_core::ready; +use futures_io::{AsyncRead, AsyncWrite}; use rustls::ClientSession; use std::future::Future; use std::pin::Pin; @@ -58,11 +59,11 @@ where let mut stream = Stream::new(io, session).set_eof(eof); if stream.session.is_handshaking() { - futures::ready!(stream.complete_io(cx))?; + ready!(stream.complete_io(cx))?; } if stream.session.wants_write() { - futures::ready!(stream.complete_io(cx))?; + ready!(stream.complete_io(cx))?; } } @@ -95,14 +96,13 @@ where // complete handshake if stream.session.is_handshaking() { - futures::ready!(stream.complete_io(cx))?; + ready!(stream.complete_io(cx))?; } // write early data (fallback) if !stream.session.is_early_data_accepted() { while *pos < data.len() { - let len = - futures::ready!(stream.as_mut_pin().poll_write(cx, &data[*pos..]))?; + let len = ready!(stream.as_mut_pin().poll_write(cx, &data[*pos..]))?; *pos += len; } } @@ -176,14 +176,13 @@ where // complete handshake if stream.session.is_handshaking() { - futures::ready!(stream.complete_io(cx))?; + ready!(stream.complete_io(cx))?; } // write early data (fallback) if !stream.session.is_early_data_accepted() { while *pos < data.len() { - let len = - futures::ready!(stream.as_mut_pin().poll_write(cx, &data[*pos..]))?; + let len = ready!(stream.as_mut_pin().poll_write(cx, &data[*pos..]))?; *pos += len; } } diff --git a/src/connector.rs b/src/connector.rs index a90368b..594be81 100644 --- a/src/connector.rs +++ b/src/connector.rs @@ -2,7 +2,7 @@ use crate::common::tls_state::TlsState; use crate::client; -use futures::io::{AsyncRead, AsyncWrite}; +use futures_io::{AsyncRead, AsyncWrite}; use rustls::{ClientConfig, ClientSession}; use std::future::Future; use std::io; diff --git a/src/rusttls/stream.rs b/src/rusttls/stream.rs index b36ac62..3b80a20 100644 --- a/src/rusttls/stream.rs +++ b/src/rusttls/stream.rs @@ -1,4 +1,5 @@ -use futures::io::{AsyncRead, AsyncWrite}; +use futures_core::ready; +use futures_io::{AsyncRead, AsyncWrite}; use rustls::Session; use std::io::{self, Read, Write}; use std::marker::Unpin; @@ -242,7 +243,7 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> AsyncWrite for Stream<' this.session.flush()?; while this.session.wants_write() { - futures::ready!(this.complete_inner_io(cx, Focus::Writable))?; + ready!(this.complete_inner_io(cx, Focus::Writable))?; } Pin::new(&mut this.io).poll_flush(cx) } @@ -251,7 +252,7 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> AsyncWrite for Stream<' let this = self.get_mut(); while this.session.wants_write() { - futures::ready!(this.complete_inner_io(cx, Focus::Writable))?; + ready!(this.complete_inner_io(cx, Focus::Writable))?; } Pin::new(&mut this.io).poll_close(cx) } diff --git a/src/rusttls/test_stream.rs b/src/rusttls/test_stream.rs index 9c1bcc9..8f4d712 100644 --- a/src/rusttls/test_stream.rs +++ b/src/rusttls/test_stream.rs @@ -1,8 +1,9 @@ use super::Stream; -use futures::executor; -use futures::io::{AsyncRead, AsyncWrite}; -use futures::prelude::*; -use futures::task::{noop_waker_ref, Context}; +use futures_executor::block_on; +use futures_io::{AsyncRead, AsyncWrite}; +use futures_util::io::{AsyncReadExt, AsyncWriteExt}; +use futures_util::task::{noop_waker_ref, Context}; +use futures_util::{future, ready}; use rustls::internal::pemfile::{certs, rsa_private_keys}; use rustls::{ClientConfig, ClientSession, NoClientAuth, ServerConfig, ServerSession, Session}; use std::io::{self, BufReader, Cursor, Read, Write}; @@ -105,7 +106,7 @@ fn stream_good() -> io::Result<()> { Ok(()) as io::Result<()> }; - executor::block_on(fut) + block_on(fut) } #[test] @@ -137,7 +138,7 @@ fn stream_bad() -> io::Result<()> { Ok(()) as io::Result<()> }; - executor::block_on(fut) + block_on(fut) } #[test] @@ -162,7 +163,7 @@ fn stream_handshake() -> io::Result<()> { Ok(()) as io::Result<()> }; - executor::block_on(fut) + block_on(fut) } #[test] @@ -183,7 +184,7 @@ fn stream_handshake_eof() -> io::Result<()> { Ok(()) as io::Result<()> }; - executor::block_on(fut) + block_on(fut) } #[test] @@ -202,7 +203,7 @@ fn stream_eof() -> io::Result<()> { Ok(()) as io::Result<()> }; - executor::block_on(fut) + block_on(fut) } fn make_pair() -> (ServerSession, ClientSession) { @@ -234,11 +235,11 @@ fn do_handshake( let mut stream = Stream::new(&mut good, client); if stream.session.is_handshaking() { - futures::ready!(stream.complete_io(cx))?; + ready!(stream.complete_io(cx))?; } if stream.session.wants_write() { - futures::ready!(stream.complete_io(cx))?; + ready!(stream.complete_io(cx))?; } Poll::Ready(Ok(())) diff --git a/src/server.rs b/src/server.rs index 3f4a7e2..1c1438d 100644 --- a/src/server.rs +++ b/src/server.rs @@ -3,7 +3,8 @@ use crate::common::tls_state::TlsState; use crate::rusttls::stream::Stream; -use futures::io::{AsyncRead, AsyncWrite}; +use futures_core::ready; +use futures_io::{AsyncRead, AsyncWrite}; use rustls::ServerSession; use std::future::Future; use std::pin::Pin; @@ -42,11 +43,11 @@ where let mut stream = Stream::new(io, session).set_eof(eof); if stream.session.is_handshaking() { - futures::ready!(stream.complete_io(cx))?; + ready!(stream.complete_io(cx))?; } if stream.session.wants_write() { - futures::ready!(stream.complete_io(cx))?; + ready!(stream.complete_io(cx))?; } } diff --git a/src/test_0rtt.rs b/src/test_0rtt.rs index 83414b7..297e749 100644 --- a/src/test_0rtt.rs +++ b/src/test_0rtt.rs @@ -1,8 +1,8 @@ use crate::{client::TlsStream, TlsConnector}; use async_std::net::TcpStream; use async_std::sync::Arc; -use futures::executor; -use futures::prelude::*; +use futures_executor::block_on; +use futures_util::io::{AsyncReadExt, AsyncWriteExt}; use rustls::ClientConfig; use std::io; use std::net::ToSocketAddrs; @@ -36,10 +36,10 @@ fn test_0rtt() { let config = Arc::new(config); let domain = "mozilla-modern.badssl.com"; - let (_, output) = executor::block_on(get(config.clone(), domain, false)).unwrap(); + let (_, output) = block_on(get(config.clone(), domain, false)).unwrap(); assert!(output.contains("mozilla-modern.badssl.com")); - let (io, output) = executor::block_on(get(config.clone(), domain, true)).unwrap(); + let (io, output) = block_on(get(config.clone(), domain, true)).unwrap(); assert!(output.contains("mozilla-modern.badssl.com")); assert_eq!(io.early_data.0, 0); diff --git a/tests/google.rs b/tests/google.rs index 627106e..5c8a60d 100644 --- a/tests/google.rs +++ b/tests/google.rs @@ -1,7 +1,7 @@ use async_std::net::TcpStream; use async_std::task; use async_tls::TlsConnector; -use futures::prelude::*; +use futures_util::io::{AsyncReadExt, AsyncWriteExt}; #[test] fn fetch_google() -> std::io::Result<()> { From e8ee12271c1f88d3424e6a065efde1a0cb0d3137 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Wed, 9 Sep 2020 14:18:08 +0200 Subject: [PATCH 23/36] v0.10.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 85ff152..fb6d47d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-tls" -version = "0.9.0" +version = "0.10.0" authors = ["The async-rs developers", "Florian Gilcher ", "dignifiedquire ", "quininer kel "] license = "MIT/Apache-2.0" repository = "https://github.com/async-std/async-tls" From 7e73190914504272fbc987c52ce18ebc31641557 Mon Sep 17 00:00:00 2001 From: Jacob Rothstein Date: Tue, 24 Nov 2020 16:32:55 -0800 Subject: [PATCH 24/36] update rustls --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fb6d47d..5298858 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,9 +18,9 @@ appveyor = { repository = "async-std/async-tls" } [dependencies] futures-io = "0.3.5" futures-core = "0.3.5" -rustls = "0.18.0" -webpki = { version = "0.21.2", optional = true } -webpki-roots = { version = "0.20.0", optional = true } +rustls = "0.19.0" +webpki = { version = "0.21.3", optional = true } +webpki-roots = { version = "0.21.0", optional = true } [features] default = ["client", "server"] From 7e9e81df2bc6e1f53baf2386c15e059dcce6b441 Mon Sep 17 00:00:00 2001 From: Jason Mobarak Date: Mon, 30 Nov 2020 15:24:49 -0800 Subject: [PATCH 25/36] update example projects too --- examples/client/Cargo.toml | 2 +- examples/server/Cargo.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/client/Cargo.toml b/examples/client/Cargo.toml index 78e95c9..03a37c0 100644 --- a/examples/client/Cargo.toml +++ b/examples/client/Cargo.toml @@ -6,6 +6,6 @@ edition = "2018" [dependencies] structopt = "0.3.9" -rustls = "0.18.0" +rustls = "0.19.0" async-std = "1.5.0" async-tls = { path = "../.." } diff --git a/examples/server/Cargo.toml b/examples/server/Cargo.toml index 8c29d81..d7aca4c 100644 --- a/examples/server/Cargo.toml +++ b/examples/server/Cargo.toml @@ -8,5 +8,5 @@ edition = "2018" structopt = "0.3.9" async-std = "1.5.0" async-tls = { path = "../.." } -rustls = "0.18.0" -webpki = "0.21.2" +rustls = "0.19.0" +webpki = "0.21.3" From 703bfd6a376b3f464a4f01dd8cf12cfa5fe71688 Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Fri, 4 Dec 2020 16:31:36 +0100 Subject: [PATCH 26/36] Add maintenance notice --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 183f266..cd7d6ad 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,20 @@
+# Maintenance Notice + +I, [Florian Gilcher](https://github.com/skade), am currently the main maintainer of `async-tls`. Due to general workload, I would like the hand the maintenance off to someone else carrying the general vision of `async-tls`: + +* Runtime-independence +* Backend-independence (currently not implemented) +* Focused on _use-case based_ configuration rather then exposing all configurations + +I expect applicants for maintainership to present a committment of at least 4h of time/week initially, so I recommend getting corporate backing first. + +I commit to weekly feedback of 30 minutes for the first 2 months - more in the initial days of handover. + +Please reach out to me at [through email](mailto:flo@andersground.net). + # Features `async-tls` can be used both in server and client programs. To save compilation times, you From b25601f08a4cfabe14a4fdcd1ccfbbeca2c1ece1 Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Fri, 4 Dec 2020 16:33:07 +0100 Subject: [PATCH 27/36] Bump version before release --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5298858..2526c9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-tls" -version = "0.10.0" +version = "0.10.1" authors = ["The async-rs developers", "Florian Gilcher ", "dignifiedquire ", "quininer kel "] license = "MIT/Apache-2.0" repository = "https://github.com/async-std/async-tls" From 6a8985cbbe426c772b0ced6e592bbc19e9dadf5b Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Fri, 4 Dec 2020 17:53:18 +0100 Subject: [PATCH 28/36] Change maintenance message --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cd7d6ad..e8f1491 100644 --- a/README.md +++ b/README.md @@ -56,11 +56,11 @@ I, [Florian Gilcher](https://github.com/skade), am currently the main maintainer * Backend-independence (currently not implemented) * Focused on _use-case based_ configuration rather then exposing all configurations -I expect applicants for maintainership to present a committment of at least 4h of time/week initially, so I recommend getting corporate backing first. +I expect applicants for maintainership to present a committment of at least 4h of time/week initially, so I recommend getting corporate backing first. The number isn't strict, but I want the process to improve maintenance. I'm happy with a group of multiple maintainers. I commit to weekly feedback of 30 minutes for the first 2 months - more in the initial days of handover. -Please reach out to me at [through email](mailto:flo@andersground.net). +If interested, please reach out to me at [through email](mailto:flo@andersground.net). # Features From 4c66ea8abc975b4f44b7ef89afe6164adc2a0c1e Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Fri, 4 Dec 2020 17:53:54 +0100 Subject: [PATCH 29/36] Tag 0.10.2 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2526c9c..8f30a6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-tls" -version = "0.10.1" +version = "0.10.2" authors = ["The async-rs developers", "Florian Gilcher ", "dignifiedquire ", "quininer kel "] license = "MIT/Apache-2.0" repository = "https://github.com/async-std/async-tls" From a8ca3ca5691e7c50f9aae34ccc5fefa331e06f3f Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Wed, 9 Dec 2020 18:16:29 +0100 Subject: [PATCH 30/36] Release and tag 0.11.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8f30a6e..daf7a87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-tls" -version = "0.10.2" +version = "0.11.0" authors = ["The async-rs developers", "Florian Gilcher ", "dignifiedquire ", "quininer kel "] license = "MIT/Apache-2.0" repository = "https://github.com/async-std/async-tls" From 55f643c2e2cc08a26a7c2cb61a7cefdfa5e5082d Mon Sep 17 00:00:00 2001 From: Matthias Wahl Date: Wed, 1 Feb 2023 22:01:36 +0100 Subject: [PATCH 31/36] feat: port to rustls 0.20 * attempt to port to rustls 0.20 * clippy * format * Fix test certificates (expired) and add a script to regenerate them. * Fix hanging and failing unit-tests UnexpectedEof errors are bubbled up from rustls. Tests needed to changed slightly, but are en par with tokio/tls. * Fix integration tests * Fix client and server examples * Update async-std version used for testing --------- Co-authored-by: Jason Mobarak --- Cargo.toml | 16 +++-- examples/client/Cargo.toml | 5 +- examples/client/src/main.rs | 19 +++--- examples/server/Cargo.toml | 9 +-- examples/server/src/main.rs | 38 +++++++---- src/acceptor.rs | 18 ++++-- src/client.rs | 19 +++--- src/connector.rs | 37 ++++++++--- src/rusttls/stream.rs | 53 ++++++++------- src/rusttls/test_stream.rs | 124 +++++++++++++++++++++--------------- src/server.rs | 28 ++++---- src/test_0rtt.rs | 19 ++++-- tests/ca.cert | 19 ++++++ tests/ca.rsa | 28 ++++++++ tests/end.cert | 40 ++++++------ tests/end.chain | 120 ++++++++++------------------------ tests/end.rsa | 55 ++++++++-------- tests/gen_cert_key.bash | 28 ++++++++ tests/google.rs | 7 +- tests/openssl.cfg | 13 ++++ tests/test.rs | 65 ++++++++++--------- 21 files changed, 442 insertions(+), 318 deletions(-) create mode 100644 tests/ca.cert create mode 100644 tests/ca.rsa create mode 100755 tests/gen_cert_key.bash create mode 100644 tests/openssl.cfg diff --git a/Cargo.toml b/Cargo.toml index daf7a87..b05fe1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,12 @@ [package] name = "async-tls" version = "0.11.0" -authors = ["The async-rs developers", "Florian Gilcher ", "dignifiedquire ", "quininer kel "] +authors = [ + "The async-rs developers", + "Florian Gilcher ", + "dignifiedquire ", + "quininer kel ", +] license = "MIT/Apache-2.0" repository = "https://github.com/async-std/async-tls" homepage = "https://github.com/async-std/async-tls" @@ -18,9 +23,10 @@ appveyor = { repository = "async-std/async-tls" } [dependencies] futures-io = "0.3.5" futures-core = "0.3.5" -rustls = "0.19.0" -webpki = { version = "0.21.3", optional = true } -webpki-roots = { version = "0.21.0", optional = true } +rustls = "0.20.6" +rustls-pemfile = "1.0" +webpki = { version = "0.22.0", optional = true } +webpki-roots = { version = "0.22.3", optional = true } [features] default = ["client", "server"] @@ -32,7 +38,7 @@ server = [] lazy_static = "1" futures-executor = "0.3.5" futures-util = { version = "0.3.5", features = ["io"] } -async-std = { version = "1.0", features = ["unstable"] } +async-std = { version = "1.11", features = ["unstable"] } [[test]] name = "test" diff --git a/examples/client/Cargo.toml b/examples/client/Cargo.toml index 03a37c0..0f23637 100644 --- a/examples/client/Cargo.toml +++ b/examples/client/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] structopt = "0.3.9" -rustls = "0.19.0" -async-std = "1.5.0" +rustls = "0.20.6" +rustls-pemfile = "1.0" +async-std = "1.11.0" async-tls = { path = "../.." } diff --git a/examples/client/src/main.rs b/examples/client/src/main.rs index 5e04678..5eedbd6 100644 --- a/examples/client/src/main.rs +++ b/examples/client/src/main.rs @@ -5,8 +5,9 @@ use async_std::task; use async_tls::TlsConnector; use rustls::ClientConfig; +use rustls_pemfile::certs; -use std::io::Cursor; +use std::io::{BufReader, Cursor}; use std::net::ToSocketAddrs; use std::path::{Path, PathBuf}; use std::sync::Arc; @@ -81,12 +82,14 @@ fn main() -> io::Result<()> { } async fn connector_for_ca_file(cafile: &Path) -> io::Result { - let mut config = ClientConfig::new(); - let file = async_std::fs::read(cafile).await?; - let mut pem = Cursor::new(file); - config - .root_store - .add_pem_file(&mut pem) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert"))?; + let mut root_store = rustls::RootCertStore::empty(); + let ca_bytes = async_std::fs::read(cafile).await?; + let cert = certs(&mut BufReader::new(Cursor::new(ca_bytes))).unwrap(); + debug_assert_eq!((1, 0), root_store.add_parsable_certificates(&cert)); + + let config = ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(root_store) + .with_no_client_auth(); Ok(TlsConnector::from(Arc::new(config))) } diff --git a/examples/server/Cargo.toml b/examples/server/Cargo.toml index d7aca4c..f69f39d 100644 --- a/examples/server/Cargo.toml +++ b/examples/server/Cargo.toml @@ -5,8 +5,9 @@ authors = ["The async-rs developers", "quininer "] edition = "2018" [dependencies] -structopt = "0.3.9" -async-std = "1.5.0" +async-std = "1.11.0" async-tls = { path = "../.." } -rustls = "0.19.0" -webpki = "0.21.3" +futures-lite = "1.12.0" +rustls = "0.20.6" +rustls-pemfile = "1.0" +structopt = "0.3.9" diff --git a/examples/server/src/main.rs b/examples/server/src/main.rs index ad6045c..ec426bb 100644 --- a/examples/server/src/main.rs +++ b/examples/server/src/main.rs @@ -1,10 +1,11 @@ use async_std::io; use async_std::net::{TcpListener, TcpStream}; -use async_std::prelude::*; +use async_std::stream::StreamExt; use async_std::task; use async_tls::TlsAcceptor; -use rustls::internal::pemfile::{certs, rsa_private_keys}; -use rustls::{Certificate, NoClientAuth, PrivateKey, ServerConfig}; +use futures_lite::io::AsyncWriteExt; +use rustls::{Certificate, PrivateKey, ServerConfig}; +use rustls_pemfile::{certs, read_one, Item}; use std::fs::File; use std::io::BufReader; @@ -28,14 +29,23 @@ struct Options { /// Load the passed certificates file fn load_certs(path: &Path) -> io::Result> { - certs(&mut BufReader::new(File::open(path)?)) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert")) + Ok(certs(&mut BufReader::new(File::open(path)?)) + .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert"))? + .into_iter() + .map(Certificate) + .collect()) } /// Load the passed keys file -fn load_keys(path: &Path) -> io::Result> { - rsa_private_keys(&mut BufReader::new(File::open(path)?)) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid key")) +fn load_key(path: &Path) -> io::Result { + match read_one(&mut BufReader::new(File::open(path)?)) { + Ok(Some(Item::RSAKey(data) | Item::PKCS8Key(data))) => Ok(PrivateKey(data)), + Ok(_) => Err(io::Error::new( + io::ErrorKind::InvalidInput, + format!("invalid key in {}", path.display()), + )), + Err(e) => Err(io::Error::new(io::ErrorKind::InvalidInput, e)), + } } /// Configure the server using rusttls @@ -44,13 +54,15 @@ fn load_keys(path: &Path) -> io::Result> { /// A TLS server needs a certificate and a fitting private key fn load_config(options: &Options) -> io::Result { let certs = load_certs(&options.cert)?; - let mut keys = load_keys(&options.key)?; + debug_assert_eq!(1, certs.len()); + let key = load_key(&options.key)?; // we don't use client authentication - let mut config = ServerConfig::new(NoClientAuth::new()); - config + let config = ServerConfig::builder() + .with_safe_defaults() + .with_no_client_auth() // set this server to use one cert together with the loaded private key - .set_single_cert(certs, keys.remove(0)) + .with_single_cert(certs, key) .map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?; Ok(config) @@ -78,7 +90,7 @@ async fn handle_connection(acceptor: &TlsAcceptor, tcp_stream: &mut TcpStream) - ) .await?; - tls_stream.flush().await?; + tls_stream.close().await?; Ok(()) } diff --git a/src/acceptor.rs b/src/acceptor.rs index 2563f8b..3901039 100644 --- a/src/acceptor.rs +++ b/src/acceptor.rs @@ -2,7 +2,7 @@ use crate::common::tls_state::TlsState; use crate::server; use futures_io::{AsyncRead, AsyncWrite}; -use rustls::{ServerConfig, ServerSession}; +use rustls::{ServerConfig, ServerConnection}; use std::future::Future; use std::io; use std::pin::Pin; @@ -39,17 +39,23 @@ impl TlsAcceptor { self.accept_with(stream, |_| ()) } - // Currently private, as exposing ServerSessions exposes rusttls + // Currently private, as exposing ServerConnections exposes rusttls fn accept_with(&self, stream: IO, f: F) -> Accept where IO: AsyncRead + AsyncWrite + Unpin, - F: FnOnce(&mut ServerSession), + F: FnOnce(&mut ServerConnection), { - let mut session = ServerSession::new(&self.inner); - f(&mut session); + let mut conn = match ServerConnection::new(self.inner.clone()) { + Ok(conn) => conn, + Err(_) => { + return Accept(server::MidHandshake::End); + } + }; + + f(&mut conn); Accept(server::MidHandshake::Handshaking(server::TlsStream { - session, + conn, io: stream, state: TlsState::Stream, })) diff --git a/src/client.rs b/src/client.rs index 890e210..2e610a6 100644 --- a/src/client.rs +++ b/src/client.rs @@ -4,20 +4,18 @@ use crate::common::tls_state::TlsState; use crate::rusttls::stream::Stream; use futures_core::ready; use futures_io::{AsyncRead, AsyncWrite}; -use rustls::ClientSession; +use rustls::ClientConnection; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use std::{io, mem}; -use rustls::Session; - /// The client end of a TLS connection. Can be used like any other bidirectional IO stream. /// Wraps the underlying TCP stream. #[derive(Debug)] pub struct TlsStream { pub(crate) io: IO, - pub(crate) session: ClientSession, + pub(crate) session: ClientConnection, pub(crate) state: TlsState, #[cfg(feature = "early-data")] @@ -58,11 +56,11 @@ where let (io, session) = (&mut stream.io, &mut stream.session); let mut stream = Stream::new(io, session).set_eof(eof); - if stream.session.is_handshaking() { + if stream.conn.is_handshaking() { ready!(stream.complete_io(cx))?; } - if stream.session.wants_write() { + if stream.conn.wants_write() { ready!(stream.complete_io(cx))?; } } @@ -90,17 +88,20 @@ where TlsState::EarlyData => { let this = self.get_mut(); + let is_handshaking = this.session.is_handshaking(); + let is_early_data_accepted = this.session.is_early_data_accepted(); + let mut stream = Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable()); let (pos, data) = &mut this.early_data; // complete handshake - if stream.session.is_handshaking() { + if is_handshaking { ready!(stream.complete_io(cx))?; } // write early data (fallback) - if !stream.session.is_early_data_accepted() { + if !is_early_data_accepted { while *pos < data.len() { let len = ready!(stream.as_mut_pin().poll_write(cx, &data[*pos..]))?; *pos += len; @@ -127,7 +128,7 @@ where Poll::Ready(Err(ref e)) if e.kind() == io::ErrorKind::ConnectionAborted => { this.state.shutdown_read(); if this.state.writeable() { - stream.session.send_close_notify(); + stream.conn.send_close_notify(); this.state.shutdown_write(); } Poll::Ready(Ok(0)) diff --git a/src/connector.rs b/src/connector.rs index 594be81..e686a42 100644 --- a/src/connector.rs +++ b/src/connector.rs @@ -3,13 +3,13 @@ use crate::common::tls_state::TlsState; use crate::client; use futures_io::{AsyncRead, AsyncWrite}; -use rustls::{ClientConfig, ClientSession}; +use rustls::{ClientConfig, ClientConnection, OwnedTrustAnchor, RootCertStore, ServerName}; +use std::convert::TryFrom; use std::future::Future; use std::io; use std::pin::Pin; use std::sync::Arc; use std::task::{Context, Poll}; -use webpki::DNSNameRef; /// The TLS connecting part. The acceptor drives /// the client side of the TLS handshake process. It works @@ -64,10 +64,18 @@ impl From for TlsConnector { impl Default for TlsConnector { fn default() -> Self { - let mut config = ClientConfig::new(); - config - .root_store - .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS); + let mut root_certs = RootCertStore::empty(); + root_certs.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| { + OwnedTrustAnchor::from_subject_spki_name_constraints( + ta.subject, + ta.spki, + ta.name_constraints, + ) + })); + let config = ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(root_certs) + .with_no_client_auth(); Arc::new(config).into() } } @@ -102,14 +110,14 @@ impl TlsConnector { self.connect_with(domain, stream, |_| ()) } - // NOTE: Currently private, exposing ClientSession exposes rusttls + // NOTE: Currently private, exposing ClientConnection exposes rusttls // Early data should be exposed differently fn connect_with<'a, IO, F>(&self, domain: impl AsRef, stream: IO, f: F) -> Connect where IO: AsyncRead + AsyncWrite + Unpin, - F: FnOnce(&mut ClientSession), + F: FnOnce(&mut ClientConnection), { - let domain = match DNSNameRef::try_from_ascii_str(domain.as_ref()) { + let domain = match ServerName::try_from(domain.as_ref()) { Ok(domain) => domain, Err(_) => { return Connect(ConnectInner::Error(Some(io::Error::new( @@ -119,7 +127,16 @@ impl TlsConnector { } }; - let mut session = ClientSession::new(&self.inner, domain); + let mut session = match ClientConnection::new(self.inner.clone(), domain) { + Ok(session) => session, + Err(_) => { + return Connect(ConnectInner::Error(Some(io::Error::new( + io::ErrorKind::Other, + "invalid connection", + )))) + } + }; + f(&mut session); #[cfg(not(feature = "early-data"))] diff --git a/src/rusttls/stream.rs b/src/rusttls/stream.rs index 3b80a20..4bb544c 100644 --- a/src/rusttls/stream.rs +++ b/src/rusttls/stream.rs @@ -1,18 +1,18 @@ use futures_core::ready; use futures_io::{AsyncRead, AsyncWrite}; -use rustls::Session; +use rustls::ConnectionCommon; use std::io::{self, Read, Write}; use std::marker::Unpin; use std::pin::Pin; use std::task::{Context, Poll}; -pub struct Stream<'a, IO, S> { +pub struct Stream<'a, IO, D> { pub io: &'a mut IO, - pub session: &'a mut S, + pub conn: &'a mut ConnectionCommon, pub eof: bool, } -trait WriteTls { +trait WriteTls { fn write_tls(&mut self, cx: &mut Context) -> io::Result; } @@ -23,11 +23,11 @@ enum Focus { Writable, } -impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> Stream<'a, IO, S> { - pub fn new(io: &'a mut IO, session: &'a mut S) -> Self { +impl<'a, IO: AsyncRead + AsyncWrite + Unpin, D: Unpin> Stream<'a, IO, D> { + pub fn new(io: &'a mut IO, conn: &'a mut ConnectionCommon) -> Self { Stream { io, - session, + conn, // The state so far is only used to detect EOF, so either Stream // or EarlyData state should both be all right. eof: false, @@ -64,13 +64,13 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> Stream<'a, IO, S> { let mut reader = Reader { io: self.io, cx }; - let n = match self.session.read_tls(&mut reader) { + let n = match self.conn.read_tls(&mut reader) { Ok(n) => n, Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => return Poll::Pending, Err(err) => return Poll::Ready(Err(err)), }; - self.session.process_new_packets().map_err(|err| { + self.conn.process_new_packets().map_err(|err| { // In case we have an alert to send describing this error, // try a last-gasp write -- but don't predate the primary // error. @@ -101,7 +101,7 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> Stream<'a, IO, S> { let mut write_would_block = false; let mut read_would_block = false; - while self.session.wants_write() { + while self.conn.wants_write() { match self.complete_write_io(cx) { Poll::Ready(Ok(n)) => wrlen += n, Poll::Pending => { @@ -112,7 +112,7 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> Stream<'a, IO, S> { } } - if !self.eof && self.session.wants_read() { + if !self.eof && self.conn.wants_read() { match self.complete_read_io(cx) { Poll::Ready(Ok(0)) => self.eof = true, Poll::Ready(Ok(n)) => rdlen += n, @@ -127,7 +127,7 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> Stream<'a, IO, S> { Focus::Writable => write_would_block, }; - match (self.eof, self.session.is_handshaking(), would_block) { + match (self.eof, self.conn.is_handshaking(), would_block) { (true, true, _) => { let err = io::Error::new(io::ErrorKind::UnexpectedEof, "tls handshake eof"); return Poll::Ready(Err(err)); @@ -153,7 +153,7 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> Stream<'a, IO, S> { } } -impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> WriteTls for Stream<'a, IO, S> { +impl<'a, IO: AsyncRead + AsyncWrite + Unpin, D: Unpin> WriteTls for Stream<'a, IO, D> { fn write_tls(&mut self, cx: &mut Context) -> io::Result { // TODO writev @@ -179,11 +179,11 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> WriteTls for Str } let mut writer = Writer { io: self.io, cx }; - self.session.write_tls(&mut writer) + self.conn.write_tls(&mut writer) } } -impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> AsyncRead for Stream<'a, IO, S> { +impl<'a, IO: AsyncRead + AsyncWrite + Unpin, D: Unpin> AsyncRead for Stream<'a, IO, D> { fn poll_read( self: Pin<&mut Self>, cx: &mut Context, @@ -191,7 +191,7 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> AsyncRead for Stream<'a ) -> Poll> { let this = self.get_mut(); - while this.session.wants_read() { + while !this.eof && this.conn.wants_read() { match this.complete_inner_io(cx, Focus::Readable) { Poll::Ready(Ok((0, _))) => break, Poll::Ready(Ok(_)) => (), @@ -200,23 +200,28 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> AsyncRead for Stream<'a } } - match this.session.read(buf) { + let mut reader = this.conn.reader(); + match reader.read(buf) { Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => Poll::Pending, + Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => { + this.eof = true; + Poll::Ready(Err(err)) + } result => Poll::Ready(result), } } } -impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> AsyncWrite for Stream<'a, IO, S> { +impl<'a, IO: AsyncRead + AsyncWrite + Unpin, D: Unpin> AsyncWrite for Stream<'a, IO, D> { fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll> { let this = self.get_mut(); - let len = match this.session.write(buf) { + let len = match this.conn.writer().write(buf) { Ok(n) => n, Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => return Poll::Pending, Err(err) => return Poll::Ready(Err(err)), }; - while this.session.wants_write() { + while this.conn.wants_write() { match this.complete_inner_io(cx, Focus::Writable) { Poll::Ready(Ok(_)) => (), Poll::Pending if len != 0 => break, @@ -229,7 +234,7 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> AsyncWrite for Stream<' Poll::Ready(Ok(len)) } else { // not write zero - match this.session.write(buf) { + match this.conn.writer().write(buf) { Ok(0) => Poll::Pending, Ok(n) => Poll::Ready(Ok(n)), Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => Poll::Pending, @@ -241,8 +246,8 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> AsyncWrite for Stream<' fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { let this = self.get_mut(); - this.session.flush()?; - while this.session.wants_write() { + this.conn.writer().flush()?; + while this.conn.wants_write() { ready!(this.complete_inner_io(cx, Focus::Writable))?; } Pin::new(&mut this.io).poll_flush(cx) @@ -251,7 +256,7 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Session> AsyncWrite for Stream<' fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let this = self.get_mut(); - while this.session.wants_write() { + while this.conn.wants_write() { ready!(this.complete_inner_io(cx, Focus::Writable))?; } Pin::new(&mut this.io).poll_close(cx) diff --git a/src/rusttls/test_stream.rs b/src/rusttls/test_stream.rs index 8f4d712..c8dc175 100644 --- a/src/rusttls/test_stream.rs +++ b/src/rusttls/test_stream.rs @@ -4,17 +4,20 @@ use futures_io::{AsyncRead, AsyncWrite}; use futures_util::io::{AsyncReadExt, AsyncWriteExt}; use futures_util::task::{noop_waker_ref, Context}; use futures_util::{future, ready}; -use rustls::internal::pemfile::{certs, rsa_private_keys}; -use rustls::{ClientConfig, ClientSession, NoClientAuth, ServerConfig, ServerSession, Session}; +use rustls::{ + Certificate, ClientConfig, ClientConnection, ConnectionCommon, PrivateKey, RootCertStore, + ServerConfig, ServerConnection, ServerName, +}; +use rustls_pemfile::{certs, pkcs8_private_keys}; +use std::convert::TryFrom; use std::io::{self, BufReader, Cursor, Read, Write}; use std::pin::Pin; use std::sync::Arc; use std::task::Poll; -use webpki::DNSNameRef; -struct Good<'a>(&'a mut dyn Session); +struct Good<'a, D>(&'a mut ConnectionCommon); -impl<'a> AsyncRead for Good<'a> { +impl<'a, D> AsyncRead for Good<'a, D> { fn poll_read( mut self: Pin<&mut Self>, _cx: &mut Context<'_>, @@ -24,7 +27,7 @@ impl<'a> AsyncRead for Good<'a> { } } -impl<'a> AsyncWrite for Good<'a> { +impl<'a, D> AsyncWrite for Good<'a, D> { fn poll_write( mut self: Pin<&mut Self>, _cx: &mut Context<'_>, @@ -37,12 +40,16 @@ impl<'a> AsyncWrite for Good<'a> { Poll::Ready(Ok(len)) } - fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + fn poll_flush(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + self.0 + .process_new_packets() + .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; Poll::Ready(Ok(())) } - fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) + fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.0.send_close_notify(); + self.poll_flush(cx) } } @@ -82,31 +89,33 @@ impl AsyncWrite for Bad { #[test] fn stream_good() -> io::Result<()> { - const FILE: &'static [u8] = include_bytes!("../../README.md"); - - let fut = async { - let (mut server, mut client) = make_pair(); - future::poll_fn(|cx| do_handshake(&mut client, &mut server, cx)).await?; - io::copy(&mut Cursor::new(FILE), &mut server)?; + block_on(_stream_good()) +} - { - let mut good = Good(&mut server); - let mut stream = Stream::new(&mut good, &mut client); +async fn _stream_good() -> io::Result<()> { + const FILE: &[u8] = include_bytes!("../../README.md"); + let (mut server, mut client) = make_pair(); + future::poll_fn(|cx| do_handshake(&mut client, &mut server, cx)).await?; + io::copy(&mut Cursor::new(FILE), &mut server.writer())?; + server.send_close_notify(); - let mut buf = Vec::new(); - stream.read_to_end(&mut buf).await?; - assert_eq!(buf, FILE); - stream.write_all(b"Hello World!").await?; - } + { + let mut good = Good(&mut server); + let mut stream = Stream::new(&mut good, &mut client); - let mut buf = String::new(); - server.read_to_string(&mut buf)?; - assert_eq!(buf, "Hello World!"); + let mut buf = Vec::new(); + stream.read_to_end(&mut buf).await?; + assert_eq!(buf, FILE); + stream.write_all(b"Hello World!").await?; + stream.conn.send_close_notify(); + stream.close().await?; + } - Ok(()) as io::Result<()> - }; + let mut buf = String::new(); + server.reader().read_to_string(&mut buf)?; + assert_eq!(buf, "Hello World!"); - block_on(fut) + Ok(()) as io::Result<()> } #[test] @@ -114,7 +123,7 @@ fn stream_bad() -> io::Result<()> { let fut = async { let (mut server, mut client) = make_pair(); future::poll_fn(|cx| do_handshake(&mut client, &mut server, cx)).await?; - client.set_buffer_limit(1024); + client.set_buffer_limit(Some(1024)); let mut bad = Bad(true); let mut stream = Stream::new(&mut bad, &mut client); @@ -193,12 +202,15 @@ fn stream_eof() -> io::Result<()> { let (mut server, mut client) = make_pair(); future::poll_fn(|cx| do_handshake(&mut client, &mut server, cx)).await?; - let mut good = Good(&mut server); - let mut stream = Stream::new(&mut good, &mut client).set_eof(true); + let mut eof_stream = Bad(false); + let mut stream = Stream::new(&mut eof_stream, &mut client); let mut buf = Vec::new(); - stream.read_to_end(&mut buf).await?; - assert_eq!(buf.len(), 0); + let res = stream.read_to_end(&mut buf).await; + assert_eq!( + res.err().map(|e| e.kind()), + Some(std::io::ErrorKind::UnexpectedEof) + ); Ok(()) as io::Result<()> }; @@ -206,39 +218,49 @@ fn stream_eof() -> io::Result<()> { block_on(fut) } -fn make_pair() -> (ServerSession, ClientSession) { +fn make_pair() -> (ServerConnection, ClientConnection) { const CERT: &str = include_str!("../../tests/end.cert"); const CHAIN: &str = include_str!("../../tests/end.chain"); const RSA: &str = include_str!("../../tests/end.rsa"); let cert = certs(&mut BufReader::new(Cursor::new(CERT))).unwrap(); - let mut keys = rsa_private_keys(&mut BufReader::new(Cursor::new(RSA))).unwrap(); - let mut sconfig = ServerConfig::new(NoClientAuth::new()); - sconfig.set_single_cert(cert, keys.pop().unwrap()).unwrap(); - let server = ServerSession::new(&Arc::new(sconfig)); - - let domain = DNSNameRef::try_from_ascii_str("localhost").unwrap(); - let mut cconfig = ClientConfig::new(); - let mut chain = BufReader::new(Cursor::new(CHAIN)); - cconfig.root_store.add_pem_file(&mut chain).unwrap(); - let client = ClientSession::new(&Arc::new(cconfig), domain); - - (server, client) + let cert = cert.into_iter().map(Certificate).collect(); + let mut keys = pkcs8_private_keys(&mut BufReader::new(Cursor::new(RSA))).unwrap(); + let key = PrivateKey(keys.pop().unwrap()); + let sconfig = ServerConfig::builder() + .with_safe_defaults() + .with_no_client_auth() + .with_single_cert(cert, key) + .unwrap(); + let server = ServerConnection::new(Arc::new(sconfig)); + + let domain = ServerName::try_from("localhost").unwrap(); + let mut root_store = RootCertStore::empty(); + let chain = certs(&mut BufReader::new(Cursor::new(CHAIN))).unwrap(); + let (added, ignored) = root_store.add_parsable_certificates(&chain); + assert!(added >= 1 && ignored == 0); + let cconfig = ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(root_store) + .with_no_client_auth(); + let client = ClientConnection::new(Arc::new(cconfig), domain); + + (server.unwrap(), client.unwrap()) } fn do_handshake( - client: &mut ClientSession, - server: &mut ServerSession, + client: &mut ClientConnection, + server: &mut ServerConnection, cx: &mut Context<'_>, ) -> Poll> { let mut good = Good(server); let mut stream = Stream::new(&mut good, client); - if stream.session.is_handshaking() { + if stream.conn.is_handshaking() { ready!(stream.complete_io(cx))?; } - if stream.session.wants_write() { + if stream.conn.wants_write() { ready!(stream.complete_io(cx))?; } diff --git a/src/server.rs b/src/server.rs index 1c1438d..6fb88e4 100644 --- a/src/server.rs +++ b/src/server.rs @@ -5,20 +5,18 @@ use crate::rusttls::stream::Stream; use futures_core::ready; use futures_io::{AsyncRead, AsyncWrite}; -use rustls::ServerSession; +use rustls::ServerConnection; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use std::{io, mem}; -use rustls::Session; - /// The server end of a TLS connection. Can be used like any other bidirectional IO stream. /// Wraps the underlying TCP stream. #[derive(Debug)] pub struct TlsStream { pub(crate) io: IO, - pub(crate) session: ServerSession, + pub(crate) conn: ServerConnection, pub(crate) state: TlsState, } @@ -39,14 +37,14 @@ where if let MidHandshake::Handshaking(stream) = this { let eof = !stream.state.readable(); - let (io, session) = (&mut stream.io, &mut stream.session); + let (io, session) = (&mut stream.io, &mut stream.conn); let mut stream = Stream::new(io, session).set_eof(eof); - if stream.session.is_handshaking() { + if stream.conn.is_handshaking() { ready!(stream.complete_io(cx))?; } - if stream.session.wants_write() { + if stream.conn.wants_write() { ready!(stream.complete_io(cx))?; } } @@ -68,8 +66,7 @@ where buf: &mut [u8], ) -> Poll> { let this = self.get_mut(); - let mut stream = - Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable()); + let mut stream = Stream::new(&mut this.io, &mut this.conn).set_eof(!this.state.readable()); match this.state { TlsState::Stream | TlsState::WriteShutdown => { @@ -82,7 +79,7 @@ where Poll::Ready(Err(ref err)) if err.kind() == io::ErrorKind::ConnectionAborted => { this.state.shutdown_read(); if this.state.writeable() { - stream.session.send_close_notify(); + stream.conn.send_close_notify(); this.state.shutdown_write(); } Poll::Ready(Ok(0)) @@ -108,27 +105,24 @@ where buf: &[u8], ) -> Poll> { let this = self.get_mut(); - let mut stream = - Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable()); + let mut stream = Stream::new(&mut this.io, &mut this.conn).set_eof(!this.state.readable()); stream.as_mut_pin().poll_write(cx, buf) } fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let this = self.get_mut(); - let mut stream = - Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable()); + let mut stream = Stream::new(&mut this.io, &mut this.conn).set_eof(!this.state.readable()); stream.as_mut_pin().poll_flush(cx) } fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { if self.state.writeable() { - self.session.send_close_notify(); + self.conn.send_close_notify(); self.state.shutdown_write(); } let this = self.get_mut(); - let mut stream = - Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable()); + let mut stream = Stream::new(&mut this.io, &mut this.conn).set_eof(!this.state.readable()); stream.as_mut_pin().poll_close(cx) } } diff --git a/src/test_0rtt.rs b/src/test_0rtt.rs index 297e749..1c13396 100644 --- a/src/test_0rtt.rs +++ b/src/test_0rtt.rs @@ -3,7 +3,7 @@ use async_std::net::TcpStream; use async_std::sync::Arc; use futures_executor::block_on; use futures_util::io::{AsyncReadExt, AsyncWriteExt}; -use rustls::ClientConfig; +use rustls::{ClientConfig, OwnedTrustAnchor, RootCertStore}; use std::io; use std::net::ToSocketAddrs; @@ -28,10 +28,19 @@ async fn get( #[test] fn test_0rtt() { - let mut config = ClientConfig::new(); - config - .root_store - .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS); + let mut root_certs = RootCertStore::empty(); + root_certs.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| { + OwnedTrustAnchor::from_subject_spki_name_constraints( + ta.subject, + ta.spki, + ta.name_constraints, + ) + })); + let config = ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(root_certs) + .with_no_client_auth(); + config.enable_early_data = true; let config = Arc::new(config); let domain = "mozilla-modern.badssl.com"; diff --git a/tests/ca.cert b/tests/ca.cert new file mode 100644 index 0000000..04426a9 --- /dev/null +++ b/tests/ca.cert @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDGTCCAgGgAwIBAgIUEEBOQwP/6Dvr6vUpsHzSKdvva68wDQYJKoZIhvcNAQEL +BQAwHDEaMBgGA1UEAwwRY2EudGVzdHNlcnZlci5jb20wHhcNMjIwNjA4MTAwOTI3 +WhcNMzIwNjA1MTAwOTI3WjAcMRowGAYDVQQDDBFjYS50ZXN0c2VydmVyLmNvbTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALxMc7nyY3HhRWUtmtyxKgPq +5jWlTKaJI4TO5xnYzCHYyDHT2Ouov3hXQxtLlRFvHEhCjLmDdElfaZvedZExxTGA +yb/4vHu1Oo0fbFQUXwgWRsdhbZweIpvvMGpeSf8TD3gM33WvJvlm0ytzMi+FcNO+ +K/agtfyuakvRnCgUqT7t+mpdApOF0GlMhW7yNurLYQErdITSEHo7B1LpyIxAzdDk +2RDg6Jw+owIqn35GRVR7KHgvmRu//eyPjN0gzTT0iPGX5FB5AE5pbv3coZ5Q3LOO +MzTM6bqTpHQWB8B/LYbAI/sgWvq9pGlzqwjD20+mIt/R3pCq3Si1PTCgvVxnCBMC +AwEAAaNTMFEwHQYDVR0OBBYEFB0N4W0qDG+IkkvDWR5+Ndx11PtvMB8GA1UdIwQY +MBaAFB0N4W0qDG+IkkvDWR5+Ndx11PtvMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI +hvcNAQELBQADggEBALe3wec6bKeolaVvh+Y6SZqcM8Dv9cTp4Hkw6oCt0pOsAThr +WCgJIwUx8XiCx9HBHiCXLHlsV4mHrbuZHCP7UFRwe4ujnT1hRvr44mu9pgvrT4Ff +483xT9AqUtkkwXdHjdgcy5LzfGaDOF404e4wp26Rcg/ZnHT4Sz5eKhZgM64L30/Q +PKy7nvz6iXtEX8+zHnfRhpC/QPn08t/YGO6hDCCkuc5kDUTMQiLxm+TtDwaw6dyC +OH2E1xTBrNAUaE0pMqQ2D2fZu81SKhZ8vjl/UvHsnWwJoix8JZDYs2Oq97DuMfpV +IAz5xDMH0GQxNX1E8ScqwoNF3pIkgZ6hvOmK8Zc= +-----END CERTIFICATE----- diff --git a/tests/ca.rsa b/tests/ca.rsa new file mode 100644 index 0000000..8846833 --- /dev/null +++ b/tests/ca.rsa @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8THO58mNx4UVl +LZrcsSoD6uY1pUymiSOEzucZ2Mwh2Mgx09jrqL94V0MbS5URbxxIQoy5g3RJX2mb +3nWRMcUxgMm/+Lx7tTqNH2xUFF8IFkbHYW2cHiKb7zBqXkn/Ew94DN91ryb5ZtMr +czIvhXDTviv2oLX8rmpL0ZwoFKk+7fpqXQKThdBpTIVu8jbqy2EBK3SE0hB6OwdS +6ciMQM3Q5NkQ4OicPqMCKp9+RkVUeyh4L5kbv/3sj4zdIM009Ijxl+RQeQBOaW79 +3KGeUNyzjjM0zOm6k6R0FgfAfy2GwCP7IFr6vaRpc6sIw9tPpiLf0d6Qqt0otT0w +oL1cZwgTAgMBAAECggEAL+fde33k+gifkKXBJAu4zkVZa2WSMj5quHOxTRyglq3i +BPdKVW5ZxEKjMpMQql5T2jiAOARvNemd40d+LsH0UutaqMoeHfUWH+hSNbP3F4Yf +XMN3UQRDtttsPGuftNMDGP5hbb3xkvsrl37X0kpHUb+szLLHijFPntmFupbDFlyi +n6xJcnNmRfeJGtEizXSvhZgQqxMX1jA1sNjZKdVSeU5b/gpKTS5b8LFKMkV55Z7M +eRZULzpiYiLj7Thfqg6blsUOnavn7jlAdYrUFhPW1+og6thLVLSuZAE9shlkvJk0 +fWHnHpU3H+Z64GSLTNJO0yzTx831EsETA1C1pdSnrQKBgQDXWnK3sRZYCimonIXJ +l8H8P/13D1H0fk5THxs9CMhp3mzg+lShrGD7TtUg6kty08NAlnanD2Gr9tSEGhwQ +99odV/VJOb2wBdVsrLXnPjATWaMDTpg8DoS9HCMNHaqva7z4H9qf5ETzz6jSDjfv +Q30HabOiu5ve2Sd1gAAz9iUAzwKBgQDf1sMtVyA93FdFd6gLLKUaf/K2i7aV6zwD +7PTgFi7Nlhpx8b2kRchfe8vL5AQX5HP6xL7Qakc/33apyDYLpiwPOfi/4WSAj62p +i4eCFSRH3KP8pCyF3CVVfvAW55kRkAgTUemARo/RKBDdKCftl7VwGVVUx66NDQgZ +UdJ9lYrtfQKBgQCSN14mbH1AP34zdjq8OmbCb2wX93XsrAlgFIG4+gqhHx0Lz8vA +jbq3RrochBfAGhm6864SFbZ6PLfkDZo6xx33yG3JTwQEzKExDT7gh++6Y6TzrNxe +AnmLsNv3nsnyGxON4Ire/uz2IWt9W5wMvuTYMKN//SOCtiw9cjAxF5HeLwKBgA3G +SJKEtw43fgNfXq75W1urHgOPy3ekVzgin9seYljycMQsTTBLvw3pL1xntrzFqUF4 +VAm9UI8ksEe4c2L6IeH5/k3IkAe9T8GMPZWKuYXWlRzZ+YdvSbjeK+Ys8GV9SJHv +y3/CV91WKtuBOhvL5zVzyaWC+EHj2Gi+eUaTKk59AoGBAKOqyM1zCKlPt82tg/12 +MsQH+83bfvZz1Az0HCfa8Qu4zLVCbpMw/XGZP6GZgqQTY0VJD/Mhk/W9XI/Qb5oP +j9MxnSd5HkeMYUyUzOhDq5iV8T7X2+bG3eW5B0JHqqXkotQUyu1G4CKDJQextLQl +oK8YBYWxdZbTg1RO1IGeofjr +-----END PRIVATE KEY----- diff --git a/tests/end.cert b/tests/end.cert index 66f087e..279199f 100644 --- a/tests/end.cert +++ b/tests/end.cert @@ -1,24 +1,20 @@ -----BEGIN CERTIFICATE----- -MIIEADCCAmigAwIBAgICAcgwDQYJKoZIhvcNAQELBQAwLDEqMCgGA1UEAwwhcG9u -eXRvd24gUlNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTE2MTIxMDE3NDIzM1oX -DTIyMDYwMjE3NDIzM1owGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1YDz66+7VD4DL1+/sVHMQ+BbDRgmD -OQlX++mfW8D3QNQm/qDBEbu7T7qqdc9GKDar4WIzBN8SBkzM1EjMGwNnZPV/Tfz0 -qUAR1L/7Zzf1GaFZvWXgksyUpfwvmprH3Iy/dpkETwtPthpTPNlui3hZnm/5kkjR -RWg9HmID4O04Ld6SK313v2ZgrPZbkKvbqlqhUnYWjL3blKVGbpXIsuZzEU9Ph+gH -tPcEhZpFsM6eLe+2TVscIrycMEOTXqAAmO6zZ9sQWtfllu3CElm904H6+jA/9Leg -al72pMmkYr8wWniqDDuijXuCPlVx5EDFFyxBmW18UeDEQaKV3kNfelaTAgMBAAGj -gb4wgbswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBsAwHQYDVR0OBBYEFIYhJkVy -AAKT6cY/ruH1Eu+NNxteMEIGA1UdIwQ7MDmAFNwuPy4Do//Sm5CZDrocHWTrNr96 -oR6kHDAaMRgwFgYDVQQDDA9wb255dG93biBSU0EgQ0GCAXswOwYDVR0RBDQwMoIO -dGVzdHNlcnZlci5jb22CFXNlY29uZC50ZXN0c2VydmVyLmNvbYIJbG9jYWxob3N0 -MA0GCSqGSIb3DQEBCwUAA4IBgQCWV76jfQDZKtfmj45fTwZzoe/PxjWPRbAvSEnt -LRHrPhqQfpMLqpun8uu/w86mHiR/AmiAySMu3zivW6wfGzlRWLi/zCyO6r9LGsgH -bNk5CF642cdZFvn1SiSm1oGXQrolIpcyXu88nUpt74RnY4ETCC1dRQKqxsYufe5T -DOmTm3ChinNW4QRG3yvW6DVuyxVAgZvofyKJOsM3GO6oogIM41aBqZ3UTwmIwp6D -oISdiATslFOzYzjnyXNR8DG8OOkv1ehWuyb8x+hQCZAuogQOWYtCSd6k3kKgd0EM -4CWbt1XDV9ZJwBf2uxZeKuCu/KIy9auNtijAwPsUv9qxuzko018zhl3lWm5p2Sqw -O7fFshU3A6df8hMw7ST6/tgFY7geT88U4iJhfWMwr/CZSRSVMXhTyJgbLIXxKYZj -Ym5v4NAIQP6hI4HixzQaYgrhW6YX6myk+emMjQLRJHT8uHvmT7fuxMJVWWgsCkr1 -C75pRQEagykN/Uzr5e6Tm8sVu88= +MIIDXDCCAkSgAwIBAgIUdMf6o8a7bRANDFQnmDuYgvN7EbEwDQYJKoZIhvcNAQEL +BQAwHDEaMBgGA1UEAwwRY2EudGVzdHNlcnZlci5jb20wHhcNMjIwNjA4MTAwOTI3 +WhcNMzIwNjA1MTAwOTI3WjAZMRcwFQYDVQQDDA50ZXN0c2VydmVyLmNvbTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJe4nuHgBT1neEVGMeyWEghVaKup +DY1p+1rwHjzBQoqHdGsLuiJWXjAuJ72EfCn+pVzYx7KYW10KS6Y19Dk4DXdvCjuN +4S0Pxh8CJbrELRSVe7RRPjDycopQsxBfkQjiTkNn8IZaSh6ITPrbDWyA0TPxwYDY +m2jln0OtRuINwAs8pCBCG2rrF3VvDtBJbO0jWhAK3Iy71zSDd0q7YKClEUj0ub6O +me4YutijMIreyZmEI/z4L4Wzk8mtEDIdiiMyRlWLsYns4Hya+EoopCbAjaVR7CnQ +KDBL4H+8M2s24QALHI9cEwVZqlDdpQM5A+lLza1C32/KeMHUt/uo8wRE420CAwEA +AaOBmDCBlTBTBgNVHREETDBKgg50ZXN0c2VydmVyLmNvbYIVc2Vjb25kLnRlc3Rz +ZXJ2ZXIuY29tgglsb2NhbGhvc3SHBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwHQYD +VR0OBBYEFAh6MVz1pzt1yPvm85irb0UZcdgQMB8GA1UdIwQYMBaAFB0N4W0qDG+I +kkvDWR5+Ndx11PtvMA0GCSqGSIb3DQEBCwUAA4IBAQBjPBb6rEshV9ZTstzNvH/K +nWpQvaivORxUfK0WwdaC/JLnkeu9pge0bAOiqbtsUhWPcqpLVxVO3Xs+IlAeZXqX +CHHtDI/8ygzMJ/me96tKaPktJI310MQiYOLJgPoOEANpVWAfpo+pPBQPKhLvzbw5 +gIK5YqV5slIg86uQJnAasvqJau2L3ex4tUy4DN/mJhdaRYD40D7IwV1RcNcbvSwh +e3TL5WnHfqjoAeuxJA5+emEaXpNe54K7ymyMweo1gZaNZiYVmLRTBuQak2WUudnJ +mSuv299j7AgRtsKqkzNyOI+g4OQfACtG1Zfi57Z+pTZKB0FcwZNDXIDhwBmJ3oIS -----END CERTIFICATE----- diff --git a/tests/end.chain b/tests/end.chain index 7c39013..fbc5e66 100644 --- a/tests/end.chain +++ b/tests/end.chain @@ -1,89 +1,39 @@ -----BEGIN CERTIFICATE----- -MIIGnzCCAoegAwIBAgIBezANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9wb255 -dG93biBSU0EgQ0EwHhcNMTYxMjEwMTc0MjMzWhcNMjYxMjA4MTc0MjMzWjAsMSow -KAYDVQQDDCFwb255dG93biBSU0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUwggGiMA0G -CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDnfb7vaJbaHEyVTflswWhmHqx5W0NO -KyKbDp2zXEJwDO+NDJq6i1HGnFd/vO4LyjJBU1wUsKtE+m55cfRmUHVuZ2w4n/VF -p7Z7n+SNuvJNcrzDxyKVy4GIZ39zQePnniqtLqXh6eI8Ow6jiMgVxC/wbWcVLKv6 -4RM+2fLjJAC9b27QfjhOlMKVeMOEvPrrpjLSauaHAktQPhuzIAwzxM0+KnvDkWWy -NVqAV/lq6fSO/9vJRhM4E2nxo6yqi7qTdxVxMmKsNn7L6HvjQgx+FXziAUs55Qd9 -cP7etCmPmoefkcgdbxDOIKH8D+DvfacZwngqcnr/q96Ff4uJ13d2OzR1mWVSZ2hE -JQt/BbZBANciqu9OZf3dj6uOOXgFF705ak0GfLtpZpc29M+fVnknXPDSiKFqjzOO -KL+SRGyuNc9ZYjBKkXPJ1OToAs6JSvgDxfOfX0thuo2rslqfpj2qCFugsRIRAqvb -eyFwg+BPM/P/EfauXlAcQtBF04fOi7xN2okCAwEAAaNeMFwwHQYDVR0OBBYEFNwu -Py4Do//Sm5CZDrocHWTrNr96MCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEF -BQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jANBgkqhkiG9w0BAQsFAAOC -BAEAMHZpBqDIUAVFZNw4XbuimXQ4K8q4uePrLGHLb4F/gHbr8kYrU4H+cy4l+xXf -2dlEBdZoqjSF7uXzQg5Fd8Ff3ZgutXd1xeUJnxo0VdpKIhqeaTPqhffC2X6FQQH5 -KrN7NVWQSnUhPNpBFELpmdpY1lHigFW7nytYj0C6VJ4QsbqhfW+n/t+Zgqtfh/Od -ZbclzxFwMM55zRA2HP6IwXS2+d61Jk/RpDHTzhWdjGH4906zGNNMa7slHpCTA9Ju -TrtjEAGt2PBSievBJOHZW80KVAoEX2n9B3ZABaz+uX0VVZG0D2FwhPpUeA57YiXu -qiktZR4Ankph3LabXp4IlAX16qpYsEW8TWE/HLreeqoM0WDoI6rF9qnTpV2KWqBf -ziMYkfSkT7hQ2bWc493lW+QwSxCsuBsDwlrCwAl6jFSf1+jEQx98/8n9rDNyD9dL -PvECmtF30WY98nwZ9/kO2DufQrd0mwSHcIT0pAwl5fimpkwTjj+TTbytO3M4jK5L -tuIzsViQ95BmJQ3XuLdkQ/Ug8rpECYRX5fQX1qXkkvl920ohpKqKyEji1OmfmJ0Z -tZChaEcu3Mp3U+gD4az2ogmle3i/Phz8ZEPFo4/21G5Qd72z0lBgaQIeyyCk5MHt -Yg0vA7X0/w4bz+OJv5tf7zJsPCYSprr+c/7YUJk9Fqu6+g9ZAavI99xFKdGhz4Og -w0trnKNCxYc6+NPopTDbXuY+fo4DK7C0CSae5sKs7013Ne6w4KvgfLKpvlemkGfg -ZA3+1FMXVfFIEH7Cw9cx6F02Sr3k1VrU68oM3wH5nvTUkELOf8nRMlzliQjVCpKB -yFSe9dzRVSFEbMDxChiEulGgNUHj/6wwpg0ZmCwPRHutppT3jkfEqizN5iHb69GH -k6kol6knJofkaL656Q3Oc9o0ZrMlFh1RwmOvAk5fVK0/CV88/phROz2Wdmy5Bz4a -t0vzqFWA54y6+9EEVoOk9SU0CYfpGtpX4URjLK1EUG/l+RR3366Uee6TPrtEZ9cg -56VQMxhSaRNAvJ6DfiSuscSCNJzwuXaMXSZydGYnnP9Tb9p6c1uy1sXdluZkBIcK -CgC+gdDMSNlDn9ghc4xZGkuA8bjzfAYuRuGKmfTt8uuklkjw2b9w3SHjC4/Cmd2W -cFRnzfg2oL6e78hNg2ZGgsLzvb6Lu6/5IhXCO7RitzYf2+HLBbc+YLFsnG3qeGe1 -28yGnXOQd97Cr4+IzFucVy/33gMQkesNUSDFJSq1gE/hGrMgTTMQJ7yC3PRqg0kG -tpqTyKNdM0g1adxlR1qfDPvpUBApkgBbySnMyWEr5+tBuoHUtH2m49oV9YD4odMJ -yJjlGxituO/YNN6O8oANlraG1Q== +MIIDXDCCAkSgAwIBAgIUdMf6o8a7bRANDFQnmDuYgvN7EbEwDQYJKoZIhvcNAQEL +BQAwHDEaMBgGA1UEAwwRY2EudGVzdHNlcnZlci5jb20wHhcNMjIwNjA4MTAwOTI3 +WhcNMzIwNjA1MTAwOTI3WjAZMRcwFQYDVQQDDA50ZXN0c2VydmVyLmNvbTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJe4nuHgBT1neEVGMeyWEghVaKup +DY1p+1rwHjzBQoqHdGsLuiJWXjAuJ72EfCn+pVzYx7KYW10KS6Y19Dk4DXdvCjuN +4S0Pxh8CJbrELRSVe7RRPjDycopQsxBfkQjiTkNn8IZaSh6ITPrbDWyA0TPxwYDY +m2jln0OtRuINwAs8pCBCG2rrF3VvDtBJbO0jWhAK3Iy71zSDd0q7YKClEUj0ub6O +me4YutijMIreyZmEI/z4L4Wzk8mtEDIdiiMyRlWLsYns4Hya+EoopCbAjaVR7CnQ +KDBL4H+8M2s24QALHI9cEwVZqlDdpQM5A+lLza1C32/KeMHUt/uo8wRE420CAwEA +AaOBmDCBlTBTBgNVHREETDBKgg50ZXN0c2VydmVyLmNvbYIVc2Vjb25kLnRlc3Rz +ZXJ2ZXIuY29tgglsb2NhbGhvc3SHBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwHQYD +VR0OBBYEFAh6MVz1pzt1yPvm85irb0UZcdgQMB8GA1UdIwQYMBaAFB0N4W0qDG+I +kkvDWR5+Ndx11PtvMA0GCSqGSIb3DQEBCwUAA4IBAQBjPBb6rEshV9ZTstzNvH/K +nWpQvaivORxUfK0WwdaC/JLnkeu9pge0bAOiqbtsUhWPcqpLVxVO3Xs+IlAeZXqX +CHHtDI/8ygzMJ/me96tKaPktJI310MQiYOLJgPoOEANpVWAfpo+pPBQPKhLvzbw5 +gIK5YqV5slIg86uQJnAasvqJau2L3ex4tUy4DN/mJhdaRYD40D7IwV1RcNcbvSwh +e3TL5WnHfqjoAeuxJA5+emEaXpNe54K7ymyMweo1gZaNZiYVmLRTBuQak2WUudnJ +mSuv299j7AgRtsKqkzNyOI+g4OQfACtG1Zfi57Z+pTZKB0FcwZNDXIDhwBmJ3oIS -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIIJBzCCBO+gAwIBAgIJAN7WS1mRS9A+MA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNV -BAMMD3Bvbnl0b3duIFJTQSBDQTAeFw0xNjEyMTAxNzQyMzNaFw0yNjEyMDgxNzQy -MzNaMBoxGDAWBgNVBAMMD3Bvbnl0b3duIFJTQSBDQTCCBCIwDQYJKoZIhvcNAQEB -BQADggQPADCCBAoCggQBAMNEzJ7aNdD2JSk9+NF9Hh2za9OQnt1d/7j6DtE3ieoT -ms8mMSXzoImXZayZ9Glx3yx/RhEb2vmINyb0vRUM4I/GH+XHdOBcs9kaJNv/Mpw4 -Ggd4e1LUqV1pzNrhYwRrTQTKyaDiDX2WEBNfQaaYnHltmSmsfyt3Klj+IMc6CyqV -q8SOQ6Go414Vn++Jj7p3E6owdwuvSvO8ERLobiA6vYB+qrS7E48c4zRIAFIO4uwt -g4TiCJLLWc1fRSoqGGX7KS+LzQF8Pq67IOHVna4e9peSe6nQnm0LQZAmaosYHvF4 -AX0Bj6TLv9PXCAGtB7Pciev5Br0tRZEdVyYfmwiVKUWcp77TghV3W+VaJVhPh5LN -X91ktvpeYek3uglqv2ZHtSG2S1KkBtTkbMOD+a2BEUfq0c0+BIsj6jdvt4cvIfet -4gUOxCvYMBs4/dmNT1zoe/kJ0lf8YXYLsXwVWdIW3jEE8QdkLtLI9XfyU9OKLZuD -mmoAf7ezvv/T3nKLFqhcwUFGgGtCIX+oWC16XSbDPBcKDBwNZn8C49b7BLdxqAg3 -msfxwhYzSs9F1MXt/h2dh7FVmkCSxtgNDX3NJn5/yT6USws2y0AS5vXVP9hRf0NV -KfKn9XlmHCxnZExwm68uZkUUYHB05jSWFojbfWE+Mf9djUeQ4FuwusztZdbyQ4yS -mMtBXO0I6SQBmjCoOa1ySW3DTuw/eKCfq+PoxqWD434bYA9nUa+pE27MP7GLyjCS -6+ED3MACizSF0YxkcC9pWUo4L5FKp+DxnNbtzMIILnsDZTVHOvKUy/gjTyTWm/+7 -2t98l7vBE8gn3Aux0V5WFe2uZIZ07wIi/OThoBO8mpt9Bm5cJTG07JStKEXX/UH1 -nL7cDZ2V5qbf4hJdDy4qixxxIZtmf//1BRlVQ9iYTOsMoy+36DXWbc3vSmjRefW1 -YENt4zxOPe4LUq2Z+LXq1OgVQrHrVevux0vieys7Rr2gA1sH8FaaNwTr7Q8dq+Av -Evk+iOUH4FuYorU1HuGHPkAkvLWosVwlB+VhfEai0V6+PmttmaOnCJNHfFTu5wCu -B9CFJ1tdzTzAbrLwgtWmO70KV7CfZPHO7lMWhSvplU0i5T9WytxP91IoFtXwRSO8 -+Ghyu0ynB3HywCH2dez89Vy903P6PEU0qTnYWRz6D/wi5+yHHNrm9CilWurs/Qex -kyB7lLD7Cb1JJc8QIFTqT6vj+cids3xd245hUdpFyZTX99YbF6IkiB2zGi5wvUmP -f1GPvkTLb7eF7bne9OClEjEqvc0hVJ2abO2WXkqxlQFEYZHNofm+y6bnby/BZZJo -beaSFcLOCe2Z8iZvVnzfHBCeLyWE89gc94z784S3LEsCAwEAAaNQME4wHQYDVR0O -BBYEFNz2wEPCQbx9OdRCNE4eALwHJfIgMB8GA1UdIwQYMBaAFNz2wEPCQbx9OdRC -NE4eALwHJfIgMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggQBACbm2YX7 -sBG0Aslj36gmVlCTTluNg2tuK2isHbK3YhNwujrH/o/o2OV7UeUkZkPwE4g4/SjC -OwDWYniRNyDKBOeD9Q0XxR5z5IZQO+pRVvXF8DXO6kygWCOJM9XheKxp9Uke0aDg -m8F02NslKLUdy7piGlLSz1sgdjiE3izIwFZRpZY7sMozNWWvSAmzprbkE78LghIm -VEydQzIQlr5soWqc65uFLNbEA6QBPoFc6dDW+mnzXf8nrZUM03CACxAsuq/YkjRp -OHgwgfdNRdlu4YhZtuQNak4BUvDmigTGxDC+aMJw0ldL1bLtqLG6BvQbyLNPOOfo -5S8lGh4y06gb//052xHaqtCh5Ax5sHUE5By6wKHAKbuJy26qyKfaRoc3Jigs4Fd5 -3CuoDWHbyXfkgKiU+sc+1mvCxQKFRJ2fpGEFP8iEcLvdUae7ZkRM4Kb0vST+QhQV -fDaFkM3Bwqtui5YaZ6cHHQVyXQdujCmfesoZXKil2yduQ3KWgePjewzRV+aDWMzk -qKaF+TRANSqWbBU6JTwwQ4veKQThU3ir7nS2ovdPbhNS/FnWoKodj6eaqXfdYuBh -XOXLewIF568MJsLOuBubeAO2a9LOlhnv6eLGp2P4M7vwEdN/LRRQtwBBmqq8C3h+ -ewrJP12B/ag0bJDi9vCgPhYtDEpjpfsnxZEIqVZwshJ/MqXykFp2kYk62ylyfDWq -veI/aHwpzT2k+4CI/XmPWXl9NlI50HPdpcwCBDy8xVHwb/x7stNgQdIhaj9tzmKa -S+eqitclc8Iqrbd523H//QDzm8yiqRZUdveNa9gioTMErR0ujCpK8tO8mVZcVfNX -i1/Vsar5++nXcPhxKsd1t8XV2dk3gUZIfMgzLLzs+KSiFg+bT3c7LkCd+I3w30Iv -fh9cxFBAyYO9giwxaCfJgoz7OYqaHOOtASF85UV7gK9ELT7/z+RAcS/UfY1xbd54 -hIi1vRZj8lfkAYNtnYlud44joi1BvW/GZGFCiJ13SSvfHNs9v/5xguyCSgyCc0qx -ZkN/fzj/5wFQbxSl3MPn/JrsvlH6wvJht1SA50uVdUvJ5e5V8EgLYfMqlJNNpTHP -wZcHF+Dw126oyu2KhUxD126Gusxp+tV6I0EEZnVwwduFQWq9xm/gT+qohpveeylf -Q2XGz56DF2udJJnSFGSqzQOl9XopNC/4ecBMwIzqdFSpaWgK3VNAcigyDajgoE4v -ZuiVDEiLhLowZvi1V8GOWzcka7R2BQBjhOLWByQGDcm8cOMS7w8oCSQCaYmJyHvE -tTHq7fX6/sXv0AJqM3ysSdU01IVBNahnr5WEkmQMaFF0DGvRfqkVdKcChwrKv7r2 -DLxargy39i2aQGg= +MIIDGTCCAgGgAwIBAgIUEEBOQwP/6Dvr6vUpsHzSKdvva68wDQYJKoZIhvcNAQEL +BQAwHDEaMBgGA1UEAwwRY2EudGVzdHNlcnZlci5jb20wHhcNMjIwNjA4MTAwOTI3 +WhcNMzIwNjA1MTAwOTI3WjAcMRowGAYDVQQDDBFjYS50ZXN0c2VydmVyLmNvbTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALxMc7nyY3HhRWUtmtyxKgPq +5jWlTKaJI4TO5xnYzCHYyDHT2Ouov3hXQxtLlRFvHEhCjLmDdElfaZvedZExxTGA +yb/4vHu1Oo0fbFQUXwgWRsdhbZweIpvvMGpeSf8TD3gM33WvJvlm0ytzMi+FcNO+ +K/agtfyuakvRnCgUqT7t+mpdApOF0GlMhW7yNurLYQErdITSEHo7B1LpyIxAzdDk +2RDg6Jw+owIqn35GRVR7KHgvmRu//eyPjN0gzTT0iPGX5FB5AE5pbv3coZ5Q3LOO +MzTM6bqTpHQWB8B/LYbAI/sgWvq9pGlzqwjD20+mIt/R3pCq3Si1PTCgvVxnCBMC +AwEAAaNTMFEwHQYDVR0OBBYEFB0N4W0qDG+IkkvDWR5+Ndx11PtvMB8GA1UdIwQY +MBaAFB0N4W0qDG+IkkvDWR5+Ndx11PtvMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI +hvcNAQELBQADggEBALe3wec6bKeolaVvh+Y6SZqcM8Dv9cTp4Hkw6oCt0pOsAThr +WCgJIwUx8XiCx9HBHiCXLHlsV4mHrbuZHCP7UFRwe4ujnT1hRvr44mu9pgvrT4Ff +483xT9AqUtkkwXdHjdgcy5LzfGaDOF404e4wp26Rcg/ZnHT4Sz5eKhZgM64L30/Q +PKy7nvz6iXtEX8+zHnfRhpC/QPn08t/YGO6hDCCkuc5kDUTMQiLxm+TtDwaw6dyC +OH2E1xTBrNAUaE0pMqQ2D2fZu81SKhZ8vjl/UvHsnWwJoix8JZDYs2Oq97DuMfpV +IAz5xDMH0GQxNX1E8ScqwoNF3pIkgZ6hvOmK8Zc= -----END CERTIFICATE----- diff --git a/tests/end.rsa b/tests/end.rsa index 744bba5..f4d2830 100644 --- a/tests/end.rsa +++ b/tests/end.rsa @@ -1,27 +1,28 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAtWA8+uvu1Q+Ay9fv7FRzEPgWw0YJgzkJV/vpn1vA90DUJv6g -wRG7u0+6qnXPRig2q+FiMwTfEgZMzNRIzBsDZ2T1f0389KlAEdS/+2c39RmhWb1l -4JLMlKX8L5qax9yMv3aZBE8LT7YaUzzZbot4WZ5v+ZJI0UVoPR5iA+DtOC3ekit9 -d79mYKz2W5Cr26paoVJ2Foy925SlRm6VyLLmcxFPT4foB7T3BIWaRbDOni3vtk1b -HCK8nDBDk16gAJjus2fbEFrX5ZbtwhJZvdOB+vowP/S3oGpe9qTJpGK/MFp4qgw7 -oo17gj5VceRAxRcsQZltfFHgxEGild5DX3pWkwIDAQABAoIBAFDTazlSbGML/pRY -TTWeyIw2UkaA7npIr45C13BJfitw+1nJPK/tDCDDveZ6i3yzLPHZhV5A/HtWzWC1 -9R7nptOrnO83PNN2nPOVQFxzOe+ClXGdQkoagQp5EXHRTspj0WD9I+FUrDDAcOjJ -BAgMJPyi6zlnZAXGDVa3NGyQDoZqwU2k36L4rEsJIkG0NVurZhpiCexNkkf32495 -TOINQ0iKdfJ4iZoEYQ9G+x4NiuAJRCHuIcH76SNfT+Uv3wX0ut5EFPtflnvtdgcp -QVcoKwYdO0+mgO5xqWlBcsujSvgBdiNAGnAxKHWiEaacuIJi4+yYovyEebP6QI2X -Zg/U2wkCgYEA794dE5CPXLOmv6nioVC/ubOESk7vjSlEka/XFbKr4EY794YEqrB1 -8TUqg09Bn3396AS1e6P2shr3bxos5ybhOxDGSLnJ+aC0tRFjd1BPKnA80vZM7ggt -5cjmdD5Zp0tIQTIAAYU5bONQOwj0ej4PE7lny26eLa5vfvCwlrD+rM0CgYEAwZMN -W/5PA2A+EM08IaHic8my0dCunrNLF890ouZnDG99SbgMGvvEsGIcCP1sai702hNh -VgGDxCz6/HUy+4O4YNFVtjY7uGEpfIEcEI7CsLQRP2ggWEFxThZtnEtO8PbM3J/i -qcS6njHdE+0XuCjgZwGgva5xH2pkWFzw/AIpEN8CgYB2HOo2axWc8T2n3TCifI+c -EqCOsqXU3cBM+MgxgASQcCUxMkX0AuZguuxPMmS+85xmdoMi+c8NTqgOhlYcEJIR -sqXgw9OH3zF8g6513w7Md+4Ld4rUHyTypGWOUfF1pmVS7RsBpKdtTdWA7FzuIMbt -0HsiujqbheyTFlPuMAOH9QKBgBWS1gJSrWuq5j/pH7J/4EUXTZ6kq1F0mgHlVRJy -qzlvk38LzA2V0a32wTkfRV3wLcnALzDuqkjK2o4YYb42R+5CZlMQaEd8TKtbmE0g -HAKljuaKLFCpun8BcOXiXsHsP5i3GQPisQnAdOsrmWEk7R2NyORa9LCToutWMGVl -uD3xAoGAA183Vldm+m4KPsKS17t8MbwBryDXvowGzruh/Z+PGA0spr+ke4XxwT1y -kMMP1+5flzmjlAf4+W8LehKuVqvQoMlPn5UVHmSxQ7cGx/O/o6Gbn8Q25/6UT+sM -B1Y0rlLoKG62pnkeXp1O4I57gnClatWRg5qw11a8V8e3jvDKIYM= ------END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCXuJ7h4AU9Z3hF +RjHslhIIVWirqQ2Nafta8B48wUKKh3RrC7oiVl4wLie9hHwp/qVc2MeymFtdCkum +NfQ5OA13bwo7jeEtD8YfAiW6xC0UlXu0UT4w8nKKULMQX5EI4k5DZ/CGWkoeiEz6 +2w1sgNEz8cGA2Jto5Z9DrUbiDcALPKQgQhtq6xd1bw7QSWztI1oQCtyMu9c0g3dK +u2CgpRFI9Lm+jpnuGLrYozCK3smZhCP8+C+Fs5PJrRAyHYojMkZVi7GJ7OB8mvhK +KKQmwI2lUewp0CgwS+B/vDNrNuEACxyPXBMFWapQ3aUDOQPpS82tQt9vynjB1Lf7 +qPMERONtAgMBAAECggEAE45tEGFfW4hcRNWk9sFrRp63tLTANfOsvg6IXz1r9c46 +79ddoTJvxpcUcUXD+WfE6eBZcUhZMndyw9RdjAiRF818zKtflH7dgz60HUxPIUGZ +Zec49Hcz02dOhXREDhiZjO+3XaICvsfD4Gve4ZcDIEZvskt5UL6UVlVd9yJdmDUA +dM8w+0CiWVDuQW6LIrLERPIbhWo+G6KMgi+wsL6nFTEpZu3qK7G+m2gcXWAc9VZ5 +nvPJE/imrWvOuCbCoHAj5CYBvtx7ZQwNGmTDwH1hupoAPirlnidIxT2uJJ8Vy7cT +FoqF0Kksxg3L5gE6/pzbOqTMqdIS1h4UVCF8bvuyIwKBgQDPko3VW6vOEv93JOHA +lT8Vbe2G6Ix8S5IEuAOHogD7Tvt4ghlAVdZsl0iG4MHM1md/arADjo1EYSMwcqpg +hma0+9Y7s4rpiChxqZQVJ29K7Xp57gXAwbma4t7DGqYmMYrZFPT0GGC4QDrVWI93 +yqSTlhJnBwdnwk0n0r68rZaUNwKBgQC7HkyXkOsFYcqBN8SSE62wqdx30xLeLdI+ +kBsdZQfTAevXk1zvuLfRk6AJlGaG7F+5TVdeYochLRibAKqcqKLjg2GMqTTZIlC7 +QNYSvWZ/Z2+Yp6vsg5c6pELIFV+EZn+xmjRRsiLMa2Gz5fcFim/VoU1+OV+KZLws +hr6GodU7ewKBgA92aV5lb8zwGVu0waRo+cQM5k7Qb/aqYnw7gPfPl6cg4Ra/CkaC +nnCEbICvqYAq0JbrSaVaLyfS3J41TH/YQzpkMDdOTqDK5chhy4gv4diBDEic9IzB +YaQqFlIOYCYkNqWpK/4q+rl+/2L5L+bKj6v21/QYz/JoxPqcdlzzyW3NAoGADuyE +uVXymLRK/XFgOTJemQeDMP9hsty+twSxVO/Y5uhxUflL4Ua/SnTWv8zZPIufutzD +SiDbnDbHjp1H/kSo8TJqVlisgWDuRXEPYeE/SowKZ4d/+9Ym+qNdPC4QNzQhnR2q +bJWjluA9o6aExCldcBF0Z8vVpekQ5RA+I+jGY/8CgYB2j36c21Z4hsyupUNBwCDB +0tkqMschuK8itsUc2t9yjlt8LDSVko35jFwOMRPR+pGWYQT0aZC13FWr7eEEAQ70 +Us62j6lCUZkx70ELRYzkOhj3eFQyHOh7Q/S88tZWuCadXk5/HsUYA40G0uvC3y+Y +y4L361HmTm9TdNKq2KyN2w== +-----END PRIVATE KEY----- diff --git a/tests/gen_cert_key.bash b/tests/gen_cert_key.bash new file mode 100755 index 0000000..33d8f67 --- /dev/null +++ b/tests/gen_cert_key.bash @@ -0,0 +1,28 @@ +#!/bin/bash + +set -ex + +DIR=${1-$(pwd)} + +CACERT="${DIR}/ca.cert" +CAKEY="${DIR}/ca.rsa" +KEY="${DIR}/end.rsa" +CERT="${DIR}/end.cert" +CHAIN="${DIR}/end.chain" + +# cleanup +if [ -f "$CERT" ]; then rm -f "$CERT"; fi +if [ -f "$KEY" ]; then rm -f "$KEY"; fi +if [ -f "$CACERT"]; then rm -f "$CACERT"; fi +if [ -f "$CAKEY"]; then rm -f "$CAKEY"; fi +if [ -f "$CHAIN"]; then rm -f "$CHAIN"; fi + +# generate ca +openssl req -x509 -newkey rsa:2048 -days 3650 -keyout "$CAKEY" -out "$CACERT" -nodes -subj /CN=ca.testserver.com + +# generate certs +openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -out "$CERT" -keyout "$KEY" -keyform P12 -subj /CN=testserver.com -config "${DIR}/openssl.cfg" -CA "$CACERT" -CAkey "$CAKEY" +# make key accessible #yolo +chmod 664 "$KEY" +# concat chain +cat "$CERT" "$CACERT" > "$CHAIN" \ No newline at end of file diff --git a/tests/google.rs b/tests/google.rs index 5c8a60d..f01418f 100644 --- a/tests/google.rs +++ b/tests/google.rs @@ -13,7 +13,12 @@ fn fetch_google() -> std::io::Result<()> { stream.write_all(b"GET / HTTP/1.0\r\n\r\n").await?; let mut res = vec![]; - stream.read_to_end(&mut res).await?; + // google might answer with a close_notify or not + match stream.read_to_end(&mut res).await { + Ok(_bytes_read) => (), + Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => (), + Err(e) => return Err(e), + } let data = String::from_utf8_lossy(&res); println!("{}", &data); diff --git a/tests/openssl.cfg b/tests/openssl.cfg new file mode 100644 index 0000000..8ed903e --- /dev/null +++ b/tests/openssl.cfg @@ -0,0 +1,13 @@ +[req] +distinguished_name=dn +x509_extensions=ext +[ dn ] +CN=testserver.com +[ ext ] +subjectAltName = @alt_names +[alt_names] +DNS.1 = testserver.com +DNS.2 = second.testserver.com +DNS.3 = localhost +IP.1 = 127.0.0.1 +IP.2 = ::1 \ No newline at end of file diff --git a/tests/test.rs b/tests/test.rs index d0f4ffa..c7b5997 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,12 +1,12 @@ +use async_std::channel::bounded; use async_std::io; use async_std::net::{TcpListener, TcpStream}; use async_std::prelude::*; -use async_std::sync::channel; use async_std::task; use async_tls::{TlsAcceptor, TlsConnector}; use lazy_static::lazy_static; -use rustls::internal::pemfile::{certs, rsa_private_keys}; -use rustls::{ClientConfig, ServerConfig}; +use rustls::{Certificate, ClientConfig, PrivateKey, RootCertStore, ServerConfig}; +use rustls_pemfile::{certs, pkcs8_private_keys}; use std::io::{BufReader, Cursor}; use std::net::SocketAddr; use std::sync::Arc; @@ -16,23 +16,26 @@ const CHAIN: &str = include_str!("end.chain"); const RSA: &str = include_str!("end.rsa"); lazy_static! { - static ref TEST_SERVER: (SocketAddr, &'static str, &'static str) = { + static ref TEST_SERVER: (SocketAddr, &'static str, Vec>) = { let cert = certs(&mut BufReader::new(Cursor::new(CERT))).unwrap(); - let mut keys = rsa_private_keys(&mut BufReader::new(Cursor::new(RSA))).unwrap(); - - let mut config = ServerConfig::new(rustls::NoClientAuth::new()); - config - .set_single_cert(cert, keys.pop().unwrap()) - .expect("invalid key or certificate"); - let acceptor = TlsAcceptor::from(Arc::new(config)); - - let (send, recv) = channel(1); + let cert = cert.into_iter().map(Certificate).collect(); + let chain = certs(&mut BufReader::new(Cursor::new(CHAIN))).unwrap(); + let mut keys = pkcs8_private_keys(&mut BufReader::new(Cursor::new(RSA))).unwrap(); + let key = PrivateKey(keys.pop().unwrap()); + let sconfig = ServerConfig::builder() + .with_safe_defaults() + .with_no_client_auth() + .with_single_cert(cert, key) + .unwrap(); + let acceptor = TlsAcceptor::from(Arc::new(sconfig)); + + let (send, recv) = bounded(1); task::spawn(async move { let addr = SocketAddr::from(([127, 0, 0, 1], 0)); let listener = TcpListener::bind(&addr).await?; - send.send(listener.local_addr()?).await; + send.send(listener.local_addr()?).await.unwrap(); let mut incoming = listener.incoming(); while let Some(stream) = incoming.next().await { @@ -50,16 +53,16 @@ lazy_static! { }); let addr = task::block_on(async move { recv.recv().await.unwrap() }); - (addr, "localhost", CHAIN) + (addr, "localhost", chain) }; } -fn start_server() -> &'static (SocketAddr, &'static str, &'static str) { +fn start_server() -> &'static (SocketAddr, &'static str, Vec>) { &*TEST_SERVER } async fn start_client(addr: SocketAddr, domain: &str, config: Arc) -> io::Result<()> { - const FILE: &'static [u8] = include_bytes!("../README.md"); + const FILE: &[u8] = include_bytes!("../README.md"); let config = TlsConnector::from(config); let mut buf = vec![0; FILE.len()]; @@ -78,24 +81,28 @@ async fn start_client(addr: SocketAddr, domain: &str, config: Arc) #[test] fn pass() { let (addr, domain, chain) = start_server(); - - let mut config = ClientConfig::new(); - let mut chain = BufReader::new(Cursor::new(chain)); - config.root_store.add_pem_file(&mut chain).unwrap(); - let config = Arc::new(config); - - task::block_on(start_client(addr.clone(), domain, config.clone())).unwrap(); + let mut root_store = RootCertStore::empty(); + let (added, ignored) = root_store.add_parsable_certificates(&chain); + assert!(added >= 1 && ignored == 0); + let config = ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(root_store) + .with_no_client_auth(); + task::block_on(start_client(*addr, domain, Arc::new(config))).unwrap(); } #[test] fn fail() { let (addr, domain, chain) = start_server(); - - let mut config = ClientConfig::new(); - let mut chain = BufReader::new(Cursor::new(chain)); - config.root_store.add_pem_file(&mut chain).unwrap(); + let mut root_store = RootCertStore::empty(); + let (added, ignored) = root_store.add_parsable_certificates(&chain); + assert!(added >= 1 && ignored == 0); + let config = ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(root_store) + .with_no_client_auth(); let config = Arc::new(config); assert_ne!(domain, &"google.com"); - assert!(task::block_on(start_client(addr.clone(), "google.com", config)).is_err()); + assert!(task::block_on(start_client(*addr, "google.com", config)).is_err()); } From b9400e6204d6dc85a85c7ee8f2a5450997f769e6 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Thu, 2 Feb 2023 14:18:51 +0100 Subject: [PATCH 32/36] chore: Release async-tls version 0.12.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b05fe1e..946195f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-tls" -version = "0.11.0" +version = "0.12.0" authors = [ "The async-rs developers", "Florian Gilcher ", From 97a5121a69390795422074456745ad24823577ae Mon Sep 17 00:00:00 2001 From: mlemesle <33993288+mlemesle@users.noreply.github.com> Date: Tue, 27 Jun 2023 11:41:31 +0200 Subject: [PATCH 33/36] Bump rustls to 0.21 (#50) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 946195f..94da8dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ appveyor = { repository = "async-std/async-tls" } [dependencies] futures-io = "0.3.5" futures-core = "0.3.5" -rustls = "0.20.6" +rustls = "0.21" rustls-pemfile = "1.0" webpki = { version = "0.22.0", optional = true } webpki-roots = { version = "0.22.3", optional = true } From c58588a276e6180f3ef99f4ec3bf9176c5f0f58c Mon Sep 17 00:00:00 2001 From: Sycrosity <72102935+Sycrosity@users.noreply.github.com> Date: Wed, 4 Oct 2023 21:51:39 +0100 Subject: [PATCH 34/36] Replace unmaintained webpki dependency with rustls-webpki (#54) * fix deprecated use of add_server_trust_anchors fn * replace "webpki" with "rustls-webpki" --- Cargo.toml | 5 +++-- src/connector.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 94da8dd..426b346 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,12 +25,13 @@ futures-io = "0.3.5" futures-core = "0.3.5" rustls = "0.21" rustls-pemfile = "1.0" -webpki = { version = "0.22.0", optional = true } +# webpki = { version = "0.22.0", optional = true } +rustls-webpki = { version = "0.101.4", optional = true } webpki-roots = { version = "0.22.3", optional = true } [features] default = ["client", "server"] -client = ["webpki", "webpki-roots"] +client = ["webpki-roots"] early-data = [] server = [] diff --git a/src/connector.rs b/src/connector.rs index e686a42..6f674ca 100644 --- a/src/connector.rs +++ b/src/connector.rs @@ -65,7 +65,7 @@ impl From for TlsConnector { impl Default for TlsConnector { fn default() -> Self { let mut root_certs = RootCertStore::empty(); - root_certs.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| { + root_certs.add_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| { OwnedTrustAnchor::from_subject_spki_name_constraints( ta.subject, ta.spki, From f7dd68132a3ee4dad5d893b146a6d248de635e70 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Thu, 18 Jan 2024 12:41:58 +0100 Subject: [PATCH 35/36] fix early-data implementation --- src/client.rs | 6 +-- src/rusttls/stream.rs | 118 ++++++++++++++++++++++++++++++++++++++---- src/test_0rtt.rs | 4 +- 3 files changed, 114 insertions(+), 14 deletions(-) diff --git a/src/client.rs b/src/client.rs index 2e610a6..96bbb03 100644 --- a/src/client.rs +++ b/src/client.rs @@ -163,7 +163,7 @@ where let (pos, data) = &mut this.early_data; // write early data - if let Some(mut early_data) = stream.session.early_data() { + if let Some(mut early_data) = stream.conn.client_early_data() { let len = match early_data.write(buf) { Ok(n) => n, Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => { @@ -176,12 +176,12 @@ where } // complete handshake - if stream.session.is_handshaking() { + if stream.conn.is_handshaking() { ready!(stream.complete_io(cx))?; } // write early data (fallback) - if !stream.session.is_early_data_accepted() { + if !stream.conn.is_early_data_accepted() { while *pos < data.len() { let len = ready!(stream.as_mut_pin().poll_write(cx, &data[*pos..]))?; *pos += len; diff --git a/src/rusttls/stream.rs b/src/rusttls/stream.rs index 4bb544c..bee787d 100644 --- a/src/rusttls/stream.rs +++ b/src/rusttls/stream.rs @@ -1,17 +1,117 @@ use futures_core::ready; use futures_io::{AsyncRead, AsyncWrite}; -use rustls::ConnectionCommon; +#[cfg(feature = "early-data")] +use rustls::client::WriteEarlyData; +use rustls::{ClientConnection, IoState, Reader, ServerConnection, Writer}; use std::io::{self, Read, Write}; use std::marker::Unpin; use std::pin::Pin; use std::task::{Context, Poll}; -pub struct Stream<'a, IO, D> { +pub struct Stream<'a, IO> { pub io: &'a mut IO, - pub conn: &'a mut ConnectionCommon, + pub conn: Conn<'a>, pub eof: bool, } +pub(crate) enum Conn<'a> { + Client(&'a mut ClientConnection), + Server(&'a mut ServerConnection), +} + +impl Conn<'_> { + pub(crate) fn is_handshaking(&self) -> bool { + match self { + Conn::Client(c) => c.is_handshaking(), + Conn::Server(c) => c.is_handshaking(), + } + } + + pub(crate) fn wants_write(&self) -> bool { + match self { + Conn::Client(c) => c.wants_write(), + Conn::Server(c) => c.wants_write(), + } + } + + pub(crate) fn wants_read(&self) -> bool { + match self { + Conn::Client(c) => c.wants_read(), + Conn::Server(c) => c.wants_read(), + } + } + + pub(crate) fn write_tls(&mut self, wr: &mut dyn io::Write) -> Result { + match self { + Conn::Client(c) => c.write_tls(wr), + Conn::Server(c) => c.write_tls(wr), + } + } + + pub(crate) fn reader(&mut self) -> Reader { + match self { + Conn::Client(c) => c.reader(), + Conn::Server(c) => c.reader(), + } + } + + pub(crate) fn writer(&mut self) -> Writer { + match self { + Conn::Client(c) => c.writer(), + Conn::Server(c) => c.writer(), + } + } + + pub(crate) fn send_close_notify(&mut self) { + match self { + Conn::Client(c) => c.send_close_notify(), + Conn::Server(c) => c.send_close_notify(), + } + } + + pub(crate) fn read_tls(&mut self, rd: &mut dyn io::Read) -> Result { + match self { + Conn::Client(c) => c.read_tls(rd), + Conn::Server(c) => c.read_tls(rd), + } + } + + pub(crate) fn process_new_packets(&mut self) -> Result { + match self { + Conn::Client(c) => c.process_new_packets(), + Conn::Server(c) => c.process_new_packets(), + } + } + + #[cfg(feature = "early-data")] + pub(crate) fn is_early_data_accepted(&self) -> bool { + match self { + Conn::Client(c) => c.is_early_data_accepted(), + Conn::Server(_) => false, + } + } + + #[cfg(feature = "early-data")] + pub(crate) fn client_early_data(&mut self) -> Option> { + match self { + Conn::Client(c) => c.early_data(), + Conn::Server(_) => None, + } + } +} + +impl<'a> From<&'a mut ClientConnection> for Conn<'a> { + fn from(conn: &'a mut ClientConnection) -> Self { + Conn::Client(conn) + } +} + +impl<'a> From<&'a mut ServerConnection> for Conn<'a> { + fn from(conn: &'a mut ServerConnection) -> Self { + Conn::Server(conn) + } +} + trait WriteTls { fn write_tls(&mut self, cx: &mut Context) -> io::Result; } @@ -23,11 +123,11 @@ enum Focus { Writable, } -impl<'a, IO: AsyncRead + AsyncWrite + Unpin, D: Unpin> Stream<'a, IO, D> { - pub fn new(io: &'a mut IO, conn: &'a mut ConnectionCommon) -> Self { +impl<'a, IO: AsyncRead + AsyncWrite + Unpin> Stream<'a, IO> { + pub fn new(io: &'a mut IO, conn: impl Into>) -> Self { Stream { io, - conn, + conn: conn.into(), // The state so far is only used to detect EOF, so either Stream // or EarlyData state should both be all right. eof: false, @@ -153,7 +253,7 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, D: Unpin> Stream<'a, IO, D> { } } -impl<'a, IO: AsyncRead + AsyncWrite + Unpin, D: Unpin> WriteTls for Stream<'a, IO, D> { +impl<'a, IO: AsyncRead + AsyncWrite + Unpin> WriteTls for Stream<'a, IO> { fn write_tls(&mut self, cx: &mut Context) -> io::Result { // TODO writev @@ -183,7 +283,7 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, D: Unpin> WriteTls for Stream<' } } -impl<'a, IO: AsyncRead + AsyncWrite + Unpin, D: Unpin> AsyncRead for Stream<'a, IO, D> { +impl<'a, IO: AsyncRead + AsyncWrite + Unpin> AsyncRead for Stream<'a, IO> { fn poll_read( self: Pin<&mut Self>, cx: &mut Context, @@ -212,7 +312,7 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, D: Unpin> AsyncRead for Stream<'a, } } -impl<'a, IO: AsyncRead + AsyncWrite + Unpin, D: Unpin> AsyncWrite for Stream<'a, IO, D> { +impl<'a, IO: AsyncRead + AsyncWrite + Unpin> AsyncWrite for Stream<'a, IO> { fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll> { let this = self.get_mut(); diff --git a/src/test_0rtt.rs b/src/test_0rtt.rs index 1c13396..d912901 100644 --- a/src/test_0rtt.rs +++ b/src/test_0rtt.rs @@ -29,14 +29,14 @@ async fn get( #[test] fn test_0rtt() { let mut root_certs = RootCertStore::empty(); - root_certs.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| { + root_certs.add_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| { OwnedTrustAnchor::from_subject_spki_name_constraints( ta.subject, ta.spki, ta.name_constraints, ) })); - let config = ClientConfig::builder() + let mut config = ClientConfig::builder() .with_safe_defaults() .with_root_certificates(root_certs) .with_no_client_auth(); From 245641a14a7315a71e2096f4fff8e9e6718c88fe Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Thu, 18 Jan 2024 12:42:24 +0100 Subject: [PATCH 36/36] chore: Release async-tls version 0.13.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 426b346..94a1969 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-tls" -version = "0.12.0" +version = "0.13.0" authors = [ "The async-rs developers", "Florian Gilcher ",