Loading openssl/src/ssl/bio.rs +16 −16 Original line number Diff line number Diff line Loading @@ -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) } } Loading @@ -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, Loading Loading @@ -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) {} Loading @@ -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) } } Loading @@ -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 _, Loading @@ -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 { Loading openssl/src/ssl/connector.rs +13 −6 Original line number Diff line number Diff line Loading @@ -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)?; } Loading @@ -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) } } Loading openssl/src/ssl/mod.rs +235 −83 Original line number Diff line number Diff line Loading @@ -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()) Loading Loading @@ -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) } Loading @@ -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, Loading @@ -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, Loading Loading @@ -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`]. Loading Loading @@ -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)) Loading @@ -3410,6 +3442,7 @@ impl<S> MidHandshakeSslStream<S> { } } } } /// A TLS session over a stream. pub struct SslStream<S> { Loading Loading @@ -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. Loading @@ -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`. Loading Loading @@ -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, Loading @@ -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(), } } Loading Loading @@ -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, })), } }, } } Loading @@ -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, })), } }, } } Loading @@ -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. Loading @@ -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 { Loading openssl/src/ssl/test/mod.rs +9 −18 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading @@ -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"))] Loading Loading
openssl/src/ssl/bio.rs +16 −16 Original line number Diff line number Diff line Loading @@ -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) } } Loading @@ -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, Loading Loading @@ -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) {} Loading @@ -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) } } Loading @@ -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 _, Loading @@ -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 { Loading
openssl/src/ssl/connector.rs +13 −6 Original line number Diff line number Diff line Loading @@ -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)?; } Loading @@ -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) } } Loading
openssl/src/ssl/mod.rs +235 −83 Original line number Diff line number Diff line Loading @@ -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()) Loading Loading @@ -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) } Loading @@ -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, Loading @@ -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, Loading Loading @@ -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`]. Loading Loading @@ -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)) Loading @@ -3410,6 +3442,7 @@ impl<S> MidHandshakeSslStream<S> { } } } } /// A TLS session over a stream. pub struct SslStream<S> { Loading Loading @@ -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. Loading @@ -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`. Loading Loading @@ -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, Loading @@ -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(), } } Loading Loading @@ -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, })), } }, } } Loading @@ -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, })), } }, } } Loading @@ -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. Loading @@ -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 { Loading
openssl/src/ssl/test/mod.rs +9 −18 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading @@ -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"))] Loading