Merge pull request #800 from sfackler/connector-construction
Adjust SslConnector and SslAcceptor construction
This commit is contained in:
commit
be04bc4064
|
|
@ -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<ErrorStack> for fmt::Error {
|
|||
pub struct Error {
|
||||
code: c_ulong,
|
||||
file: *const c_char,
|
||||
line: c_int,
|
||||
line: u32,
|
||||
data: Option<Cow<'static, str>>,
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<SslContextBuilder, ErrorStack> {
|
|||
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<SslConnectorBuilder, ErrorStack> {
|
||||
pub fn builder(method: SslMethod) -> Result<SslConnectorBuilder, ErrorStack> {
|
||||
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<I>(
|
||||
method: SslMethod,
|
||||
private_key: &PKeyRef,
|
||||
certificate: &X509Ref,
|
||||
chain: I,
|
||||
) -> Result<SslAcceptorBuilder, ErrorStack>
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: AsRef<X509Ref>,
|
||||
{
|
||||
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<I>(
|
||||
method: SslMethod,
|
||||
private_key: &PKeyRef,
|
||||
certificate: &X509Ref,
|
||||
chain: I,
|
||||
) -> Result<SslAcceptorBuilder, ErrorStack>
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: AsRef<X509Ref>,
|
||||
{
|
||||
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<SslAcceptorBuilder, ErrorStack> {
|
||||
pub fn mozilla_intermediate(method: SslMethod) -> Result<SslAcceptorBuilder, ErrorStack> {
|
||||
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<SslAcceptorBuilder, ErrorStack> {
|
||||
/// 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<SslAcceptorBuilder, ErrorStack> {
|
||||
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<I>(
|
||||
mut self,
|
||||
private_key: &PKeyRef,
|
||||
certificate: &X509Ref,
|
||||
chain: I,
|
||||
) -> Result<SslAcceptorBuilder, ErrorStack>
|
||||
/// Initiates a server-side TLS session on a stream.
|
||||
pub fn accept<S>(&self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: AsRef<X509Ref>,
|
||||
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<S>(&self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
//!
|
||||
|
|
|
|||
|
|
@ -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::<X509>)
|
||||
.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::<X509>)
|
||||
.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();
|
||||
|
|
|
|||
Loading…
Reference in New Issue