aboutsummaryrefslogtreecommitdiff
path: root/openssl/src/ssl/mod.rs
diff options
context:
space:
mode:
authorBenjamin Cheng <[email protected]>2018-06-02 10:56:31 -0400
committerBenjamin Cheng <[email protected]>2018-06-02 10:56:31 -0400
commitb1eb1224f50b6242f82cdeca7a876409c98e1d3a (patch)
tree4aad295a6847fb1bd2d54880cf5bcd4b7ec522f5 /openssl/src/ssl/mod.rs
parentAdd wrapper for SSL_CTX_set_psk_server_callback (diff)
parentMerge pull request #940 from CmdrMoozy/rsa_padding (diff)
downloadrust-openssl-b1eb1224f50b6242f82cdeca7a876409c98e1d3a.tar.xz
rust-openssl-b1eb1224f50b6242f82cdeca7a876409c98e1d3a.zip
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'openssl/src/ssl/mod.rs')
-rw-r--r--openssl/src/ssl/mod.rs565
1 files changed, 395 insertions, 170 deletions
diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs
index 37f5086c..b69247db 100644
--- a/openssl/src/ssl/mod.rs
+++ b/openssl/src/ssl/mod.rs
@@ -78,23 +78,24 @@ use std::str;
use std::sync::{Arc, Mutex};
use dh::{Dh, DhRef};
-#[cfg(any(ossl101, ossl102))]
+#[cfg(all(ossl101, not(ossl110)))]
use ec::EcKey;
use ec::EcKeyRef;
use error::ErrorStack;
use ex_data::Index;
#[cfg(ossl111)]
use hash::MessageDigest;
+#[cfg(ossl110)]
use nid::Nid;
use pkey::{HasPrivate, PKeyRef, Params, Private};
use ssl::bio::BioMethod;
use ssl::callbacks::*;
use ssl::error::InnerError;
use stack::{Stack, StackRef};
-#[cfg(any(ossl102, ossl110))]
+#[cfg(ossl102)]
use x509::store::X509Store;
use x509::store::{X509StoreBuilderRef, X509StoreRef};
-#[cfg(any(ossl102, ossl110))]
+#[cfg(any(ossl102, libressl261))]
use x509::verify::X509VerifyParamRef;
use x509::{X509, X509Name, X509Ref, X509StoreContextRef, X509VerifyResult};
use {cvt, cvt_n, cvt_p, init};
@@ -284,7 +285,7 @@ impl SslMethod {
/// This corresponds to `TLS_method` on OpenSSL 1.1.0 and `SSLv23_method`
/// on OpenSSL 1.0.x.
pub fn tls() -> SslMethod {
- SslMethod(compat::tls_method())
+ unsafe { SslMethod(TLS_method()) }
}
/// Support all versions of the DTLS protocol.
@@ -292,7 +293,7 @@ impl SslMethod {
/// This corresponds to `DTLS_method` on OpenSSL 1.1.0 and `DTLSv1_method`
/// on OpenSSL 1.0.x.
pub fn dtls() -> SslMethod {
- SslMethod(compat::dtls_method())
+ unsafe { SslMethod(DTLS_method()) }
}
/// Constructs an `SslMethod` from a pointer to the underlying OpenSSL value.
@@ -506,12 +507,12 @@ impl SslAlert {
/// An error returned from an ALPN selection callback.
///
-/// Requires OpenSSL 1.0.2 or newer.
-#[cfg(any(ossl102, ossl110))]
+/// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
+#[cfg(any(ossl102, libressl261))]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct AlpnError(c_int);
-#[cfg(any(ossl102, ossl110))]
+#[cfg(any(ossl102, libressl261))]
impl AlpnError {
/// Terminate the handshake with a fatal alert.
///
@@ -767,7 +768,7 @@ impl SslContextBuilder {
/// Requires OpenSSL 1.0.1 or 1.0.2.
///
/// This corresponds to `SSL_CTX_set_tmp_ecdh_callback`.
- #[cfg(any(ossl101, ossl102))]
+ #[cfg(all(ossl101, not(ossl110)))]
pub fn set_tmp_ecdh_callback<F>(&mut self, callback: F)
where
F: Fn(&mut SslRef, bool, u32) -> Result<EcKey<Params>, ErrorStack> + 'static + Sync + Send,
@@ -976,7 +977,7 @@ impl SslContextBuilder {
/// This corresponds to [`SSL_CTX_set_ecdh_auto`].
///
/// [`SSL_CTX_set_ecdh_auto`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_ecdh_auto.html
- #[cfg(any(ossl102, libressl))]
+ #[cfg(any(libressl, all(ossl102, not(ossl110))))]
pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::SSL_CTX_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) }
}
@@ -992,7 +993,7 @@ impl SslContextBuilder {
///
/// [`SSL_CTX_set_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html
pub fn set_options(&mut self, option: SslOptions) -> SslOptions {
- let bits = unsafe { compat::SSL_CTX_set_options(self.as_ptr(), option.bits()) };
+ let bits = unsafe { ffi::SSL_CTX_set_options(self.as_ptr(), option.bits()) };
SslOptions { bits }
}
@@ -1002,7 +1003,7 @@ impl SslContextBuilder {
///
/// [`SSL_CTX_get_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html
pub fn options(&self) -> SslOptions {
- let bits = unsafe { compat::SSL_CTX_get_options(self.as_ptr()) };
+ let bits = unsafe { ffi::SSL_CTX_get_options(self.as_ptr()) };
SslOptions { bits }
}
@@ -1012,7 +1013,7 @@ impl SslContextBuilder {
///
/// [`SSL_CTX_clear_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html
pub fn clear_options(&mut self, option: SslOptions) -> SslOptions {
- let bits = unsafe { compat::SSL_CTX_clear_options(self.as_ptr(), option.bits()) };
+ let bits = unsafe { ffi::SSL_CTX_clear_options(self.as_ptr(), option.bits()) };
SslOptions { bits }
}
@@ -1023,15 +1024,15 @@ impl SslContextBuilder {
///
/// This corresponds to [`SSL_CTX_set_min_proto_version`].
///
- /// Requires OpenSSL 1.1.0 or newer.
+ /// Requires OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer.
///
/// [`SSL_CTX_set_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html
- #[cfg(any(ossl110))]
+ #[cfg(any(ossl110, libressl261))]
pub fn set_min_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::SSL_CTX_set_min_proto_version(
self.as_ptr(),
- version.map_or(0, |v| v.0),
+ version.map_or(0, |v| v.0 as _),
)).map(|_| ())
}
}
@@ -1043,15 +1044,15 @@ impl SslContextBuilder {
///
/// This corresponds to [`SSL_CTX_set_max_proto_version`].
///
- /// Requires OpenSSL 1.1.0 or newer.
+ /// Requires OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer.
///
/// [`SSL_CTX_set_max_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html
- #[cfg(any(ossl110))]
+ #[cfg(any(ossl110, libressl261))]
pub fn set_max_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::SSL_CTX_set_max_proto_version(
self.as_ptr(),
- version.map_or(0, |v| v.0),
+ version.map_or(0, |v| v.0 as _),
)).map(|_| ())
}
}
@@ -1063,10 +1064,10 @@ impl SslContextBuilder {
///
/// This corresponds to [`SSL_CTX_get_min_proto_version`].
///
- /// Requires OpenSSL 1.1.0g or newer.
+ /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer.
///
/// [`SSL_CTX_get_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html
- #[cfg(any(ossl110g))]
+ #[cfg(any(ossl110g, libressl270))]
pub fn min_proto_version(&mut self) -> Option<SslVersion> {
unsafe {
let r = ffi::SSL_CTX_get_min_proto_version(self.as_ptr());
@@ -1085,10 +1086,10 @@ impl SslContextBuilder {
///
/// This corresponds to [`SSL_CTX_get_max_proto_version`].
///
- /// Requires OpenSSL 1.1.0g or newer.
+ /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer.
///
/// [`SSL_CTX_get_max_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html
- #[cfg(any(ossl110g))]
+ #[cfg(any(ossl110g, libressl270))]
pub fn max_proto_version(&mut self) -> Option<SslVersion> {
unsafe {
let r = ffi::SSL_CTX_get_max_proto_version(self.as_ptr());
@@ -1109,10 +1110,10 @@ impl SslContextBuilder {
///
/// This corresponds to [`SSL_CTX_set_alpn_protos`].
///
- /// Requires OpenSSL 1.0.2 or newer.
+ /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
///
/// [`SSL_CTX_set_alpn_protos`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_alpn_protos.html
- #[cfg(any(ossl102, ossl110))]
+ #[cfg(any(ossl102, libressl261))]
pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> {
unsafe {
assert!(protocols.len() <= c_uint::max_value() as usize);
@@ -1140,12 +1141,12 @@ impl SslContextBuilder {
///
/// This corresponds to [`SSL_CTX_set_alpn_select_cb`].
///
- /// Requires OpenSSL 1.0.2 or newer.
+ /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
///
/// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos
/// [`select_next_proto`]: fn.select_next_proto.html
/// [`SSL_CTX_set_alpn_select_cb`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_alpn_protos.html
- #[cfg(any(ossl102, ossl110))]
+ #[cfg(any(ossl102, libressl261))]
pub fn set_alpn_select_callback<F>(&mut self, callback: F)
where
F: for<'a> Fn(&mut SslRef, &'a [u8]) -> Result<&'a [u8], AlpnError> + 'static + Sync + Send,
@@ -1512,6 +1513,24 @@ impl SslContextBuilder {
}
}
+ /// Sets the maximum amount of early data that will be accepted on incoming connections.
+ ///
+ /// Defaults to 0.
+ ///
+ /// Requires OpenSSL 1.1.1 or newer.
+ ///
+ /// This corresponds to [`SSL_CTX_set_max_early_data`].
+ ///
+ /// [`SSL_CTX_set_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_max_early_data.html
+ #[cfg(ossl111)]
+ pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> {
+ if unsafe { ffi::SSL_CTX_set_max_early_data(self.as_ptr(), bytes) } == 1 {
+ Ok(())
+ } else {
+ Err(ErrorStack::get())
+ }
+ }
+
/// Consumes the builder, returning a new `SslContext`.
pub fn build(self) -> SslContext {
self.0
@@ -1537,7 +1556,7 @@ foreign_type_and_impl_send_sync! {
impl Clone for SslContext {
fn clone(&self) -> Self {
unsafe {
- compat::SSL_CTX_up_ref(self.as_ptr());
+ SSL_CTX_up_ref(self.as_ptr());
SslContext::from_ptr(self.as_ptr())
}
}
@@ -1570,7 +1589,7 @@ impl SslContext {
{
unsafe {
ffi::init();
- let idx = cvt_n(compat::get_new_idx(free_data_box::<T>))?;
+ let idx = cvt_n(get_new_idx(free_data_box::<T>))?;
Ok(Index::from_raw(idx))
}
}
@@ -1666,6 +1685,18 @@ impl SslContextRef {
}
}
}
+
+ /// Gets the maximum amount of early data that will be accepted on incoming connections.
+ ///
+ /// Requires OpenSSL 1.1.1 or newer.
+ ///
+ /// This corresponds to [`SSL_CTX_get_max_early_data`].
+ ///
+ /// [`SSL_CTX_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_get_max_early_data.html
+ #[cfg(ossl111)]
+ pub fn max_early_data(&self) -> u32 {
+ unsafe { ffi::SSL_CTX_get_max_early_data(self.as_ptr()) }
+ }
}
/// Information about the state of a cipher.
@@ -1814,7 +1845,7 @@ impl SslCipherRef {
}
}
-foreign_type! {
+foreign_type_and_impl_send_sync! {
type CType = ffi::SSL_SESSION;
fn drop = ffi::SSL_SESSION_free;
@@ -1829,9 +1860,6 @@ foreign_type! {
pub struct SslSessionRef;
}
-unsafe impl Sync for SslSession {}
-unsafe impl Send for SslSession {}
-
impl Clone for SslSession {
fn clone(&self) -> SslSession {
SslSessionRef::to_owned(self)
@@ -1856,7 +1884,7 @@ impl ToOwned for SslSessionRef {
fn to_owned(&self) -> SslSession {
unsafe {
- compat::SSL_SESSION_up_ref(self.as_ptr());
+ SSL_SESSION_up_ref(self.as_ptr());
SslSession(self.as_ptr())
}
}
@@ -1882,7 +1910,7 @@ impl SslSessionRef {
///
/// [`SSL_SESSION_get_master_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_SESSION_get_master_key.html
pub fn master_key_len(&self) -> usize {
- unsafe { compat::SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) }
+ unsafe { SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) }
}
/// Copies the master key into the provided buffer.
@@ -1893,7 +1921,19 @@ impl SslSessionRef {
///
/// [`SSL_SESSION_get_master_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_SESSION_get_master_key.html
pub fn master_key(&self, buf: &mut [u8]) -> usize {
- unsafe { compat::SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) }
+ unsafe { SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) }
+ }
+
+ /// Gets the maximum amount of early data that can be sent on this session.
+ ///
+ /// Requires OpenSSL 1.1.1 or newer.
+ ///
+ /// This corresponds to [`SSL_SESSION_get_max_early_data`].
+ ///
+ /// [`SSL_SESSION_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_SESSION_get_max_early_data.html
+ #[cfg(ossl111)]
+ pub fn max_early_data(&self) -> u32 {
+ unsafe { ffi::SSL_SESSION_get_max_early_data(self.as_ptr()) }
}
to_der! {
@@ -1907,7 +1947,7 @@ impl SslSessionRef {
}
}
-foreign_type! {
+foreign_type_and_impl_send_sync! {
type CType = ffi::SSL;
fn drop = ffi::SSL_free;
@@ -1925,9 +1965,6 @@ foreign_type! {
pub struct SslRef;
}
-unsafe impl Sync for Ssl {}
-unsafe impl Send for Ssl {}
-
impl fmt::Debug for Ssl {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, fmt)
@@ -1949,7 +1986,7 @@ impl Ssl {
{
unsafe {
ffi::init();
- let idx = cvt_n(compat::get_new_ssl_idx(free_data_box::<T>))?;
+ let idx = cvt_n(get_new_ssl_idx(free_data_box::<T>))?;
Ok(Index::from_raw(idx))
}
}
@@ -2114,7 +2151,7 @@ impl SslRef {
/// This corresponds to `SSL_set_tmp_ecdh_callback`.
///
/// [`SslContextBuilder::set_tmp_ecdh_callback`]: struct.SslContextBuilder.html#method.set_tmp_ecdh_callback
- #[cfg(any(ossl101, ossl102))]
+ #[cfg(any(all(ossl101, not(ossl110))))]
pub fn set_tmp_ecdh_callback<F>(&mut self, callback: F)
where
F: Fn(&mut SslRef, bool, u32) -> Result<EcKey<Params>, ErrorStack> + 'static + Sync + Send,
@@ -2134,7 +2171,7 @@ impl SslRef {
///
/// [`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(ossl102)]
+ #[cfg(all(ossl102, not(ossl110)))]
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(|_| ()) }
}
@@ -2234,6 +2271,30 @@ impl SslRef {
}
}
+ /// Returns the verified certificate chani of the peer, including the leaf certificate.
+ ///
+ /// If verification was not successful (i.e. [`verify_result`] does not return
+ /// [`X509VerifyResult::OK`]), this chain may be incomplete or invalid.
+ ///
+ /// Requires OpenSSL 1.1.0 or newer.
+ ///
+ /// This corresponds to [`SSL_get0_verified_chain`].
+ ///
+ /// [`verify_result`]: #method.verify_result
+ /// [`X509VerifyResult::OK`]: ../x509/struct.X509VerifyResult.html#associatedconstant.OK
+ /// [`SSL_get0_verified_chain`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get0_verified_chain.html
+ #[cfg(ossl110)]
+ pub fn verified_chain(&self) -> Option<&StackRef<X509>> {
+ unsafe {
+ let ptr = ffi::SSL_get0_verified_chain(self.as_ptr());
+ if ptr.is_null() {
+ None
+ } else {
+ Some(StackRef::from_ptr(ptr))
+ }
+ }
+ }
+
/// Like [`SslContext::certificate`].
///
/// This corresponds to `SSL_get_certificate`.
@@ -2306,12 +2367,12 @@ impl SslRef {
/// The protocol's name is returned is an opaque sequence of bytes. It is up to the client
/// to interpret it.
///
- /// Requires OpenSSL 1.0.2 or newer.
+ /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
///
/// 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(ossl102, ossl110))]
+ #[cfg(any(ossl102, libressl261))]
pub fn selected_alpn_protocol(&self) -> Option<&[u8]> {
unsafe {
let mut data: *const c_uchar = ptr::null();
@@ -2346,14 +2407,38 @@ impl SslRef {
///
/// This corresponds to [`SSL_get_servername`].
///
+ /// # Note
+ ///
+ /// While the SNI specification requires that servernames be valid domain names (and therefore
+ /// ASCII), OpenSSL does not enforce this restriction. If the servername provided by the client
+ /// is not valid UTF-8, this function will return `None`. The `servername_raw` method returns
+ /// the raw bytes and does not have this restriction.
+ ///
/// [`SSL_get_servername`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername.html
+ // FIXME maybe rethink in 0.11?
pub fn servername(&self, type_: NameType) -> Option<&str> {
+ self.servername_raw(type_)
+ .and_then(|b| str::from_utf8(b).ok())
+ }
+
+ /// 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`].
+ ///
+ /// # Note
+ ///
+ /// Unlike `servername`, this method does not require the name be valid UTF-8.
+ ///
+ /// [`SSL_get_servername`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername.html
+ pub fn servername_raw(&self, type_: NameType) -> Option<&[u8]> {
unsafe {
let name = ffi::SSL_get_servername(self.as_ptr(), type_.0);
if name == ptr::null() {
None
} else {
- Some(str::from_utf8(CStr::from_ptr(name as *const _).to_bytes()).unwrap())
+ Some(CStr::from_ptr(name as *const _).to_bytes())
}
}
}
@@ -2386,7 +2471,7 @@ impl SslRef {
/// This corresponds to [`SSL_get0_param`].
///
/// [`SSL_get0_param`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get0_param.html
- #[cfg(any(ossl102, ossl110))]
+ #[cfg(any(ossl102, libressl261))]
pub fn param_mut(&mut self) -> &mut X509VerifyParamRef {
unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) }
}
@@ -2479,6 +2564,36 @@ impl SslRef {
}
}
+ /// Derives keying material for application use in accordance to RFC 5705.
+ ///
+ /// This function is only usable with TLSv1.3, wherein there is no distinction between an empty context and no
+ /// context. Therefore, unlike `export_keying_material`, `context` must always be supplied.
+ ///
+ /// Requires OpenSSL 1.1.1 or newer.
+ ///
+ /// This corresponds to [`SSL_export_keying_material_early`].
+ ///
+ /// [`SSL_export_keying_material_early`]: https://www.openssl.org/docs/manmaster/man3/SSL_export_keying_material_early.html
+ #[cfg(ossl111)]
+ pub fn export_keying_material_early(
+ &self,
+ out: &mut [u8],
+ label: &str,
+ context: &[u8],
+ ) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::SSL_export_keying_material_early(
+ self.as_ptr(),
+ out.as_mut_ptr() as *mut c_uchar,
+ out.len(),
+ label.as_ptr() as *const c_char,
+ label.len(),
+ context.as_ptr() as *const c_uchar,
+ context.len(),
+ )).map(|_| ())
+ }
+ }
+
/// Sets the session to be used.
///
/// This should be called before the handshake to attempt to reuse a previously established
@@ -2564,7 +2679,7 @@ impl SslRef {
///
/// [`SSL_is_server`]: https://www.openssl.org/docs/manmaster/man3/SSL_is_server.html
pub fn is_server(&self) -> bool {
- unsafe { compat::SSL_is_server(self.as_ptr()) != 0 }
+ unsafe { SSL_is_server(self.as_ptr()) != 0 }
}
/// Sets the extra data at the specified index.
@@ -2617,6 +2732,57 @@ impl SslRef {
}
}
}
+
+ /// Sets the maximum amount of early data that will be accepted on this connection.
+ ///
+ /// Requires OpenSSL 1.1.1 or newer.
+ ///
+ /// This corresponds to [`SSL_set_max_early_data`].
+ ///
+ /// [`SSL_set_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_set_max_early_data.html
+ #[cfg(ossl111)]
+ pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> {
+ if unsafe { ffi::SSL_set_max_early_data(self.as_ptr(), bytes) } == 1 {
+ Ok(())
+ } else {
+ Err(ErrorStack::get())
+ }
+ }
+
+ /// Gets the maximum amount of early data that can be sent on this connection.
+ ///
+ /// Requires OpenSSL 1.1.1 or newer.
+ ///
+ /// This corresponds to [`SSL_get_max_early_data`].
+ ///
+ /// [`SSL_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_get_max_early_data.html
+ #[cfg(ossl111)]
+ pub fn max_early_data(&self) -> u32 {
+ unsafe { ffi::SSL_get_max_early_data(self.as_ptr()) }
+ }
+
+ /// Copies the contents of the last Finished message sent to the peer into the provided buffer.
+ ///
+ /// The total size of the message is returned, so this can be used to determine the size of the
+ /// buffer required.
+ ///
+ /// This corresponds to `SSL_get_finished`.
+ pub fn finished(&self, buf: &mut [u8]) -> usize {
+ unsafe { ffi::SSL_get_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) }
+ }
+
+ /// Copies the contents of the last Finished message received from the peer into the provided
+ /// buffer.
+ ///
+ /// The total size of the message is returned, so this can be used to determine the size of the
+ /// buffer required.
+ ///
+ /// This corresponds to `SSL_get_finished`.
+ pub fn peer_finished(&self, buf: &mut [u8]) -> usize {
+ unsafe {
+ ffi::SSL_get_peer_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len())
+ }
+ }
}
/// An SSL stream midway through the handshake process.
@@ -2860,7 +3026,8 @@ impl<S: Read + Write> Read for SslStream<S> {
}
Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {}
Err(e) => {
- return Err(e.into_io_error()
+ return Err(e
+ .into_io_error()
.unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e)))
}
}
@@ -2875,7 +3042,8 @@ impl<S: Read + Write> Write for SslStream<S> {
Ok(n) => return Ok(n),
Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {}
Err(e) => {
- return Err(e.into_io_error()
+ return Err(e
+ .into_io_error()
.unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e)))
}
}
@@ -2927,6 +3095,24 @@ where
}
}
+ /// 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.inner.ssl.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.inner.ssl.as_ptr()) }
+ }
+
/// See `Ssl::connect`
pub fn connect(self) -> Result<SslStream<S>, HandshakeError<S>> {
let mut stream = self.inner;
@@ -2967,7 +3153,91 @@ where
}
}
- // Future work: early IO methods
+ /// 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 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() {
+ ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => Err(HandshakeError::WouldBlock(
+ MidHandshakeSslStream { stream, error },
+ )),
+ _ => Err(HandshakeError::Failure(MidHandshakeSslStream {
+ stream,
+ error,
+ })),
+ }
+ }
+ }
+
+ /// Read application data transmitted by a client before handshake
+ /// completion.
+ ///
+ /// Useful for reducing latency, but vulnerable to replay attacks. Call
+ /// `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.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!(),
+ }
+ }
+
+ /// Send data to the server without blocking on handshake completion.
+ ///
+ /// Useful for reducing latency, but vulnerable to replay attacks. Call
+ /// `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.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))
+ }
+ }
}
impl<S> SslStreamBuilder<S> {
@@ -3008,133 +3278,88 @@ pub enum ShutdownResult {
Received,
}
-#[cfg(ossl110)]
-mod compat {
- use std::ptr;
-
- use ffi;
- use libc::c_int;
-
- pub use ffi::{
- SSL_CTX_clear_options, SSL_CTX_get_options, SSL_CTX_set_options, SSL_CTX_up_ref,
- SSL_SESSION_get_master_key, SSL_SESSION_up_ref, SSL_is_server,
- };
-
- pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
- ffi::CRYPTO_get_ex_new_index(
- ffi::CRYPTO_EX_INDEX_SSL_CTX,
- 0,
- ptr::null_mut(),
- None,
- None,
- Some(f),
- )
- }
-
- pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int {
- ffi::CRYPTO_get_ex_new_index(
- ffi::CRYPTO_EX_INDEX_SSL,
- 0,
- ptr::null_mut(),
- None,
- None,
- Some(f),
- )
- }
-
- pub fn tls_method() -> *const ffi::SSL_METHOD {
- unsafe { ffi::TLS_method() }
- }
-
- pub fn dtls_method() -> *const ffi::SSL_METHOD {
- unsafe { ffi::DTLS_method() }
- }
-}
-
-#[cfg(ossl10x)]
-#[allow(bad_style)]
-mod compat {
- use std::ptr;
-
- use ffi;
- use libc::{self, c_int, c_long, c_uchar, c_ulong, size_t};
-
- pub unsafe fn SSL_CTX_get_options(ctx: *const ffi::SSL_CTX) -> c_ulong {
- ffi::SSL_CTX_ctrl(ctx as *mut _, ffi::SSL_CTRL_OPTIONS, 0, ptr::null_mut()) as c_ulong
- }
-
- pub unsafe fn SSL_CTX_set_options(ctx: *const ffi::SSL_CTX, op: c_ulong) -> c_ulong {
- ffi::SSL_CTX_ctrl(
- ctx as *mut _,
- ffi::SSL_CTRL_OPTIONS,
- op as c_long,
- ptr::null_mut(),
- ) as c_ulong
- }
-
- pub unsafe fn SSL_CTX_clear_options(ctx: *const ffi::SSL_CTX, op: c_ulong) -> c_ulong {
- ffi::SSL_CTX_ctrl(
- ctx as *mut _,
- ffi::SSL_CTRL_CLEAR_OPTIONS,
- op as c_long,
- ptr::null_mut(),
- ) as c_ulong
- }
-
- pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
- ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f))
- }
+cfg_if! {
+ if #[cfg(ossl110)] {
+ use ffi::{
+ SSL_CTX_up_ref,
+ SSL_SESSION_get_master_key, SSL_SESSION_up_ref, SSL_is_server, TLS_method, DTLS_method,
+ };
- pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int {
- ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f))
- }
+ pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
+ ffi::CRYPTO_get_ex_new_index(
+ ffi::CRYPTO_EX_INDEX_SSL_CTX,
+ 0,
+ ptr::null_mut(),
+ None,
+ None,
+ Some(f),
+ )
+ }
- pub unsafe fn SSL_CTX_up_ref(ssl: *mut ffi::SSL_CTX) -> libc::c_int {
- ffi::CRYPTO_add_lock(
- &mut (*ssl).references,
- 1,
- ffi::CRYPTO_LOCK_SSL_CTX,
- "mod.rs\0".as_ptr() as *const _,
- line!() as libc::c_int,
- );
- 0
- }
+ pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int {
+ ffi::CRYPTO_get_ex_new_index(
+ ffi::CRYPTO_EX_INDEX_SSL,
+ 0,
+ ptr::null_mut(),
+ None,
+ None,
+ Some(f),
+ )
+ }
+ } else {
+ use ffi::{SSLv23_method as TLS_method, DTLSv1_method as DTLS_method};
- pub unsafe fn SSL_SESSION_get_master_key(
- session: *const ffi::SSL_SESSION,
- out: *mut c_uchar,
- mut outlen: size_t,
- ) -> size_t {
- if outlen == 0 {
- return (*session).master_key_length as size_t;
+ pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
+ ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f))
}
- if outlen > (*session).master_key_length as size_t {
- outlen = (*session).master_key_length as size_t;
+
+ pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int {
+ ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f))
}
- ptr::copy_nonoverlapping((*session).master_key.as_ptr(), out, outlen);
- outlen
- }
- pub fn tls_method() -> *const ffi::SSL_METHOD {
- unsafe { ffi::SSLv23_method() }
- }
+ #[allow(bad_style)]
+ pub unsafe fn SSL_CTX_up_ref(ssl: *mut ffi::SSL_CTX) -> c_int {
+ ffi::CRYPTO_add_lock(
+ &mut (*ssl).references,
+ 1,
+ ffi::CRYPTO_LOCK_SSL_CTX,
+ "mod.rs\0".as_ptr() as *const _,
+ line!() as c_int,
+ );
+ 0
+ }
- pub fn dtls_method() -> *const ffi::SSL_METHOD {
- unsafe { ffi::DTLSv1_method() }
- }
+ #[allow(bad_style)]
+ pub unsafe fn SSL_SESSION_get_master_key(
+ session: *const ffi::SSL_SESSION,
+ out: *mut c_uchar,
+ mut outlen: usize,
+ ) -> usize {
+ if outlen == 0 {
+ return (*session).master_key_length as usize;
+ }
+ if outlen > (*session).master_key_length as usize {
+ outlen = (*session).master_key_length as usize;
+ }
+ ptr::copy_nonoverlapping((*session).master_key.as_ptr(), out, outlen);
+ outlen
+ }
- pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int {
- (*s).server
- }
+ #[allow(bad_style)]
+ pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int {
+ (*s).server
+ }
- pub unsafe fn SSL_SESSION_up_ref(ses: *mut ffi::SSL_SESSION) -> c_int {
- ffi::CRYPTO_add_lock(
- &mut (*ses).references,
- 1,
- ffi::CRYPTO_LOCK_SSL_CTX,
- "mod.rs\0".as_ptr() as *const _,
- line!() as libc::c_int,
- );
- 0
+ #[allow(bad_style)]
+ pub unsafe fn SSL_SESSION_up_ref(ses: *mut ffi::SSL_SESSION) -> c_int {
+ ffi::CRYPTO_add_lock(
+ &mut (*ses).references,
+ 1,
+ ffi::CRYPTO_LOCK_SSL_CTX,
+ "mod.rs\0".as_ptr() as *const _,
+ line!() as c_int,
+ );
+ 0
+ }
}
}