diff --git a/.travis.yml b/.travis.yml index ccaf12f1738e0f1943cb4fcc069d51b3761482e7..95afcc5bb95336f3e0fd23147d282263b4bf860f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -77,8 +77,7 @@ matrix: before_install: - ./openssl/test/build.sh - - curl https://static.rust-lang.org/rustup.sh | - sh -s -- --add-target=$TARGET --disable-sudo -y --prefix=`rustc --print sysroot` + - rustup target add $TARGET || true script: - ./openssl/test/run.sh diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 3ca5c718f2e7f069f8ad3f14d591a2a473bb5322..737cb930ed8167012552995bf83c1b9584014766 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1356,7 +1356,7 @@ pub unsafe fn SSL_CTX_add_extra_chain_cert(ctx: *mut SSL_CTX, x509: *mut X509) - #[cfg(not(any(ossl101, libressl)))] pub unsafe fn SSL_CTX_set0_verify_cert_store(ctx: *mut SSL_CTX, st: *mut X509_STORE) -> c_long { - SSL_CTX_ctrl(ctx, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, st as *mut c_void) + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, st as *mut c_void) } pub unsafe fn SSL_CTX_set_tlsext_servername_callback(ctx: *mut SSL_CTX, @@ -1891,6 +1891,7 @@ extern { client: *const c_uchar, client_len: c_uint) -> c_int; pub fn SSL_get0_next_proto_negotiated(s: *const SSL, data: *mut *const c_uchar, len: *mut c_uint); pub fn SSL_get_session(s: *const SSL) -> *mut SSL_SESSION; + pub fn SSL_set_session(ssl: *mut SSL, session: *mut SSL_SESSION) -> c_int; #[cfg(not(any(ossl101, libressl)))] pub fn SSL_is_server(s: *mut SSL) -> c_int; diff --git a/openssl-sys/src/libressl.rs b/openssl-sys/src/libressl.rs index dc3bfe11e8b015ab329d92d9340e4235d5f977c5..d43587f05b440e4c525569ba9dfbedf91cc9e497 100644 --- a/openssl-sys/src/libressl.rs +++ b/openssl-sys/src/libressl.rs @@ -1,6 +1,7 @@ use std::sync::{Mutex, MutexGuard}; use std::sync::{Once, ONCE_INIT}; use std::mem; +use std::ptr; use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong}; use libc::time_t; @@ -500,7 +501,7 @@ pub struct SSL_SESSION { verify_result: c_long, timeout: c_long, time: time_t, - references: c_int, + pub references: c_int, cipher: *const c_void, cipher_id: c_ulong, ciphers: *mut c_void, @@ -533,6 +534,7 @@ pub struct X509_VERIFY_PARAM { pub enum X509_VERIFY_PARAM_ID {} pub enum PKCS12 {} +pub const SSL_CTRL_GET_SESSION_REUSED: c_int = 8; pub const SSL_CTRL_OPTIONS: c_int = 32; pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94; @@ -565,6 +567,7 @@ pub const SSLEAY_DIR : c_int = 5; pub const CRYPTO_LOCK_X509: c_int = 3; pub const CRYPTO_LOCK_SSL_CTX: c_int = 12; +pub const CRYPTO_LOCK_SSL_SESSION: c_int = 14; static mut MUTEXES: *mut Vec> = 0 as *mut Vec>; static mut GUARDS: *mut Vec>> = 0 as *mut Vec>>; @@ -622,11 +625,15 @@ fn set_id_callback() {} // macros pub unsafe fn SSL_CTX_set_ecdh_auto(ctx: *mut SSL_CTX, onoff: c_int) -> c_int { - ::SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ::std::ptr::null_mut()) as c_int + ::SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ptr::null_mut()) as c_int } pub unsafe fn SSL_set_ecdh_auto(ssl: *mut ::SSL, onoff: c_int) -> c_int { - ::SSL_ctrl(ssl, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ::std::ptr::null_mut()) as c_int + ::SSL_ctrl(ssl, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ptr::null_mut()) as c_int +} + +pub unsafe fn SSL_session_reused(ssl: *mut ::SSL) -> c_int { + ::SSL_ctrl(ssl, SSL_CTRL_GET_SESSION_REUSED, 0, ptr::null_mut()) as c_int } extern { diff --git a/openssl-sys/src/ossl10x.rs b/openssl-sys/src/ossl10x.rs index fade0f9995a84544c41d78efceaecc35ce8909ee..23c0ee722abda0db4190f29dfaca9167fa13a891 100644 --- a/openssl-sys/src/ossl10x.rs +++ b/openssl-sys/src/ossl10x.rs @@ -1,6 +1,7 @@ use std::sync::{Mutex, MutexGuard}; use std::sync::{Once, ONCE_INIT}; use std::mem; +use std::ptr; use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong}; #[cfg(not(ossl101))] @@ -610,7 +611,7 @@ pub struct SSL_SESSION { sess_cert: *mut c_void, peer: *mut X509, verify_result: c_long, - references: c_int, + pub references: c_int, timeout: c_long, time: c_long, compress_meth: c_uint, @@ -678,6 +679,7 @@ pub struct X509_VERIFY_PARAM { pub enum X509_VERIFY_PARAM_ID {} pub enum PKCS12 {} +pub const SSL_CTRL_GET_SESSION_REUSED: c_int = 8; pub const SSL_CTRL_OPTIONS: c_int = 32; pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; #[cfg(ossl102)] @@ -708,6 +710,7 @@ pub const SSLEAY_DIR : c_int = 5; pub const CRYPTO_LOCK_X509: c_int = 3; pub const CRYPTO_LOCK_SSL_CTX: c_int = 12; +pub const CRYPTO_LOCK_SSL_SESSION: c_int = 14; static mut MUTEXES: *mut Vec> = 0 as *mut Vec>; static mut GUARDS: *mut Vec>> = 0 as *mut Vec>>; @@ -766,12 +769,16 @@ fn set_id_callback() {} #[cfg(ossl102)] pub unsafe fn SSL_CTX_set_ecdh_auto(ctx: *mut SSL_CTX, onoff: c_int) -> c_int { - ::SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ::std::ptr::null_mut()) as c_int + ::SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ptr::null_mut()) as c_int } #[cfg(ossl102)] pub unsafe fn SSL_set_ecdh_auto(ssl: *mut ::SSL, onoff: c_int) -> c_int { - ::SSL_ctrl(ssl, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ::std::ptr::null_mut()) as c_int + ::SSL_ctrl(ssl, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ptr::null_mut()) as c_int +} + +pub unsafe fn SSL_session_reused(ssl: *mut ::SSL) -> c_int { + ::SSL_ctrl(ssl, SSL_CTRL_GET_SESSION_REUSED, 0, ptr::null_mut()) as c_int } extern { diff --git a/openssl-sys/src/ossl110.rs b/openssl-sys/src/ossl110.rs index 37564c7a49c18b224b1660dc35374b00f69d43aa..e83e04542b1e029b965687dc9dd405c83d661eec 100644 --- a/openssl-sys/src/ossl110.rs +++ b/openssl-sys/src/ossl110.rs @@ -172,10 +172,12 @@ extern { -> c_int; pub fn X509_up_ref(x: *mut X509) -> c_int; pub fn SSL_CTX_up_ref(x: *mut SSL_CTX) -> c_int; + pub fn SSL_session_reused(ssl: *mut SSL) -> c_int; pub fn SSL_SESSION_get_master_key(session: *const SSL_SESSION, out: *mut c_uchar, outlen: size_t) -> size_t; + pub fn SSL_SESSION_up_ref(ses: *mut SSL_SESSION) -> c_int; pub fn X509_get0_extensions(req: *const ::X509) -> *const stack_st_X509_EXTENSION; pub fn X509_STORE_CTX_get0_chain(ctx: *mut ::X509_STORE_CTX) -> *mut stack_st_X509; pub fn EVP_MD_CTX_new() -> *mut EVP_MD_CTX; diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 73d7b675051f7409636d0dab325754d7dc1008d2..548e3e97c1b78c3fce1eb0c589d06249fdb8fa81 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -93,11 +93,7 @@ impl SslConnector { pub fn connect(&self, domain: &str, stream: S) -> Result, HandshakeError> where S: Read + Write { - let mut ssl = try!(Ssl::new(&self.0)); - try!(ssl.set_hostname(domain)); - try!(setup_verify(&mut ssl, domain)); - - ssl.connect(stream) + try!(self.configure()).connect(domain, stream) } /// Initiates a client-side TLS session on a stream without performing hostname verification. @@ -113,7 +109,56 @@ impl SslConnector { &self, stream: S) -> Result, HandshakeError> where S: Read + Write { - try!(Ssl::new(&self.0)).connect(stream) + try!(self.configure()) + .danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(stream) + } + + /// Returns a structure allowing for configuration of a single TLS session before connection. + pub fn configure(&self) -> Result { + Ssl::new(&self.0).map(ConnectConfiguration) + } +} + +/// A type which allows for configuration of a client-side TLS session before connection. +pub struct ConnectConfiguration(Ssl); + +impl ConnectConfiguration { + /// Returns a shared reference to the inner `Ssl`. + pub fn ssl(&self) -> &Ssl { + &self.0 + } + + /// Returns a mutable reference to the inner `Ssl`. + pub fn ssl_mut(&mut self) -> &mut Ssl { + &mut self.0 + } + + /// Initiates a client-side TLS session on a stream. + /// + /// The domain is used for SNI and hostname verification. + pub fn connect(mut self, domain: &str, stream: S) -> Result, HandshakeError> + where S: Read + Write + { + try!(self.0.set_hostname(domain)); + try!(setup_verify(&mut self.0, domain)); + + self.0.connect(stream) + } + + /// Initiates a client-side TLS session on a stream without performing hostname verification. + /// + /// The verification configuration of the connector's `SslContext` is not overridden. + /// + /// # Warning + /// + /// You should think very carefully before you use this method. If hostname verification is not + /// used, *any* valid certificate for *any* site will be trusted for use from any other. This + /// introduces a significant vulnerability to man-in-the-middle attacks. + pub fn danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication( + self, stream: S) -> Result, HandshakeError> + where S: Read + Write + { + self.0.connect(stream) } } diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 7fd5a2d0da3adcd6487eb6d9c4b1fb54e23cd461..0f24499d3f7e2676164744f061ef208c133a53fd 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -76,6 +76,7 @@ use libc::{c_int, c_void, c_long, c_ulong}; use libc::{c_uchar, c_uint}; use std::any::Any; use std::any::TypeId; +use std::borrow::Borrow; use std::cmp; use std::collections::HashMap; use std::ffi::{CStr, CString}; @@ -1161,6 +1162,32 @@ foreign_type! { pub struct SslSessionRef; } +unsafe impl Sync for SslSession {} +unsafe impl Send for SslSession {} + +impl Clone for SslSession { + fn clone(&self) -> SslSession { + self.to_owned() + } +} + +impl Borrow for SslSession { + fn borrow(&self) -> &SslSessionRef { + &self + } +} + +impl ToOwned for SslSessionRef { + type Owned = SslSession; + + fn to_owned(&self) -> SslSession { + unsafe { + compat::SSL_SESSION_up_ref(self.as_ptr()); + SslSession(self.as_ptr()) + } + } +} + impl SslSessionRef { /// Returns the SSL session ID. pub fn id(&self) -> &[u8] { @@ -1508,6 +1535,23 @@ impl SslRef { } } + /// Sets the session to be used. + /// + /// # Safety + /// + /// The caller of this method is responsible for ensuring that the session is associated + /// with the same `SslContext` as this `Ssl`. + pub unsafe fn set_session(&mut self, session: &SslSessionRef) -> Result<(), ErrorStack> { + cvt(ffi::SSL_set_session(self.as_ptr(), session.as_ptr())).map(|_| ()) + } + + /// Determines if the session provided to `set_session` was successfully reused. + pub fn session_reused(&self) -> bool { + unsafe { + ffi::SSL_session_reused(self.as_ptr()) != 0 + } + } + /// Sets the status response a client wishes the server to reply with. pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> { unsafe { @@ -1918,7 +1962,7 @@ mod compat { use libc::c_int; pub use ffi::{SSL_CTX_get_options, SSL_CTX_set_options, SSL_CTX_clear_options, SSL_CTX_up_ref, - SSL_SESSION_get_master_key, SSL_is_server}; + SSL_SESSION_get_master_key, SSL_is_server, SSL_SESSION_up_ref}; 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, @@ -2014,4 +2058,13 @@ mod compat { 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 + } }