Merge pull request #789 from sfackler/ssl-docs-2

Finish documentation for the ssl module
This commit is contained in:
Steven Fackler 2017-12-05 09:12:50 -08:00 committed by GitHub
commit f85816389d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 241 additions and 50 deletions

View File

@ -3,7 +3,7 @@ use std::ops::{Deref, DerefMut};
use dh::Dh; use dh::Dh;
use error::ErrorStack; use error::ErrorStack;
use ssl::{self, HandshakeError, Ssl, SslContext, SslContextBuilder, SslMethod, SslStream, use ssl::{self, HandshakeError, Ssl, SslRef, SslContext, SslContextBuilder, SslMethod, SslStream,
SSL_VERIFY_PEER}; SSL_VERIFY_PEER};
use pkey::PKeyRef; use pkey::PKeyRef;
use version; use version;
@ -91,7 +91,7 @@ impl SslConnectorBuilder {
self self
} }
/// Consumes the builder, returning a `SslConnector`. /// Consumes the builder, returning an `SslConnector`.
pub fn build(self) -> SslConnector { pub fn build(self) -> SslConnector {
SslConnector(self.0.build()) SslConnector(self.0.build())
} }
@ -162,12 +162,14 @@ impl SslConnector {
pub struct ConnectConfiguration(Ssl); pub struct ConnectConfiguration(Ssl);
impl ConnectConfiguration { impl ConnectConfiguration {
/// Returns a shared reference to the inner `Ssl`. #[deprecated(since = "0.9.23",
note = "ConnectConfiguration now implements Deref<Target=SslRef>")]
pub fn ssl(&self) -> &Ssl { pub fn ssl(&self) -> &Ssl {
&self.0 &self.0
} }
/// Returns a mutable reference to the inner `Ssl`. #[deprecated(since = "0.9.23",
note = "ConnectConfiguration now implements DerefMut<Target=SslRef>")]
pub fn ssl_mut(&mut self) -> &mut Ssl { pub fn ssl_mut(&mut self) -> &mut Ssl {
&mut self.0 &mut self.0
} }
@ -207,6 +209,20 @@ impl ConnectConfiguration {
} }
} }
impl Deref for ConnectConfiguration {
type Target = SslRef;
fn deref(&self) -> &SslRef {
&self.0
}
}
impl DerefMut for ConnectConfiguration {
fn deref_mut(&mut self) -> &mut SslRef {
&mut self.0
}
}
/// A builder for `SslAcceptor`s. /// A builder for `SslAcceptor`s.
pub struct SslAcceptorBuilder(SslContextBuilder); pub struct SslAcceptorBuilder(SslContextBuilder);

View File

@ -8,6 +8,7 @@ use error::ErrorStack;
use ssl::MidHandshakeSslStream; use ssl::MidHandshakeSslStream;
/// An SSL error. /// An SSL error.
// FIXME this is missing variants
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
/// The SSL session has been closed by the other end /// The SSL session has been closed by the other end
@ -100,7 +101,9 @@ pub enum HandshakeError<S> {
SetupFailure(ErrorStack), SetupFailure(ErrorStack),
/// The handshake failed. /// The handshake failed.
Failure(MidHandshakeSslStream<S>), Failure(MidHandshakeSslStream<S>),
/// The handshake was interrupted midway through. This error will never be returned for blocking streams. /// The handshake was interrupted midway through.
///
/// This error will never be returned for blocking streams.
// FIXME change to WouldBlock // FIXME change to WouldBlock
Interrupted(MidHandshakeSslStream<S>), Interrupted(MidHandshakeSslStream<S>),
} }

View File

