Skip to content

Commit

Permalink
Introduce setup_accept and setup_connect
Browse files Browse the repository at this point in the history
These two new kinds of methods immediately return a MidHandshakeSslStream
instead of actually initiating a handshake. This greatly simplifies
loops around MidHandshakeSslStream::WouldBlock.
  • Loading branch information
nox committed Aug 3, 2023
1 parent 4b16781 commit b27a6e7
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 119 deletions.
70 changes: 64 additions & 6 deletions boring/src/ssl/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use crate::ssl::{
};
use crate::version;

use super::MidHandshakeSslStream;

const FFDHE_2048: &str = "
-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
Expand Down Expand Up @@ -98,11 +100,30 @@ impl SslConnector {
/// Initiates a client-side TLS session on a stream.
///
/// The domain is used for SNI and hostname verification.
pub fn setup_connect<S>(
&self,
domain: &str,
stream: S,
) -> Result<MidHandshakeSslStream<S>, ErrorStack>
where
S: Read + Write,
{
self.configure()?.setup_connect(domain, stream)
}

/// Attempts a client-side TLS session on a stream.
///
/// The domain is used for SNI and hostname verification.
///
/// This is a convenience method which combines [`Self::setup_connect`] and
/// [`MidHandshakeSslStream::handshake`].
pub fn connect<S>(&self, domain: &str, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
where
S: Read + Write,
{
self.configure()?.connect(domain, stream)
self.setup_connect(domain, stream)
.map_err(HandshakeError::SetupFailure)?
.handshake()
}

/// Returns a structure allowing for configuration of a single TLS session before connection.
Expand Down Expand Up @@ -192,7 +213,13 @@ impl ConnectConfiguration {
/// Initiates a client-side TLS session on a stream.
///
/// The domain is used for SNI and hostname verification if enabled.
pub fn connect<S>(mut self, domain: &str, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
///
/// See [`Ssl::setup_connect`] for more details.
pub fn setup_connect<S>(
mut self,
domain: &str,
stream: S,
) -> Result<MidHandshakeSslStream<S>, ErrorStack>
where
S: Read + Write,
{
Expand All @@ -210,7 +237,22 @@ impl ConnectConfiguration {
setup_verify_hostname(&mut self.ssl, domain)?;
}

self.ssl.connect(stream)
Ok(self.ssl.setup_connect(stream))
}

/// Attempts a client-side TLS session on a stream.
///
/// The domain is used for SNI and hostname verification if enabled.
///
/// This is a convenience method which combines [`Self::setup_connect`] and
/// [`MidHandshakeSslStream::handshake`].
pub fn connect<S>(self, domain: &str, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
where
S: Read + Write,
{
self.setup_connect(domain, stream)
.map_err(HandshakeError::SetupFailure)?
.handshake()
}
}

Expand Down Expand Up @@ -319,13 +361,29 @@ impl SslAcceptor {
Ok(SslAcceptorBuilder(ctx))
}

/// Initiates a server-side TLS session on a stream.
pub fn accept<S>(&self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
/// Initiates a server-side TLS handshake on a stream.
///
/// See [`Ssl::setup_accept`] for more details.
pub fn setup_accept<S>(&self, stream: S) -> Result<MidHandshakeSslStream<S>, ErrorStack>
where
S: Read + Write,
{
let ssl = Ssl::new(&self.0)?;
ssl.accept(stream)

Ok(ssl.setup_accept(stream))
}

/// Attempts a server-side TLS handshake on a stream.
///
/// This is a convenience method which combines [`Self::setup_accept`] and
/// [`MidHandshakeSslStream::handshake`].
pub fn accept<S>(&self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
where
S: Read + Write,
{
self.setup_accept(stream)
.map_err(HandshakeError::SetupFailure)?
.handshake()
}

/// Consumes the `SslAcceptor`, returning the inner raw `SslContext`.
Expand Down
146 changes: 98 additions & 48 deletions boring/src/ssl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2306,34 +2306,52 @@ impl Ssl {
}
}

/// Initiates a client-side TLS handshake.
/// Initiates a client-side TLS handshake, returning a [`MidHandshakeSslStream`].
///
/// This corresponds to [`SSL_connect`].
/// This method is guaranteed to return without calling any callback defined
/// in the internal [`Ssl`] or [`SslContext`].
///
/// See [`SslStreamBuilder::setup_connect`] for more details.
///
/// # Warning
///
/// OpenSSL's default configuration is insecure. It is highly recommended to use
/// `SslConnector` rather than `Ssl` directly, as it manages that configuration.
/// BoringSSL's default configuration is insecure. It is highly recommended to use
/// [`SslConnector`] rather than [`Ssl`] directly, as it manages that configuration.
pub fn setup_connect<S>(self, stream: S) -> MidHandshakeSslStream<S>
where
S: Read + Write,
{
SslStreamBuilder::new(self, stream).setup_connect()
}

/// Attempts a client-side TLS handshake.
///
/// This is a convenience method which combines [`Self::setup_connect`] and
/// [`MidHandshakeSslStream::handshake`].
///
/// # Warning
///
/// [`SSL_connect`]: https://www.openssl.org/docs/manmaster/man3/SSL_connect.html
/// OpenSSL's default configuration is insecure. It is highly recommended to use
/// [`SslConnector`] rather than `Ssl` directly, as it manages that configuration.
pub fn connect<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
where
S: Read + Write,
{
SslStreamBuilder::new(self, stream).connect()
self.setup_connect(stream).handshake()
}

/// Initiates a server-side TLS handshake.
///
/// This corresponds to [`SSL_accept`].
/// This method is guaranteed to return without calling any callback defined
/// in the internal [`Ssl`] or [`SslContext`].
///
/// # Warning
/// See [`SslStreamBuilder::setup_accept`] for more details.
///
/// OpenSSL's default configuration is insecure. It is highly recommended to use
/// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration.
/// # Warning
///
/// [`SSL_accept`]: https://www.openssl.org/docs/manmaster/man3/SSL_accept.html
pub fn accept<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
/// BoringSSL's default configuration is insecure. It is highly recommended to use
/// [`SslAcceptor`] rather than [`Ssl`] directly, as it manages that configuration.
pub fn setup_accept<S>(self, stream: S) -> MidHandshakeSslStream<S>
where
S: Read + Write,
{
Expand All @@ -2352,7 +2370,25 @@ impl Ssl {
}
}

SslStreamBuilder::new(self, stream).accept()
SslStreamBuilder::new(self, stream).setup_accept()
}

/// Attempts a server-side TLS handshake.
///
/// This is a convenience method which combines [`Self::setup_accept`] and
/// [`MidHandshakeSslStream::handshake`].
///
/// # Warning
///
/// OpenSSL's default configuration is insecure. It is highly recommended to use
/// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration.
///
/// [`SSL_accept`]: https://www.openssl.org/docs/manmaster/man3/SSL_accept.html
pub fn accept<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
where
S: Read + Write,
{
self.setup_accept(stream).handshake()
}
}

Expand Down Expand Up @@ -3461,46 +3497,60 @@ where
unsafe { ffi::SSL_set_accept_state(self.inner.ssl.as_ptr()) }
}

/// See `Ssl::connect`
/// Initiates a client-side TLS handshake, returning a [`MidHandshakeSslStream`].
///
/// This method calls [`Self::set_connect_state`] and returns without actually
/// initiating the handshake. The caller is then free to call
/// [`MidHandshakeSslStream`] and loop on [`HandshakeError::WouldBlock`].
pub fn setup_connect(mut self) -> MidHandshakeSslStream<S> {
self.set_connect_state();

MidHandshakeSslStream {
stream: self.inner,
error: Error {
code: ErrorCode::WANT_WRITE,
cause: Some(InnerError::Io(io::Error::new(
io::ErrorKind::WouldBlock,
"connect handshake has not started yet",
))),
},
}
}

/// Attempts a client-side TLS handshake.
///
/// This is a convenience method which combines [`Self::setup_connect`] and
/// [`MidHandshakeSslStream::handshake`].
pub fn connect(self) -> Result<SslStream<S>, HandshakeError<S>> {
let mut stream = self.inner;
let ret = unsafe { ffi::SSL_connect(stream.ssl.as_ptr()) };
if ret > 0 {
Ok(stream)
} else {
let error = stream.make_error(ret);
match error.would_block() {
true => Err(HandshakeError::WouldBlock(MidHandshakeSslStream {
stream,
error,
})),
false => Err(HandshakeError::Failure(MidHandshakeSslStream {
stream,
error,
})),
}
self.setup_connect().handshake()
}

/// Initiates a server-side TLS handshake, returning a [`MidHandshakeSslStream`].
///
/// This method calls [`Self::set_accept_state`] and returns without actually
/// initiating the handshake. The caller is then free to call
/// [`MidHandshakeSslStream`] and loop on [`HandshakeError::WouldBlock`].
pub fn setup_accept(mut self) -> MidHandshakeSslStream<S> {
self.set_accept_state();

MidHandshakeSslStream {
stream: self.inner,
error: Error {
code: ErrorCode::WANT_READ,
cause: Some(InnerError::Io(io::Error::new(
io::ErrorKind::WouldBlock,
"accept handshake has not started yet",
))),
},
}
}

/// See `Ssl::accept`
/// Attempts a server-side TLS handshake.
///
/// This is a convenience method which combines [`Self::setup_accept`] and
/// [`MidHandshakeSslStream::handshake`].
pub fn accept(self) -> Result<SslStream<S>, HandshakeError<S>> {
let mut stream = self.inner;
let ret = unsafe { ffi::SSL_accept(stream.ssl.as_ptr()) };
if ret > 0 {
Ok(stream)
} else {
let error = stream.make_error(ret);
match error.would_block() {
true => Err(HandshakeError::WouldBlock(MidHandshakeSslStream {
stream,
error,
})),
false => Err(HandshakeError::Failure(MidHandshakeSslStream {
stream,
error,
})),
}
}
self.setup_accept().handshake()
}

/// Initiates the handshake.
Expand Down
Loading

0 comments on commit b27a6e7

Please sign in to comment.