Unverified Commit 09dd721f authored by Steven Fackler's avatar Steven Fackler Committed by GitHub
Browse files

Merge pull request #1397 from sfackler/always-unpin

Allow construction of unconnected SslStreams.
parents bc657d1c 625205de
Loading
Loading
Loading
Loading
+16 −16
Original line number Diff line number Diff line
@@ -24,8 +24,8 @@ pub struct StreamState<S> {
pub struct BioMethod(BIO_METHOD);

impl BioMethod {
    fn new<S: Read + Write>() -> BioMethod {
        BioMethod(BIO_METHOD::new::<S>())
    fn new<S: Read + Write>() -> Result<BioMethod, ErrorStack> {
        BIO_METHOD::new::<S>().map(BioMethod)
    }
}

@@ -33,7 +33,7 @@ unsafe impl Sync for BioMethod {}
unsafe impl Send for BioMethod {}

pub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, BioMethod), ErrorStack> {
    let method = BioMethod::new::<S>();
    let method = BioMethod::new::<S>()?;

    let state = Box::new(StreamState {
        stream,
@@ -191,6 +191,7 @@ unsafe extern "C" fn destroy<S>(bio: *mut BIO) -> c_int {
cfg_if! {
    if #[cfg(any(ossl110, libressl273))] {
        use ffi::{BIO_get_data, BIO_set_data, BIO_set_flags, BIO_set_init};
        use cvt;

        #[allow(bad_style)]
        unsafe fn BIO_set_num(_bio: *mut ffi::BIO, _num: c_int) {}
@@ -199,18 +200,17 @@ cfg_if! {
        struct BIO_METHOD(*mut ffi::BIO_METHOD);

        impl BIO_METHOD {
            fn new<S: Read + Write>() -> BIO_METHOD {
            fn new<S: Read + Write>() -> Result<BIO_METHOD, ErrorStack> {
                unsafe {
                    let ptr = ffi::BIO_meth_new(ffi::BIO_TYPE_NONE, b"rust\0".as_ptr() as *const _);
                    assert!(!ptr.is_null());
                    let ret = BIO_METHOD(ptr);
                    assert!(ffi::BIO_meth_set_write(ptr, bwrite::<S>) != 0);
                    assert!(ffi::BIO_meth_set_read(ptr, bread::<S>) != 0);
                    assert!(ffi::BIO_meth_set_puts(ptr, bputs::<S>) != 0);
                    assert!(ffi::BIO_meth_set_ctrl(ptr, ctrl::<S>) != 0);
                    assert!(ffi::BIO_meth_set_create(ptr, create) != 0);
                    assert!(ffi::BIO_meth_set_destroy(ptr, destroy::<S>) != 0);
                    ret
                    let ptr = cvt_p(ffi::BIO_meth_new(ffi::BIO_TYPE_NONE, b"rust\0".as_ptr() as *const _))?;
                    let method = BIO_METHOD(ptr);
                    cvt(ffi::BIO_meth_set_write(method.0, bwrite::<S>))?;
                    cvt(ffi::BIO_meth_set_read(method.0, bread::<S>))?;
                    cvt(ffi::BIO_meth_set_puts(method.0, bputs::<S>))?;
                    cvt(ffi::BIO_meth_set_ctrl(method.0, ctrl::<S>))?;
                    cvt(ffi::BIO_meth_set_create(method.0, create))?;
                    cvt(ffi::BIO_meth_set_destroy(method.0, destroy::<S>))?;
                    Ok(method)
                }
            }

@@ -231,7 +231,7 @@ cfg_if! {
        struct BIO_METHOD(*mut ffi::BIO_METHOD);

        impl BIO_METHOD {
            fn new<S: Read + Write>() -> BIO_METHOD {
            fn new<S: Read + Write>() -> Result<BIO_METHOD, ErrorStack> {
                let ptr = Box::new(ffi::BIO_METHOD {
                    type_: ffi::BIO_TYPE_NONE,
                    name: b"rust\0".as_ptr() as *const _,
@@ -245,7 +245,7 @@ cfg_if! {
                    callback_ctrl: None,
                });

                BIO_METHOD(Box::into_raw(ptr))
                Ok(BIO_METHOD(Box::into_raw(ptr)))
            }

            fn get(&self) -> *mut ffi::BIO_METHOD {
+13 −6
Original line number Diff line number Diff line
@@ -168,13 +168,10 @@ impl ConnectConfiguration {
        self.verify_hostname = verify_hostname;
    }

    /// Initiates a client-side TLS session on a stream.
    /// Returns an `Ssl` configured to connect to the provided domain.
    ///
    /// 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>>
    where
        S: Read + Write,
    {
    pub fn into_ssl(mut self, domain: &str) -> Result<Ssl, ErrorStack> {
        if self.sni {
            self.ssl.set_hostname(domain)?;
        }
@@ -183,7 +180,17 @@ impl ConnectConfiguration {
            setup_verify_hostname(&mut self.ssl, domain)?;
        }

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

    /// Initiates a client-side TLS session on a stream.
    ///
    /// The domain is used for SNI and hostname verification if enabled.
    pub fn connect<S>(self, domain: &str, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
    where
        S: Read + Write,
    {
        self.into_ssl(domain)?.connect(stream)
    }
}

+235 −83
Original line number Diff line number Diff line
@@ -1823,6 +1823,14 @@ foreign_type_and_impl_send_sync! {

impl Clone for SslContext {
    fn clone(&self) -> Self {
        (**self).to_owned()
    }
}

impl ToOwned for SslContextRef {
    type Owned = SslContext;

    fn to_owned(&self) -> Self::Owned {
        unsafe {
            SSL_CTX_up_ref(self.as_ptr());
            SslContext::from_ptr(self.as_ptr())
@@ -2381,11 +2389,11 @@ impl Ssl {
    ///
    /// [`SSL_new`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_new.html
    // FIXME should take &SslContextRef
    pub fn new(ctx: &SslContext) -> Result<Ssl, ErrorStack> {
    pub fn new(ctx: &SslContextRef) -> Result<Ssl, ErrorStack> {
        unsafe {
            let ptr = cvt_p(ffi::SSL_new(ctx.as_ptr()))?;
            let mut ssl = Ssl::from_ptr(ptr);
            ssl.set_ex_data(*SESSION_CTX_INDEX, ctx.clone());
            ssl.set_ex_data(*SESSION_CTX_INDEX, ctx.to_owned());

            Ok(ssl)
        }
@@ -2401,6 +2409,7 @@ impl Ssl {
    /// `SslConnector` rather than `Ssl` directly, as it manages that configuration.
    ///
    /// [`SSL_connect`]: https://www.openssl.org/docs/manmaster/man3/SSL_connect.html
    #[allow(deprecated)]
    pub fn connect<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
    where
        S: Read + Write,
@@ -2418,6 +2427,7 @@ impl Ssl {
    /// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration.
    ///
    /// [`SSL_accept`]: https://www.openssl.org/docs/manmaster/man3/SSL_accept.html
    #[allow(deprecated)]
    pub fn accept<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
    where
        S: Read + Write,
@@ -2454,6 +2464,24 @@ impl SslRef {
        unsafe { ErrorCode::from_raw(ffi::SSL_get_error(self.as_ptr(), ret)) }
    }

    /// Configure as an outgoing stream from a client.
    ///
    /// This corresponds to [`SSL_set_connect_state`].
    ///
    /// [`SSL_set_connect_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_connect_state.html
    pub fn set_connect_state(&mut self) {
        unsafe { ffi::SSL_set_connect_state(self.as_ptr()) }
    }

    /// Configure as an incoming stream to a server.
    ///
    /// This corresponds to [`SSL_set_accept_state`].
    ///
    /// [`SSL_set_accept_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_accept_state.html
    pub fn set_accept_state(&mut self) {
        unsafe { ffi::SSL_set_accept_state(self.as_ptr()) }
    }

    /// Like [`SslContextBuilder::set_verify`].
    ///
    /// This corresponds to [`SSL_set_verify`].
@@ -3389,18 +3417,22 @@ impl<S> MidHandshakeSslStream<S> {
    pub fn into_error(self) -> Error {
        self.error
    }
}

impl<S> MidHandshakeSslStream<S>
where
    S: Read + Write,
{
    /// Restarts the handshake process.
    ///
    /// This corresponds to [`SSL_do_handshake`].
    ///
    /// [`SSL_do_handshake`]: https://www.openssl.org/docs/manmaster/man3/SSL_do_handshake.html
    pub fn handshake(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
        let ret = unsafe { ffi::SSL_do_handshake(self.stream.ssl.as_ptr()) };
        if ret > 0 {
            Ok(self.stream)
        } else {
            self.error = self.stream.make_error(ret);
        match self.stream.do_handshake() {
            Ok(()) => Ok(self.stream),
            Err(error) => {
                self.error = error;
                match self.error.code() {
                    ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => {
                        Err(HandshakeError::WouldBlock(self))
@@ -3410,6 +3442,7 @@ impl<S> MidHandshakeSslStream<S> {
            }
        }
    }
}

/// A TLS session over a stream.
pub struct SslStream<S> {
@@ -3441,17 +3474,28 @@ where
}

impl<S: Read + Write> SslStream<S> {
    fn new_base(ssl: Ssl, stream: S) -> Self {
    /// Creates a new `SslStream`.
    ///
    /// This function performs no IO; the stream will not have performed any part of the handshake
    /// with the peer. If the `Ssl` was configured with [`SslRef::set_client_state`] or
    /// [`SslRef::set_server_state`], the handshake can be performed automatically during the first
    /// call to read or write. Otherwise the `connect` and `accept` methods can be used to
    /// explicitly perform the handshake.
    ///
    /// This corresponds to [`SSL_set_bio`].
    ///
    /// [`SSL_set_bio`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_bio.html
    pub fn new(ssl: Ssl, stream: S) -> Result<Self, ErrorStack> {
        let (bio, method) = bio::new(stream)?;
        unsafe {
            let (bio, method) = bio::new(stream).unwrap();
            ffi::SSL_set_bio(ssl.as_ptr(), bio, bio);
        }

            SslStream {
        Ok(SslStream {
            ssl: ManuallyDrop::new(ssl),
            method: ManuallyDrop::new(method),
            _p: PhantomData,
            }
        }
        })
    }

    /// Constructs an `SslStream` from a pointer to the underlying OpenSSL `SSL` struct.
@@ -3461,9 +3505,150 @@ impl<S: Read + Write> SslStream<S> {
    /// # Safety
    ///
    /// The caller must ensure the pointer is valid.
    #[deprecated(
        since = "0.10.32",
        note = "use Ssl::from_ptr and SslStream::new instead"
    )]
    pub unsafe fn from_raw_parts(ssl: *mut ffi::SSL, stream: S) -> Self {
        let ssl = Ssl::from_ptr(ssl);
        Self::new_base(ssl, stream)
        Self::new(ssl, stream).unwrap()
    }

    /// Read application data transmitted by a client before handshake completion.
    ///
    /// Useful for reducing latency, but vulnerable to replay attacks. Call
    /// [`SslRef::set_accept_state`] first.
    ///
    /// Returns `Ok(0)` if all early data has been read.
    ///
    /// Requires OpenSSL 1.1.1 or newer.
    ///
    /// This corresponds to [`SSL_read_early_data`].
    ///
    /// [`SSL_read_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_read_early_data.html
    #[cfg(ossl111)]
    pub fn read_early_data(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
        let mut read = 0;
        let ret = unsafe {
            ffi::SSL_read_early_data(
                self.ssl.as_ptr(),
                buf.as_ptr() as *mut c_void,
                buf.len(),
                &mut read,
            )
        };
        match ret {
            ffi::SSL_READ_EARLY_DATA_ERROR => Err(self.make_error(ret)),
            ffi::SSL_READ_EARLY_DATA_SUCCESS => Ok(read),
            ffi::SSL_READ_EARLY_DATA_FINISH => Ok(0),
            _ => unreachable!(),
        }
    }

    /// Send data to the server without blocking on handshake completion.
    ///
    /// Useful for reducing latency, but vulnerable to replay attacks. Call
    /// [`SslRef::set_connect_state`] first.
    ///
    /// Requires OpenSSL 1.1.1 or newer.
    ///
    /// This corresponds to [`SSL_write_early_data`].
    ///
    /// [`SSL_write_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_write_early_data.html
    #[cfg(ossl111)]
    pub fn write_early_data(&mut self, buf: &[u8]) -> Result<usize, Error> {
        let mut written = 0;
        let ret = unsafe {
            ffi::SSL_write_early_data(
                self.ssl.as_ptr(),
                buf.as_ptr() as *const c_void,
                buf.len(),
                &mut written,
            )
        };
        if ret > 0 {
            Ok(written as usize)
        } else {
            Err(self.make_error(ret))
        }
    }

    /// Initiates a client-side TLS handshake.
    ///
    /// This corresponds to [`SSL_connect`].
    ///
    /// # Warning
    ///
    /// OpenSSL's default configuration is insecure. It is highly recommended to use
    /// `SslConnector` rather than `Ssl` directly, as it manages that configuration.
    ///
    /// [`SSL_connect`]: https://www.openssl.org/docs/manmaster/man3/SSL_connect.html
    pub fn connect(&mut self) -> Result<(), Error> {
        let ret = unsafe { ffi::SSL_connect(self.ssl.as_ptr()) };
        if ret > 0 {
            Ok(())
        } else {
            Err(self.make_error(ret))
        }
    }

    /// Initiates a server-side TLS handshake.
    ///
    /// This corresponds to [`SSL_accept`].
    ///
    /// # 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(&mut self) -> Result<(), Error> {
        let ret = unsafe { ffi::SSL_accept(self.ssl.as_ptr()) };
        if ret > 0 {
            Ok(())
        } else {
            Err(self.make_error(ret))
        }
    }

    /// Initiates the handshake.
    ///
    /// This will fail if `set_accept_state` or `set_connect_state` was not called first.
    ///
    /// This corresponds to [`SSL_do_handshake`].
    ///
    /// [`SSL_do_handshake`]: https://www.openssl.org/docs/manmaster/man3/SSL_do_handshake.html
    pub fn do_handshake(&mut self) -> Result<(), Error> {
        let ret = unsafe { ffi::SSL_do_handshake(self.ssl.as_ptr()) };
        if ret > 0 {
            Ok(())
        } else {
            Err(self.make_error(ret))
        }
    }

    /// 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.ssl.as_ptr()) } {
            1 => Ok(true),
            0 => Ok(false),
            -1 => Err(ErrorStack::get()),
            _ => unreachable!(),
        }
    }

    /// Like `read`, but returns an `ssl::Error` rather than an `io::Error`.
@@ -3664,10 +3849,15 @@ impl<S: Read + Write> Write for SslStream<S> {
}

/// A partially constructed `SslStream`, useful for unusual handshakes.
#[deprecated(
    since = "0.10.32",
    note = "use the methods directly on Ssl/SslStream instead"
)]
pub struct SslStreamBuilder<S> {
    inner: SslStream<S>,
}

#[allow(deprecated)]
impl<S> SslStreamBuilder<S>
where
    S: Read + Write,
@@ -3675,7 +3865,7 @@ where
    /// Begin creating an `SslStream` atop `stream`
    pub fn new(ssl: Ssl, stream: S) -> Self {
        Self {
            inner: SslStream::new_base(ssl, stream),
            inner: SslStream::new(ssl, stream).unwrap(),
        }
    }

@@ -3722,48 +3912,40 @@ where
    }

    /// 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() {
    pub fn connect(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
        match self.inner.connect() {
            Ok(()) => Ok(self.inner),
            Err(error) => match error.code() {
                ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => {
                    Err(HandshakeError::WouldBlock(MidHandshakeSslStream {
                        stream,
                        stream: self.inner,
                        error,
                    }))
                }
                _ => Err(HandshakeError::Failure(MidHandshakeSslStream {
                    stream,
                    stream: self.inner,
                    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() {
    pub fn accept(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
        match self.inner.accept() {
            Ok(()) => Ok(self.inner),
            Err(error) => match error.code() {
                ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => {
                    Err(HandshakeError::WouldBlock(MidHandshakeSslStream {
                        stream,
                        stream: self.inner,
                        error,
                    }))
                }
                _ => Err(HandshakeError::Failure(MidHandshakeSslStream {
                    stream,
                    stream: self.inner,
                    error,
                })),
            }
            },
        }
    }

@@ -3774,25 +3956,21 @@ where
    /// This corresponds to [`SSL_do_handshake`].
    ///
    /// [`SSL_do_handshake`]: https://www.openssl.org/docs/manmaster/man3/SSL_do_handshake.html
    pub fn handshake(self) -> Result<SslStream<S>, HandshakeError<S>> {
        let mut stream = self.inner;
        let ret = unsafe { ffi::SSL_do_handshake(stream.ssl.as_ptr()) };
        if ret > 0 {
            Ok(stream)
        } else {
            let error = stream.make_error(ret);
            match error.code() {
    pub fn handshake(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
        match self.inner.do_handshake() {
            Ok(()) => Ok(self.inner),
            Err(error) => match error.code() {
                ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => {
                    Err(HandshakeError::WouldBlock(MidHandshakeSslStream {
                        stream,
                        stream: self.inner,
                        error,
                    }))
                }
                _ => Err(HandshakeError::Failure(MidHandshakeSslStream {
                    stream,
                    stream: self.inner,
                    error,
                })),
            }
            },
        }
    }

@@ -3811,21 +3989,7 @@ where
    /// [`SSL_read_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_read_early_data.html
    #[cfg(ossl111)]
    pub fn read_early_data(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
        let mut read = 0;
        let ret = unsafe {
            ffi::SSL_read_early_data(
                self.inner.ssl.as_ptr(),
                buf.as_ptr() as *mut c_void,
                buf.len(),
                &mut read,
            )
        };
        match ret {
            ffi::SSL_READ_EARLY_DATA_ERROR => Err(self.inner.make_error(ret)),
            ffi::SSL_READ_EARLY_DATA_SUCCESS => Ok(read),
            ffi::SSL_READ_EARLY_DATA_FINISH => Ok(0),
            _ => unreachable!(),
        }
        self.inner.read_early_data(buf)
    }

    /// Send data to the server without blocking on handshake completion.
@@ -3840,23 +4004,11 @@ where
    /// [`SSL_write_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_write_early_data.html
    #[cfg(ossl111)]
    pub fn write_early_data(&mut self, buf: &[u8]) -> Result<usize, Error> {
        let mut written = 0;
        let ret = unsafe {
            ffi::SSL_write_early_data(
                self.inner.ssl.as_ptr(),
                buf.as_ptr() as *const c_void,
                buf.len(),
                &mut written,
            )
        };
        if ret > 0 {
            Ok(written as usize)
        } else {
            Err(self.inner.make_error(ret))
        }
        self.inner.write_early_data(buf)
    }
}

#[allow(deprecated)]
impl<S> SslStreamBuilder<S> {
    /// Returns a shared reference to the underlying stream.
    pub fn get_ref(&self) -> &S {
+9 −18
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ use ssl::{ClientHelloResponse, ExtensionContext};
use ssl::{
    Error, HandshakeError, MidHandshakeSslStream, ShutdownResult, ShutdownState, Ssl, SslAcceptor,
    SslAcceptorBuilder, SslConnector, SslContext, SslContextBuilder, SslFiletype, SslMethod,
    SslOptions, SslSessionCacheMode, SslStream, SslStreamBuilder, SslVerifyMode, StatusType,
    SslOptions, SslSessionCacheMode, SslStream, SslVerifyMode, StatusType,
};
#[cfg(ossl102)]
use x509::store::X509StoreBuilder;
@@ -1253,23 +1253,14 @@ fn stateless() {
        to.extend_incoming(&from.take_outgoing());
    }

    fn hs<S: ::std::fmt::Debug>(
        stream: Result<SslStream<S>, HandshakeError<S>>,
    ) -> Result<SslStream<S>, MidHandshakeSslStream<S>> {
        match stream {
            Ok(stream) => Ok(stream),
            Err(HandshakeError::WouldBlock(stream)) => Err(stream),
            Err(e) => panic!("unexpected error: {:?}", e),
        }
    }

    //
    // Setup
    //

    let mut client_ctx = SslContext::builder(SslMethod::tls()).unwrap();
    client_ctx.clear_options(SslOptions::ENABLE_MIDDLEBOX_COMPAT);
    let client_stream = Ssl::new(&client_ctx.build()).unwrap();
    let mut client_stream =
        SslStream::new(Ssl::new(&client_ctx.build()).unwrap(), MemoryStream::new()).unwrap();

    let mut server_ctx = SslContext::builder(SslMethod::tls()).unwrap();
    server_ctx
@@ -1285,29 +1276,29 @@ fn stateless() {
    });
    server_ctx.set_stateless_cookie_verify_cb(|_tls, buf| buf == COOKIE);
    let mut server_stream =
        ssl::SslStreamBuilder::new(Ssl::new(&server_ctx.build()).unwrap(), MemoryStream::new());
        SslStream::new(Ssl::new(&server_ctx.build()).unwrap(), MemoryStream::new()).unwrap();

    //
    // Handshake
    //

    // Initial ClientHello
    let mut client_stream = hs(client_stream.connect(MemoryStream::new())).unwrap_err();
    client_stream.connect().unwrap_err();
    send(client_stream.get_mut(), server_stream.get_mut());
    // HelloRetryRequest
    assert!(!server_stream.stateless().unwrap());
    send(server_stream.get_mut(), client_stream.get_mut());
    // Second ClientHello
    let mut client_stream = hs(client_stream.handshake()).unwrap_err();
    client_stream.do_handshake().unwrap_err();
    send(client_stream.get_mut(), server_stream.get_mut());
    // OldServerHello
    assert!(server_stream.stateless().unwrap());
    let mut server_stream = hs(server_stream.accept()).unwrap_err();
    server_stream.accept().unwrap_err();
    send(server_stream.get_mut(), client_stream.get_mut());
    // Finished
    let mut client_stream = hs(client_stream.handshake()).unwrap();
    client_stream.do_handshake().unwrap();
    send(client_stream.get_mut(), server_stream.get_mut());
    hs(server_stream.handshake()).unwrap();
    server_stream.do_handshake().unwrap();
}

#[cfg(not(osslconf = "OPENSSL_NO_PSK"))]