@ -1508,20 +1508,22 @@ impl SslRef {
unsafe { ffi::SSL_get_error(self.as_ptr(), ret) } unsafe { ffi::SSL_get_error(self.as_ptr(), ret) }
} }
/// Sets the verification mode to be used during the handshake process. /// Like [`SslContextBuilder::set_verify`].
/// ///
/// Use `set_verify_callback` to additionally add a callback. /// This corresponds to [`SSL_set_verify`].
///
/// [`SslContextBuilder::set_verify`]: struct.SslContextBuilder.html#method.set_verify
/// [`SSL_set_verify`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html
pub fn set_verify(&mut self, mode: SslVerifyMode) { pub fn set_verify(&mut self, mode: SslVerifyMode) {
unsafe { ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, None) } unsafe { ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, None) }
} }
/// Sets the certificate verification callback to be used during the /// Like [`SslContextBuilder::set_verify_callback`].
/// handshake process.
/// ///
/// The callback is provided with a boolean indicating if the /// This corresponds to [`SSL_set_verify`].
/// preveification process was successful, and an object providing access ///
/// to the certificate chain. It should return `true` if the certificate /// [`SslContextBuilder::set_verify_callback`]: struct.SslContextBuilder.html#method.set_verify_callback
/// chain is valid and `false` otherwise. /// [`SSL_set_verify`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html
pub fn set_verify_callback<F>(&mut self, mode: SslVerifyMode, verify: F) pub fn set_verify_callback<F>(&mut self, mode: SslVerifyMode, verify: F)
where where
// FIXME should take a mutable reference to the x509 store // FIXME should take a mutable reference to the x509 store
@ -1538,10 +1540,22 @@ impl SslRef {
} }
} }
/// Like [`SslContextBuilder::set_tmp_dh`].
///
/// This corresponds to [`SSL_set_tmp_dh`].
///
/// [`SslContextBuilder::set_tmp_dh`]: struct.SslContextBuilder.html#method.set_tmp_dh
/// [`SSL_set_tmp_dh`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tmp_dh.html
pub fn set_tmp_dh(&mut self, dh: &DhRef) -> Result<(), ErrorStack> { pub fn set_tmp_dh(&mut self, dh: &DhRef) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::SSL_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) } unsafe { cvt(ffi::SSL_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) }
} }
/// Like [`SslContextBuilder::set_tmp_dh_callback`].
///
/// This corresponds to [`SSL_set_tmp_dh_callback`].
///
/// [`SslContextBuilder::set_tmp_dh_callback`]: struct.SslContextBuilder.html#method.set_tmp_dh_callback
/// [`SSL_set_tmp_dh_callback`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tmp_dh.html
pub fn set_tmp_dh_callback<F>(&mut self, callback: F) pub fn set_tmp_dh_callback<F>(&mut self, callback: F)
where where
F: Fn(&mut SslRef, bool, u32) -> Result<Dh, ErrorStack> + Any + 'static + Sync + Send, F: Fn(&mut SslRef, bool, u32) -> Result<Dh, ErrorStack> + Any + 'static + Sync + Send,
@ -1558,11 +1572,22 @@ impl SslRef {
} }
} }
/// Like [`SslContextBuilder::set_tmp_ecdh`].
///
/// This corresponds to `SSL_set_tmp_ecdh`.
///
/// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh
pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> { pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::SSL_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) } unsafe { cvt(ffi::SSL_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) }
} }
/// Like [`SslContextBuilder::set_tmp_ecdh_callback`].
///
/// Requires the `v101` feature and OpenSSL 1.0.1, or the `v102` feature and OpenSSL 1.0.2. /// Requires the `v101` feature and OpenSSL 1.0.1, or the `v102` feature and OpenSSL 1.0.2.
///
/// This corresponds to `SSL_set_tmp_ecdh_callback`.
///
/// [`SslContextBuilder::set_tmp_ecdh_callback`]: struct.SslContextBuilder.html#method.set_tmp_ecdh_callback
#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))]
pub fn set_tmp_ecdh_callback<F>(&mut self, callback: F) pub fn set_tmp_ecdh_callback<F>(&mut self, callback: F)
where where
@ -1580,16 +1605,24 @@ impl SslRef {
} }
} }
/// If `onoff` is set to `true`, enable ECDHE for key exchange with /// Like [`SslContextBuilder::set_ecdh_auto`].
/// compatible clients, and automatically select an appropriate elliptic
/// curve.
/// ///
/// Requires the `v102` feature and OpenSSL 1.0.2. /// Requires the `v102` feature and OpenSSL 1.0.2.
///
/// This corresponds to [`SSL_set_ecdh_auto`].
///
/// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh
/// [`SSL_set_ecdh_auto`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_ecdh_auto.html
#[cfg(all(feature = "v102", ossl102))] #[cfg(all(feature = "v102", ossl102))]
pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::SSL_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) } unsafe { cvt(ffi::SSL_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) }
} }
/// Returns the current cipher if the session is active.
///
/// This corresponds to [`SSL_get_current_cipher`].
///
/// [`SSL_get_current_cipher`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_current_cipher.html
pub fn current_cipher(&self) -> Option<&SslCipherRef> { pub fn current_cipher(&self) -> Option<&SslCipherRef> {
unsafe { unsafe {
let ptr = ffi::SSL_get_current_cipher(self.as_ptr()); let ptr = ffi::SSL_get_current_cipher(self.as_ptr());
@ -1602,6 +1635,11 @@ impl SslRef {
} }
} }
/// Returns a short string describing the state of the session.
///
/// This corresponds to [`SSL_state_string`].
///
/// [`SSL_state_string`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_state_string.html
pub fn state_string(&self) -> &'static str { pub fn state_string(&self) -> &'static str {
let state = unsafe { let state = unsafe {
let ptr = ffi::SSL_state_string(self.as_ptr()); let ptr = ffi::SSL_state_string(self.as_ptr());
@ -1611,6 +1649,11 @@ impl SslRef {
str::from_utf8(state.to_bytes()).unwrap() str::from_utf8(state.to_bytes()).unwrap()
} }
/// Returns a longer string describing the state of the session.
///
/// This corresponds to [`SSL_state_string_long`].
///
/// [`SSL_state_string_long`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_state_string_long.html
pub fn state_string_long(&self) -> &'static str { pub fn state_string_long(&self) -> &'static str {
let state = unsafe { let state = unsafe {
let ptr = ffi::SSL_state_string_long(self.as_ptr()); let ptr = ffi::SSL_state_string_long(self.as_ptr());
@ -1620,7 +1663,13 @@ impl SslRef {
str::from_utf8(state.to_bytes()).unwrap() str::from_utf8(state.to_bytes()).unwrap()
} }
/// Sets the host name to be used with SNI (Server Name Indication). /// Sets the host name to be sent to the server for Server Name Indication (SNI).
///
/// It has no effect for a server-side connection.
///
/// This corresponds to [`SSL_set_tlsext_host_name`].
///
/// [`SSL_set_tlsext_host_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername_type.html
pub fn set_hostname(&mut self, hostname: &str) -> Result<(), ErrorStack> { pub fn set_hostname(&mut self, hostname: &str) -> Result<(), ErrorStack> {
let cstr = CString::new(hostname).unwrap(); let cstr = CString::new(hostname).unwrap();
unsafe { unsafe {
@ -1629,7 +1678,11 @@ impl SslRef {
} }
} }
/// Returns the certificate of the peer, if present. /// Returns the peer's certificate, if present.
///
/// This corresponds to [`SSL_get_peer_certificate`].
///
/// [`SSL_get_peer_certificate`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_peer_certificate.html
pub fn peer_certificate(&self) -> Option<X509> { pub fn peer_certificate(&self) -> Option<X509> {
unsafe { unsafe {
let ptr = ffi::SSL_get_peer_certificate(self.as_ptr()); let ptr = ffi::SSL_get_peer_certificate(self.as_ptr());
@ -1645,6 +1698,10 @@ impl SslRef {
/// ///
/// On the client side, the chain includes the leaf certificate, but on the server side it does /// On the client side, the chain includes the leaf certificate, but on the server side it does
/// not. Fun! /// not. Fun!
///
/// This corresponds to [`SSL_get_peer_cert_chain`].
///
/// [`SSL_get_peer_cert_chain`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_peer_cert_chain.html
pub fn peer_cert_chain(&self) -> Option<&StackRef<X509>> { pub fn peer_cert_chain(&self) -> Option<&StackRef<X509>> {
unsafe { unsafe {
let ptr = ffi::SSL_get_peer_cert_chain(self.as_ptr()); let ptr = ffi::SSL_get_peer_cert_chain(self.as_ptr());
@ -1656,7 +1713,11 @@ impl SslRef {
} }
} }
/// Returns the certificate associated with this `Ssl`, if present. /// Like [`SslContext::certificate`].
///
/// This corresponds to `SSL_get_certificate`.
///
/// [`SslContext::certificate`]: struct.SslContext.html#method.certificate
pub fn certificate(&self) -> Option<&X509Ref> { pub fn certificate(&self) -> Option<&X509Ref> {
unsafe { unsafe {
let ptr = ffi::SSL_get_certificate(self.as_ptr()); let ptr = ffi::SSL_get_certificate(self.as_ptr());
@ -1668,7 +1729,11 @@ impl SslRef {
} }
} }
/// Returns the private key associated with this `Ssl`, if present. /// Like [`SslContext::private_key`].
///
/// This corresponds to `SSL_get_privatekey`.
///
/// [`SslContext::private_key`]: struct.SslContext.html#method.private_key
pub fn private_key(&self) -> Option<&PKeyRef> { pub fn private_key(&self) -> Option<&PKeyRef> {
unsafe { unsafe {
let ptr = ffi::SSL_get_privatekey(self.as_ptr()); let ptr = ffi::SSL_get_privatekey(self.as_ptr());
@ -1680,7 +1745,11 @@ impl SslRef {
} }
} }
/// Returns the name of the protocol used for the connection, e.g. "TLSv1.2", "SSLv3", etc. /// Returns a string describing the protocol version of the session.
///
/// This corresponds to [`SSL_get_version`].
///
/// [`SSL_get_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_version.html
pub fn version(&self) -> &'static str { pub fn version(&self) -> &'static str {
let version = unsafe { let version = unsafe {
let ptr = ffi::SSL_get_version(self.as_ptr()); let ptr = ffi::SSL_get_version(self.as_ptr());
@ -1694,6 +1763,10 @@ impl SslRef {
/// ///
/// The protocol's name is returned is an opaque sequence of bytes. It is up to the client /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client
/// to interpret it. /// to interpret it.
///
/// This corresponds to [`SSL_get0_next_proto_negotiated`].
///
/// [`SSL_get0_next_proto_negotiated`]: https://www.openssl.org/docs/manmaster/man3/SSL_get0_next_proto_negotiated.html
#[cfg(not(any(libressl261, libressl262, libressl26x)))] #[cfg(not(any(libressl261, libressl262, libressl26x)))]
pub fn selected_npn_protocol(&self) -> Option<&[u8]> { pub fn selected_npn_protocol(&self) -> Option<&[u8]> {
unsafe { unsafe {
@ -1717,6 +1790,10 @@ impl SslRef {
/// to interpret it. /// to interpret it.
/// ///
/// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0. /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
///
/// This corresponds to [`SSL_get0_alpn_selected`].
///
/// [`SSL_get0_alpn_selected`]: https://www.openssl.org/docs/manmaster/man3/SSL_get0_next_proto_negotiated.html
#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
pub fn selected_alpn_protocol(&self) -> Option<&[u8]> { pub fn selected_alpn_protocol(&self) -> Option<&[u8]> {
unsafe { unsafe {
@ -1734,16 +1811,21 @@ impl SslRef {
} }
} }
/// Returns the number of bytes remaining in the currently processed TLS /// Returns the number of bytes remaining in the currently processed TLS record.
/// record. ///
/// If this is greater than 0, the next call to `read` will not call down to the underlying
/// stream.
///
/// This corresponds to [`SSL_pending]`.
///
/// [`SSL_pending`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_pending.html
pub fn pending(&self) -> usize { pub fn pending(&self) -> usize {
unsafe { ffi::SSL_pending(self.as_ptr()) as usize } unsafe { ffi::SSL_pending(self.as_ptr()) as usize }
} }
/// Returns the compression currently in use. /// Returns the compression method currently in use.
/// ///
/// The result will be either None, indicating no compression is in use, or /// This corresponds to `SSL_get_current_compression`.
/// a string with the compression name.
pub fn compression(&self) -> Option<&str> { pub fn compression(&self) -> Option<&str> {
self._compression() self._compression()
} }
@ -1765,7 +1847,14 @@ impl SslRef {
None None
} }
/// Returns the server's name for the current connection /// Returns the servername sent by the client via Server Name Indication (SNI).
///
/// It is only useful on the server side.
///
/// This corresponds to [`SSL_get_servername`].
///
/// [`SSL_get_servername`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername.html
// FIXME add name parameter
pub fn servername(&self) -> Option<&str> { pub fn servername(&self) -> Option<&str> {
unsafe { unsafe {
let name = ffi::SSL_get_servername(self.as_ptr(), ffi::TLSEXT_NAMETYPE_host_name); let name = ffi::SSL_get_servername(self.as_ptr(), ffi::TLSEXT_NAMETYPE_host_name);
@ -1778,11 +1867,19 @@ impl SslRef {
} }
/// Changes the context corresponding to the current connection. /// Changes the context corresponding to the current connection.
///
/// It is most commonly used in the Server Name Indication (SNI) callback.
///
/// This corresponds to `SSL_set_SSL_CTX`.
pub fn set_ssl_context(&mut self, ctx: &SslContextRef) -> Result<(), ErrorStack> { pub fn set_ssl_context(&mut self, ctx: &SslContextRef) -> Result<(), ErrorStack> {
unsafe { cvt_p(ffi::SSL_set_SSL_CTX(self.as_ptr(), ctx.as_ptr())).map(|_| ()) } unsafe { cvt_p(ffi::SSL_set_SSL_CTX(self.as_ptr(), ctx.as_ptr())).map(|_| ()) }
} }
/// Returns the context corresponding to the current connection /// Returns the context corresponding to the current connection.
///
/// This corresponds to [`SSL_get_SSL_CTX`].
///
/// [`SSL_get_SSL_CTX`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get_SSL_CTX.html
pub fn ssl_context(&self) -> &SslContextRef { pub fn ssl_context(&self) -> &SslContextRef {
unsafe { unsafe {
let ssl_ctx = ffi::SSL_get_SSL_CTX(self.as_ptr()); let ssl_ctx = ffi::SSL_get_SSL_CTX(self.as_ptr());
@ -1790,9 +1887,13 @@ impl SslRef {
} }
} }
/// Returns the X509 verification configuration. /// Returns a mutable reference to the X509 verification configuration.
/// ///
/// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or 1.1.0. /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or 1.1.0.
///
/// This corresponds to [`SSL_get0_param`].
///
/// [`SSL_get0_param`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get0_param.html
#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
pub fn param_mut(&mut self) -> &mut X509VerifyParamRef { pub fn param_mut(&mut self) -> &mut X509VerifyParamRef {
self._param_mut() self._param_mut()
@ -1803,12 +1904,20 @@ impl SslRef {
unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) } unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) }
} }
/// Returns the result of X509 certificate verification. /// Returns the certificate verification result.
///
/// This corresponds to [`SSL_get_verify_result`].
///
/// [`SSL_get_verify_result`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get_verify_result.html
pub fn verify_result(&self) -> Option<X509VerifyError> { pub fn verify_result(&self) -> Option<X509VerifyError> {
unsafe { X509VerifyError::from_raw(ffi::SSL_get_verify_result(self.as_ptr())) } unsafe { X509VerifyError::from_raw(ffi::SSL_get_verify_result(self.as_ptr())) }
} }
/// Returns the SSL session. /// Returns a shared reference to the SSL session.
///
/// This corresponds to [`SSL_get_session`].
///
/// [`SSL_get_session`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_session.html
pub fn session(&self) -> Option<&SslSessionRef> { pub fn session(&self) -> Option<&SslSessionRef> {
unsafe { unsafe {
let p = ffi::SSL_get_session(self.as_ptr()); let p = ffi::SSL_get_session(self.as_ptr());
@ -1822,20 +1931,36 @@ impl SslRef {
/// Sets the session to be used. /// Sets the session to be used.
/// ///
/// This should be called before the handshake to attempt to reuse a previously established
/// session. If the server is not willing to reuse the session, a new one will be transparently
/// negotiated.
///
/// This corresponds to [`SSL_set_session`].
///
/// # Safety /// # Safety
/// ///
/// The caller of this method is responsible for ensuring that the session is associated /// The caller of this method is responsible for ensuring that the session is associated
/// with the same `SslContext` as this `Ssl`. /// with the same `SslContext` as this `Ssl`.
///
/// [`SSL_set_session`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_session.html
pub unsafe fn set_session(&mut self, session: &SslSessionRef) -> Result<(), ErrorStack> { pub unsafe fn set_session(&mut self, session: &SslSessionRef) -> Result<(), ErrorStack> {
cvt(ffi::SSL_set_session(self.as_ptr(), session.as_ptr())).map(|_| ()) cvt(ffi::SSL_set_session(self.as_ptr(), session.as_ptr())).map(|_| ())
} }
/// Determines if the session provided to `set_session` was successfully reused. /// Determines if the session provided to `set_session` was successfully reused.
///
/// This corresponds to [`SSL_session_reused`].
///
/// [`SSL_session_reused`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_session_reused.html
pub fn session_reused(&self) -> bool { pub fn session_reused(&self) -> bool {
unsafe { ffi::SSL_session_reused(self.as_ptr()) != 0 } unsafe { ffi::SSL_session_reused(self.as_ptr()) != 0 }
} }
/// Sets the status response a client wishes the server to reply with. /// Sets the status response a client wishes the server to reply with.
///
/// This corresponds to [`SSL_set_tlsext_status_type`].
///
/// [`SSL_set_tlsext_status_type`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tlsext_status_type.html
pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> { pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> {
unsafe { unsafe {
cvt(ffi::SSL_set_tlsext_status_type(self.as_ptr(), type_.as_raw()) as c_int).map(|_| ()) cvt(ffi::SSL_set_tlsext_status_type(self.as_ptr(), type_.as_raw()) as c_int).map(|_| ())
@ -1843,6 +1968,10 @@ impl SslRef {
} }
/// Returns the server's OCSP response, if present. /// Returns the server's OCSP response, if present.
///
/// This corresponds to [`SSL_get_tlsext_status_oscp_resp`].
///
/// [`SSL_get_tlsext_status_ocsp_resp`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tlsext_status_type.html
pub fn ocsp_status(&self) -> Option<&[u8]> { pub fn ocsp_status(&self) -> Option<&[u8]> {
unsafe { unsafe {
let mut p = ptr::null_mut(); let mut p = ptr::null_mut();
@ -1857,6 +1986,10 @@ impl SslRef {
} }
/// Sets the OCSP response to be returned to the client. /// Sets the OCSP response to be returned to the client.
///
/// This corresponds to [`SSL_set_tlsext_status_oscp_resp`].
///
/// [`SSL_set_tlsext_status_ocsp_resp`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tlsext_status_type.html
pub fn set_ocsp_status(&mut self, response: &[u8]) -> Result<(), ErrorStack> { pub fn set_ocsp_status(&mut self, response: &[u8]) -> Result<(), ErrorStack> {
unsafe { unsafe {
assert!(response.len() <= c_int::max_value() as usize); assert!(response.len() <= c_int::max_value() as usize);
@ -1876,11 +2009,22 @@ impl SslRef {
} }
/// Determines if this `Ssl` is configured for server-side or client-side use. /// Determines if this `Ssl` is configured for server-side or client-side use.
///
/// This corresponds to [`SSL_is_server`].
///
/// [`SSL_is_server`]: https://www.openssl.org/docs/manmaster/man3/SSL_is_server.html
pub fn is_server(&self) -> bool { pub fn is_server(&self) -> bool {
unsafe { compat::SSL_is_server(self.as_ptr()) != 0 } unsafe { compat::SSL_is_server(self.as_ptr()) != 0 }
} }
/// Sets the extra data at the specified index. /// Sets the extra data at the specified index.
///
/// This can be used to provide data to callbacks registered with the context. Use the
/// `Ssl::new_ex_index` method to create an `Index`.
///
/// This corresponds to [`SSL_set_ex_data`].
///
/// [`SSL_set_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_ex_data.html
pub fn set_ex_data<T>(&mut self, index: Index<Ssl, T>, data: T) { pub fn set_ex_data<T>(&mut self, index: Index<Ssl, T>, data: T) {
unsafe { unsafe {
let data = Box::new(data); let data = Box::new(data);
@ -1893,6 +2037,10 @@ impl SslRef {
} }
/// Returns a reference to the extra data at the specified index. /// Returns a reference to the extra data at the specified index.
///
/// This corresponds to [`SSL_get_ex_data`].
///
/// [`SSL_get_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_ex_data.html
pub fn ex_data<T>(&self, index: Index<Ssl, T>) -> Option<&T> { pub fn ex_data<T>(&self, index: Index<Ssl, T>) -> Option<&T> {
unsafe { unsafe {
let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw()); let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw());
@ -1915,6 +2063,11 @@ impl fmt::Debug for Ssl {
} }
impl Ssl { impl Ssl {
/// Creates a new `Ssl`.
///
/// This corresponds to [`SSL_new`].
///
/// [`SSL_new`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_new.html
pub fn new(ctx: &SslContext) -> Result<Ssl, ErrorStack> { pub fn new(ctx: &SslContext) -> Result<Ssl, ErrorStack> {
unsafe { unsafe {
let ssl = cvt_p(ffi::SSL_new(ctx.as_ptr()))?; let ssl = cvt_p(ffi::SSL_new(ctx.as_ptr()))?;
@ -1922,12 +2075,16 @@ impl Ssl {
} }
} }
/// Creates an SSL/TLS client operating over the provided stream. /// Initiates a client-side TLS handshake.
///
/// This corresponds to [`SSL_connect`].
/// ///
/// # Warning /// # Warning
/// ///
/// OpenSSL's default configuration is insecure. It is highly recommended to use /// OpenSSL's default configuration is insecure. It is highly recommended to use
/// `SslConnector` rather than `Ssl` directly, as it manages that configuration. /// `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<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>> pub fn connect<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
where where
S: Read + Write, S: Read + Write,
@ -1952,12 +2109,16 @@ impl Ssl {
} }
} }
/// Creates an SSL/TLS server operating over the provided stream. /// Initiates a server-side TLS handshake.
///
/// This corresponds to [`SSL_accept`].
/// ///
/// # Warning /// # Warning
/// ///
/// OpenSSL's default configuration is insecure. It is highly recommended to use /// OpenSSL's default configuration is insecure. It is highly recommended to use
/// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration. /// `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>> pub fn accept<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
where where
S: Read + Write, S: Read + Write,
@ -2017,6 +2178,10 @@ impl<S> MidHandshakeSslStream<S> {
} }
/// Restarts the handshake process. /// 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>> { pub fn handshake(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
let ret = unsafe { ffi::SSL_do_handshake(self.stream.ssl.as_ptr()) }; let ret = unsafe { ffi::SSL_do_handshake(self.stream.ssl.as_ptr()) };
if ret > 0 { if ret > 0 {
@ -2036,7 +2201,7 @@ impl<S> MidHandshakeSslStream<S> {
} }
} }
/// A stream wrapper which handles SSL encryption for an underlying stream. /// A TLS session over a stream.
pub struct SslStream<S> { pub struct SslStream<S> {
// FIXME use ManuallyDrop // FIXME use ManuallyDrop
ssl: Ssl, ssl: Ssl,
@ -2072,8 +2237,12 @@ impl<S: Read + Write> SslStream<S> {
/// Like `read`, but returns an `ssl::Error` rather than an `io::Error`. /// Like `read`, but returns an `ssl::Error` rather than an `io::Error`.
/// ///
/// This is particularly useful with a nonblocking socket, where the error /// It is particularly useful with a nonblocking socket, where the error value will identify if
/// value will identify if OpenSSL is waiting on read or write readiness. /// OpenSSL is waiting on read or write readiness.
///
/// This corresponds to [`SSL_read`].
///
/// [`SSL_read`]: https://www.openssl.org/docs/manmaster/man3/SSL_read.html
pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
// The intepretation of the return code here is a little odd with a // The intepretation of the return code here is a little odd with a
// zero-length write. OpenSSL will likely correctly report back to us // zero-length write. OpenSSL will likely correctly report back to us
@ -2099,8 +2268,12 @@ impl<S: Read + Write> SslStream<S> {
/// Like `write`, but returns an `ssl::Error` rather than an `io::Error`. /// Like `write`, but returns an `ssl::Error` rather than an `io::Error`.
/// ///
/// This is particularly useful with a nonblocking socket, where the error /// It is particularly useful with a nonblocking socket, where the error value will identify if
/// value will identify if OpenSSL is waiting on read or write readiness. /// OpenSSL is waiting on read or write readiness.
///
/// This corresponds to [`SSL_write`].
///
/// [`SSL_write`]: https://www.openssl.org/docs/manmaster/man3/SSL_write.html
pub fn ssl_write(&mut self, buf: &[u8]) -> Result<usize, Error> { pub fn ssl_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
// See above for why we short-circuit on zero-length buffers // See above for why we short-circuit on zero-length buffers
if buf.len() == 0 { if buf.len() == 0 {
@ -2117,16 +2290,15 @@ impl<S: Read + Write> SslStream<S> {
/// Shuts down the session. /// Shuts down the session.
/// ///
/// The shutdown process consists of two steps. The first step sends a /// The shutdown process consists of two steps. The first step sends a close notify message to
/// close notify message to the peer, after which `ShutdownResult::Sent` /// the peer, after which `ShutdownResult::Sent` is returned. The second step awaits the receipt
/// is returned. The second step awaits the receipt of a close notify /// of a close notify message from the peer, after which `ShutdownResult::Received` is returned.
/// message from the peer, after which `ShutdownResult::Received` is
/// returned.
/// ///
/// While the connection may be closed after the first step, it is /// While the connection may be closed after the first step, it is recommended to fully shut the
/// recommended to fully shut the session down. In particular, it must /// session down. In particular, it must be fully shut down if the connection is to be used for
/// be fully shut down if the connection is to be used for further /// further communication in the future.
/// communication in the future. ///
/// This corresponds to [`SSL_shutdown`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_shutdown.html
pub fn shutdown(&mut self) -> Result<ShutdownResult, Error> { pub fn shutdown(&mut self) -> Result<ShutdownResult, Error> {
match unsafe { ffi::SSL_shutdown(self.ssl.as_ptr()) } { match unsafe { ffi::SSL_shutdown(self.ssl.as_ptr()) } {
0 => Ok(ShutdownResult::Sent), 0 => Ok(ShutdownResult::Sent),
@ -2191,7 +2363,7 @@ impl<S> SslStream<S> {
unsafe { bio::take_error::<S>(self.ssl.get_raw_rbio()) } unsafe { bio::take_error::<S>(self.ssl.get_raw_rbio()) }
} }
/// Returns a reference to the underlying stream. /// Returns a shared reference to the underlying stream.
pub fn get_ref(&self) -> &S { pub fn get_ref(&self) -> &S {
unsafe { unsafe {
let bio = self.ssl.get_raw_rbio(); let bio = self.ssl.get_raw_rbio();
@ -2201,7 +2373,7 @@ impl<S> SslStream<S> {
/// Returns a mutable reference to the underlying stream. /// Returns a mutable reference to the underlying stream.
/// ///
/// ## Warning /// # Warning
/// ///
/// It is inadvisable to read from or write to the underlying stream as it /// It is inadvisable to read from or write to the underlying stream as it
/// will most likely corrupt the SSL session. /// will most likely corrupt the SSL session.
@ -2212,7 +2384,7 @@ impl<S> SslStream<S> {
} }
} }
/// Returns the OpenSSL `Ssl` object associated with this stream. /// Returns a shared reference to the `Ssl` object associated with this stream.
pub fn ssl(&self) -> &SslRef { pub fn ssl(&self) -> &SslRef {
&self.ssl &self.ssl
} }