From 19dc6ce1eb09e8796bb70eeed16bb29043d1ed33 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 26 Dec 2017 10:39:21 -0700 Subject: [PATCH] Adjust SslConnector and SslAcceptor construction --- openssl/src/error.rs | 14 +-- openssl/src/ssl/connector.rs | 171 ++++++++++++----------------------- openssl/src/ssl/mod.rs | 28 ++---- openssl/src/ssl/tests/mod.rs | 42 ++++----- 4 files changed, 97 insertions(+), 158 deletions(-) diff --git a/openssl/src/error.rs b/openssl/src/error.rs index 5f3e21709..30558912b 100644 --- a/openssl/src/error.rs +++ b/openssl/src/error.rs @@ -15,7 +15,7 @@ //! Err(e) => println!("Parsing Error: {:?}", e), //! } //! ``` -use libc::{c_ulong, c_char, c_int}; +use libc::{c_char, c_ulong}; use std::fmt; use std::error; use std::ffi::CStr; @@ -87,7 +87,7 @@ impl From for fmt::Error { pub struct Error { code: c_ulong, file: *const c_char, - line: c_int, + line: u32, data: Option>, } @@ -122,10 +122,10 @@ impl Error { None }; Some(Error { - code: code, - file: file, - line: line, - data: data, + code, + file, + line: line as u32, + data, }) } } @@ -183,7 +183,7 @@ impl Error { } /// Returns the line in the source file which encountered the error. - pub fn line(&self) -> c_int { + pub fn line(&self) -> u32 { self.line } diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 215d03582..6b2d98647 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -5,9 +5,7 @@ use dh::Dh; use error::ErrorStack; use ssl::{HandshakeError, Ssl, SslContext, SslContextBuilder, SslMethod, SslMode, SslOptions, SslRef, SslStream, SslVerifyMode}; -use pkey::PKeyRef; use version; -use x509::X509Ref; #[cfg(ossl101)] lazy_static! { @@ -51,14 +49,21 @@ fn ctx(method: SslMethod) -> Result { Ok(ctx) } -/// A builder for `SslConnector`s. -pub struct SslConnectorBuilder(SslContextBuilder); +/// A type which wraps client-side streams in a TLS session. +/// +/// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL +/// structures, configuring cipher suites, session options, hostname verification, and more. +/// +/// OpenSSL's built in hostname verification is used when linking against OpenSSL 1.0.2 or 1.1.0, +/// and a custom implementation is used when linking against OpenSSL 1.0.1. +#[derive(Clone)] +pub struct SslConnector(SslContext); -impl SslConnectorBuilder { +impl SslConnector { /// Creates a new builder for TLS connections. /// /// The default configuration is subject to change, and is currently derived from Python. - pub fn new(method: SslMethod) -> Result { + pub fn builder(method: SslMethod) -> Result { let mut ctx = ctx(method)?; ctx.set_default_verify_paths()?; // From https://github.com/python/cpython/blob/a170fa162dc03f0a014373349e548954fff2e567/Lib/ssl.py#L193 @@ -72,37 +77,6 @@ impl SslConnectorBuilder { Ok(SslConnectorBuilder(ctx)) } - /// Consumes the builder, returning an `SslConnector`. - pub fn build(self) -> SslConnector { - SslConnector(self.0.build()) - } -} - -impl Deref for SslConnectorBuilder { - type Target = SslContextBuilder; - - fn deref(&self) -> &SslContextBuilder { - &self.0 - } -} - -impl DerefMut for SslConnectorBuilder { - fn deref_mut(&mut self) -> &mut SslContextBuilder { - &mut self.0 - } -} - -/// A type which wraps client-side streams in a TLS session. -/// -/// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL -/// structures, configuring cipher suites, session options, hostname verification, and more. -/// -/// OpenSSL's built in hostname verification is used when linking against OpenSSL 1.0.2 or 1.1.0, -/// and a custom implementation is used when linking against OpenSSL 1.0.1. -#[derive(Clone)] -pub struct SslConnector(SslContext); - -impl SslConnector { /// Initiates a client-side TLS session on a stream. /// /// The domain is used for SNI and hostname verification. @@ -123,6 +97,30 @@ impl SslConnector { } } +/// A builder for `SslConnector`s. +pub struct SslConnectorBuilder(SslContextBuilder); + +impl SslConnectorBuilder { + /// Consumes the builder, returning an `SslConnector`. + pub fn build(self) -> SslConnector { + SslConnector(self.0.build()) + } +} + +impl Deref for SslConnectorBuilder { + type Target = SslContextBuilder; + + fn deref(&self) -> &SslContextBuilder { + &self.0 + } +} + +impl DerefMut for SslConnectorBuilder { + fn deref_mut(&mut self) -> &mut SslContextBuilder { + &mut self.0 + } +} + /// A type which allows for configuration of a client-side TLS session before connection. pub struct ConnectConfiguration { ssl: Ssl, @@ -186,10 +184,14 @@ impl DerefMut for ConnectConfiguration { } } -/// A builder for `SslAcceptor`s. -pub struct SslAcceptorBuilder(SslContextBuilder); +/// A type which wraps server-side streams in a TLS session. +/// +/// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL +/// structures, configuring cipher suites, session options, and more. +#[derive(Clone)] +pub struct SslAcceptor(SslContext); -impl SslAcceptorBuilder { +impl SslAcceptor { /// Creates a new builder configured to connect to non-legacy clients. This should generally be /// considered a reasonable default choice. /// @@ -197,42 +199,7 @@ impl SslAcceptorBuilder { /// recommendations. See its [documentation][docs] for more details on specifics. /// /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS - pub fn mozilla_intermediate( - method: SslMethod, - private_key: &PKeyRef, - certificate: &X509Ref, - chain: I, - ) -> Result - where - I: IntoIterator, - I::Item: AsRef, - { - let builder = SslAcceptorBuilder::mozilla_intermediate_raw(method)?; - builder.finish_setup(private_key, certificate, chain) - } - - /// Creates a new builder configured to connect to modern clients. - /// - /// This corresponds to the modern configuration of Mozilla's server side TLS recommendations. - /// See its [documentation][docs] for more details on specifics. - /// - /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS - pub fn mozilla_modern( - method: SslMethod, - private_key: &PKeyRef, - certificate: &X509Ref, - chain: I, - ) -> Result - where - I: IntoIterator, - I::Item: AsRef, - { - let builder = SslAcceptorBuilder::mozilla_modern_raw(method)?; - builder.finish_setup(private_key, certificate, chain) - } - - /// Like `mozilla_intermediate`, but does not load the certificate chain and private key. - pub fn mozilla_intermediate_raw(method: SslMethod) -> Result { + pub fn mozilla_intermediate(method: SslMethod) -> Result { let mut ctx = ctx(method)?; let dh = Dh::from_pem(DHPARAM_PEM.as_bytes())?; ctx.set_tmp_dh(&dh)?; @@ -252,8 +219,13 @@ impl SslAcceptorBuilder { Ok(SslAcceptorBuilder(ctx)) } - /// Like `mozilla_modern`, but does not load the certificate chain and private key. - pub fn mozilla_modern_raw(method: SslMethod) -> Result { + /// Creates a new builder configured to connect to modern clients. + /// + /// This corresponds to the modern configuration of Mozilla's server side TLS recommendations. + /// See its [documentation][docs] for more details on specifics. + /// + /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS + pub fn mozilla_modern(method: SslMethod) -> Result { let mut ctx = ctx(method)?; setup_curves(&mut ctx)?; ctx.set_cipher_list( @@ -265,25 +237,20 @@ impl SslAcceptorBuilder { Ok(SslAcceptorBuilder(ctx)) } - fn finish_setup( - mut self, - private_key: &PKeyRef, - certificate: &X509Ref, - chain: I, - ) -> Result + /// Initiates a server-side TLS session on a stream. + pub fn accept(&self, stream: S) -> Result, HandshakeError> where - I: IntoIterator, - I::Item: AsRef, + S: Read + Write, { - self.0.set_private_key(private_key)?; - self.0.set_certificate(certificate)?; - self.0.check_private_key()?; - for cert in chain { - self.0.add_extra_chain_cert(cert.as_ref().to_owned())?; - } - Ok(self) + let ssl = Ssl::new(&self.0)?; + ssl.accept(stream) } +} + +/// A builder for `SslAcceptor`s. +pub struct SslAcceptorBuilder(SslContextBuilder); +impl SslAcceptorBuilder { /// Consumes the builder, returning a `SslAcceptor`. pub fn build(self) -> SslAcceptor { SslAcceptor(self.0.build()) @@ -323,24 +290,6 @@ fn setup_curves(_: &mut SslContextBuilder) -> Result<(), ErrorStack> { Ok(()) } -/// A type which wraps server-side streams in a TLS session. -/// -/// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL -/// structures, configuring cipher suites, session options, and more. -#[derive(Clone)] -pub struct SslAcceptor(SslContext); - -impl SslAcceptor { - /// Initiates a server-side TLS session on a stream. - pub fn accept(&self, stream: S) -> Result, HandshakeError> - where - S: Read + Write, - { - let ssl = Ssl::new(&self.0)?; - ssl.accept(stream) - } -} - #[cfg(any(ossl102, ossl110))] fn setup_verify(ctx: &mut SslContextBuilder) { ctx.set_verify(SslVerifyMode::PEER); diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 7915748db..0748140de 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -8,11 +8,11 @@ //! To connect as a client to a remote server: //! //! ``` -//! use openssl::ssl::{SslMethod, SslConnectorBuilder}; +//! use openssl::ssl::{SslMethod, SslConnector}; //! use std::io::{Read, Write}; //! use std::net::TcpStream; //! -//! let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); +//! let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); //! //! let stream = TcpStream::connect("google.com:443").unwrap(); //! let mut stream = connector.connect("google.com", stream).unwrap(); @@ -26,30 +26,20 @@ //! To accept connections as a server from remote clients: //! //! ```no_run -//! use openssl::pkcs12::Pkcs12; -//! use openssl::ssl::{SslMethod, SslAcceptorBuilder, SslStream}; +//! use openssl::ssl::{SslMethod, SslAcceptor, SslStream}; +//! use openssl::x509::X509Filetype; //! 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(b"password123").unwrap(); //! -//! let acceptor = SslAcceptorBuilder::mozilla_intermediate(SslMethod::tls(), -//! &identity.pkey, -//! &identity.cert, -//! &identity.chain.unwrap()) -//! .unwrap() -//! .build(); -//! let acceptor = Arc::new(acceptor); +//! let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); +//! acceptor.set_private_key_file("key.pem", X509Filetype::PEM).unwrap(); +//! acceptor.set_certificate_chain_file("certs.pem").unwrap(); +//! acceptor.check_private_key().unwrap(); +//! let acceptor = Arc::new(acceptor.build()); //! //! let listener = TcpListener::bind("0.0.0.0:8443").unwrap(); //! diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index ee4c4a990..a5594254f 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -18,8 +18,8 @@ use dh::Dh; use hash::MessageDigest; use ocsp::{OcspResponse, OcspResponseStatus}; use ssl; -use ssl::{Error, HandshakeError, ShutdownResult, Ssl, SslAcceptorBuilder, SslConnectorBuilder, - SslContext, SslMethod, SslStream, SslVerifyMode, StatusType}; +use ssl::{Error, HandshakeError, ShutdownResult, Ssl, SslAcceptor, SslConnector, SslContext, + SslMethod, SslStream, SslVerifyMode, StatusType}; use x509::{X509, X509Filetype, X509Name, X509StoreContext}; #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] use x509::verify::X509CheckFlags; @@ -1022,7 +1022,7 @@ fn verify_invalid_hostname() { #[test] fn connector_valid_hostname() { - let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); + let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); let s = TcpStream::connect("google.com:443").unwrap(); let mut socket = connector.connect("google.com", s).unwrap(); @@ -1038,7 +1038,7 @@ fn connector_valid_hostname() { #[test] fn connector_invalid_hostname() { - let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); + let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); let s = TcpStream::connect("google.com:443").unwrap(); assert!(connector.connect("foobar.com", s).is_err()); @@ -1046,7 +1046,7 @@ fn connector_invalid_hostname() { #[test] fn connector_invalid_no_hostname_verification() { - let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); + let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); let s = TcpStream::connect("google.com:443").unwrap(); connector @@ -1062,7 +1062,7 @@ fn connector_invalid_no_hostname_verification() { fn connector_no_hostname_still_verifies() { let (_s, tcp) = Server::new(); - let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); + let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); assert!( connector @@ -1078,7 +1078,7 @@ fn connector_no_hostname_still_verifies() { fn connector_no_hostname_can_disable_verify() { let (_s, tcp) = Server::new(); - let mut connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap(); + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); connector.set_verify(SslVerifyMode::NONE); let connector = connector.build(); @@ -1098,17 +1098,17 @@ fn connector_client_server_mozilla_intermediate() { let t = thread::spawn(move || { let key = PKey::private_key_from_pem(KEY).unwrap(); let cert = X509::from_pem(CERT).unwrap(); - let connector = - SslAcceptorBuilder::mozilla_intermediate(SslMethod::tls(), &key, &cert, None::) - .unwrap() - .build(); + let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); + acceptor.set_private_key(&key).unwrap(); + acceptor.set_certificate(&cert).unwrap(); + let acceptor = acceptor.build(); let stream = listener.accept().unwrap().0; - let mut stream = connector.accept(stream).unwrap(); + let mut stream = acceptor.accept(stream).unwrap(); stream.write_all(b"hello").unwrap(); }); - let mut connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap(); + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); connector.set_ca_file("test/root-ca.pem").unwrap(); let connector = connector.build(); @@ -1130,17 +1130,17 @@ fn connector_client_server_mozilla_modern() { let t = thread::spawn(move || { let key = PKey::private_key_from_pem(KEY).unwrap(); let cert = X509::from_pem(CERT).unwrap(); - let connector = - SslAcceptorBuilder::mozilla_modern(SslMethod::tls(), &key, &cert, None::) - .unwrap() - .build(); + let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); + acceptor.set_private_key(&key).unwrap(); + acceptor.set_certificate(&cert).unwrap(); + let acceptor = acceptor.build(); let stream = listener.accept().unwrap().0; - let mut stream = connector.accept(stream).unwrap(); + let mut stream = acceptor.accept(stream).unwrap(); stream.write_all(b"hello").unwrap(); }); - let mut connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap(); + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); connector.set_ca_file("test/root-ca.pem").unwrap(); let connector = connector.build(); @@ -1203,7 +1203,7 @@ fn cert_store() { let cert = X509::from_pem(ROOT_CERT).unwrap(); - let mut ctx = SslConnectorBuilder::new(SslMethod::tls()).unwrap(); + let mut ctx = SslConnector::builder(SslMethod::tls()).unwrap(); ctx.cert_store_mut().add_cert(cert).unwrap(); let ctx = ctx.build(); @@ -1355,7 +1355,7 @@ fn idle_session() { #[test] fn active_session() { - let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); + let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); let s = TcpStream::connect("google.com:443").unwrap(); let socket = connector.connect("google.com", s).unwrap(); -- GitLab