From 4c7a5a418ee6a71f26fb6cc720a36b5bca6f3376 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 29 Oct 2016 14:02:26 -0700 Subject: Implement client and server connectors --- openssl/src/ssl/mod.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'openssl/src/ssl/mod.rs') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index cc9069dc..19b21d9d 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -22,19 +22,22 @@ use ffi; use {init, cvt, cvt_p}; use dh::Dh; use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError}; -#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] -use x509::verify::X509VerifyParamRef; +#[cfg(any(ossl102, ossl110))] +use verify::X509VerifyParamRef; use pkey::PKey; use error::ErrorStack; use opaque::Opaque; pub mod error; +mod connector; mod bio; #[cfg(test)] mod tests; use self::bio::BioMethod; +pub use ssl::connector::{ClientConnectorBuilder, ClientConnector, ServerConnectorBuilder, + ServerConnector}; #[doc(inline)] pub use ssl::error::Error; @@ -1030,6 +1033,11 @@ impl SslRef { /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or 1.1.0. #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] pub fn param_mut(&mut self) -> &mut X509VerifyParamRef { + self._param_mut() + } + + #[cfg(any(ossl102, ossl110))] + fn _param_mut(&mut self) -> &mut X509VerifyParamRef { unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) } @@ -1153,6 +1161,8 @@ impl Ssl { /// An error or intermediate state after a TLS handshake attempt. #[derive(Debug)] pub enum HandshakeError { + /// Setup failed. + SetupFailure(ErrorStack), /// The handshake failed. Failure(MidHandshakeSslStream), /// The handshake was interrupted midway through. @@ -1162,6 +1172,7 @@ pub enum HandshakeError { impl stderror::Error for HandshakeError { fn description(&self) -> &str { match *self { + HandshakeError::SetupFailure(_) => "stream setup failed", HandshakeError::Failure(_) => "the handshake failed", HandshakeError::Interrupted(_) => "the handshake was interrupted", } @@ -1169,6 +1180,7 @@ impl stderror::Error for HandshakeError { fn cause(&self) -> Option<&stderror::Error> { match *self { + HandshakeError::SetupFailure(ref e) => Some(e), HandshakeError::Failure(ref s) | HandshakeError::Interrupted(ref s) => Some(s.error()), } } @@ -1178,6 +1190,7 @@ impl fmt::Display for HandshakeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(f.write_str(stderror::Error::description(self))); match *self { + HandshakeError::SetupFailure(ref e) => try!(write!(f, ": {}", e)), HandshakeError::Failure(ref s) | HandshakeError::Interrupted(ref s) => { try!(write!(f, ": {}", s.error())); if let Some(err) = s.ssl().verify_result() { @@ -1189,6 +1202,12 @@ impl fmt::Display for HandshakeError { } } +impl From for HandshakeError { + fn from(e: ErrorStack) -> HandshakeError { + HandshakeError::SetupFailure(e) + } +} + /// An SSL stream midway through the handshake process. #[derive(Debug)] pub struct MidHandshakeSslStream { -- cgit v1.2.3 From 57d10ebbc3c04d5089b034b9d88f40c302783c96 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 29 Oct 2016 14:19:09 -0700 Subject: Add PKeyRef --- openssl/src/ssl/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'openssl/src/ssl/mod.rs') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 19b21d9d..9e39d8bf 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -24,7 +24,7 @@ use dh::Dh; use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError}; #[cfg(any(ossl102, ossl110))] use verify::X509VerifyParamRef; -use pkey::PKey; +use pkey::PKeyRef; use error::ErrorStack; use opaque::Opaque; @@ -532,7 +532,7 @@ impl SslContextBuilder { } /// Specifies the private key - pub fn set_private_key(&mut self, key: &PKey) -> Result<(), ErrorStack> { + pub fn set_private_key(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr())).map(|_| ()) } -- cgit v1.2.3 From e72533c058967f56b302e40c63175cb1b078d052 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 29 Oct 2016 15:00:46 -0700 Subject: Docs for connectors --- openssl/src/ssl/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'openssl/src/ssl/mod.rs') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 9e39d8bf..ddf27460 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -342,6 +342,7 @@ pub enum SniError { NoAck, } +/// A builder for `SslContext`s. pub struct SslContextBuilder(*mut ffi::SSL_CTX); impl Drop for SslContextBuilder { @@ -793,6 +794,7 @@ impl SslCipherRef { } } +/// A reference to an `Ssl`. pub struct SslRef(Opaque); unsafe impl Send for SslRef {} @@ -1104,6 +1106,11 @@ impl Ssl { } /// Creates an SSL/TLS client operating over the provided stream. + /// + /// # Warning + /// + /// OpenSSL's default configuration is insecure. It is highly recommended to use + /// `ClientConnector` rather than `Ssl` directly, as it manages that configuration. pub fn connect(self, stream: S) -> Result, HandshakeError> where S: Read + Write { @@ -1131,6 +1138,11 @@ impl Ssl { } /// Creates an SSL/TLS server operating over the provided stream. + /// + /// # Warning + /// + /// OpenSSL's default configuration is insecure. It is highly recommended to use + /// `ServerConnector` rather than `Ssl` directly, as it manages that configuration. pub fn accept(self, stream: S) -> Result, HandshakeError> where S: Read + Write { -- cgit v1.2.3 From 761dd780c179d667c1b0ee6dd0a6e8e05c24ca46 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 29 Oct 2016 17:25:01 -0700 Subject: Add module level docs --- openssl/src/ssl/mod.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) (limited to 'openssl/src/ssl/mod.rs') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index ddf27460..ae7abea9 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1,3 +1,72 @@ +//! SSL/TLS support. +//! +//! The `ClientConnector` and `ServerConnector` should be used in most cases - they handle +//! configuration of the OpenSSL primitives for you. +//! +//! # Examples +//! +//! To connect as a client to a remote server: +//! +//! ```no_run +//! use openssl::ssl::ClientConnectorBuilder; +//! use std::io::{Read, Write}; +//! use std::net::TcpStream; +//! +//! let connector = ClientConnectorBuilder::tls().unwrap().build(); +//! +//! let stream = TcpStream::connect("google.com:443").unwrap(); +//! let mut stream = connector.connect("google.com", stream).unwrap(); +//! +//! stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); +//! let mut res = vec![]; +//! stream.read_to_end(&mut res).unwrap(); +//! println!("{}", String::from_utf8_lossy(&res)); +//! ``` +//! +//! To accept connections as a server from remote clients: +//! +//! ```no_run +//! use openssl::pkcs12::Pkcs12; +//! use openssl::ssl::{ServerConnectorBuilder, SslStream}; +//! use std::fs::File; +//! use std::io::{Read, Write}; +//! use std::net::{TcpListener, TcpStream}; +//! use std::sync::Arc; +//! use std::thread; +//! +//! // In this example we retrieve our keypair and certificate chain from a PKCS #12 archive, +//! // but but they can also be retrieved from, for example, individual PEM- or DER-formatted +//! // files. See the documentation for the `PKey` and `X509` types for more details. +//! let mut file = File::open("identity.pfx").unwrap(); +//! let mut pkcs12 = vec![]; +//! file.read_to_end(&mut pkcs12).unwrap(); +//! let pkcs12 = Pkcs12::from_der(&pkcs12).unwrap(); +//! let identity = pkcs12.parse("password123").unwrap(); +//! +//! let connector = ServerConnectorBuilder::tls(&identity.pkey, &identity.cert, &identity.chain) +//! .unwrap() +//! .build(); +//! let connector = Arc::new(connector); +//! +//! let listener = TcpListener::bind("0.0.0.0:8443").unwrap(); +//! +//! fn handle_client(stream: SslStream) { +//! // ... +//! } +//! +//! for stream in listener.incoming() { +//! match stream { +//! Ok(stream) => { +//! let connector = connector.clone(); +//! thread::spawn(move || { +//! let stream = connector.connect(stream).unwrap(); +//! handle_client(stream); +//! }); +//! } +//! Err(e) => { /* connection failed */ } +//! } +//! } +//! ``` use libc::{c_int, c_void, c_long, c_ulong}; use std::any::Any; use std::any::TypeId; -- cgit v1.2.3 From 23fe1e85e96a1148da1b9bfee570880770eca3cb Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 29 Oct 2016 18:16:45 -0700 Subject: Pull Curl's CA list for Windows tests --- openssl/src/ssl/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openssl/src/ssl/mod.rs') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index ae7abea9..cd7c1426 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -7,7 +7,7 @@ //! //! To connect as a client to a remote server: //! -//! ```no_run +//! ``` //! use openssl::ssl::ClientConnectorBuilder; //! use std::io::{Read, Write}; //! use std::net::TcpStream; -- cgit v1.2.3