From aa7c27536ad56def21afad4043d6d658f517ecc4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 8 Nov 2016 22:38:48 +0000 Subject: Make sure to override SslContext verify callback always The 1.0.1 code has to override this to setup hostname validation, and don't want behavior to silently change depending on the OpenSSL version you're building against. --- openssl/src/ssl/connector.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 55177767..c5189c9e 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -255,7 +255,9 @@ impl SslAcceptor { #[cfg(any(ossl102, ossl110))] fn setup_verify(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { - ssl.set_verify(SSL_VERIFY_PEER); + // pass a noop closure in here to ensure that we consistently override any callback on the + // context + ssl.set_verify_callback(SSL_VERIFY_PEER, |p, _| p); let param = ssl._param_mut(); param.set_hostflags(::verify::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); param.set_host(domain) -- cgit v1.2.3 From a42c6e8713702175001686c6f146bb4b99023613 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 9 Nov 2016 20:35:23 +0000 Subject: Drop rustc-serialize dependency --- openssl/src/ssl/tests/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 146d0806..96c0d585 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -11,7 +11,6 @@ use std::path::Path; use std::process::{Command, Child, Stdio, ChildStdin}; use std::thread; use std::time::Duration; - use tempdir::TempDir; use hash::MessageDigest; @@ -170,7 +169,7 @@ macro_rules! run_test( use ssl::SSL_VERIFY_PEER; use hash::MessageDigest; use x509::X509StoreContext; - use serialize::hex::FromHex; + use hex::FromHex; use types::OpenSslTypeRef; use super::Server; @@ -302,7 +301,7 @@ run_test!(verify_callback_data, |method, stream| { // Command: openssl x509 -in test/cert.pem -outform DER | openssl dgst -sha256 // Please update if "test/cert.pem" will ever change let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; - let node_id = node_hash_str.from_hex().unwrap(); + let node_id = Vec::from_hex(node_hash_str).unwrap(); ctx.set_verify_callback(SSL_VERIFY_PEER, move |_preverify_ok, x509_ctx| { let cert = x509_ctx.current_cert(); match cert { @@ -330,7 +329,7 @@ run_test!(ssl_verify_callback, |method, stream| { let mut ssl = Ssl::new(&ctx.build()).unwrap(); let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; - let node_id = node_hash_str.from_hex().unwrap(); + let node_id = Vec::from_hex(node_hash_str).unwrap(); ssl.set_verify_callback(SSL_VERIFY_PEER, move |_, x509| { CHECKED.store(1, Ordering::SeqCst); match x509.current_cert() { @@ -427,7 +426,7 @@ run_test!(get_peer_certificate, |method, stream| { let cert = stream.ssl().peer_certificate().unwrap(); let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap(); let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; - let node_id = node_hash_str.from_hex().unwrap(); + let node_id = Vec::from_hex(node_hash_str).unwrap(); assert_eq!(node_id, fingerprint) }); -- cgit v1.2.3 From 898e7f02df5ca722f4b4b42a8e116f96f72b9452 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Nov 2016 15:10:30 +0000 Subject: Fix EOF detection See https://github.com/openssl/openssl/issues/1903 for details --- openssl/src/ssl/mod.rs | 54 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 19 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 1e7efc63..c92bf56b 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1323,10 +1323,14 @@ impl SslStream { /// value will identify if OpenSSL is waiting on read or write readiness. pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result { let ret = self.ssl.read(buf); - if ret >= 0 { + if ret > 0 { Ok(ret as usize) } else { - Err(self.make_error(ret)) + match self.make_error(ret) { + // Don't treat unexpected EOFs as errors when reading + Error::Stream(ref e) if e.kind() == io::ErrorKind::ConnectionAborted => Ok(0), + e => Err(e), + } } } @@ -1336,7 +1340,7 @@ impl SslStream { /// value will identify if OpenSSL is waiting on read or write readiness. pub fn ssl_write(&mut self, buf: &[u8]) -> Result { let ret = self.ssl.write(buf); - if ret >= 0 { + if ret > 0 { Ok(ret as usize) } else { Err(self.make_error(ret)) @@ -1373,19 +1377,38 @@ impl SslStream { ffi::SSL_ERROR_SYSCALL => { let errs = ErrorStack::get(); if errs.errors().is_empty() { - if ret == 0 { - Error::Stream(io::Error::new(io::ErrorKind::ConnectionAborted, - "unexpected EOF observed")) - } else { - Error::Stream(self.get_bio_error()) + match self.get_bio_error() { + Some(err) => Error::Stream(err), + None => { + Error::Stream(io::Error::new(io::ErrorKind::ConnectionAborted, + "unexpected EOF observed")) + } } } else { Error::Ssl(errs) } } ffi::SSL_ERROR_ZERO_RETURN => Error::ZeroReturn, - ffi::SSL_ERROR_WANT_WRITE => Error::WantWrite(self.get_bio_error()), - ffi::SSL_ERROR_WANT_READ => Error::WantRead(self.get_bio_error()), + ffi::SSL_ERROR_WANT_WRITE => { + let err = match self.get_bio_error() { + Some(err) => err, + None => { + io::Error::new(io::ErrorKind::Other, + "BUG: got an SSL_ERROR_WANT_WRITE with no error in the BIO") + } + }; + Error::WantWrite(err) + }, + ffi::SSL_ERROR_WANT_READ => { + let err = match self.get_bio_error() { + Some(err) => err, + None => { + io::Error::new(io::ErrorKind::Other, + "BUG: got an SSL_ERROR_WANT_WRITE with no error in the BIO") + } + }; + Error::WantRead(err) + }, err => { Error::Stream(io::Error::new(io::ErrorKind::InvalidData, format!("unexpected error {}", err))) @@ -1399,15 +1422,8 @@ impl SslStream { } } - fn get_bio_error(&mut self) -> io::Error { - let error = unsafe { bio::take_error::(self.ssl.get_raw_rbio()) }; - match error { - Some(error) => error, - None => { - io::Error::new(io::ErrorKind::Other, - "BUG: got an ErrorSyscall without an error in the BIO?") - } - } + fn get_bio_error(&mut self) -> Option { + unsafe { bio::take_error::(self.ssl.get_raw_rbio()) } } /// Returns a reference to the underlying stream. -- cgit v1.2.3 From 26a3358a2b70b46bf06403b2810c379f5299a551 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 00:24:12 +0000 Subject: Add basic X509_STORE access There's more to do here, but this enabled addition of trusted CAs from X509 objects. Closes #394 --- openssl/src/ssl/mod.rs | 11 +++++++++++ openssl/src/ssl/tests/mod.rs | 14 ++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index c92bf56b..1e0d2e66 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -94,6 +94,7 @@ use {init, cvt, cvt_p}; use dh::DhRef; use ec_key::EcKeyRef; use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError, X509Name}; +use x509::store::X509StoreBuilderRef; #[cfg(any(ossl102, ossl110))] use verify::X509VerifyParamRef; use pkey::PKeyRef; @@ -739,6 +740,16 @@ impl SslContextBuilder { unsafe { cvt(ffi::SSL_CTX_check_private_key(self.as_ptr())).map(|_| ()) } } + /// Returns a shared reference to the context's certificate store. + pub fn cert_store(&self) -> &X509StoreBuilderRef { + unsafe { X509StoreBuilderRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) } + } + + /// Returns a mutable reference to the context's certificate store. + pub fn cert_store_mut(&mut self) -> &mut X509StoreBuilderRef { + unsafe { X509StoreBuilderRef::from_ptr_mut(ffi::SSL_CTX_get_cert_store(self.as_ptr())) } + } + pub fn build(self) -> SslContext { let ctx = SslContext(self.0); mem::forget(self); diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 96c0d585..fa7c6024 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -28,6 +28,7 @@ use std::net::UdpSocket; mod select; +static ROOT_CERT: &'static [u8] = include_bytes!("../../../test/root-ca.pem"); static CERT: &'static [u8] = include_bytes!("../../../test/cert.pem"); static KEY: &'static [u8] = include_bytes!("../../../test/key.pem"); @@ -1192,6 +1193,19 @@ fn client_ca_list() { ctx.set_client_ca_list(names); } +#[test] +fn cert_store() { + let (_s, tcp) = Server::new(); + + let cert = X509::from_pem(ROOT_CERT).unwrap(); + + let mut ctx = SslConnectorBuilder::new(SslMethod::tls()).unwrap(); + ctx.builder_mut().cert_store_mut().add_cert(cert).unwrap(); + let ctx = ctx.build(); + + ctx.connect("foobar.com", tcp).unwrap(); +} + fn _check_kinds() { fn is_send() {} fn is_sync() {} -- cgit v1.2.3 From 563754fb0892ebf8021bb6043f4540c98f3b86a6 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 12:43:44 +0000 Subject: Add SslContextBuilder::set_tmp_{ec,}dh_callback --- openssl/src/ssl/mod.rs | 91 +++++++++++++++++++++++++++++++++++++++++--- openssl/src/ssl/tests/mod.rs | 65 +++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 6 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 1e0d2e66..ed3f023c 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -91,8 +91,10 @@ use std::str; use std::sync::Mutex; use {init, cvt, cvt_p}; -use dh::DhRef; +use dh::{Dh, DhRef}; use ec_key::EcKeyRef; +#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] +use ec_key::EcKey; use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError, X509Name}; use x509::store::X509StoreBuilderRef; #[cfg(any(ossl102, ossl110))] @@ -219,7 +221,7 @@ lazy_static! { // Creates a static index for user data of type T // Registers a destructor for the data which will be called // when context is freed -fn get_verify_data_idx() -> c_int { +fn get_callback_idx() -> c_int { *INDEXES.lock().unwrap().entry(TypeId::of::()).or_insert_with(|| get_new_idx::()) } @@ -272,7 +274,7 @@ extern "C" fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_ let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx(); let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx); let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl as *const _); - let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::()); + let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::()); let verify: &F = &*(verify as *mut F); let ctx = X509StoreContextRef::from_ptr(x509_ctx); @@ -301,7 +303,7 @@ extern "C" fn raw_sni(ssl: *mut ffi::SSL, al: *mut c_int, _arg: *mut c_void) { unsafe { let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); - let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::()); + let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::()); let callback: &F = &*(callback as *mut F); let ssl = SslRef::from_ptr_mut(ssl); @@ -373,6 +375,55 @@ extern "C" fn raw_alpn_select_cb(ssl: *mut ffi::SSL, unsafe { select_proto_using(ssl, out as *mut _, outlen, inbuf, inlen, *ALPN_PROTOS_IDX) } } +unsafe extern fn raw_tmp_dh(ssl: *mut ffi::SSL, + is_export: c_int, + keylength: c_int) + -> *mut ffi::DH + where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send +{ + let ctx = ffi::SSL_get_SSL_CTX(ssl); + let callback = ffi::SSL_CTX_get_ex_data(ctx, get_callback_idx::()); + let callback = &*(callback as *mut F); + + let ssl = SslRef::from_ptr_mut(ssl); + match callback(ssl, is_export != 0, keylength as u32) { + Ok(dh) => { + let ptr = dh.as_ptr(); + mem::forget(dh); + ptr + } + Err(_) => { + // FIXME reset error stack + ptr::null_mut() + } + } +} + +#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] +unsafe extern fn raw_tmp_ecdh(ssl: *mut ffi::SSL, + is_export: c_int, + keylength: c_int) + -> *mut ffi::EC_KEY + where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send +{ + let ctx = ffi::SSL_get_SSL_CTX(ssl); + let callback = ffi::SSL_CTX_get_ex_data(ctx, get_callback_idx::()); + let callback = &*(callback as *mut F); + + let ssl = SslRef::from_ptr_mut(ssl); + match callback(ssl, is_export != 0, keylength as u32) { + Ok(ec_key) => { + let ptr = ec_key.as_ptr(); + mem::forget(ec_key); + ptr + } + Err(_) => { + // FIXME reset error stack + ptr::null_mut() + } + } +} + /// The function is given as the callback to `SSL_CTX_set_next_protos_advertised_cb`. /// /// It causes the parameter `out` to point at a `*const c_uchar` instance that @@ -472,7 +523,7 @@ impl SslContextBuilder { unsafe { let verify = Box::new(verify); ffi::SSL_CTX_set_ex_data(self.as_ptr(), - get_verify_data_idx::(), + get_callback_idx::(), mem::transmute(verify)); ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, Some(raw_verify::)); } @@ -488,7 +539,7 @@ impl SslContextBuilder { unsafe { let callback = Box::new(callback); ffi::SSL_CTX_set_ex_data(self.as_ptr(), - get_verify_data_idx::(), + get_callback_idx::(), mem::transmute(callback)); let f: extern "C" fn(_, _, _) -> _ = raw_sni::; let f: extern "C" fn() = mem::transmute(f); @@ -520,10 +571,38 @@ impl SslContextBuilder { unsafe { cvt(ffi::SSL_CTX_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) } } + pub fn set_tmp_dh_callback(&mut self, callback: F) + where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send + { + unsafe { + let callback = Box::new(callback); + ffi::SSL_CTX_set_ex_data(self.as_ptr(), + get_callback_idx::(), + Box::into_raw(callback) as *mut c_void); + let f: unsafe extern fn (_, _, _) -> _ = raw_tmp_dh::; + ffi::SSL_CTX_set_tmp_dh_callback(self.as_ptr(), f); + } + } + pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) } } + /// Requires the `v101` feature and OpenSSL 1.0.1, or the `v102` feature and OpenSSL 1.0.2. + #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] + pub fn set_tmp_ecdh_callback(&mut self, callback: F) + where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send + { + unsafe { + let callback = Box::new(callback); + ffi::SSL_CTX_set_ex_data(self.as_ptr(), + get_callback_idx::(), + Box::into_raw(callback) as *mut c_void); + let f: unsafe extern fn(_, _, _) -> _ = raw_tmp_ecdh::; + ffi::SSL_CTX_set_tmp_ecdh_callback(self.as_ptr(), f); + } + } + /// Use the default locations of trusted certificates for verification. /// /// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR` diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index fa7c6024..d79e5386 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -9,10 +9,12 @@ use std::mem; use std::net::{TcpStream, TcpListener, SocketAddr}; use std::path::Path; use std::process::{Command, Child, Stdio, ChildStdin}; +use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; use std::thread; use std::time::Duration; use tempdir::TempDir; +use dh::Dh; use hash::MessageDigest; use ssl; use ssl::SSL_VERIFY_PEER; @@ -1206,6 +1208,69 @@ fn cert_store() { ctx.connect("foobar.com", tcp).unwrap(); } +#[test] +fn tmp_dh_callback() { + static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; + + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + + thread::spawn(move ||{ + let stream = listener.accept().unwrap().0; + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM).unwrap(); + ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM).unwrap(); + ctx.set_tmp_dh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + let dh = include_bytes!("../../../test/dhparams.pem"); + Dh::from_pem(dh) + }); + let ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.accept(stream).unwrap(); + }); + + let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_cipher_list("DHE").unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.connect(stream).unwrap(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] +fn tmp_ecdh_callback() { + use ec_key::EcKey; + use nid; + + static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; + + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + + thread::spawn(move ||{ + let stream = listener.accept().unwrap().0; + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM).unwrap(); + ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM).unwrap(); + ctx.set_tmp_ecdh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + EcKey::new_by_curve_name(nid::X9_62_PRIME256V1) + }); + let ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.accept(stream).unwrap(); + }); + + let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_cipher_list("ECDHE").unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.connect(stream).unwrap(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + fn _check_kinds() { fn is_send() {} fn is_sync() {} -- cgit v1.2.3 From 780c46e0e722f683ba6a8b7a8b2a7924e49695c3 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 12:56:58 +0000 Subject: Add SslRef::set_tmp_{ec,}dh_calback --- openssl/src/ssl/mod.rs | 81 ++++++++++++++++++++++++++++++++++++++++++-- openssl/src/ssl/tests/mod.rs | 63 ++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+), 3 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index ed3f023c..bcaa4c74 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -225,7 +225,7 @@ fn get_callback_idx() -> c_int { *INDEXES.lock().unwrap().entry(TypeId::of::()).or_insert_with(|| get_new_idx::()) } -fn get_ssl_verify_data_idx() -> c_int { +fn get_ssl_callback_idx() -> c_int { *SSL_INDEXES.lock().unwrap().entry(TypeId::of::()).or_insert_with(|| get_new_ssl_idx::()) } @@ -289,7 +289,7 @@ extern "C" fn ssl_raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_ST unsafe { let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx(); let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx); - let verify = ffi::SSL_get_ex_data(ssl as *const _, get_ssl_verify_data_idx::()); + let verify = ffi::SSL_get_ex_data(ssl as *const _, get_ssl_callback_idx::()); let verify: &F = &*(verify as *mut F); let ctx = X509StoreContextRef::from_ptr(x509_ctx); @@ -424,6 +424,53 @@ unsafe extern fn raw_tmp_ecdh(ssl: *mut ffi::SSL, } } +unsafe extern fn raw_tmp_dh_ssl(ssl: *mut ffi::SSL, + is_export: c_int, + keylength: c_int) + -> *mut ffi::DH + where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send +{ + let callback = ffi::SSL_get_ex_data(ssl, get_ssl_callback_idx::()); + let callback = &*(callback as *mut F); + + let ssl = SslRef::from_ptr_mut(ssl); + match callback(ssl, is_export != 0, keylength as u32) { + Ok(dh) => { + let ptr = dh.as_ptr(); + mem::forget(dh); + ptr + } + Err(_) => { + // FIXME reset error stack + ptr::null_mut() + } + } +} + +#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] +unsafe extern fn raw_tmp_ecdh_ssl(ssl: *mut ffi::SSL, + is_export: c_int, + keylength: c_int) + -> *mut ffi::EC_KEY + where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send +{ + let callback = ffi::SSL_get_ex_data(ssl, get_ssl_callback_idx::()); + let callback = &*(callback as *mut F); + + let ssl = SslRef::from_ptr_mut(ssl); + match callback(ssl, is_export != 0, keylength as u32) { + Ok(ec_key) => { + let ptr = ec_key.as_ptr(); + mem::forget(ec_key); + ptr + } + Err(_) => { + // FIXME reset error stack + ptr::null_mut() + } + } +} + /// The function is given as the callback to `SSL_CTX_set_next_protos_advertised_cb`. /// /// It causes the parameter `out` to point at a `*const c_uchar` instance that @@ -1030,12 +1077,40 @@ impl SslRef { unsafe { let verify = Box::new(verify); ffi::SSL_set_ex_data(self.as_ptr(), - get_ssl_verify_data_idx::(), + get_ssl_callback_idx::(), mem::transmute(verify)); ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, Some(ssl_raw_verify::)); } } + pub fn set_tmp_dh_callback(&mut self, callback: F) + where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send + { + unsafe { + let callback = Box::new(callback); + ffi::SSL_set_ex_data(self.as_ptr(), + get_ssl_callback_idx::(), + Box::into_raw(callback) as *mut c_void); + let f: unsafe extern fn (_, _, _) -> _ = raw_tmp_dh_ssl::; + ffi::SSL_set_tmp_dh_callback(self.as_ptr(), f); + } + } + + /// Requires the `v101` feature and OpenSSL 1.0.1, or the `v102` feature and OpenSSL 1.0.2. + #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] + pub fn set_tmp_ecdh_callback(&mut self, callback: F) + where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send + { + unsafe { + let callback = Box::new(callback); + ffi::SSL_set_ex_data(self.as_ptr(), + get_ssl_callback_idx::(), + Box::into_raw(callback) as *mut c_void); + let f: unsafe extern fn(_, _, _) -> _ = raw_tmp_ecdh_ssl::; + ffi::SSL_set_tmp_ecdh_callback(self.as_ptr(), f); + } + } + pub fn current_cipher(&self) -> Option<&SslCipherRef> { unsafe { let ptr = ffi::SSL_get_current_cipher(self.as_ptr()); diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index d79e5386..e2afb6f7 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1271,6 +1271,69 @@ fn tmp_ecdh_callback() { assert!(CALLED_BACK.load(Ordering::SeqCst)); } +#[test] +fn tmp_dh_callback_ssl() { + static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; + + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + + thread::spawn(move ||{ + let stream = listener.accept().unwrap().0; + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM).unwrap(); + ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM).unwrap(); + let mut ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.set_tmp_dh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + let dh = include_bytes!("../../../test/dhparams.pem"); + Dh::from_pem(dh) + }); + ssl.accept(stream).unwrap(); + }); + + let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_cipher_list("DHE").unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.connect(stream).unwrap(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] +fn tmp_ecdh_callback_ssl() { + use ec_key::EcKey; + use nid; + + static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; + + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + + thread::spawn(move ||{ + let stream = listener.accept().unwrap().0; + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM).unwrap(); + ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM).unwrap(); + let mut ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.set_tmp_ecdh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + EcKey::new_by_curve_name(nid::X9_62_PRIME256V1) + }); + ssl.accept(stream).unwrap(); + }); + + let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_cipher_list("ECDHE").unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.connect(stream).unwrap(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + fn _check_kinds() { fn is_send() {} fn is_sync() {} -- cgit v1.2.3 From 93253ba5991414a86fe10db4e74c4a7bfeae19fc Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 13:09:12 +0000 Subject: Adjust cipher lists to work on older versions --- openssl/src/ssl/tests/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index e2afb6f7..becf4fd3 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1231,7 +1231,7 @@ fn tmp_dh_callback() { let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("DHE").unwrap(); + ctx.set_cipher_list("EDH").unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.connect(stream).unwrap(); @@ -1264,7 +1264,7 @@ fn tmp_ecdh_callback() { let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("ECDHE").unwrap(); + ctx.set_cipher_list("kECDHe").unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.connect(stream).unwrap(); @@ -1294,7 +1294,7 @@ fn tmp_dh_callback_ssl() { let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("DHE").unwrap(); + ctx.set_cipher_list("EDH").unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.connect(stream).unwrap(); @@ -1327,7 +1327,7 @@ fn tmp_ecdh_callback_ssl() { let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("ECDHE").unwrap(); + ctx.set_cipher_list("kECDHe").unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.connect(stream).unwrap(); -- cgit v1.2.3 From 2a1d7b2bcb229283c85a991dd97aa83f59b02ed2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 13:35:51 +0000 Subject: Pick different cipher lists on 1.0.1 and 1.0.2 --- openssl/src/ssl/tests/mod.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index becf4fd3..50299aa8 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1264,7 +1264,11 @@ fn tmp_ecdh_callback() { let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("kECDHe").unwrap(); + if cfg!(ossl101) { + ctx.set_cipher_list("kECDHe").unwrap(); + } else { + ctx.set_cipher_list("ECDHE").unwrap(); + } let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.connect(stream).unwrap(); @@ -1327,7 +1331,11 @@ fn tmp_ecdh_callback_ssl() { let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("kECDHe").unwrap(); + if cfg!(ossl101) { + ctx.set_cipher_list("kECDHe").unwrap(); + } else { + ctx.set_cipher_list("ECDHE").unwrap(); + } let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.connect(stream).unwrap(); -- cgit v1.2.3 From 96d24c89575c4d2e193f31de67e1ba273f15d6b0 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 13:45:54 +0000 Subject: Add SslRef::set_{tmp_dh,tmp_ecdh,ecdh_auto} --- openssl/src/ssl/mod.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index bcaa4c74..2c444400 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1083,6 +1083,10 @@ impl SslRef { } } + 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(|_| ()) } + } + pub fn set_tmp_dh_callback(&mut self, callback: F) where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send { @@ -1096,6 +1100,10 @@ impl SslRef { } } + 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(|_| ()) } + } + /// Requires the `v101` feature and OpenSSL 1.0.1, or the `v102` feature and OpenSSL 1.0.2. #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] pub fn set_tmp_ecdh_callback(&mut self, callback: F) @@ -1111,6 +1119,16 @@ impl SslRef { } } + /// If `onoff` is set to `true`, enable ECDHE for key exchange with + /// compatible clients, and automatically select an appropriate elliptic + /// curve. + /// + /// Requires the `v102` feature and OpenSSL 1.0.2. + #[cfg(all(feature = "v102", ossl102))] + 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(|_| ()) } + } + pub fn current_cipher(&self) -> Option<&SslCipherRef> { unsafe { let ptr = ffi::SSL_get_current_cipher(self.as_ptr()); -- cgit v1.2.3 From 7cdb58bc47fdc8060593b48d5624e7d14b5ac285 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 14:42:48 +0000 Subject: Simplify test logic a bit --- openssl/src/ssl/tests/mod.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 50299aa8..3cc3a28c 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1264,11 +1264,7 @@ fn tmp_ecdh_callback() { let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - if cfg!(ossl101) { - ctx.set_cipher_list("kECDHe").unwrap(); - } else { - ctx.set_cipher_list("ECDHE").unwrap(); - } + ctx.set_cipher_list("ECDH").unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.connect(stream).unwrap(); @@ -1331,11 +1327,7 @@ fn tmp_ecdh_callback_ssl() { let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - if cfg!(ossl101) { - ctx.set_cipher_list("kECDHe").unwrap(); - } else { - ctx.set_cipher_list("ECDHE").unwrap(); - } + ctx.set_cipher_list("ECDH").unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.connect(stream).unwrap(); -- cgit v1.2.3 From 6b3599d319977ac3c60677638d29783a9e9f4f60 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 16:45:18 +0000 Subject: Add a connect method that does not perform hostname verification The method name is intentionally painful to type to discourage its use --- openssl/src/ssl/connector.rs | 17 +++++++++++++++++ openssl/src/ssl/tests/mod.rs | 36 ++++++++++++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 4 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index c5189c9e..f838edf4 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -61,6 +61,7 @@ impl SslConnectorBuilder { try!(ctx.set_cipher_list("ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:\ DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:RSA+AESGCM:\ RSA+AES:RSA+HIGH:!aNULL:!eNULL:!MD5:!3DES")); + ctx.set_verify(SSL_VERIFY_PEER); Ok(SslConnectorBuilder(ctx)) } @@ -103,6 +104,22 @@ impl SslConnector { ssl.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 connect_without_providing_domain_for_certificate_verification_and_server_name_indication( + &self, stream: S) -> Result, HandshakeError> + where S: Read + Write + { + try!(Ssl::new(&self.0)).connect(stream) + } } /// A builder for `SslAcceptor`s. diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 3cc3a28c..855903c9 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -17,10 +17,8 @@ use tempdir::TempDir; use dh::Dh; use hash::MessageDigest; use ssl; -use ssl::SSL_VERIFY_PEER; -use ssl::{SslMethod, HandshakeError}; -use ssl::{SslContext, SslStream, Ssl, ShutdownResult, SslConnectorBuilder, SslAcceptorBuilder, - Error}; +use ssl::{SslMethod, HandshakeError, SslContext, SslStream, Ssl, ShutdownResult, + SslConnectorBuilder, SslAcceptorBuilder, Error, SSL_VERIFY_PEER, SSL_VERIFY_NONE}; use x509::{X509StoreContext, X509, X509Name, X509_FILETYPE_PEM}; #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] use x509::verify::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS; @@ -1090,6 +1088,36 @@ fn connector_invalid_hostname() { assert!(connector.connect("foobar.com", s).is_err()); } +#[test] +fn connector_invalid_no_hostname_verification() { + let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); + + let s = TcpStream::connect("google.com:443").unwrap(); + connector.connect_without_providing_domain_for_certificate_verification_and_server_name_indication(s) + .unwrap(); +} + +#[test] +fn connector_no_hostname_still_verifies() { + let (_s, tcp) = Server::new(); + + let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); + + assert!(connector.connect_without_providing_domain_for_certificate_verification_and_server_name_indication(tcp) + .is_err()); +} + +#[test] +fn connector_no_hostname_can_disable_verify() { + let (_s, tcp) = Server::new(); + + let mut connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap(); + connector.builder_mut().set_verify(SSL_VERIFY_NONE); + let connector = connector.build(); + + connector.connect_without_providing_domain_for_certificate_verification_and_server_name_indication(tcp).unwrap(); +} + #[test] fn connector_client_server_mozilla_intermediate() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); -- cgit v1.2.3 From 2f8301fc63114120b930fbb5779e383f1b100635 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 16:51:26 +0000 Subject: Be a bit more emphatic about the danger --- openssl/src/ssl/connector.rs | 2 +- openssl/src/ssl/tests/mod.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index f838edf4..39c19841 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -114,7 +114,7 @@ impl SslConnector { /// 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 connect_without_providing_domain_for_certificate_verification_and_server_name_indication( + pub fn danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication( &self, stream: S) -> Result, HandshakeError> where S: Read + Write { diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 855903c9..fb9a96b9 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1093,7 +1093,7 @@ fn connector_invalid_no_hostname_verification() { let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); let s = TcpStream::connect("google.com:443").unwrap(); - connector.connect_without_providing_domain_for_certificate_verification_and_server_name_indication(s) + connector.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(s) .unwrap(); } @@ -1103,7 +1103,7 @@ fn connector_no_hostname_still_verifies() { let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); - assert!(connector.connect_without_providing_domain_for_certificate_verification_and_server_name_indication(tcp) + assert!(connector.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(tcp) .is_err()); } @@ -1115,7 +1115,7 @@ fn connector_no_hostname_can_disable_verify() { connector.builder_mut().set_verify(SSL_VERIFY_NONE); let connector = connector.build(); - connector.connect_without_providing_domain_for_certificate_verification_and_server_name_indication(tcp).unwrap(); + connector.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(tcp).unwrap(); } #[test] -- cgit v1.2.3 From 64e9932ac92bdb63896b49922146c602769e066d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 17:52:58 +0000 Subject: Use ffdhe2048 in mozilla_intermediate --- openssl/src/ssl/connector.rs | 50 +++++++------------------------------------- 1 file changed, 8 insertions(+), 42 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 39c19841..213c90b7 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -7,21 +7,15 @@ use ssl::{self, SslMethod, SslContextBuilder, SslContext, Ssl, SSL_VERIFY_PEER, use pkey::PKeyRef; use x509::X509Ref; -// Serialized form of DH_get_2048_256 -#[cfg(any(ossl101, all(test, any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))))] +// ffdhe2048 from https://wiki.mozilla.org/Security/Server_Side_TLS#ffdhe2048 const DHPARAM_PEM: &'static str = r#" -----BEGIN DH PARAMETERS----- -MIICCQKCAQEAh6jmHbS2Zjz/u9GcZRlZmYzu9ghmDdDyXSzu1ENeOwDgDfjx1hlX -1Pr330VhsqowFsPZETQJb6o79Cltgw6afCCeDGSXUXq9WoqdMGvPZ+2R+eZyW0dY -wCLgse9Cdb97bFv8EdRfkIi5QfVOseWbuLw5oL8SMH9cT9twxYGyP3a2Osrhyqa3 -kC1SUmc1SIoO8TxtmlG/pKs62DR3llJNjvahZ7WkGCXZZ+FE5RQFZCUcysuD5rSG -9rPKP3lxUGAmwLhX9omWKFbe1AEKvQvmIcOjlgpU5xDDdfJjddcBQQOktUMwwZiv -EmEW0iduEXFfaTh3+tfvCcrbCUrpHhoVlwKCAQA/syybcxNNCy53UGZg7b1ITKex -jyHvIFQH9Hk6GguhJRDbwVB3vkY//0/tSqwLtVW+OmwbDGtHsbw3c79+jG9ikBIo -+MKMuxilWuMTQQAKZQGW+THHelfy3fRj5ensFEt3feYqqrioYorDdtKC1u04ZOZ5 -gkKOvIMdFDSPby+Rk7UEWvJ2cWTh38lnwfs/LlWkvRv/6DucgNBSuYXRguoK2yo7 -cxPT/hTISEseBSWIubfSu9LfAWGZ7NBuFVfNCRWzNTu7ZODsN3/QKDcN+StSx4kU -KM3GfrYYS1I9HbJGwy9jB4SQ8A741kfRSNR5VFFeIyfP75jFgmZLTA9sxBZZ +MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz ++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a +87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 +YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi +7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD +ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== -----END DH PARAMETERS----- "#; @@ -142,7 +136,7 @@ impl SslAcceptorBuilder { I::Item: AsRef { let mut ctx = try!(ctx(method)); - let dh = try!(get_dh()); + let dh = try!(Dh::from_pem(DHPARAM_PEM.as_bytes())); try!(ctx.set_tmp_dh(&dh)); try!(setup_curves(&mut ctx)); try!(ctx.set_cipher_list("ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\ @@ -219,22 +213,6 @@ impl SslAcceptorBuilder { } } -#[cfg(ossl101)] -fn get_dh() -> Result { - Dh::from_pem(DHPARAM_PEM.as_bytes()) -} - -#[cfg(not(ossl101))] -fn get_dh() -> Result { - use ffi; - - use cvt_p; - use types::OpenSslType; - - // manually call into ffi to avoid forcing the features - unsafe { cvt_p(ffi::DH_get_2048_256()).map(|p| Dh::from_ptr(p)) } -} - #[cfg(ossl101)] fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { use ec_key::EcKey; @@ -456,15 +434,3 @@ mod verify { } } } - -#[cfg(test)] -mod test { - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] - #[test] - fn check_dhparam() { - use dh::Dh; - - let expected = String::from_utf8(Dh::get_2048_256().unwrap().to_pem().unwrap()).unwrap(); - assert_eq!(expected.trim(), super::DHPARAM_PEM.trim()); - } -} -- cgit v1.2.3 From 85c1474ce68932d4fad0e53144cf43428b5e12c7 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 12:19:31 +0000 Subject: No need to use a raw string anymore --- openssl/src/ssl/connector.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 213c90b7..07c44ce7 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -8,7 +8,7 @@ use pkey::PKeyRef; use x509::X509Ref; // ffdhe2048 from https://wiki.mozilla.org/Security/Server_Side_TLS#ffdhe2048 -const DHPARAM_PEM: &'static str = r#" +const DHPARAM_PEM: &'static str = " -----BEGIN DH PARAMETERS----- MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz +8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a @@ -17,7 +17,7 @@ YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi 7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== -----END DH PARAMETERS----- -"#; +"; fn ctx(method: SslMethod) -> Result { let mut ctx = try!(SslContextBuilder::new(method)); -- cgit v1.2.3 From 0d0b5080e25fb0a2f9ada042810b98d28f5e0414 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 20:21:44 +0000 Subject: Rename new_by_curve_name to from_curve_name --- openssl/src/ssl/connector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 07c44ce7..c002b966 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -218,7 +218,7 @@ fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { use ec_key::EcKey; use nid; - let curve = try!(EcKey::new_by_curve_name(nid::X9_62_PRIME256V1)); + let curve = try!(EcKey::from_curve_name(nid::X9_62_PRIME256V1)); ctx.set_tmp_ecdh(&curve) } -- cgit v1.2.3 From 6794a45d602def6812a70841f8b012445f62c7ac Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 14 Nov 2016 22:37:01 +0100 Subject: Rename ec_key to ec --- openssl/src/ssl/connector.rs | 2 +- openssl/src/ssl/mod.rs | 4 ++-- openssl/src/ssl/tests/mod.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index c002b966..043014c4 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -215,7 +215,7 @@ impl SslAcceptorBuilder { #[cfg(ossl101)] fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { - use ec_key::EcKey; + use ec::EcKey; use nid; let curve = try!(EcKey::from_curve_name(nid::X9_62_PRIME256V1)); diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 2c444400..ac41dec6 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -92,9 +92,9 @@ use std::sync::Mutex; use {init, cvt, cvt_p}; use dh::{Dh, DhRef}; -use ec_key::EcKeyRef; +use ec::EcKeyRef; #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] -use ec_key::EcKey; +use ec::EcKey; use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError, X509Name}; use x509::store::X509StoreBuilderRef; #[cfg(any(ossl102, ossl110))] diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index fb9a96b9..2f6bbe1f 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1269,7 +1269,7 @@ fn tmp_dh_callback() { #[test] #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] fn tmp_ecdh_callback() { - use ec_key::EcKey; + use ec::EcKey; use nid; static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; @@ -1332,7 +1332,7 @@ fn tmp_dh_callback_ssl() { #[test] #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] fn tmp_ecdh_callback_ssl() { - use ec_key::EcKey; + use ec::EcKey; use nid; static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; -- cgit v1.2.3 From 234f126d7d9718bd95655aca5fa6f57dc2c4270a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 19 Nov 2016 10:19:52 -0800 Subject: Cleanup --- openssl/src/ssl/bio.rs | 13 ++++--------- openssl/src/ssl/connector.rs | 4 ++-- openssl/src/ssl/mod.rs | 3 ++- 3 files changed, 8 insertions(+), 12 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs index 486b4dba..c5152a41 100644 --- a/openssl/src/ssl/bio.rs +++ b/openssl/src/ssl/bio.rs @@ -5,6 +5,7 @@ use std::any::Any; use std::io; use std::io::prelude::*; use std::mem; +use std::panic::{AssertUnwindSafe, catch_unwind}; use std::ptr; use std::slice; @@ -70,19 +71,13 @@ unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState { mem::transmute(compat::BIO_get_data(bio)) } -fn catch_unwind(f: F) -> Result> - where F: FnOnce() -> T -{ - ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(f)) -} - unsafe extern "C" fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int { BIO_clear_retry_flags(bio); let state = state::(bio); let buf = slice::from_raw_parts(buf as *const _, len as usize); - match catch_unwind(|| state.stream.write(buf)) { + match catch_unwind(AssertUnwindSafe(|| state.stream.write(buf))) { Ok(Ok(len)) => len as c_int, Ok(Err(err)) => { if retriable_error(&err) { @@ -104,7 +99,7 @@ unsafe extern "C" fn bread(bio: *mut BIO, buf: *mut c_char, len: c_int) let state = state::(bio); let buf = slice::from_raw_parts_mut(buf as *mut _, len as usize); - match catch_unwind(|| state.stream.read(buf)) { + match catch_unwind(AssertUnwindSafe(|| state.stream.read(buf))) { Ok(Ok(len)) => len as c_int, Ok(Err(err)) => { if retriable_error(&err) { @@ -140,7 +135,7 @@ unsafe extern "C" fn ctrl(bio: *mut BIO, if cmd == BIO_CTRL_FLUSH { let state = state::(bio); - match catch_unwind(|| state.stream.flush()) { + match catch_unwind(AssertUnwindSafe(|| state.stream.flush())) { Ok(Ok(())) => 1, Ok(Err(err)) => { state.error = Some(err); diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 043014c4..9ff89c0e 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -23,10 +23,10 @@ fn ctx(method: SslMethod) -> Result { let mut ctx = try!(SslContextBuilder::new(method)); let mut opts = ssl::SSL_OP_ALL; - opts |= ssl::SSL_OP_NO_TICKET; - opts |= ssl::SSL_OP_NO_COMPRESSION; opts &= !ssl::SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; opts &= !ssl::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; + opts |= ssl::SSL_OP_NO_TICKET; + opts |= ssl::SSL_OP_NO_COMPRESSION; opts |= ssl::SSL_OP_NO_SSLV2; opts |= ssl::SSL_OP_NO_SSLV3; opts |= ssl::SSL_OP_SINGLE_DH_USE; diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index ac41dec6..6e0c92c3 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -84,6 +84,7 @@ use std::io::prelude::*; use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; +use std::panic::resume_unwind; use std::path::Path; use std::ptr; use std::slice; @@ -1601,7 +1602,7 @@ impl SslStream { fn check_panic(&mut self) { if let Some(err) = unsafe { bio::take_panic::(self.ssl.get_raw_rbio()) } { - ::std::panic::resume_unwind(err) + resume_unwind(err) } } -- cgit v1.2.3 From 146512099b484928e9b9396d4b8a476b1c47ee54 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 27 Nov 2016 21:35:35 -0800 Subject: Implement Clone for SslConnector and SslAcceptor --- openssl/src/ssl/connector.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 9ff89c0e..cc5c5273 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -83,6 +83,7 @@ impl SslConnectorBuilder { /// /// OpenSSL's built in hostname verification is used when linking against OpenSSL 1.0.2 or 1.1.0, /// and a custom implementation is used when linking against OpenSSL 1.0.1. +#[derive(Clone)] pub struct SslConnector(SslContext); impl SslConnector { @@ -236,6 +237,7 @@ fn setup_curves(_: &mut SslContextBuilder) -> Result<(), ErrorStack> { /// /// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL /// structures, configuring cipher suites, session options, and more. +#[derive(Clone)] pub struct SslAcceptor(SslContext); impl SslAcceptor { -- cgit v1.2.3 From 8e01f8d2502098497e642ee477d926a99ee619a8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 20 Dec 2016 14:04:10 -0800 Subject: Handle zero-length reads/writes This commit adds some short-circuits for zero-length reads/writes to `SslStream`. Because OpenSSL returns 0 on error, then we could mistakenly confuse a 0-length success as an actual error, so we avoid writing or reading 0 bytes by returning quickly with a success. --- openssl/src/ssl/mod.rs | 14 ++++++++++++++ openssl/src/ssl/tests/mod.rs | 10 ++++++++++ 2 files changed, 24 insertions(+) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 6e0c92c3..47c83453 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1506,6 +1506,15 @@ impl SslStream { /// This is particularly useful with a nonblocking socket, where the error /// value will identify if OpenSSL is waiting on read or write readiness. pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result { + // The intepretation of the return code here is a little odd with a + // zero-length write. OpenSSL will likely correctly report back to us + // that it read zero bytes, but zero is also the sentinel for "error". + // To avoid that confusion short-circuit that logic and return quickly + // if `buf` has a length of zero. + if buf.len() == 0 { + return Ok(0) + } + let ret = self.ssl.read(buf); if ret > 0 { Ok(ret as usize) @@ -1523,6 +1532,11 @@ impl SslStream { /// This is particularly useful with a nonblocking socket, where the error /// value will identify if OpenSSL is waiting on read or write readiness. pub fn ssl_write(&mut self, buf: &[u8]) -> Result { + // See above for why we short-circuit on zero-length buffers + if buf.len() == 0 { + return Ok(0) + } + let ret = self.ssl.write(buf); if ret > 0 { Ok(ret as usize) diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 2f6bbe1f..66f9dca9 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -421,6 +421,16 @@ fn test_write() { stream.flush().unwrap(); } +#[test] +fn zero_length_buffers() { + let (_s, stream) = Server::new(); + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let mut stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap(); + + assert_eq!(stream.write(b"").unwrap(), 0); + assert_eq!(stream.read(&mut []).unwrap(), 0); +} + run_test!(get_peer_certificate, |method, stream| { let ctx = SslContext::builder(method).unwrap(); let stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap(); -- cgit v1.2.3 From b3526cbd2b8ca9e4eff4d4a0f1c3461cedcae776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Wed, 21 Dec 2016 08:58:16 +0100 Subject: Add LibreSSL 2.5.0 support --- openssl/src/ssl/mod.rs | 3 +++ openssl/src/ssl/tests/mod.rs | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 6e0c92c3..9803949d 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -166,8 +166,11 @@ bitflags! { const SSL_MODE_AUTO_RETRY = ffi::SSL_MODE_AUTO_RETRY, const SSL_MODE_NO_AUTO_CHAIN = ffi::SSL_MODE_NO_AUTO_CHAIN, const SSL_MODE_RELEASE_BUFFERS = ffi::SSL_MODE_RELEASE_BUFFERS, + #[cfg(not(libressl))] const SSL_MODE_SEND_CLIENTHELLO_TIME = ffi::SSL_MODE_SEND_CLIENTHELLO_TIME, + #[cfg(not(libressl))] const SSL_MODE_SEND_SERVERHELLO_TIME = ffi::SSL_MODE_SEND_SERVERHELLO_TIME, + #[cfg(not(libressl))] const SSL_MODE_SEND_FALLBACK_SCSV = ffi::SSL_MODE_SEND_FALLBACK_SCSV, } } diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 2f6bbe1f..437bec8a 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -181,7 +181,7 @@ macro_rules! run_test( } #[test] - #[cfg_attr(any(windows, target_arch = "arm"), ignore)] // FIXME(#467) + #[cfg_attr(any(libressl, windows, target_arch = "arm"), ignore)] // FIXME(#467) fn dtlsv1() { let (_s, stream) = Server::new_dtlsv1(Some("hello")); $blk(SslMethod::dtls(), stream); @@ -432,7 +432,7 @@ run_test!(get_peer_certificate, |method, stream| { }); #[test] -#[cfg_attr(any(windows, target_arch = "arm"), ignore)] // FIXME(#467) +#[cfg_attr(any(libressl, windows, target_arch = "arm"), ignore)] // FIXME(#467) fn test_write_dtlsv1() { let (_s, stream) = Server::new_dtlsv1(iter::repeat("y\n")); let ctx = SslContext::builder(SslMethod::dtls()).unwrap(); @@ -771,7 +771,7 @@ fn test_alpn_server_select_none() { } #[test] -#[cfg_attr(any(windows, target_arch = "arm"), ignore)] // FIXME(#467) +#[cfg_attr(any(libressl, windows, target_arch = "arm"), ignore)] // FIXME(#467) fn test_read_dtlsv1() { let (_s, stream) = Server::new_dtlsv1(Some("hello")); @@ -849,7 +849,7 @@ fn test_write_nonblocking() { } #[test] -#[cfg_attr(any(windows, target_arch = "arm"), ignore)] // FIXME(#467) +#[cfg_attr(any(libressl, windows, target_arch = "arm"), ignore)] // FIXME(#467) fn test_read_nonblocking() { let (_s, stream) = Server::new(); stream.set_nonblocking(true).unwrap(); -- cgit v1.2.3 From 0e0bee50a59ab65c310122dc6300416eadfea851 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 1 Jan 2017 10:18:43 -0800 Subject: Clean up bio --- openssl/src/ssl/bio.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs index c5152a41..4dc7cbd4 100644 --- a/openssl/src/ssl/bio.rs +++ b/openssl/src/ssl/bio.rs @@ -68,10 +68,10 @@ pub unsafe fn get_mut<'a, S: 'a>(bio: *mut BIO) -> &'a mut S { } unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState { - mem::transmute(compat::BIO_get_data(bio)) + &mut *(compat::BIO_get_data(bio) as *mut _) } -unsafe extern "C" fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int { +unsafe extern fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int { BIO_clear_retry_flags(bio); let state = state::(bio); @@ -93,7 +93,7 @@ unsafe extern "C" fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_ } } -unsafe extern "C" fn bread(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int { +unsafe extern fn bread(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int { BIO_clear_retry_flags(bio); let state = state::(bio); @@ -123,11 +123,11 @@ fn retriable_error(err: &io::Error) -> bool { } } -unsafe extern "C" fn bputs(bio: *mut BIO, s: *const c_char) -> c_int { +unsafe extern fn bputs(bio: *mut BIO, s: *const c_char) -> c_int { bwrite::(bio, s, strlen(s) as c_int) } -unsafe extern "C" fn ctrl(bio: *mut BIO, +unsafe extern fn ctrl(bio: *mut BIO, cmd: c_int, _num: c_long, _ptr: *mut c_void) @@ -151,7 +151,7 @@ unsafe extern "C" fn ctrl(bio: *mut BIO, } } -unsafe extern "C" fn create(bio: *mut BIO) -> c_int { +unsafe extern fn create(bio: *mut BIO) -> c_int { compat::BIO_set_init(bio, 0); compat::BIO_set_num(bio, 0); compat::BIO_set_data(bio, ptr::null_mut()); @@ -159,7 +159,7 @@ unsafe extern "C" fn create(bio: *mut BIO) -> c_int { 1 } -unsafe extern "C" fn destroy(bio: *mut BIO) -> c_int { +unsafe extern fn destroy(bio: *mut BIO) -> c_int { if bio.is_null() { return 0; } -- cgit v1.2.3 From cfb2539ed45fd11cec1af850256078ec494d8987 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 2 Jan 2017 09:37:31 -0800 Subject: Typo --- openssl/src/ssl/connector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index cc5c5273..43dad17d 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -379,7 +379,7 @@ mod verify { // the same thing we do here. // // The Public Suffix (https://www.publicsuffix.org/) list could - // potentically be used here, but it's both huge and updated frequently + // potentially be used here, but it's both huge and updated frequently // enough that management would be a PITA. if dot_idxs.next().is_none() { return None; -- cgit v1.2.3 From 88a7032f4b78895eaeeb72d3837dd698e571e882 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 20:59:46 -0800 Subject: Types and accessor for SslSession --- openssl/src/ssl/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 3eead8f2..d1ed55fe 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1334,6 +1334,11 @@ impl SslRef { pub fn verify_result(&self) -> Option { unsafe { X509VerifyError::from_raw(ffi::SSL_get_verify_result(self.as_ptr())) } } + + /// Returns the SSL session. + pub fn session(&self) -> &SslSessionRef { + unsafe { SslSessionRef::from_ptr(ffi::SSL_get_session(self.as_ptr())) } + } } unsafe impl Sync for Ssl {} @@ -1345,6 +1350,8 @@ impl fmt::Debug for Ssl { } } +type_!(SslSession, SslSessionRef, ffi::SSL_SESSION, ffi::SSL_SESSION_free); + impl Ssl { pub fn new(ctx: &SslContext) -> Result { unsafe { -- cgit v1.2.3 From 5d53405597f2e8dc3a6543e8c4a56705b0ecd47a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 21:07:51 -0800 Subject: Provide access to the session ID --- openssl/src/ssl/mod.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index d1ed55fe..3949210d 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1029,6 +1029,19 @@ impl SslCipherRef { } } +type_!(SslSession, SslSessionRef, ffi::SSL_SESSION, ffi::SSL_SESSION_free); + +impl SslSessionRef { + /// Returns the SSL session ID. + pub fn id(&self) -> &[u8] { + unsafe { + let mut len = 0; + let p = ffi::SSL_SESSION_get_id(self.as_ptr(), &mut len); + slice::from_raw_parts(p as *const u8, len as usize) + } + } +} + type_!(Ssl, SslRef, ffi::SSL, ffi::SSL_free); impl fmt::Debug for SslRef { @@ -1350,8 +1363,6 @@ impl fmt::Debug for Ssl { } } -type_!(SslSession, SslSessionRef, ffi::SSL_SESSION, ffi::SSL_SESSION_free); - impl Ssl { pub fn new(ctx: &SslContext) -> Result { unsafe { -- cgit v1.2.3 From 0b1bfee46d6c986d6cb073c922045ae98b598900 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 21:15:09 -0800 Subject: session is nullable --- openssl/src/ssl/mod.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 3949210d..ce9d65ef 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1349,8 +1349,15 @@ impl SslRef { } /// Returns the SSL session. - pub fn session(&self) -> &SslSessionRef { - unsafe { SslSessionRef::from_ptr(ffi::SSL_get_session(self.as_ptr())) } + pub fn session(&self) -> Option<&SslSessionRef> { + unsafe { + let p = ffi::SSL_get_session(self.as_ptr()); + if p.is_null() { + None + } else { + Some(SslSessionRef::from_ptr(p)) + } + } } } -- cgit v1.2.3 From a2c118bf82ac4fbb13d5dd32b931490862ccd930 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 21:18:13 -0800 Subject: Add basic session tests --- openssl/src/ssl/tests/mod.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index e685d658..744b2688 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1372,6 +1372,22 @@ fn tmp_ecdh_callback_ssl() { assert!(CALLED_BACK.load(Ordering::SeqCst)); } +#[test] +fn idle_session() { + let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); + let ssl = Ssl::new(&ctx).unwrap(); + assert!(ssl.session().is_none()); +} + +#[test] +fn active_session() { + let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); + + let s = TcpStream::connect("google.com:443").unwrap(); + let socket = connector.connect("google.com", s).unwrap(); + assert!(socket.ssl().session().is_some()); +} + fn _check_kinds() { fn is_send() {} fn is_sync() {} -- cgit v1.2.3 From 404e0341d82d5aab58daaa48b864eaf1a281d101 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 21:33:47 -0800 Subject: Provide master key access --- openssl/src/ssl/mod.rs | 28 +++++++++++++++++++++++++++- openssl/src/ssl/tests/mod.rs | 10 +++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index ce9d65ef..6d49f2b1 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1040,6 +1040,18 @@ impl SslSessionRef { slice::from_raw_parts(p as *const u8, len as usize) } } + + /// Returns the length of the master key. + pub fn master_key_len(&self) -> usize { + unsafe { compat::SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) } + } + + /// Copies the master key into the provided buffer. + /// + /// Returns the number of bytes written. + 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()) } + } } type_!(Ssl, SslRef, ffi::SSL, ffi::SSL_free); @@ -1728,6 +1740,7 @@ mod compat { pub use ffi::{SSL_CTX_get_options, SSL_CTX_set_options}; pub use ffi::{SSL_CTX_clear_options, SSL_CTX_up_ref}; + pub use ffi::SSL_SESSION_get_master_key; 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, @@ -1762,7 +1775,7 @@ mod compat { use std::ptr; use ffi; - use libc::{self, c_long, c_ulong, c_int}; + use libc::{self, c_long, c_ulong, c_int, size_t, c_uchar}; 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 @@ -1799,6 +1812,19 @@ mod compat { 0 } + 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; + } + if outlen > (*session).master_key_length as size_t { + outlen = (*session).master_key_length as size_t; + } + ptr::copy_nonoverlapping((*session).master_key.as_ptr(), out, outlen); + outlen + } + pub fn tls_method() -> *const ffi::SSL_METHOD { unsafe { ffi::SSLv23_method() } } diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 744b2688..14bb2f71 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1385,7 +1385,15 @@ fn active_session() { let s = TcpStream::connect("google.com:443").unwrap(); let socket = connector.connect("google.com", s).unwrap(); - assert!(socket.ssl().session().is_some()); + let session = socket.ssl().session().unwrap(); + let len = session.master_key_len(); + let mut buf = vec![0; len - 1]; + let copied = session.master_key(&mut buf); + assert_eq!(copied, buf.len()); + let mut buf = vec![0; len + 1]; + let copied = session.master_key(&mut buf); + assert_eq!(copied, len); + } fn _check_kinds() { -- cgit v1.2.3 From 0978f870956ff06dee2e7dcbb6a30c6cbfce6e1e Mon Sep 17 00:00:00 2001 From: Marc-Antoine Perennou Date: Thu, 5 Jan 2017 16:15:53 +0100 Subject: libressl: make set_ecdh_auto available Signed-off-by: Marc-Antoine Perennou --- openssl/src/ssl/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 3eead8f2..722225e7 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -774,12 +774,12 @@ impl SslContextBuilder { /// curve. /// /// Requires the `v102` feature and OpenSSL 1.0.2. - #[cfg(all(feature = "v102", ossl102))] + #[cfg(all(feature = "v102", any(ossl102, libressl)))] pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { self._set_ecdh_auto(onoff) } - #[cfg(ossl102)] + #[cfg(any(ossl102,libressl))] 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(|_| ()) } } -- cgit v1.2.3 From 1942977408a6483770332f316fc012e06ad757b9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 8 Jan 2017 10:57:04 -0800 Subject: Add methods to construct SslAcceptorBuilder without key and cert This will allow, in particular, initialization directly from files rather than having to load and parse them manually. --- openssl/src/ssl/connector.rs | 56 +++++++++++++++++++++++++++----------------- openssl/src/ssl/mod.rs | 27 +++++++++++++-------- 2 files changed, 51 insertions(+), 32 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 43dad17d..458eace0 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -136,6 +136,30 @@ impl SslAcceptorBuilder { where I: IntoIterator, I::Item: AsRef { + let builder = try!(SslAcceptorBuilder::mozilla_intermedia_raw(method)); + builder.finish_setup(private_key, certificate, chain) + } + + /// Creates a new builder configured to connect to modern clients. + /// + /// This corresponds to the modern configuration of Mozilla's server side TLS recommendations. + /// See its [documentation][docs] for more details on specifics. + /// + /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS + pub fn mozilla_modern(method: SslMethod, + private_key: &PKeyRef, + certificate: &X509Ref, + chain: I) + -> Result + where I: IntoIterator, + I::Item: AsRef + { + let builder = try!(SslAcceptorBuilder::mozilla_modern_raw(method)); + builder.finish_setup(private_key, certificate, chain) + } + + /// Like `mozilla_intermediate`, but does not load the certificate chain and private key. + pub fn mozilla_intermedia_raw(method: SslMethod) -> Result { let mut ctx = try!(ctx(method)); let dh = try!(Dh::from_pem(DHPARAM_PEM.as_bytes())); try!(ctx.set_tmp_dh(&dh)); @@ -154,23 +178,11 @@ impl SslAcceptorBuilder { EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:\ AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:\ DES-CBC3-SHA:!DSS")); - SslAcceptorBuilder::finish_setup(ctx, private_key, certificate, chain) + Ok(SslAcceptorBuilder(ctx)) } - /// Creates a new builder configured to connect to modern clients. - /// - /// This corresponds to the modern configuration of Mozilla's server side TLS recommendations. - /// See its [documentation][docs] for more details on specifics. - /// - /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS - pub fn mozilla_modern(method: SslMethod, - private_key: &PKeyRef, - certificate: &X509Ref, - chain: I) - -> Result - where I: IntoIterator, - I::Item: AsRef - { + /// Like `mozilla_modern`, but does not load the certificate chain and private key. + pub fn mozilla_modern_raw(method: SslMethod) -> Result { let mut ctx = try!(ctx(method)); try!(setup_curves(&mut ctx)); try!(ctx.set_cipher_list("ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\ @@ -178,10 +190,10 @@ impl SslAcceptorBuilder { ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\ ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:\ ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256")); - SslAcceptorBuilder::finish_setup(ctx, private_key, certificate, chain) + Ok(SslAcceptorBuilder(ctx)) } - fn finish_setup(mut ctx: SslContextBuilder, + fn finish_setup(mut self, private_key: &PKeyRef, certificate: &X509Ref, chain: I) @@ -189,13 +201,13 @@ impl SslAcceptorBuilder { where I: IntoIterator, I::Item: AsRef { - try!(ctx.set_private_key(private_key)); - try!(ctx.set_certificate(certificate)); - try!(ctx.check_private_key()); + try!(self.0.set_private_key(private_key)); + try!(self.0.set_certificate(certificate)); + try!(self.0.check_private_key()); for cert in chain { - try!(ctx.add_extra_chain_cert(cert.as_ref().to_owned())); + try!(self.0.add_extra_chain_cert(cert.as_ref().to_owned())); } - Ok(SslAcceptorBuilder(ctx)) + Ok(self) } /// Returns a shared reference to the inner `SslContextBuilder`. diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 6d49f2b1..f412ca93 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -702,7 +702,7 @@ impl SslContextBuilder { } } - /// Specifies the file that contains certificate + /// Loads a certificate from a file. pub fn set_certificate_file>(&mut self, file: P, file_type: X509FileType) @@ -716,7 +716,11 @@ impl SslContextBuilder { } } - /// Specifies the file that contains certificate chain + /// Loads a certificate chain from a file. + /// + /// The file should contain a sequence of PEM-formatted certificates, the first being the leaf + /// certificate, and the remainder forming the chain of certificates up to and including the + /// trusted root certificate. pub fn set_certificate_chain_file>(&mut self, file: P) -> Result<(), ErrorStack> { @@ -727,13 +731,15 @@ impl SslContextBuilder { } } - /// Specifies the certificate + /// Sets the certificate. pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_use_certificate(self.as_ptr(), cert.as_ptr())).map(|_| ()) } } - /// Adds a certificate to the certificate chain presented together with the - /// certificate specified using set_certificate() + /// Appends a certificate to the certificate chain. + /// + /// This chain should contain all certificates necessary to go from the certificate specified by + /// `set_certificate` to a trusted root. pub fn add_extra_chain_cert(&mut self, cert: X509) -> Result<(), ErrorStack> { unsafe { try!(cvt(ffi::SSL_CTX_add_extra_chain_cert(self.as_ptr(), cert.as_ptr()) as c_int)); @@ -742,7 +748,7 @@ impl SslContextBuilder { } } - /// Specifies the file that contains private key + /// Loads the private key from a file. pub fn set_private_key_file>(&mut self, file: P, file_type: X509FileType) @@ -756,11 +762,14 @@ impl SslContextBuilder { } } - /// Specifies the private key + /// Sets the private key. pub fn set_private_key(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr())).map(|_| ()) } } + /// Sets the cipher configuration. + /// + /// See `man 1 ciphers` for details on the format. pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { let cipher_list = CString::new(cipher_list).unwrap(); unsafe { @@ -769,9 +778,7 @@ impl SslContextBuilder { } } - /// If `onoff` is set to `true`, enable ECDHE for key exchange with - /// compatible clients, and automatically select an appropriate elliptic - /// curve. + /// Enables ECDHE key exchange with an automatically chosen curve list. /// /// Requires the `v102` feature and OpenSSL 1.0.2. #[cfg(all(feature = "v102", ossl102))] -- cgit v1.2.3 From 1fbe8f8d71b2559d901c6cc1f5a1a754634a966d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 8 Jan 2017 11:04:47 -0800 Subject: Fix typo --- openssl/src/ssl/connector.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 458eace0..73d7b675 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -136,7 +136,7 @@ impl SslAcceptorBuilder { where I: IntoIterator, I::Item: AsRef { - let builder = try!(SslAcceptorBuilder::mozilla_intermedia_raw(method)); + let builder = try!(SslAcceptorBuilder::mozilla_intermediate_raw(method)); builder.finish_setup(private_key, certificate, chain) } @@ -159,7 +159,7 @@ impl SslAcceptorBuilder { } /// Like `mozilla_intermediate`, but does not load the certificate chain and private key. - pub fn mozilla_intermedia_raw(method: SslMethod) -> Result { + pub fn mozilla_intermediate_raw(method: SslMethod) -> Result { let mut ctx = try!(ctx(method)); let dh = try!(Dh::from_pem(DHPARAM_PEM.as_bytes())); try!(ctx.set_tmp_dh(&dh)); -- cgit v1.2.3 From 920ab0d6fb60c17077f43d7f08ad3ff391201689 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 13 Jan 2017 19:38:12 -0800 Subject: OCSP functionality --- openssl/src/ssl/mod.rs | 144 +++++++++++++++++++++++++++++++++++++++++-- openssl/src/ssl/tests/mod.rs | 45 +++++++++++++- 2 files changed, 183 insertions(+), 6 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index f412ca93..2fc7605a 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -97,14 +97,14 @@ use ec::EcKeyRef; #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] use ec::EcKey; use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError, X509Name}; -use x509::store::X509StoreBuilderRef; +use x509::store::{X509StoreBuilderRef, X509StoreRef}; #[cfg(any(ossl102, ossl110))] use verify::X509VerifyParamRef; use pkey::PKeyRef; use error::ErrorStack; use types::{OpenSslType, OpenSslTypeRef}; use util::Opaque; -use stack::Stack; +use stack::{Stack, StackRef}; mod error; mod connector; @@ -217,6 +217,22 @@ bitflags! { } } +#[derive(Copy, Clone)] +pub struct StatusType(c_int); + +impl StatusType { + pub fn from_raw(raw: c_int) -> StatusType { + StatusType(raw) + } + + pub fn as_raw(&self) -> c_int { + self.0 + } +} + +/// An OSCP status. +pub const STATUS_TYPE_OCSP: StatusType = StatusType(ffi::TLSEXT_STATUSTYPE_ocsp); + lazy_static! { static ref INDEXES: Mutex> = Mutex::new(HashMap::new()); static ref SSL_INDEXES: Mutex> = Mutex::new(HashMap::new()); @@ -475,6 +491,37 @@ unsafe extern fn raw_tmp_ecdh_ssl(ssl: *mut ffi::SSL, } } +unsafe extern fn raw_tlsext_status(ssl: *mut ffi::SSL, _: *mut c_void) -> c_int + where F: Fn(&mut SslRef) -> Result + Any + 'static + Sync + Send +{ + let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl as *const _); + let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::()); + let callback = &*(callback as *mut F); + + let ssl = SslRef::from_ptr_mut(ssl); + let ret = callback(ssl); + + if ssl.is_server() { + match ret { + Ok(true) => ffi::SSL_TLSEXT_ERR_OK, + Ok(false) => ffi::SSL_TLSEXT_ERR_NOACK, + Err(_) => { + // FIXME reset error stack + ffi::SSL_TLSEXT_ERR_ALERT_FATAL + } + } + } else { + match ret { + Ok(true) => 1, + Ok(false) => 0, + Err(_) => { + // FIXME reset error stack + -1 + } + } + } +} + /// The function is given as the callback to `SSL_CTX_set_next_protos_advertised_cb`. /// /// It causes the parameter `out` to point at a `*const c_uchar` instance that @@ -887,6 +934,31 @@ impl SslContextBuilder { unsafe { X509StoreBuilderRef::from_ptr_mut(ffi::SSL_CTX_get_cert_store(self.as_ptr())) } } + /// Sets the callback dealing with OCSP stapling. + /// + /// On the client side, this callback is responsible for validating the OCSP status response + /// returned by the server. The status may be retrieved with the `SslRef::ocsp_status` method. + /// A response of `Ok(true)` indicates that the OCSP status is valid, and a response of + /// `Ok(false)` indicates that the OCSP status is invalid and the handshake should be + /// terminated. + /// + /// On the server side, this callback is resopnsible for setting the OCSP status response to be + /// returned to clients. The status may be set with the `SslRef::set_ocsp_status` method. A + /// response of `Ok(true)` indicates that the OCSP status should be returned to the client, and + /// `Ok(false)` indicates that the status should not be returned to the client. + pub fn set_status_callback(&mut self, callback: F) -> Result<(), ErrorStack> + where F: Fn(&mut SslRef) -> Result + Any + 'static + Sync + Send + { + unsafe { + let callback = Box::new(callback); + ffi::SSL_CTX_set_ex_data(self.as_ptr(), + get_callback_idx::(), + Box::into_raw(callback) as *mut c_void); + let f: unsafe extern fn (_, _) -> _ = raw_tlsext_status::; + cvt(ffi::SSL_CTX_set_tlsext_status_cb(self.as_ptr(), Some(f)) as c_int).map(|_| ()) + } + } + pub fn build(self) -> SslContext { let ctx = SslContext(self.0); mem::forget(self); @@ -951,6 +1023,22 @@ impl SslContextRef { } } } + + /// Returns the certificate store used for verification. + pub fn cert_store(&self) -> &X509StoreRef { + unsafe { + X509StoreRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) + } + } + + pub fn extra_chain_certs(&self) -> &StackRef { + unsafe { + let mut chain = ptr::null_mut(); + ffi::SSL_CTX_get_extra_chain_certs(self.as_ptr(), &mut chain); + assert!(!chain.is_null()); + StackRef::from_ptr(chain) + } + } } pub struct CipherBits { @@ -1378,6 +1466,49 @@ impl SslRef { } } } + + /// Sets the status response a client wishes the server to reply with. + pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_set_tlsext_status_type(self.as_ptr(), type_.as_raw()) as c_int).map(|_| ()) + } + } + + /// Returns the server's OCSP response, if present. + pub fn ocsp_status(&self) -> Option<&[u8]> { + unsafe { + let mut p = ptr::null_mut(); + let len = ffi::SSL_get_tlsext_status_ocsp_resp(self.as_ptr(), &mut p); + + if len < 0 { + None + } else { + Some(slice::from_raw_parts(p as *const u8, len as usize)) + } + } + } + + /// Sets the OCSP response to be returned to the client. + pub fn set_ocsp_status(&mut self, response: &[u8]) -> Result<(), ErrorStack> { + unsafe { + assert!(response.len() <= c_int::max_value() as usize); + let p = try!(cvt_p(ffi::CRYPTO_malloc(response.len() as _, + concat!(file!(), "\0").as_ptr() as *const _, + line!() as c_int))); + ptr::copy_nonoverlapping(response.as_ptr(), p as *mut u8, response.len()); + cvt(ffi::SSL_set_tlsext_status_ocsp_resp(self.as_ptr(), + p as *mut c_uchar, + response.len() as c_long) as c_int) + .map(|_| ()) + } + } + + /// Determines if this `Ssl` is configured for server-side or client-side use. + pub fn is_server(&self) -> bool { + unsafe { + compat::SSL_is_server(self.as_ptr()) != 0 + } + } } unsafe impl Sync for Ssl {} @@ -1745,9 +1876,8 @@ mod compat { use ffi; use libc::c_int; - pub use ffi::{SSL_CTX_get_options, SSL_CTX_set_options}; - pub use ffi::{SSL_CTX_clear_options, SSL_CTX_up_ref}; - pub use ffi::SSL_SESSION_get_master_key; + 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}; 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, @@ -1839,4 +1969,8 @@ mod compat { pub fn dtls_method() -> *const ffi::SSL_METHOD { unsafe { ffi::DTLSv1_method() } } + + pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int { + (*s).server + } } diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 14bb2f71..349c7a4d 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -16,9 +16,11 @@ use tempdir::TempDir; use dh::Dh; use hash::MessageDigest; +use ocsp::{OcspResponse, RESPONSE_STATUS_UNAUTHORIZED}; use ssl; use ssl::{SslMethod, HandshakeError, SslContext, SslStream, Ssl, ShutdownResult, - SslConnectorBuilder, SslAcceptorBuilder, Error, SSL_VERIFY_PEER, SSL_VERIFY_NONE}; + SslConnectorBuilder, SslAcceptorBuilder, Error, SSL_VERIFY_PEER, SSL_VERIFY_NONE, + STATUS_TYPE_OCSP}; use x509::{X509StoreContext, X509, X509Name, X509_FILETYPE_PEM}; #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] use x509::verify::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS; @@ -1393,7 +1395,48 @@ fn active_session() { let mut buf = vec![0; len + 1]; let copied = session.master_key(&mut buf); assert_eq!(copied, len); +} + +#[test] +fn status_callbacks() { + static CALLED_BACK_SERVER: AtomicBool = ATOMIC_BOOL_INIT; + static CALLED_BACK_CLIENT: AtomicBool = ATOMIC_BOOL_INIT; + + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + let guard = thread::spawn(move || { + let stream = listener.accept().unwrap().0; + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM).unwrap(); + ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM).unwrap(); + ctx.set_status_callback(|ssl| { + CALLED_BACK_SERVER.store(true, Ordering::SeqCst); + let response = OcspResponse::create(RESPONSE_STATUS_UNAUTHORIZED, None).unwrap(); + let response = response.to_der().unwrap(); + ssl.set_ocsp_status(&response).unwrap(); + Ok(true) + }).unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.accept(stream).unwrap(); + }); + + let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_status_callback(|ssl| { + CALLED_BACK_CLIENT.store(true, Ordering::SeqCst); + let response = OcspResponse::from_der(ssl.ocsp_status().unwrap()).unwrap(); + assert_eq!(response.status(), RESPONSE_STATUS_UNAUTHORIZED); + Ok(true) + }); + let mut ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.set_status_type(STATUS_TYPE_OCSP).unwrap(); + ssl.connect(stream).unwrap(); + + assert!(CALLED_BACK_SERVER.load(Ordering::SeqCst)); + assert!(CALLED_BACK_CLIENT.load(Ordering::SeqCst)); + + guard.join().unwrap(); } fn _check_kinds() { -- cgit v1.2.3 From 1ffdf8a1ab75f49b95bae96d4dac31ab6cd3f526 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 21 Jan 2017 14:43:43 +0000 Subject: Fix test warnings --- openssl/src/ssl/tests/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 349c7a4d..536088ab 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -100,6 +100,7 @@ impl Server { Server::new_tcp(&["-www"]) } + #[allow(dead_code)] fn new_alpn() -> (Server, TcpStream) { Server::new_tcp(&["-www", "-nextprotoneg", @@ -1428,7 +1429,7 @@ fn status_callbacks() { let response = OcspResponse::from_der(ssl.ocsp_status().unwrap()).unwrap(); assert_eq!(response.status(), RESPONSE_STATUS_UNAUTHORIZED); Ok(true) - }); + }).unwrap(); let mut ssl = Ssl::new(&ctx.build()).unwrap(); ssl.set_status_type(STATUS_TYPE_OCSP).unwrap(); ssl.connect(stream).unwrap(); -- cgit v1.2.3 From 12ae31ad476d373ce93b4222d3875b9663f3da17 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 3 Feb 2017 01:24:05 -0800 Subject: Switch to foreign_types --- openssl/src/ssl/mod.rs | 30 ++++++++++++++++++++++++------ openssl/src/ssl/tests/mod.rs | 2 +- 2 files changed, 25 insertions(+), 7 deletions(-) (limited to 'openssl/src/ssl') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index dd7f72cc..860e2e00 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -71,6 +71,7 @@ //! } //! ``` use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_void, c_long, c_ulong}; use libc::{c_uchar, c_uint}; use std::any::Any; @@ -102,7 +103,6 @@ use x509::store::{X509StoreBuilderRef, X509StoreRef}; use verify::X509VerifyParamRef; use pkey::PKeyRef; use error::ErrorStack; -use types::{OpenSslType, OpenSslTypeRef}; use util::Opaque; use stack::{Stack, StackRef}; @@ -966,7 +966,13 @@ impl SslContextBuilder { } } -type_!(SslContext, SslContextRef, ffi::SSL_CTX, ffi::SSL_CTX_free); +foreign_type! { + type CType = ffi::SSL_CTX; + fn drop = ffi::SSL_CTX_free; + + pub struct SslContext; + pub struct SslContextRef; +} unsafe impl Send for SslContext {} unsafe impl Sync for SslContext {} @@ -1051,7 +1057,7 @@ pub struct CipherBits { pub struct SslCipher(*mut ffi::SSL_CIPHER); -impl OpenSslType for SslCipher { +impl ForeignType for SslCipher { type CType = ffi::SSL_CIPHER; type Ref = SslCipherRef; @@ -1076,7 +1082,7 @@ impl DerefMut for SslCipher { pub struct SslCipherRef(Opaque); -impl OpenSslTypeRef for SslCipherRef { +impl ForeignTypeRef for SslCipherRef { type CType = ffi::SSL_CIPHER; } @@ -1124,7 +1130,13 @@ impl SslCipherRef { } } -type_!(SslSession, SslSessionRef, ffi::SSL_SESSION, ffi::SSL_SESSION_free); +foreign_type! { + type CType = ffi::SSL_SESSION; + fn drop = ffi::SSL_SESSION_free; + + pub struct SslSession; + pub struct SslSessionRef; +} impl SslSessionRef { /// Returns the SSL session ID. @@ -1149,7 +1161,13 @@ impl SslSessionRef { } } -type_!(Ssl, SslRef, ffi::SSL, ffi::SSL_free); +foreign_type! { + type CType = ffi::SSL; + fn drop = ffi::SSL_free; + + pub struct Ssl; + pub struct SslRef; +} impl fmt::Debug for SslRef { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 536088ab..9c00e3ed 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -174,7 +174,7 @@ macro_rules! run_test( use hash::MessageDigest; use x509::X509StoreContext; use hex::FromHex; - use types::OpenSslTypeRef; + use foreign_types::ForeignTypeRef; use super::Server; #[test] -- cgit v1.2.3