Skip to content

Commit

Permalink
Introduce SslStreamBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
Ralith committed Mar 29, 2018
1 parent bbb1cb6 commit 99fdb2b
Showing 1 changed file with 114 additions and 34 deletions.
148 changes: 114 additions & 34 deletions openssl/src/ssl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1432,7 +1432,8 @@ impl SslContextBuilder {
}
}

/// Sets the callback for generating an application cookie for stateless handshakes.
/// Sets the callback for generating an application cookie for TLS1.3
/// stateless handshakes.
///
/// The callback will be called with the SSL context and a slice into which the cookie
/// should be written. The callback should return the number of bytes written.
Expand All @@ -1454,7 +1455,8 @@ impl SslContextBuilder {
}
}

/// Sets the callback for verifying an application cookie for stateless handshakes.
/// Sets the callback for verifying an application cookie for TLS1.3
/// stateless handshakes.
///
/// The callback will be called with the SSL context and the cookie supplied by the
/// client. It should return true if and only if the cookie is valid.
Expand Down Expand Up @@ -2632,22 +2634,7 @@ impl Ssl {
where
S: Read + Write,
{
let mut stream = SslStream::new_base(self, stream);
let ret = unsafe { ffi::SSL_connect(stream.ssl.as_ptr()) };
if ret > 0 {
Ok(stream)
} else {
let error = stream.make_error(ret);
match error.code() {
ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => Err(HandshakeError::WouldBlock(
MidHandshakeSslStream { stream, error },
)),
_ => Err(HandshakeError::Failure(MidHandshakeSslStream {
stream,
error,
})),
}
}
SslStreamBuilder::new(self, stream).connect()
}

/// Initiates a server-side TLS handshake.
Expand All @@ -2664,22 +2651,7 @@ impl Ssl {
where
S: Read + Write,
{
let mut stream = SslStream::new_base(self, stream);
let ret = unsafe { ffi::SSL_accept(stream.ssl.as_ptr()) };
if ret > 0 {
Ok(stream)
} else {
let error = stream.make_error(ret);
match error.code() {
ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => Err(HandshakeError::WouldBlock(
MidHandshakeSslStream { stream, error },
)),
_ => Err(HandshakeError::Failure(MidHandshakeSslStream {
stream,
error,
})),
}
}
SslStreamBuilder::new(self, stream).accept()
}
}

Expand Down Expand Up @@ -2951,6 +2923,114 @@ impl<S: Read + Write> Write for SslStream<S> {
}
}

/// A partially constructed `SslStream`, useful for unusual handshakes.
pub struct SslStreamBuilder<S> {
inner: SslStream<S>
}

impl<S> SslStreamBuilder<S>
where S: Read + Write
{
/// Begin creating an `SslStream` atop `stream`
pub fn new(ssl: Ssl, stream: S) -> Self {
Self {
inner: SslStream::new_base(ssl, stream),
}
}

/// Perform a stateless server-side handshake
///
/// Requires that cookie generation and verification callbacks were
/// set on the SSL context.
///
/// Returns `Ok(true)` if a complete ClientHello containing a valid cookie
/// was read, in which case the handshake should be continued via
/// `accept`. If a HelloRetryRequest containing a fresh cookie was
/// transmitted, `Ok(false)` is returned instead. If the handshake cannot
/// proceed at all, `Err` is returned.
///
/// This corresponds to [`SSL_stateless`]
///
/// [`SSL_stateless`]: https://www.openssl.org/docs/manmaster/man3/SSL_stateless.html
#[cfg(ossl111)]
pub fn stateless(&mut self) -> Result<bool, ErrorStack> {
match unsafe { ffi::SSL_stateless(self.inner.ssl.as_ptr()) } {
1 => Ok(true),
0 => Ok(false),
-1 => Err(ErrorStack::get()),
_ => unreachable!(),
}
}

/// See `Ssl::connect`
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.code() {
ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => Err(HandshakeError::WouldBlock(
MidHandshakeSslStream { stream, error },
)),
_ => Err(HandshakeError::Failure(MidHandshakeSslStream {
stream,
error,
})),
}
}
}

/// See `Ssl::accept`
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.code() {
ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => Err(HandshakeError::WouldBlock(
MidHandshakeSslStream { stream, error },
)),
_ => Err(HandshakeError::Failure(MidHandshakeSslStream {
stream,
error,
})),
}
}
}

// Future work: early IO methods
}

impl<S> SslStreamBuilder<S> {
/// Returns a shared reference to the underlying stream.
pub fn get_ref(&self) -> &S {
unsafe {
let bio = self.inner.ssl.get_raw_rbio();
bio::get_ref(bio)
}
}

/// Returns a mutable reference to the underlying stream.
///
/// # Warning
///
/// It is inadvisable to read from or write to the underlying stream as it
/// will most likely corrupt the SSL session.
pub fn get_mut(&mut self) -> &mut S {
unsafe {
let bio = self.inner.ssl.get_raw_rbio();
bio::get_mut(bio)
}
}

/// Returns a shared reference to the `Ssl` object associated with this builder.
pub fn ssl(&self) -> &SslRef { &self.inner.ssl }
}

/// The result of a shutdown request.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ShutdownResult {
Expand Down

0 comments on commit 99fdb2b

Please sign in to comment.