diff --git a/.travis.yml b/.travis.yml index 51650c8..65f600e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,6 @@ language: rust cache: cargo rust: - nightly -- 1.11.0 +- 1.21.0 script: - cargo test diff --git a/Cargo.toml b/Cargo.toml index 4695661..3d9d14e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,19 +1,14 @@ [package] name = "hyper-native-tls" -version = "0.2.0" +version = "0.3.0" authors = ["Steven Fackler "] exclude = ["test/*"] license = "MIT/Apache-2.0" description = "native-tls support for Hyper" repository = "https://github.com/sfackler/hyper-native-tls" -documentation = "https://docs.rs/hyper-native-tls/0.2.0/hyper_native_tls" readme = "README.md" [dependencies] antidote = "1.0" -native-tls = "0.1" +native-tls = "0.2" hyper = "0.10" - -[dev-dependencies] -openssl = "0.9" -hyper-openssl = "0.2" diff --git a/README.md b/README.md index 75c4837..9f8f088 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,14 @@ -# hyper-native-tls +# `hyper-native-tls` [![Build Status](https://travis-ci.org/sfackler/hyper-native-tls.svg?branch=master)](https://travis-ci.org/sfackler/hyper-native-tls) [Documentation](https://docs.rs/hyper-native-tls) -native-tls support for Hyper. +`native-tls` support for Hyper 0.10. + +## Warning + +This crate does not support the Tokio-based Hyper 0.11 release. Use the `tokio-tls` crate instead. ## License diff --git a/src/lib.rs b/src/lib.rs index 51af588..ea4ea91 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,32 +40,39 @@ //! } //! ``` #![warn(missing_docs)] -#![doc(html_root_url="https://docs.rs/hyper-native-tls/0.2.0")] +#![doc(html_root_url="https://docs.rs/hyper-native-tls/0.3")] extern crate antidote; extern crate hyper; -extern crate native_tls; - -#[cfg(test)] -extern crate hyper_openssl; -#[cfg(test)] -extern crate openssl; +pub extern crate native_tls; use antidote::Mutex; use hyper::net::{SslClient, SslServer, NetworkStream}; -use native_tls::{TlsAcceptor, TlsConnector, Pkcs12}; +use native_tls::{TlsAcceptor, TlsConnector, Identity}; use std::net::SocketAddr; use std::time::Duration; use std::error::Error; use std::io::{self, Read}; use std::fs::File; +use std::ops::{Deref, DerefMut}; use std::sync::Arc; use std::fmt; use std::path::Path; +pub use native_tls::Certificate; + /// A Hyper stream using native_tls. -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct TlsStream(Arc>>); +impl TlsStream + where S: io::Read + io::Write +{ + /// Returns a guard around a locked TLS stream. + pub fn lock(&self) -> StreamGuard { + StreamGuard(self.0.lock()) + } +} + impl io::Read for TlsStream where S: io::Read + io::Write { @@ -102,19 +109,48 @@ impl NetworkStream for TlsStream } } +/// A guard around a locked inner `TlsStream`. +pub struct StreamGuard<'a, T: io::Read + io::Write + 'a>(antidote::MutexGuard<'a, native_tls::TlsStream>); + +impl<'a, T> Deref for StreamGuard<'a, T> + where T: io::Read + io::Write + 'a +{ + type Target = native_tls::TlsStream; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'a, T> DerefMut for StreamGuard<'a, T> + where T: io::Read + io::Write + 'a +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + /// An `SslClient` implementation using native-tls. -pub struct NativeTlsClient(TlsConnector); +pub struct NativeTlsClient { + connector: TlsConnector, +} impl NativeTlsClient { /// Returns a `NativeTlsClient` with a default configuration. + /// + /// To customize the configuration, build a `TlsConnector` and then use + /// `NativeTlsClient`'s `From` implementation. pub fn new() -> native_tls::Result { - TlsConnector::builder().and_then(|b| b.build()).map(NativeTlsClient) + TlsConnector::builder().build() + .map(NativeTlsClient::from) } } impl From for NativeTlsClient { fn from(t: TlsConnector) -> NativeTlsClient { - NativeTlsClient(t) + NativeTlsClient { + connector: t, + } } } @@ -124,7 +160,8 @@ impl SslClient for NativeTlsClient type Stream = TlsStream; fn wrap_client(&self, stream: T, host: &str) -> hyper::Result> { - match self.0.connect(host, stream) { + let stream = self.connector.connect(host, stream); + match stream { Ok(s) => Ok(TlsStream(Arc::new(Mutex::new(s)))), Err(e) => Err(hyper::Error::Ssl(Box::new(e))), } @@ -137,18 +174,21 @@ pub struct NativeTlsServer(Arc); impl NativeTlsServer { /// Returns a `NativeTlsServer` with a default configuration. + /// + /// To customize the configuration, build a `TlsAcceptor` and then use + /// `NativeTlsServer`'s `From` implementation. pub fn new

