-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor SSL support into two modules
Pull as much of the implementation specific code for OpenSSL and Rustls into their own modules, then re-export either of them as `SslContextImpl` and `SslStream`, where there is an implicit trait contract between the two implementations.
- Loading branch information
Showing
8 changed files
with
352 additions
and
189 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,4 +39,4 @@ fn main() { | |
.respond(response) | ||
.unwrap_or(println!("Failed to respond to request")); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
//! Modules providing SSL/TLS implementations. For backwards compatibility, OpenSSL is the default | ||
//! implementation, but Rustls is highly recommended as a pure Rust alternative. | ||
//! | ||
//! In order to simplify the swappable implementations these SSL/TLS modules adhere to an implicit | ||
//! trait contract and specific implementations are re-exported as [`SslContextImpl`] and [`SslStream`]. | ||
//! The concrete type of these aliases will depend on which module you enable in `Cargo.toml`. | ||
|
||
#[cfg(feature = "ssl-openssl")] | ||
pub(crate) mod openssl; | ||
#[cfg(feature = "ssl-openssl")] | ||
pub(crate) use self::openssl::OpenSslContext as SslContextImpl; | ||
#[cfg(feature = "ssl-openssl")] | ||
pub(crate) use self::openssl::SplitOpenSslStream as SslStream; | ||
|
||
#[cfg(feature = "ssl-rustls")] | ||
pub(crate) mod rustls; | ||
#[cfg(feature = "ssl-rustls")] | ||
pub(crate) use self::rustls::RustlsContext as SslContextImpl; | ||
#[cfg(feature = "ssl-rustls")] | ||
pub(crate) use self::rustls::RustlsStream as SslStream; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
use crate::util::refined_tcp_stream::Stream as RefinedStream; | ||
use std::error::Error; | ||
use std::io::{Read, Write}; | ||
use std::net::{Shutdown, SocketAddr, TcpStream}; | ||
use std::sync::{Arc, Mutex}; | ||
use zeroize::Zeroizing; | ||
|
||
pub(crate) struct OpenSslStream { | ||
inner: openssl::ssl::SslStream<TcpStream>, | ||
} | ||
|
||
/// An OpenSSL stream which has been split into two mutually exclusive streams (e.g. for read / write) | ||
pub(crate) struct SplitOpenSslStream(Arc<Mutex<OpenSslStream>>); | ||
|
||
// These struct methods form the implict contract for swappable TLS implementations | ||
impl SplitOpenSslStream { | ||
pub(crate) fn peer_addr(&mut self) -> std::io::Result<SocketAddr> { | ||
self.0.lock().unwrap().inner.get_mut().peer_addr() | ||
} | ||
|
||
pub(crate) fn shutdown(&mut self, how: Shutdown) -> std::io::Result<()> { | ||
self.0.lock().unwrap().inner.get_mut().shutdown(how) | ||
} | ||
} | ||
|
||
impl Clone for SplitOpenSslStream { | ||
fn clone(&self) -> Self { | ||
Self(self.0.clone()) | ||
} | ||
} | ||
|
||
impl Read for SplitOpenSslStream { | ||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { | ||
self.0.lock().unwrap().read(buf) | ||
} | ||
} | ||
|
||
impl Write for SplitOpenSslStream { | ||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { | ||
self.0.lock().unwrap().write(buf) | ||
} | ||
|
||
fn flush(&mut self) -> std::io::Result<()> { | ||
self.0.lock().unwrap().flush() | ||
} | ||
} | ||
|
||
impl Read for OpenSslStream { | ||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { | ||
self.inner.read(buf) | ||
} | ||
} | ||
|
||
impl Write for OpenSslStream { | ||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { | ||
self.inner.write(buf) | ||
} | ||
|
||
fn flush(&mut self) -> std::io::Result<()> { | ||
self.inner.flush() | ||
} | ||
} | ||
|
||
pub(crate) struct OpenSslContext(openssl::ssl::SslContext); | ||
|
||
impl OpenSslContext { | ||
pub fn from_pem( | ||
certificates: Vec<u8>, | ||
private_key: Zeroizing<Vec<u8>>, | ||
) -> Result<Self, Box<dyn Error + Send + Sync>> { | ||
use openssl::pkey::PKey; | ||
use openssl::ssl::{self, SslVerifyMode}; | ||
use openssl::x509::X509; | ||
|
||
let mut ctx = openssl::ssl::SslContext::builder(ssl::SslMethod::tls())?; | ||
ctx.set_cipher_list("DEFAULT")?; | ||
let cert = X509::from_pem(&certificates)?; | ||
ctx.set_certificate(&cert)?; | ||
let key = PKey::private_key_from_pem(&private_key)?; | ||
ctx.set_private_key(&key)?; | ||
ctx.set_verify(SslVerifyMode::NONE); | ||
ctx.check_private_key()?; | ||
|
||
Ok(Self(ctx.build())) | ||
} | ||
|
||
pub fn accept( | ||
&self, | ||
stream: TcpStream, | ||
) -> Result<OpenSslStream, Box<dyn Error + Send + Sync + 'static>> { | ||
use openssl::ssl::Ssl; | ||
let session = Ssl::new(&self.0).expect("Failed to create new OpenSSL session"); | ||
let stream = session.accept(stream)?; | ||
Ok(OpenSslStream { inner: stream }) | ||
} | ||
} | ||
|
||
impl From<OpenSslStream> for RefinedStream { | ||
fn from(stream: OpenSslStream) -> Self { | ||
RefinedStream::Https(SplitOpenSslStream(Arc::new(Mutex::new(stream)))) | ||
} | ||
} |
Oops, something went wrong.