diff --git a/Cargo.toml b/Cargo.toml index ebea3ab..7e7344c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,5 @@ [workspace] members = [ - "tokio-native-tls", "tokio-rustls", "tokio-rustls/examples/client", "tokio-rustls/examples/server" diff --git a/tokio-native-tls/CHANGELOG.md b/tokio-native-tls/CHANGELOG.md deleted file mode 100644 index 1994302..0000000 --- a/tokio-native-tls/CHANGELOG.md +++ /dev/null @@ -1,11 +0,0 @@ -# 0.3.0 (December 23, 2020) - -- Upgrade to `tokio 1.0`. - -# 0.2.0 (October 16, 2020) - -- Upgrade to `tokio 0.3`. - -# 0.1.0 (January 9th, 2019) - -- Initial release from `tokio-tls 0.3` diff --git a/tokio-native-tls/Cargo.toml b/tokio-native-tls/Cargo.toml deleted file mode 100644 index 9b47807..0000000 --- a/tokio-native-tls/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "tokio-native-tls" -# When releasing to crates.io: -# - Remove path dependencies -# - Update html_root_url. -# - Update doc url -# - Cargo.toml -# - README.md -# - Update CHANGELOG.md. -# - Create "v0.1.x" git tag. -version = "0.3.1" -edition = "2018" -authors = ["Tokio Contributors "] -license = "MIT" -repository = "https://github.com/tokio-rs/tls" -homepage = "https://tokio.rs" -documentation = "https://docs.rs/tokio-native-tls" -description = """ -An implementation of TLS/SSL streams for Tokio using native-tls giving an implementation of TLS -for nonblocking I/O streams. -""" -categories = ["asynchronous", "network-programming"] - -[dependencies] -native-tls = "0.2" -tokio = "1.0" - -[features] -vendored = ["native-tls/vendored"] - -[dev-dependencies] -tokio = { version = "1.0", features = ["macros", "rt", "rt-multi-thread", "io-util", "net"] } -cfg-if = "1.0" -env_logger = { version = "0.10", default-features = false } -futures = { version = "0.3.0", features = ["async-await"] } - -tempfile = "3.1" -lazy_static = "1.4.0" - -[package.metadata.docs.rs] -all-features = true diff --git a/tokio-native-tls/LICENSE b/tokio-native-tls/LICENSE deleted file mode 100644 index cdb28b4..0000000 --- a/tokio-native-tls/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2019 Tokio Contributors - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/tokio-native-tls/README.md b/tokio-native-tls/README.md deleted file mode 100644 index 7b7aea3..0000000 --- a/tokio-native-tls/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# tokio-native-tls -[![github actions](https://github.com/tokio-rs/tls/workflows/CI/badge.svg)](https://github.com/tokio-rs/tls/actions) -[![crates](https://img.shields.io/crates/v/tokio-native-tls.svg)](https://crates.io/crates/tokio-native-tls) -[![license](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/tokio-rs/tls/blob/master/tokio-native-tls/LICENSE) -[![docs.rs](https://docs.rs/tokio-native-tls/badge.svg)](https://docs.rs/tokio-native-tls/) - -An implementation of TLS/SSL streams for Tokio built on top of the -[`native-tls`](https://crates.io/crates/native-tls) crate. - -## License - -This project is licensed under the [MIT license](./LICENSE). - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in Tokio by you, shall be licensed as MIT, without any additional -terms or conditions. diff --git a/tokio-native-tls/examples/download-rust-lang.rs b/tokio-native-tls/examples/download-rust-lang.rs deleted file mode 100644 index 6f864c3..0000000 --- a/tokio-native-tls/examples/download-rust-lang.rs +++ /dev/null @@ -1,39 +0,0 @@ -// #![warn(rust_2018_idioms)] - -use native_tls::TlsConnector; -use std::error::Error; -use std::net::ToSocketAddrs; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio::net::TcpStream; - -#[tokio::main] -async fn main() -> Result<(), Box> { - let addr = "www.rust-lang.org:443" - .to_socket_addrs()? - .next() - .ok_or("failed to resolve www.rust-lang.org")?; - - let socket = TcpStream::connect(&addr).await?; - let cx = TlsConnector::builder().build()?; - let cx = tokio_native_tls::TlsConnector::from(cx); - - let mut socket = cx.connect("www.rust-lang.org", socket).await?; - - socket - .write_all( - "\ - GET / HTTP/1.0\r\n\ - Host: www.rust-lang.org\r\n\ - \r\n\ - " - .as_bytes(), - ) - .await?; - - let mut data = Vec::new(); - socket.read_to_end(&mut data).await?; - - // println!("data: {:?}", &data); - println!("{}", String::from_utf8_lossy(&data[..])); - Ok(()) -} diff --git a/tokio-native-tls/examples/echo.rs b/tokio-native-tls/examples/echo.rs deleted file mode 100644 index 74c0564..0000000 --- a/tokio-native-tls/examples/echo.rs +++ /dev/null @@ -1,52 +0,0 @@ -#![warn(rust_2018_idioms)] - -// A tiny async TLS echo server with Tokio -use native_tls::Identity; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio::net::TcpListener; - -/** -an example to setup a tls server. -how to test: -wget https://127.0.0.1:12345 --no-check-certificate -*/ -#[tokio::main] -async fn main() -> Result<(), Box> { - // Bind the server's socket - let addr = "127.0.0.1:12345".to_string(); - let tcp: TcpListener = TcpListener::bind(&addr).await?; - - // Create the TLS acceptor. - let der = include_bytes!("identity.p12"); - let cert = Identity::from_pkcs12(der, "mypass")?; - let tls_acceptor = - tokio_native_tls::TlsAcceptor::from(native_tls::TlsAcceptor::builder(cert).build()?); - loop { - // Asynchronously wait for an inbound socket. - let (socket, remote_addr) = tcp.accept().await?; - let tls_acceptor = tls_acceptor.clone(); - println!("accept connection from {}", remote_addr); - tokio::spawn(async move { - // Accept the TLS connection. - let mut tls_stream = tls_acceptor.accept(socket).await.expect("accept error"); - // In a loop, read data from the socket and write the data back. - - let mut buf = [0; 1024]; - let n = tls_stream - .read(&mut buf) - .await - .expect("failed to read data from socket"); - - if n == 0 { - return; - } - println!("read={}", unsafe { - String::from_utf8_unchecked(buf[0..n].into()) - }); - tls_stream - .write_all(&buf[0..n]) - .await - .expect("failed to write data to socket"); - }); - } -} diff --git a/tokio-native-tls/examples/identity.p12 b/tokio-native-tls/examples/identity.p12 deleted file mode 100644 index d16abb8..0000000 Binary files a/tokio-native-tls/examples/identity.p12 and /dev/null differ diff --git a/tokio-native-tls/src/lib.rs b/tokio-native-tls/src/lib.rs deleted file mode 100644 index 8ce19c0..0000000 --- a/tokio-native-tls/src/lib.rs +++ /dev/null @@ -1,384 +0,0 @@ -#![doc(html_root_url = "https://docs.rs/tokio-native-tls/0.3.0")] -#![warn( - missing_debug_implementations, - missing_docs, - rust_2018_idioms, - unreachable_pub -)] -#![deny(rustdoc::broken_intra_doc_links)] -#![doc(test( - no_crate_inject, - attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables)) -))] - -//! Async TLS streams -//! -//! This library is an implementation of TLS streams using the most appropriate -//! system library by default for negotiating the connection. That is, on -//! Windows this library uses SChannel, on OSX it uses SecureTransport, and on -//! other platforms it uses OpenSSL. -//! -//! Each TLS stream implements the `Read` and `Write` traits to interact and -//! interoperate with the rest of the futures I/O ecosystem. Client connections -//! initiated from this crate verify hostnames automatically and by default. -//! -//! This crate primarily exports this ability through two newtypes, -//! `TlsConnector` and `TlsAcceptor`. These newtypes augment the -//! functionality provided by the `native-tls` crate, on which this crate is -//! built. Configuration of TLS parameters is still primarily done through the -//! `native-tls` crate. - -use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; - -use crate::native_tls::{Error, HandshakeError, MidHandshakeTlsStream}; -use std::fmt; -use std::future::Future; -use std::io::{self, Read, Write}; -use std::marker::Unpin; -#[cfg(unix)] -use std::os::unix::io::{AsRawFd, RawFd}; -#[cfg(windows)] -use std::os::windows::io::{AsRawSocket, RawSocket}; -use std::pin::Pin; -use std::ptr::null_mut; -use std::task::{Context, Poll}; - -/// An intermediate wrapper for the inner stream `S`. -#[derive(Debug)] -pub struct AllowStd { - inner: S, - context: *mut (), -} - -impl AllowStd { - /// Returns a shared reference to the inner stream. - pub fn get_ref(&self) -> &S { - &self.inner - } - - /// Returns a mutable reference to the inner stream. - pub fn get_mut(&mut self) -> &mut S { - &mut self.inner - } -} - -/// A wrapper around an underlying raw stream which implements the TLS or SSL -/// protocol. -/// -/// A `TlsStream` represents a handshake that has been completed successfully -/// and both the server and the client are ready for receiving and sending -/// data. Bytes read from a `TlsStream` are decrypted from `S` and bytes written -/// to a `TlsStream` are encrypted when passing through to `S`. -#[derive(Debug)] -pub struct TlsStream(native_tls::TlsStream>); - -/// A wrapper around a `native_tls::TlsConnector`, providing an async `connect` -/// method. -#[derive(Clone)] -pub struct TlsConnector(native_tls::TlsConnector); - -/// A wrapper around a `native_tls::TlsAcceptor`, providing an async `accept` -/// method. -#[derive(Clone)] -pub struct TlsAcceptor(native_tls::TlsAcceptor); - -struct MidHandshake(Option>>); - -enum StartedHandshake { - Done(TlsStream), - Mid(MidHandshakeTlsStream>), -} - -struct StartedHandshakeFuture(Option>); -struct StartedHandshakeFutureInner { - f: F, - stream: S, -} - -struct Guard<'a, S>(&'a mut TlsStream) -where - AllowStd: Read + Write; - -impl Drop for Guard<'_, S> -where - AllowStd: Read + Write, -{ - fn drop(&mut self) { - (self.0).0.get_mut().context = null_mut(); - } -} - -// *mut () context is neither Send nor Sync -unsafe impl Send for AllowStd {} -unsafe impl Sync for AllowStd {} - -impl AllowStd -where - S: Unpin, -{ - fn with_context(&mut self, f: F) -> io::Result - where - F: FnOnce(&mut Context<'_>, Pin<&mut S>) -> Poll>, - { - unsafe { - assert!(!self.context.is_null()); - let waker = &mut *(self.context as *mut _); - match f(waker, Pin::new(&mut self.inner)) { - Poll::Ready(r) => r, - Poll::Pending => Err(io::Error::from(io::ErrorKind::WouldBlock)), - } - } - } -} - -impl Read for AllowStd -where - S: AsyncRead + Unpin, -{ - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let mut buf = ReadBuf::new(buf); - self.with_context(|ctx, stream| stream.poll_read(ctx, &mut buf))?; - Ok(buf.filled().len()) - } -} - -impl Write for AllowStd -where - S: AsyncWrite + Unpin, -{ - fn write(&mut self, buf: &[u8]) -> io::Result { - self.with_context(|ctx, stream| stream.poll_write(ctx, buf)) - } - - fn flush(&mut self) -> io::Result<()> { - self.with_context(|ctx, stream| stream.poll_flush(ctx)) - } -} - -impl TlsStream { - fn with_context(&mut self, ctx: &mut Context<'_>, f: F) -> Poll> - where - F: FnOnce(&mut native_tls::TlsStream>) -> io::Result, - AllowStd: Read + Write, - { - self.0.get_mut().context = ctx as *mut _ as *mut (); - let g = Guard(self); - match f(&mut (g.0).0) { - Ok(v) => Poll::Ready(Ok(v)), - Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Poll::Pending, - Err(e) => Poll::Ready(Err(e)), - } - } - - /// Returns a shared reference to the inner stream. - pub fn get_ref(&self) -> &native_tls::TlsStream> { - &self.0 - } - - /// Returns a mutable reference to the inner stream. - pub fn get_mut(&mut self) -> &mut native_tls::TlsStream> { - &mut self.0 - } -} - -impl AsyncRead for TlsStream -where - S: AsyncRead + AsyncWrite + Unpin, -{ - fn poll_read( - mut self: Pin<&mut Self>, - ctx: &mut Context<'_>, - buf: &mut ReadBuf<'_>, - ) -> Poll> { - self.with_context(ctx, |s| { - let n = s.read(buf.initialize_unfilled())?; - buf.advance(n); - Ok(()) - }) - } -} - -impl AsyncWrite for TlsStream -where - S: AsyncRead + AsyncWrite + Unpin, -{ - fn poll_write( - mut self: Pin<&mut Self>, - ctx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - self.with_context(ctx, |s| s.write(buf)) - } - - fn poll_flush(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll> { - self.with_context(ctx, |s| s.flush()) - } - - fn poll_shutdown(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll> { - self.with_context(ctx, |s| s.shutdown()) - } -} - -#[cfg(unix)] -impl AsRawFd for TlsStream -where - S: AsRawFd, -{ - fn as_raw_fd(&self) -> RawFd { - self.get_ref().get_ref().get_ref().as_raw_fd() - } -} - -#[cfg(windows)] -impl AsRawSocket for TlsStream -where - S: AsRawSocket, -{ - fn as_raw_socket(&self) -> RawSocket { - self.get_ref().get_ref().get_ref().as_raw_socket() - } -} - -async fn handshake(f: F, stream: S) -> Result, Error> -where - F: FnOnce( - AllowStd, - ) -> Result>, HandshakeError>> - + Unpin, - S: AsyncRead + AsyncWrite + Unpin, -{ - let start = StartedHandshakeFuture(Some(StartedHandshakeFutureInner { f, stream })); - - match start.await { - Err(e) => Err(e), - Ok(StartedHandshake::Done(s)) => Ok(s), - Ok(StartedHandshake::Mid(s)) => MidHandshake(Some(s)).await, - } -} - -impl Future for StartedHandshakeFuture -where - F: FnOnce( - AllowStd, - ) -> Result>, HandshakeError>> - + Unpin, - S: Unpin, - AllowStd: Read + Write, -{ - type Output = Result, Error>; - - fn poll( - mut self: Pin<&mut Self>, - ctx: &mut Context<'_>, - ) -> Poll, Error>> { - let inner = self.0.take().expect("future polled after completion"); - let stream = AllowStd { - inner: inner.stream, - context: ctx as *mut _ as *mut (), - }; - - match (inner.f)(stream) { - Ok(mut s) => { - s.get_mut().context = null_mut(); - Poll::Ready(Ok(StartedHandshake::Done(TlsStream(s)))) - } - Err(HandshakeError::WouldBlock(mut s)) => { - s.get_mut().context = null_mut(); - Poll::Ready(Ok(StartedHandshake::Mid(s))) - } - Err(HandshakeError::Failure(e)) => Poll::Ready(Err(e)), - } - } -} - -impl TlsConnector { - /// Connects the provided stream with this connector, assuming the provided - /// domain. - /// - /// This function will internally call `TlsConnector::connect` to connect - /// the stream and returns a future representing the resolution of the - /// connection operation. The returned future will resolve to either - /// `TlsStream` or `Error` depending if it's successful or not. - /// - /// This is typically used for clients who have already established, for - /// example, a TCP connection to a remote server. That stream is then - /// provided here to perform the client half of a connection to a - /// TLS-powered server. - pub async fn connect(&self, domain: &str, stream: S) -> Result, Error> - where - S: AsyncRead + AsyncWrite + Unpin, - { - handshake(move |s| self.0.connect(domain, s), stream).await - } -} - -impl fmt::Debug for TlsConnector { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TlsConnector").finish() - } -} - -impl From for TlsConnector { - fn from(inner: native_tls::TlsConnector) -> TlsConnector { - TlsConnector(inner) - } -} - -impl TlsAcceptor { - /// Accepts a new client connection with the provided stream. - /// - /// This function will internally call `TlsAcceptor::accept` to connect - /// the stream and returns a future representing the resolution of the - /// connection operation. The returned future will resolve to either - /// `TlsStream` or `Error` depending if it's successful or not. - /// - /// This is typically used after a new socket has been accepted from a - /// `TcpListener`. That socket is then passed to this function to perform - /// the server half of accepting a client connection. - pub async fn accept(&self, stream: S) -> Result, Error> - where - S: AsyncRead + AsyncWrite + Unpin, - { - handshake(move |s| self.0.accept(s), stream).await - } -} - -impl fmt::Debug for TlsAcceptor { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TlsAcceptor").finish() - } -} - -impl From for TlsAcceptor { - fn from(inner: native_tls::TlsAcceptor) -> TlsAcceptor { - TlsAcceptor(inner) - } -} - -impl Future for MidHandshake { - type Output = Result, Error>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut_self = self.get_mut(); - let mut s = mut_self.0.take().expect("future polled after completion"); - - s.get_mut().context = cx as *mut _ as *mut (); - match s.handshake() { - Ok(mut s) => { - s.get_mut().context = null_mut(); - Poll::Ready(Ok(TlsStream(s))) - } - Err(HandshakeError::WouldBlock(mut s)) => { - s.get_mut().context = null_mut(); - mut_self.0 = Some(s); - Poll::Pending - } - Err(HandshakeError::Failure(e)) => Poll::Ready(Err(e)), - } - } -} - -/// re-export native_tls -pub mod native_tls { - pub use native_tls::*; -} diff --git a/tokio-native-tls/tests/bad.rs b/tokio-native-tls/tests/bad.rs deleted file mode 100644 index 862d998..0000000 --- a/tokio-native-tls/tests/bad.rs +++ /dev/null @@ -1,122 +0,0 @@ -#![warn(rust_2018_idioms)] - -use cfg_if::cfg_if; -use native_tls::TlsConnector; -use std::io::{self, Error}; -use std::net::ToSocketAddrs; -use tokio::net::TcpStream; - -macro_rules! t { - ($e:expr) => { - match $e { - Ok(e) => e, - Err(e) => panic!("{} failed with {:?}", stringify!($e), e), - } - }; -} - -cfg_if! { - if #[cfg(feature = "force-rustls")] { - fn verify_failed(err: &Error, s: &str) { - let err = err.to_string(); - assert!(err.contains(s), "bad error: {}", err); - } - - fn assert_expired_error(err: &Error) { - verify_failed(err, "CertExpired"); - } - - fn assert_wrong_host(err: &Error) { - verify_failed(err, "CertNotValidForName"); - } - - fn assert_self_signed(err: &Error) { - verify_failed(err, "UnknownIssuer"); - } - - fn assert_untrusted_root(err: &Error) { - verify_failed(err, "UnknownIssuer"); - } - } else if #[cfg(any(feature = "force-openssl", - all(not(target_os = "macos"), - not(target_os = "windows"), - not(target_os = "ios"))))] { - fn verify_failed(err: &Error) { - assert!(format!("{}", err).contains("certificate verify failed")) - } - - use verify_failed as assert_expired_error; - use verify_failed as assert_wrong_host; - use verify_failed as assert_self_signed; - use verify_failed as assert_untrusted_root; - } else if #[cfg(any(target_os = "macos", target_os = "ios"))] { - - fn assert_invalid_cert_chain(err: &Error) { - assert!(format!("{}", err).contains("was not trusted.")) - } - - use crate::assert_invalid_cert_chain as assert_expired_error; - use crate::assert_invalid_cert_chain as assert_wrong_host; - use crate::assert_invalid_cert_chain as assert_self_signed; - use crate::assert_invalid_cert_chain as assert_untrusted_root; - } else { - fn assert_expired_error(err: &Error) { - let s = err.to_string(); - assert!(s.contains("system clock"), "error = {:?}", s); - } - - fn assert_wrong_host(err: &Error) { - let s = err.to_string(); - assert!(s.contains("CN name"), "error = {:?}", s); - } - - fn assert_self_signed(err: &Error) { - let s = err.to_string(); - assert!(s.contains("root certificate which is not trusted"), "error = {:?}", s); - } - - use assert_self_signed as assert_untrusted_root; - } -} - -async fn get_host(host: &'static str) -> Error { - drop(env_logger::try_init()); - - let addr = format!("{}:443", host); - let addr = t!(addr.to_socket_addrs()).next().unwrap(); - - let socket = t!(TcpStream::connect(&addr).await); - let builder = TlsConnector::builder(); - let cx = t!(builder.build()); - let cx = tokio_native_tls::TlsConnector::from(cx); - let res = cx - .connect(host, socket) - .await - .map_err(|e| Error::new(io::ErrorKind::Other, e)); - - assert!(res.is_err()); - res.err().unwrap() -} - -#[tokio::test] -async fn expired() { - assert_expired_error(&get_host("expired.badssl.com").await) -} - -// TODO: the OSX builders on Travis apparently fail this tests spuriously? -// passes locally though? Seems... bad! -#[tokio::test] -#[cfg_attr(all(target_os = "macos", feature = "force-openssl"), ignore)] -async fn wrong_host() { - assert_wrong_host(&get_host("wrong.host.badssl.com").await) -} - -#[tokio::test] -async fn self_signed() { - assert_self_signed(&get_host("self-signed.badssl.com").await) -} - -#[tokio::test] -async fn untrusted_root() { - assert_untrusted_root(&get_host("untrusted-root.badssl.com").await) -} diff --git a/tokio-native-tls/tests/cert.der b/tokio-native-tls/tests/cert.der deleted file mode 100644 index e1f964d..0000000 Binary files a/tokio-native-tls/tests/cert.der and /dev/null differ diff --git a/tokio-native-tls/tests/google.rs b/tokio-native-tls/tests/google.rs deleted file mode 100644 index 179358e..0000000 --- a/tokio-native-tls/tests/google.rs +++ /dev/null @@ -1,99 +0,0 @@ -#![warn(rust_2018_idioms)] - -use cfg_if::cfg_if; -use native_tls::TlsConnector; -use std::io; -use std::net::ToSocketAddrs; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio::net::TcpStream; - -macro_rules! t { - ($e:expr) => { - match $e { - Ok(e) => e, - Err(e) => panic!("{} failed with {:?}", stringify!($e), e), - } - }; -} - -cfg_if! { - if #[cfg(feature = "force-rustls")] { - fn assert_bad_hostname_error(err: &io::Error) { - let err = err.to_string(); - assert!(err.contains("CertNotValidForName"), "bad error: {}", err); - } - } else if #[cfg(any(feature = "force-openssl", - all(not(target_os = "macos"), - not(target_os = "windows"), - not(target_os = "ios"))))] { - fn assert_bad_hostname_error(err: &io::Error) { - let err = err.get_ref().unwrap(); - let err = err.downcast_ref::().unwrap(); - assert!(format!("{}", err).contains("certificate verify failed")); - } - } else if #[cfg(any(target_os = "macos", target_os = "ios"))] { - fn assert_bad_hostname_error(err: &io::Error) { - let err = err.get_ref().unwrap(); - let err = err.downcast_ref::().unwrap(); - assert!(format!("{}", err).contains("was not trusted.")); - } - } else { - fn assert_bad_hostname_error(err: &io::Error) { - let err = err.get_ref().unwrap(); - let err = err.downcast_ref::().unwrap(); - assert!(format!("{}", err).contains("CN name")); - } - } -} - -#[tokio::test] -async fn fetch_google() { - drop(env_logger::try_init()); - - // First up, resolve google.com - let addr = t!("google.com:443".to_socket_addrs()).next().unwrap(); - - let socket = TcpStream::connect(&addr).await.unwrap(); - - // Send off the request by first negotiating an SSL handshake, then writing - // of our request, then flushing, then finally read off the response. - let builder = TlsConnector::builder(); - let connector = t!(builder.build()); - let connector = tokio_native_tls::TlsConnector::from(connector); - let mut socket = t!(connector.connect("google.com", socket).await); - t!(socket.write_all(b"GET / HTTP/1.0\r\n\r\n").await); - let mut data = Vec::new(); - t!(socket.read_to_end(&mut data).await); - - // any response code is fine - assert!(data.starts_with(b"HTTP/1.0 ")); - - let data = String::from_utf8_lossy(&data); - let data = data.trim_end(); - assert!(data.ends_with("") || data.ends_with("")); -} - -fn native2io(e: native_tls::Error) -> io::Error { - io::Error::new(io::ErrorKind::Other, e) -} - -// see comment in bad.rs for ignore reason -#[cfg_attr(all(target_os = "macos", feature = "force-openssl"), ignore)] -#[tokio::test] -async fn wrong_hostname_error() { - drop(env_logger::try_init()); - - let addr = t!("google.com:443".to_socket_addrs()).next().unwrap(); - - let socket = t!(TcpStream::connect(&addr).await); - let builder = TlsConnector::builder(); - let connector = t!(builder.build()); - let connector = tokio_native_tls::TlsConnector::from(connector); - let res = connector - .connect("rust-lang.org", socket) - .await - .map_err(native2io); - - assert!(res.is_err()); - assert_bad_hostname_error(&res.err().unwrap()); -} diff --git a/tokio-native-tls/tests/identity.p12 b/tokio-native-tls/tests/identity.p12 deleted file mode 100644 index d16abb8..0000000 Binary files a/tokio-native-tls/tests/identity.p12 and /dev/null differ diff --git a/tokio-native-tls/tests/root-ca.der b/tokio-native-tls/tests/root-ca.der deleted file mode 100644 index a9335c6..0000000 Binary files a/tokio-native-tls/tests/root-ca.der and /dev/null differ diff --git a/tokio-native-tls/tests/smoke.rs b/tokio-native-tls/tests/smoke.rs deleted file mode 100644 index 994fdde..0000000 --- a/tokio-native-tls/tests/smoke.rs +++ /dev/null @@ -1,172 +0,0 @@ -use futures::join; -use lazy_static::lazy_static; -use native_tls::{Certificate, Identity}; -use std::{fs, io::Error, path::PathBuf, process::Command}; -use tokio::{ - io::{AsyncReadExt, AsyncWrite, AsyncWriteExt}, - net::{TcpListener, TcpStream}, -}; -use tokio_native_tls::{TlsAcceptor, TlsConnector}; - -lazy_static! { - static ref CERT_DIR: PathBuf = { - if cfg!(unix) { - let dir = tempfile::TempDir::new().unwrap(); - let path = dir.path().to_str().unwrap(); - - Command::new("sh") - .arg("-c") - .arg(format!("./scripts/generate-certificate.sh {}", path)) - .output() - .expect("failed to execute process"); - - dir.into_path() - } else { - PathBuf::from("tests") - } - }; -} - -#[tokio::test] -async fn client_to_server() { - let srv = TcpListener::bind("127.0.0.1:0").await.unwrap(); - let addr = srv.local_addr().unwrap(); - - let (server_tls, client_tls) = context(); - - // Create a future to accept one socket, connect the ssl stream, and then - // read all the data from it. - let server = async move { - let (socket, _) = srv.accept().await.unwrap(); - let mut socket = server_tls.accept(socket).await.unwrap(); - - // Verify access to all of the nested inner streams (e.g. so that peer - // certificates can be accessed). This is just a compile check. - let native_tls_stream: &native_tls::TlsStream<_> = socket.get_ref(); - let _peer_cert = native_tls_stream.peer_certificate().unwrap(); - let allow_std_stream: &tokio_native_tls::AllowStd<_> = native_tls_stream.get_ref(); - let _tokio_tcp_stream: &tokio::net::TcpStream = allow_std_stream.get_ref(); - - let mut data = Vec::new(); - socket.read_to_end(&mut data).await.unwrap(); - data - }; - - // Create a future to connect to our server, connect the ssl stream, and - // then write a bunch of data to it. - let client = async move { - let socket = TcpStream::connect(&addr).await.unwrap(); - let socket = client_tls.connect("foobar.com", socket).await.unwrap(); - copy_data(socket).await - }; - - // Finally, run everything! - let (data, _) = join!(server, client); - // assert_eq!(amt, AMT); - assert!(data == vec![9; AMT]); -} - -#[tokio::test] -async fn server_to_client() { - // Create a server listening on a port, then figure out what that port is - let srv = TcpListener::bind("127.0.0.1:0").await.unwrap(); - let addr = srv.local_addr().unwrap(); - - let (server_tls, client_tls) = context(); - - let server = async move { - let (socket, _) = srv.accept().await.unwrap(); - let socket = server_tls.accept(socket).await.unwrap(); - copy_data(socket).await - }; - - let client = async move { - let socket = TcpStream::connect(&addr).await.unwrap(); - let mut socket = client_tls.connect("foobar.com", socket).await.unwrap(); - let mut data = Vec::new(); - socket.read_to_end(&mut data).await.unwrap(); - data - }; - - // Finally, run everything! - let (_, data) = join!(server, client); - assert!(data == vec![9; AMT]); -} - -#[tokio::test] -async fn one_byte_at_a_time() { - const AMT: usize = 1024; - - let srv = TcpListener::bind("127.0.0.1:0").await.unwrap(); - let addr = srv.local_addr().unwrap(); - - let (server_tls, client_tls) = context(); - - let server = async move { - let (socket, _) = srv.accept().await.unwrap(); - let mut socket = server_tls.accept(socket).await.unwrap(); - let mut amt = 0; - for b in std::iter::repeat(9).take(AMT) { - let data = [b as u8]; - socket.write_all(&data).await.unwrap(); - amt += 1; - } - amt - }; - - let client = async move { - let socket = TcpStream::connect(&addr).await.unwrap(); - let mut socket = client_tls.connect("foobar.com", socket).await.unwrap(); - let mut data = Vec::new(); - loop { - let mut buf = [0; 1]; - match socket.read_exact(&mut buf).await { - Ok(_) => data.extend_from_slice(&buf), - Err(ref err) if err.kind() == std::io::ErrorKind::UnexpectedEof => break, - Err(err) => panic!("{}", err), - } - } - data - }; - - let (amt, data) = join!(server, client); - assert_eq!(amt, AMT); - assert!(data == vec![9; AMT as usize]); -} - -fn context() -> (TlsAcceptor, TlsConnector) { - let pkcs12 = fs::read(CERT_DIR.join("identity.p12")).unwrap(); - let der = fs::read(CERT_DIR.join("root-ca.der")).unwrap(); - - let identity = Identity::from_pkcs12(&pkcs12, "mypass").unwrap(); - let acceptor = native_tls::TlsAcceptor::builder(identity).build().unwrap(); - - let cert = Certificate::from_der(&der).unwrap(); - let connector = native_tls::TlsConnector::builder() - .add_root_certificate(cert) - .build() - .unwrap(); - - (acceptor.into(), connector.into()) -} - -const AMT: usize = 128 * 1024; - -async fn copy_data(mut w: W) -> Result { - let mut data = vec![9; AMT as usize]; - let mut amt = 0; - while !data.is_empty() { - let written = w.write(&data).await?; - if written <= data.len() { - amt += written; - data.resize(data.len() - written, 0); - } else { - w.write_all(&data).await?; - amt += data.len(); - break; - } - - println!("remaining: {}", data.len()); - } - Ok(amt) -}