(identity: P, password: &str) -> Result where P: AsRef { let mut buf = vec![]; try!(File::open(identity) - .and_then(|mut f| f.read_to_end(&mut buf)) - .map_err(ServerError::Io)); - let identity = try!(Pkcs12::from_der(&buf, password).map_err(ServerError::Tls)); + .and_then(|mut f| f.read_to_end(&mut buf)) + .map_err(ServerError::Io)); + let identity = try!(Identity::from_pkcs12(&buf, password).map_err(ServerError::Tls)); let acceptor = try!(TlsAcceptor::builder(identity) - .and_then(|b| b.build()) - .map_err(ServerError::Tls)); + .build() + .map_err(ServerError::Tls)); Ok(acceptor.into()) } } @@ -212,8 +252,7 @@ mod test { use hyper::{Client, Server}; use hyper::server::{Request, Response, Fresh}; use hyper::net::HttpsConnector; - use hyper_openssl::OpensslClient; - use openssl::ssl::{SslMethod, SslConnectorBuilder}; + use std::fs::File; use std::io::Read; use std::mem; @@ -236,19 +275,32 @@ mod test { let ssl = NativeTlsServer::new("test/identity.p12", "mypass").unwrap(); let server = Server::https("127.0.0.1:0", ssl).unwrap(); - let listening = server.handle(|_: Request, resp: Response| { - resp.send(b"hello").unwrap() - }).unwrap(); + let listening = server + .handle(|_: Request, resp: Response| resp.send(b"hello").unwrap()) + .unwrap(); let port = listening.socket.port(); mem::forget(listening); - let mut ssl = SslConnectorBuilder::new(SslMethod::tls()).unwrap(); - ssl.builder_mut().set_ca_file("test/root-ca.pem").unwrap(); - let ssl = OpensslClient::from(ssl.build()); - let connector = HttpsConnector::new(ssl); + + let mut buf = Vec::new(); + let _ = File::open("test/root-ca.der") + .unwrap() + .read_to_end(&mut buf) + .unwrap(); + let cert = Certificate::from_der(&buf).unwrap(); + + let mut tls_connector_builder = TlsConnector::builder(); + tls_connector_builder.add_root_certificate(cert); + let tls_connector = tls_connector_builder.build().unwrap(); + + let native_tls_client = NativeTlsClient::from(tls_connector); + let connector = HttpsConnector::new(native_tls_client); let client = Client::with_connector(connector); - let mut resp = client.get(&format!("https://localhost:{}", port)).send().unwrap(); + let mut resp = client + .get(&format!("https://localhost:{}", port)) + .send() + .unwrap(); let mut body = vec![]; resp.read_to_end(&mut body).unwrap(); assert_eq!(body, b"hello"); diff --git a/test/root-ca.der b/test/root-ca.der new file mode 100644 index 0000000..79d1a68 Binary files /dev/null and b/test/root-ca.der differ