From cb4263f91e6d772e097c9c4a366921b68d804585 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Sat, 21 Nov 2015 17:46:39 +0100 Subject: [PATCH 01/28] test SNI support --- openssl-sys/src/lib.rs | 6 +++ openssl/src/ssl/mod.rs | 96 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 239f8d9e..be33ea4c 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -135,6 +135,8 @@ pub const PKCS5_SALT_LEN: 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_TLSEXT_SERVERNAME_CB: c_int = 53; +pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG: c_int = 54; pub const SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55; pub const SSL_CTRL_EXTRA_CHAIN_CERT: c_int = 14; @@ -538,6 +540,8 @@ extern "C" { pub fn SSL_state_string(ssl: *mut SSL) -> *const c_char; pub fn SSL_state_string_long(ssl: *mut SSL) -> *const c_char; + pub fn SSL_get_servername(ssl: *const SSL, name_type: c_long) -> *const c_char; + pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char; pub fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX; @@ -567,6 +571,8 @@ extern "C" { pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int; pub fn SSL_CTX_ctrl(ssl: *mut SSL_CTX, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; + pub fn SSL_CTX_callback_ctrl(ssl: *mut SSL_CTX, cmd: c_int, callback: Option) -> c_long; + #[cfg(feature = "npn")] pub fn SSL_CTX_set_next_protos_advertised_cb(ssl: *mut SSL_CTX, cb: extern "C" fn(ssl: *mut SSL, diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index cca369a2..f73c263a 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -32,6 +32,7 @@ pub mod error; mod tests; static mut VERIFY_IDX: c_int = -1; +static mut SNI_IDX: c_int = -1; /// Manually initialize SSL. /// It is optional to call this function and safe to do so more than once. @@ -46,6 +47,11 @@ pub fn init() { None, None); assert!(verify_idx >= 0); VERIFY_IDX = verify_idx; + + let sni_idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, + None, None); + assert!(sni_idx >= 0); + SNI_IDX = sni_idx; }); } } @@ -297,6 +303,51 @@ extern fn raw_verify_with_data(preverify_ok: c_int, } } +extern fn raw_sni(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_void) + -> c_int { + println!("openssl called raw_sni. ad=={:?}", *ad); + unsafe { + let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); + let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, SNI_IDX); + let callback: Option = mem::transmute(callback); + let mut ssl = Ssl { ssl: ssl }; + println!("openssl got callback"); + + let res = match callback { + None => ffi::SSL_TLSEXT_ERR_ALERT_FATAL, + Some(callback) => callback(&mut ssl, ad) + }; + println!("openssl got callback result: {}", res); + res + } +} + +extern fn raw_sni_with_data(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_void) -> c_int + where T: Any + 'static { + unsafe { + let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); + + let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, SNI_IDX); + let callback: Option> = mem::transmute(callback); + let mut ssl = Ssl { ssl: ssl }; + + let data: Box = mem::transmute(arg); + + let res = match callback { + None => ffi::SSL_TLSEXT_ERR_ALERT_FATAL, + Some(callback) => callback(&mut ssl, ad, &*data) + }; + + // Since data might be required on the next verification + // it is time to forget about it and avoid dropping + // data will be freed once OpenSSL considers it is time + // to free all context data + mem::forget(data); + res + } +} + + #[cfg(any(feature = "npn", feature = "alpn"))] unsafe fn select_proto_using(ssl: *mut ffi::SSL, out: *mut *mut c_uchar, outlen: *mut c_uchar, @@ -404,6 +455,11 @@ pub type VerifyCallbackData = fn(preverify_ok: bool, x509_ctx: &X509StoreContext, data: &T) -> bool; +/// The signature of functions that can be used to choose the context depending on the server name +pub type ServerNameCallback = fn(ssl: &mut Ssl, ad: &mut i32) -> i32; + +pub type ServerNameCallbackData = fn(ssl: &mut Ssl, ad: &mut i32, data: &T) -> i32; + // FIXME: macro may be instead of inlining? #[inline] fn wrap_ssl_result(res: c_int) -> Result<(),SslError> { @@ -485,6 +541,31 @@ impl SslContext { } } + /// Configures the certificate verification method for new connections. + pub fn set_servername_callback(&mut self, callback: Option) { + unsafe { + ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX, + mem::transmute(callback)); + //let f: extern fn(c_int, *mut ffi::X509_STORE_CTX) -> c_int = raw_sni; + let f: extern fn() = mem::transmute(raw_sni); + ffi::SSL_CTX_callback_ctrl(self.ctx, ffi::SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, Some(f)); + } + } + + pub fn set_servername_callback_with_data(&mut self, callback: ServerNameCallbackData, + data: T) + where T: Any + 'static { + let data = Box::new(data); + unsafe { + ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX, + mem::transmute(Some(callback))); + + ffi::SSL_CTX_ctrl(self.ctx, ffi::SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, mem::transmute(data)); + let f: extern fn() = mem::transmute(raw_sni_with_data::); + ffi::SSL_CTX_callback_ctrl(self.ctx, ffi::SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, Some(f)); + } + } + /// Sets verification depth pub fn set_verify_depth(&mut self, depth: u32) { unsafe { @@ -673,6 +754,7 @@ impl SslContext { ffi::SSL_CTX_set_alpn_select_cb(self.ctx, raw_alpn_select_cb, ptr::null_mut()); } } + } #[allow(dead_code)] @@ -886,6 +968,20 @@ impl Ssl { SslMethod::from_raw(method) } } + + /// Returns the server name for the current connection + pub fn get_servername(&self) -> Option { + let name = unsafe { ffi::SSL_get_servername(self.ssl, ffi::TLSEXT_NAMETYPE_host_name) }; + if name == ptr::null() { + return None; + } + + println!("openssl will return servername"); + unsafe { + String::from_utf8(CStr::from_ptr(name).to_bytes().to_vec()).ok() + } + } + } macro_rules! make_LibSslError { From dba3a0ced24147414abaa9f8394b9f249b08f599 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Sun, 22 Nov 2015 20:01:41 +0100 Subject: [PATCH 02/28] implement get/set ssl context --- openssl-sys/src/lib.rs | 1 + openssl/src/ssl/mod.rs | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index be33ea4c..e2eaab38 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -534,6 +534,7 @@ extern "C" { pub fn SSL_write(ssl: *mut SSL, buf: *const c_void, num: c_int) -> c_int; pub fn SSL_get_ex_data_X509_STORE_CTX_idx() -> c_int; pub fn SSL_get_SSL_CTX(ssl: *mut SSL) -> *mut SSL_CTX; + pub fn SSL_set_SSL_CTX(ssl: *mut SSL, ctx: *mut SSL_CTX) -> *mut SSL_CTX; pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const COMP_METHOD; pub fn SSL_get_peer_certificate(ssl: *mut SSL) -> *mut X509; pub fn SSL_get_ssl_method(ssl: *mut SSL) -> *const SSL_METHOD; diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index f73c263a..736e6b4c 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -982,6 +982,14 @@ impl Ssl { } } + pub fn set_ssl_context(&self, ctx: &SslContext) -> SslContext { + SslContext { ctx: unsafe { ffi::SSL_set_SSL_CTX(self.ssl, ctx.ctx) } } + } + + pub fn get_ssl_context(&self) -> SslContext { + let ssl_ctx = unsafe { ffi::SSL_get_SSL_CTX(self.ssl) }; + SslContext { ctx: ssl_ctx } + } } macro_rules! make_LibSslError { From 667e3f44b99450fbf9b1d80a8949183ce295fbf8 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Sun, 22 Nov 2015 20:01:56 +0100 Subject: [PATCH 03/28] Avoid freeing the SSL object when Ssl is dropped --- openssl/src/ssl/mod.rs | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 736e6b4c..e49b28b2 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -305,19 +305,19 @@ extern fn raw_verify_with_data(preverify_ok: c_int, extern fn raw_sni(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_void) -> c_int { - println!("openssl called raw_sni. ad=={:?}", *ad); unsafe { let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, SNI_IDX); let callback: Option = mem::transmute(callback); - let mut ssl = Ssl { ssl: ssl }; - println!("openssl got callback"); + let mut s = Ssl { ssl: ssl }; let res = match callback { None => ffi::SSL_TLSEXT_ERR_ALERT_FATAL, - Some(callback) => callback(&mut ssl, ad) + Some(callback) => callback(&mut s, ad) }; - println!("openssl got callback result: {}", res); + + // Allows dropping the Ssl instance without calling SSL_FREE on the SSL object + s.ssl = ptr::null_mut() as *mut ffi::SSL; res } } @@ -329,15 +329,18 @@ extern fn raw_sni_with_data(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_v let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, SNI_IDX); let callback: Option> = mem::transmute(callback); - let mut ssl = Ssl { ssl: ssl }; + let mut s = Ssl { ssl: ssl }; let data: Box = mem::transmute(arg); let res = match callback { None => ffi::SSL_TLSEXT_ERR_ALERT_FATAL, - Some(callback) => callback(&mut ssl, ad, &*data) + Some(callback) => callback(&mut s, ad, &*data) }; + // Allows dropping the Ssl instance without calling SSL_FREE on the SSL object + s.ssl = ptr::null_mut() as *mut ffi::SSL; + // Since data might be required on the next verification // it is time to forget about it and avoid dropping // data will be freed once OpenSSL considers it is time @@ -541,7 +544,10 @@ impl SslContext { } } - /// Configures the certificate verification method for new connections. + /// Configures the server name indication (SNI) callback for new connections + /// + /// obtain the server name with `get_servername` then set the corresponding context + /// with `set_ssl_context` pub fn set_servername_callback(&mut self, callback: Option) { unsafe { ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX, @@ -552,6 +558,8 @@ impl SslContext { } } + /// Configures the server name indication (SNI) callback for new connections + /// carrying supplied data pub fn set_servername_callback_with_data(&mut self, callback: ServerNameCallbackData, data: T) where T: Any + 'static { @@ -969,23 +977,24 @@ impl Ssl { } } - /// Returns the server name for the current connection + /// Returns the server's name for the current connection pub fn get_servername(&self) -> Option { let name = unsafe { ffi::SSL_get_servername(self.ssl, ffi::TLSEXT_NAMETYPE_host_name) }; if name == ptr::null() { return None; } - println!("openssl will return servername"); unsafe { String::from_utf8(CStr::from_ptr(name).to_bytes().to_vec()).ok() } } + /// change the context corresponding to the current connection pub fn set_ssl_context(&self, ctx: &SslContext) -> SslContext { SslContext { ctx: unsafe { ffi::SSL_set_SSL_CTX(self.ssl, ctx.ctx) } } } + /// obtain the context corresponding to the current connection pub fn get_ssl_context(&self) -> SslContext { let ssl_ctx = unsafe { ffi::SSL_get_SSL_CTX(self.ssl) }; SslContext { ctx: ssl_ctx } From e48694432008c752d17dbe08a26a2f7fbeb18155 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Wed, 25 Nov 2015 07:51:22 +0100 Subject: [PATCH 04/28] fix memory management --- openssl/src/ssl/mod.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index e49b28b2..8de09396 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -317,7 +317,7 @@ extern fn raw_sni(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_void) }; // Allows dropping the Ssl instance without calling SSL_FREE on the SSL object - s.ssl = ptr::null_mut() as *mut ffi::SSL; + mem::forget(s); res } } @@ -331,7 +331,7 @@ extern fn raw_sni_with_data(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_v let callback: Option> = mem::transmute(callback); let mut s = Ssl { ssl: ssl }; - let data: Box = mem::transmute(arg); + let data: &T = mem::transmute(arg); let res = match callback { None => ffi::SSL_TLSEXT_ERR_ALERT_FATAL, @@ -339,13 +339,12 @@ extern fn raw_sni_with_data(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_v }; // Allows dropping the Ssl instance without calling SSL_FREE on the SSL object - s.ssl = ptr::null_mut() as *mut ffi::SSL; + mem::forget(s); // Since data might be required on the next verification // it is time to forget about it and avoid dropping // data will be freed once OpenSSL considers it is time // to free all context data - mem::forget(data); res } } @@ -552,7 +551,6 @@ impl SslContext { unsafe { ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX, mem::transmute(callback)); - //let f: extern fn(c_int, *mut ffi::X509_STORE_CTX) -> c_int = raw_sni; let f: extern fn() = mem::transmute(raw_sni); ffi::SSL_CTX_callback_ctrl(self.ctx, ffi::SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, Some(f)); } From 7835ea1c906450c524b8575a668860ee9e0b2d85 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Wed, 25 Nov 2015 08:10:36 +0100 Subject: [PATCH 05/28] Make shims for SSL_CTX_ctrl and SSL_CTX_callback_ctrl macro wrappers --- openssl-sys-extras/src/lib.rs | 6 +++++- openssl-sys-extras/src/openssl_shim.c | 8 ++++++++ openssl-sys/src/lib.rs | 3 --- openssl/src/ssl/mod.rs | 6 +++--- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/openssl-sys-extras/src/lib.rs b/openssl-sys-extras/src/lib.rs index a768f436..f17c7fd5 100644 --- a/openssl-sys-extras/src/lib.rs +++ b/openssl-sys-extras/src/lib.rs @@ -4,7 +4,7 @@ extern crate openssl_sys; extern crate libc; -use libc::{c_int, c_uint, c_long, c_char}; +use libc::{c_int, c_uint, c_long, c_char, c_void}; use openssl_sys::{HMAC_CTX, EVP_MD, ENGINE, SSL_CTX, BIO, X509, stack_st_X509_EXTENSION, SSL, DH}; macro_rules! import_options { @@ -65,4 +65,8 @@ extern { pub fn SSL_CTX_set_tmp_dh(s: *mut SSL, dh: *const DH) -> c_long; #[link_name = "X509_get_extensions_shim"] pub fn X509_get_extensions(x: *mut X509) -> *mut stack_st_X509_EXTENSION; + #[link_name = "SSL_CTX_set_tlsext_servername_callback_shim"] + pub fn SSL_CTX_set_tlsext_servername_callback(ssl: *mut SSL_CTX, callback: Option); + #[link_name = "SSL_CTX_set_tlsext_servername_arg_shim"] + pub fn SSL_CTX_set_tlsext_servername_arg(ssl: *mut SSL_CTX, arg: *const c_void); } diff --git a/openssl-sys-extras/src/openssl_shim.c b/openssl-sys-extras/src/openssl_shim.c index 84adb47b..302e539a 100644 --- a/openssl-sys-extras/src/openssl_shim.c +++ b/openssl-sys-extras/src/openssl_shim.c @@ -115,6 +115,14 @@ long SSL_CTX_set_tmp_dh_shim(SSL_CTX *ctx, DH *dh) { return SSL_CTX_set_tmp_dh(ctx, dh); } +long SSL_CTX_set_tlsext_servername_callback_shim(SSL_CTX *ctx, int (*callback)(SSL_CTX *, int *, void*)) { + return SSL_CTX_set_tlsext_servername_callback(ctx, callback); +} + +long SSL_CTX_set_tlsext_servername_arg_shim(SSL_CTX *ctx, void* arg) { + return SSL_CTX_set_tlsext_servername_arg(ctx, arg); +} + #if OPENSSL_VERSION_NUMBER >= 0x10002000L int SSL_CTX_set_ecdh_auto_shim(SSL_CTX *ctx, int onoff) { return SSL_CTX_set_ecdh_auto(ctx, onoff); diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index e2eaab38..b9b4e3e9 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -571,9 +571,6 @@ extern "C" { pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int; - pub fn SSL_CTX_ctrl(ssl: *mut SSL_CTX, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; - pub fn SSL_CTX_callback_ctrl(ssl: *mut SSL_CTX, cmd: c_int, callback: Option) -> c_long; - #[cfg(feature = "npn")] pub fn SSL_CTX_set_next_protos_advertised_cb(ssl: *mut SSL_CTX, cb: extern "C" fn(ssl: *mut SSL, diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 8de09396..b25e7d28 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -552,7 +552,7 @@ impl SslContext { ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX, mem::transmute(callback)); let f: extern fn() = mem::transmute(raw_sni); - ffi::SSL_CTX_callback_ctrl(self.ctx, ffi::SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, Some(f)); + ffi_extras::SSL_CTX_set_tlsext_servername_callback(self.ctx, Some(f)); } } @@ -566,9 +566,9 @@ impl SslContext { ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX, mem::transmute(Some(callback))); - ffi::SSL_CTX_ctrl(self.ctx, ffi::SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, mem::transmute(data)); + ffi_extras::SSL_CTX_set_tlsext_servername_arg(self.ctx, mem::transmute(data)); let f: extern fn() = mem::transmute(raw_sni_with_data::); - ffi::SSL_CTX_callback_ctrl(self.ctx, ffi::SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, Some(f)); + ffi_extras::SSL_CTX_set_tlsext_servername_callback(self.ctx, Some(f)); } } From 1d09eec7342c6490baace9568575dfc83f4e64e2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 28 Nov 2015 17:18:47 -0800 Subject: [PATCH 06/28] Mention el cap changes in readme --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d8cc1ec1..83896575 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,9 @@ sudo pacman -S openssl OpenSSL 0.9.8 is preinstalled on OSX. Some features are only available when linking against OpenSSL 1.0.0 or greater; see below on how to point -rust-openssl to a separate installation. +rust-openssl to a separate installation. OSX releases starting at 10.11, "El +Capitan", no longer include OpenSSL headers which will prevent the `openssl` +crate from compiling. ### Windows From f54af75eb7f8c861383119722f548cb2866ca813 Mon Sep 17 00:00:00 2001 From: Ondrej Perutka Date: Mon, 30 Nov 2015 21:06:54 +0100 Subject: [PATCH 07/28] Cast correctly c_char raw pointers (fixes build on ARM #314) --- openssl/src/bn/mod.rs | 8 ++++---- openssl/src/ssl/error.rs | 9 ++++++--- openssl/src/ssl/mod.rs | 18 +++++++++--------- openssl/src/x509/mod.rs | 6 +++--- 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/openssl/src/bn/mod.rs b/openssl/src/bn/mod.rs index 3c973438..2d678da2 100644 --- a/openssl/src/bn/mod.rs +++ b/openssl/src/bn/mod.rs @@ -89,7 +89,7 @@ impl BigNum { pub fn from_dec_str(s: &str) -> Result { BigNum::new().and_then(|v| unsafe { let c_str = CString::new(s.as_bytes()).unwrap(); - try_ssl!(ffi::BN_dec2bn(v.raw_ptr(), c_str.as_ptr())); + try_ssl!(ffi::BN_dec2bn(v.raw_ptr(), c_str.as_ptr() as *const _)); Ok(v) }) } @@ -97,7 +97,7 @@ impl BigNum { pub fn from_hex_str(s: &str) -> Result { BigNum::new().and_then(|v| unsafe { let c_str = CString::new(s.as_bytes()).unwrap(); - try_ssl!(ffi::BN_hex2bn(v.raw_ptr(), c_str.as_ptr())); + try_ssl!(ffi::BN_hex2bn(v.raw_ptr(), c_str.as_ptr() as *const _)); Ok(v) }) } @@ -421,7 +421,7 @@ impl BigNum { unsafe { let buf = ffi::BN_bn2dec(self.raw()); assert!(!buf.is_null()); - let str = String::from_utf8(CStr::from_ptr(buf).to_bytes().to_vec()).unwrap(); + let str = String::from_utf8(CStr::from_ptr(buf as *const _).to_bytes().to_vec()).unwrap(); ffi::CRYPTO_free(buf as *mut c_void); str } @@ -431,7 +431,7 @@ impl BigNum { unsafe { let buf = ffi::BN_bn2hex(self.raw()); assert!(!buf.is_null()); - let str = String::from_utf8(CStr::from_ptr(buf).to_bytes().to_vec()).unwrap(); + let str = String::from_utf8(CStr::from_ptr(buf as *const _).to_bytes().to_vec()).unwrap(); ffi::CRYPTO_free(buf as *mut c_void); str } diff --git a/openssl/src/ssl/error.rs b/openssl/src/ssl/error.rs index 0126b277..d76494f1 100644 --- a/openssl/src/ssl/error.rs +++ b/openssl/src/ssl/error.rs @@ -117,21 +117,24 @@ pub enum OpensslError { fn get_lib(err: c_ulong) -> String { unsafe { - let bytes = CStr::from_ptr(ffi::ERR_lib_error_string(err)).to_bytes().to_vec(); + let cstr = ffi::ERR_lib_error_string(err); + let bytes = CStr::from_ptr(cstr as *const _).to_bytes().to_vec(); String::from_utf8(bytes).unwrap() } } fn get_func(err: c_ulong) -> String { unsafe { - let bytes = CStr::from_ptr(ffi::ERR_func_error_string(err)).to_bytes().to_vec(); + let cstr = ffi::ERR_func_error_string(err); + let bytes = CStr::from_ptr(cstr as *const _).to_bytes().to_vec(); String::from_utf8(bytes).unwrap() } } fn get_reason(err: c_ulong) -> String { unsafe { - let bytes = CStr::from_ptr(ffi::ERR_reason_error_string(err)).to_bytes().to_vec(); + let cstr = ffi::ERR_reason_error_string(err); + let bytes = CStr::from_ptr(cstr as *const _).to_bytes().to_vec(); String::from_utf8(bytes).unwrap() } } diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index cca369a2..a26b714a 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -510,7 +510,7 @@ impl SslContext { let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap(); wrap_ssl_result( unsafe { - ffi::SSL_CTX_load_verify_locations(self.ctx, file.as_ptr(), ptr::null()) + ffi::SSL_CTX_load_verify_locations(self.ctx, file.as_ptr() as *const _, ptr::null()) }) } @@ -520,7 +520,7 @@ impl SslContext { let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap(); wrap_ssl_result( unsafe { - ffi::SSL_CTX_use_certificate_file(self.ctx, file.as_ptr(), file_type as c_int) + ffi::SSL_CTX_use_certificate_file(self.ctx, file.as_ptr() as *const _, file_type as c_int) }) } @@ -530,7 +530,7 @@ impl SslContext { let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap(); wrap_ssl_result( unsafe { - ffi::SSL_CTX_use_certificate_chain_file(self.ctx, file.as_ptr(), file_type as c_int) + ffi::SSL_CTX_use_certificate_chain_file(self.ctx, file.as_ptr() as *const _, file_type as c_int) }) } @@ -557,7 +557,7 @@ impl SslContext { let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap(); wrap_ssl_result( unsafe { - ffi::SSL_CTX_use_PrivateKey_file(self.ctx, file.as_ptr(), file_type as c_int) + ffi::SSL_CTX_use_PrivateKey_file(self.ctx, file.as_ptr() as *const _, file_type as c_int) }) } @@ -581,7 +581,7 @@ impl SslContext { wrap_ssl_result( unsafe { let cipher_list = CString::new(cipher_list).unwrap(); - ffi::SSL_CTX_set_cipher_list(self.ctx, cipher_list.as_ptr()) + ffi::SSL_CTX_set_cipher_list(self.ctx, cipher_list.as_ptr() as *const _) }) } @@ -768,7 +768,7 @@ impl Ssl { pub fn state_string(&self) -> &'static str { let state = unsafe { let ptr = ffi::SSL_state_string(self.ssl); - CStr::from_ptr(ptr) + CStr::from_ptr(ptr as *const _) }; str::from_utf8(state.to_bytes()).unwrap() @@ -777,7 +777,7 @@ impl Ssl { pub fn state_string_long(&self) -> &'static str { let state = unsafe { let ptr = ffi::SSL_state_string_long(self.ssl); - CStr::from_ptr(ptr) + CStr::from_ptr(ptr as *const _) }; str::from_utf8(state.to_bytes()).unwrap() @@ -786,7 +786,7 @@ impl Ssl { /// Sets the host name to be used with SNI (Server Name Indication). pub fn set_hostname(&self, hostname: &str) -> Result<(), SslError> { let cstr = CString::new(hostname).unwrap(); - let ret = unsafe { ffi_extras::SSL_set_tlsext_host_name(self.ssl, cstr.as_ptr()) }; + let ret = unsafe { ffi_extras::SSL_set_tlsext_host_name(self.ssl, cstr.as_ptr() as *const _) }; // For this case, 0 indicates failure. if ret == 0 { @@ -874,7 +874,7 @@ impl Ssl { let meth = unsafe { ffi::SSL_COMP_get_name(ptr) }; let s = unsafe { - String::from_utf8(CStr::from_ptr(meth).to_bytes().to_vec()).unwrap() + String::from_utf8(CStr::from_ptr(meth as *const _).to_bytes().to_vec()).unwrap() }; Some(s) diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 5574077a..c7039089 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -50,7 +50,7 @@ impl Deref for SslString { impl SslString { unsafe fn new(buf: *const c_char) -> SslString { SslString { - s: str::from_utf8(CStr::from_ptr(buf).to_bytes()).unwrap() + s: str::from_utf8(CStr::from_ptr(buf as *const _).to_bytes()).unwrap() } } } @@ -275,8 +275,8 @@ impl X509Generator { lift_ssl!(unsafe { let key = CString::new(key.as_bytes()).unwrap(); let value = CString::new(value.as_bytes()).unwrap(); - ffi::X509_NAME_add_entry_by_txt(name, key.as_ptr(), ffi::MBSTRING_UTF8, - value.as_ptr(), value_len, -1, 0) + ffi::X509_NAME_add_entry_by_txt(name, key.as_ptr() as *const _, ffi::MBSTRING_UTF8, + value.as_ptr() as *const _, value_len, -1, 0) }) } From 6850c810d32a11330c9b1dd4889b447fa8434c36 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Thu, 3 Dec 2015 12:26:55 +0100 Subject: [PATCH 08/28] Increment SSL_CTX's reference count in Ssl::get_ssl_context() Without this, whenever the returned SslContext is released, the refcount of the underlying SSL_CTX will decrease and it will be freed too soon --- openssl-sys-extras/src/lib.rs | 2 ++ openssl-sys-extras/src/openssl_shim.c | 5 +++++ openssl/src/ssl/mod.rs | 1 + 3 files changed, 8 insertions(+) diff --git a/openssl-sys-extras/src/lib.rs b/openssl-sys-extras/src/lib.rs index f17c7fd5..69a1fee9 100644 --- a/openssl-sys-extras/src/lib.rs +++ b/openssl-sys-extras/src/lib.rs @@ -69,4 +69,6 @@ extern { pub fn SSL_CTX_set_tlsext_servername_callback(ssl: *mut SSL_CTX, callback: Option); #[link_name = "SSL_CTX_set_tlsext_servername_arg_shim"] pub fn SSL_CTX_set_tlsext_servername_arg(ssl: *mut SSL_CTX, arg: *const c_void); + #[link_name = "SSL_CTX_increment_refcount_shim"] + pub fn SSL_CTX_increment_refcount(ssl: *mut SSL_CTX) -> c_long; } diff --git a/openssl-sys-extras/src/openssl_shim.c b/openssl-sys-extras/src/openssl_shim.c index 302e539a..51630daf 100644 --- a/openssl-sys-extras/src/openssl_shim.c +++ b/openssl-sys-extras/src/openssl_shim.c @@ -123,6 +123,11 @@ long SSL_CTX_set_tlsext_servername_arg_shim(SSL_CTX *ctx, void* arg) { return SSL_CTX_set_tlsext_servername_arg(ctx, arg); } +long SSL_CTX_increment_refcount_shim(SSL_CTX *ctx) { + int i = CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX); + return i; +} + #if OPENSSL_VERSION_NUMBER >= 0x10002000L int SSL_CTX_set_ecdh_auto_shim(SSL_CTX *ctx, int onoff) { return SSL_CTX_set_ecdh_auto(ctx, onoff); diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index b25e7d28..a2096f41 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -995,6 +995,7 @@ impl Ssl { /// obtain the context corresponding to the current connection pub fn get_ssl_context(&self) -> SslContext { let ssl_ctx = unsafe { ffi::SSL_get_SSL_CTX(self.ssl) }; + let count = unsafe { ffi_extras::SSL_CTX_increment_refcount(ssl_ctx) }; SslContext { ctx: ssl_ctx } } } From 640888dd4ab63bb9aae516e54e44814884f9cd6f Mon Sep 17 00:00:00 2001 From: Andrew Roetker Date: Mon, 7 Dec 2015 18:27:18 -0800 Subject: [PATCH 09/28] (maint) Update appveyor link to the OpenSSL download This commit updates the link in appveyor to the OpenSSL download to fix Windows PR testing. --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 31c41ee1..99583432 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,8 +8,8 @@ environment: - TARGET: x86_64-pc-windows-msvc BITS: 64 install: - - ps: Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-1_0_2d.exe" - - Win%BITS%OpenSSL-1_0_2d.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL" + - ps: Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-1_0_2e.exe" + - Win%BITS%OpenSSL-1_0_2e.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL" - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin From 8cc69267fd7261d66be681c9815bc3ff137dda6a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 7 Dec 2015 19:03:29 -0800 Subject: [PATCH 10/28] Bump openssl version for travis --- openssl/test/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openssl/test/build.sh b/openssl/test/build.sh index 1b923cb1..9b336b77 100755 --- a/openssl/test/build.sh +++ b/openssl/test/build.sh @@ -3,7 +3,7 @@ set -e mkdir /tmp/openssl cd /tmp/openssl -curl https://openssl.org/source/openssl-1.0.2d.tar.gz | tar --strip-components=1 -xzf - +curl https://openssl.org/source/openssl-1.0.2e.tar.gz | tar --strip-components=1 -xzf - ./config --prefix=$HOME/openssl shared make make install From f79fd8cea985540098bae78503b444130c2e433f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 7 Dec 2015 23:28:28 -0800 Subject: [PATCH 11/28] Add BIO type definitions --- openssl-sys/src/lib.rs | 57 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 0f40bfed..324d7621 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -15,11 +15,8 @@ use std::sync::{Once, ONCE_INIT}; pub type ASN1_INTEGER = c_void; pub type ASN1_STRING = c_void; pub type ASN1_TIME = c_void; -pub type BIO = c_void; -pub type BIO_METHOD = c_void; pub type BN_CTX = c_void; pub type COMP_METHOD = c_void; -pub type CRYPTO_EX_DATA = c_void; pub type DH = c_void; pub type ENGINE = c_void; pub type EVP_CIPHER = c_void; @@ -39,6 +36,60 @@ pub type X509_NAME_ENTRY = c_void; pub type X509_REQ = c_void; pub type X509_STORE_CTX = c_void; pub type stack_st_X509_EXTENSION = c_void; +pub type stack_st_void = c_void; +pub type bio_st = c_void; + +pub type bio_info_cb = Option; + +#[repr(C)] +pub struct BIO_METHOD { + pub type_: c_int, + pub name: *const c_char, + pub bwrite: Option c_int>, + pub bread: Option c_int>, + pub bputs: Option c_int>, + pub bgets: Option c_int>, + pub ctrl: Option c_long>, + pub create: Option c_int>, + pub destroy: Option c_int>, + pub callback_ctrl: Option c_long>, +} + +#[repr(C)] +pub struct BIO { + pub method: *mut BIO_METHOD, + pub callback: Option c_long>, + pub cb_arg: *mut c_char, + pub init: c_int, + pub shutdown: c_int, + pub flags: c_int, + pub retry_reason: c_int, + pub num: c_int, + pub ptr: *mut c_void, + pub next_bio: *mut BIO, + pub prev_bio: *mut BIO, + pub references: c_int, + pub num_read: c_ulong, + pub num_write: c_ulong, + pub ex_data: CRYPTO_EX_DATA, +} + +#[repr(C)] +pub struct CRYPTO_EX_DATA { + pub sk: *mut stack_st_void, + pub dummy: c_int, +} #[repr(C)] pub struct EVP_MD_CTX { From 4d883d488eed9431ebd8ec4e2b5a45d9cbf2e0d8 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 8 Dec 2015 21:57:04 -0800 Subject: [PATCH 12/28] Custom BIO infrastructure --- openssl-sys-extras/src/lib.rs | 6 ++ openssl-sys-extras/src/openssl_shim.c | 12 +++ openssl-sys/src/lib.rs | 3 + openssl/src/ssl/bio.rs | 141 ++++++++++++++++++++++++++ openssl/src/ssl/mod.rs | 1 + 5 files changed, 163 insertions(+) create mode 100644 openssl/src/ssl/bio.rs diff --git a/openssl-sys-extras/src/lib.rs b/openssl-sys-extras/src/lib.rs index a768f436..dfeb06e5 100644 --- a/openssl-sys-extras/src/lib.rs +++ b/openssl-sys-extras/src/lib.rs @@ -49,6 +49,12 @@ extern { pub fn BIO_set_nbio(b: *mut BIO, enabled: c_long) -> c_long; #[link_name = "BIO_set_mem_eof_return_shim"] pub fn BIO_set_mem_eof_return(b: *mut BIO, v: c_int); + #[link_name = "BIO_clear_retry_flags_shim"] + pub fn BIO_clear_retry_flags(b: *mut BIO); + #[link_name = "BIO_set_retry_read_shim"] + pub fn BIO_set_retry_read(b: *mut BIO); + #[link_name = "BIO_set_retry_write_shim"] + pub fn BIO_set_retry_write(b: *mut BIO); pub fn SSL_CTX_set_options_shim(ctx: *mut SSL_CTX, options: c_long) -> c_long; pub fn SSL_CTX_get_options_shim(ctx: *mut SSL_CTX) -> c_long; pub fn SSL_CTX_clear_options_shim(ctx: *mut SSL_CTX, options: c_long) -> c_long; diff --git a/openssl-sys-extras/src/openssl_shim.c b/openssl-sys-extras/src/openssl_shim.c index 84adb47b..95847ac1 100644 --- a/openssl-sys-extras/src/openssl_shim.c +++ b/openssl-sys-extras/src/openssl_shim.c @@ -91,6 +91,18 @@ void BIO_set_mem_eof_return_shim(BIO *b, int v) { BIO_set_mem_eof_return(b, v); } +void BIO_clear_retry_flags_shim(BIO *b) { + BIO_clear_retry_flags(b); +} + +void BIO_set_retry_read_shim(BIO *b) { + BIO_set_retry_read(b); +} + +void BIO_set_retry_write_shim(BIO *b) { + BIO_set_retry_write(b); +} + long SSL_CTX_set_options_shim(SSL_CTX *ctx, long options) { return SSL_CTX_set_options(ctx, options); } diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 324d7621..f19fa16c 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -167,7 +167,10 @@ pub type PasswordCallback = extern "C" fn(buf: *mut c_char, size: c_int, rwflag: c_int, user_data: *mut c_void) -> c_int; +pub const BIO_TYPE_NONE: c_int = 0; + pub const BIO_CTRL_EOF: c_int = 2; +pub const BIO_CTRL_FLUSH: c_int = 11; pub const BIO_C_SET_BUF_MEM_EOF_RETURN: c_int = 130; pub const CRYPTO_LOCK: c_int = 1; diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs new file mode 100644 index 00000000..92479b37 --- /dev/null +++ b/openssl/src/ssl/bio.rs @@ -0,0 +1,141 @@ +use libc::{c_char, c_int, c_long, c_void, strlen}; +use ffi::{BIO, BIO_METHOD, BIO_CTRL_FLUSH, BIO_TYPE_NONE, BIO_new}; +use ffi_extras::{BIO_clear_retry_flags, BIO_set_retry_read, BIO_set_retry_write}; +use std::any::Any; +use std::io; +use std::io::prelude::*; +use std::marker::PhantomData; +use std::mem; +use std::slice; +use std::sync::Mutex; +use std::ptr; + +use ssl::error::SslError; + +pub struct StreamState { + pub stream: S, + pub error: Option, +} + +pub fn new_bio(stream: S) -> Result<(*mut BIO, Box), SslError> { + // "rust" + static NAME: [c_char; 5] = [114, 117, 115, 116, 0]; + + let method = Box::new(BIO_METHOD { + type_: BIO_TYPE_NONE, + name: &NAME[0], + bwrite: Some(bwrite::), + bread: Some(bread::), + bputs: Some(bputs::), + bgets: None, + ctrl: Some(ctrl::), + create: Some(create), + destroy: Some(destroy), + callback_ctrl: None, + }); + + let state = Box::new(StreamState { + stream: stream, + error: None, + }); + + unsafe { + let bio = BIO_new(&*method); + if bio.is_null() { + return Err(SslError::get()); + } + + (*bio).ptr = Box::into_raw(state) as *mut _; + + return Ok((bio, method)); + } +} + +pub unsafe fn take_error(bio: *mut BIO) -> Option { + let state = state::(bio); + state.error.take() +} + +pub unsafe fn take_stream(bio: *mut BIO) -> S { + let state: Box> = Box::from_raw((*bio).ptr as *mut _); + (*bio).ptr = ptr::null_mut(); + state.stream +} + +unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState { + mem::transmute((*bio).ptr) +} + +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 state.stream.write(buf) { + Ok(len) => len as c_int, + Err(err) => { + if err.kind() == io::ErrorKind::WouldBlock { + BIO_set_retry_write(bio); + } + state.error = Some(err); + -1 + } + } +} + +unsafe extern "C" fn bread(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int { + BIO_clear_retry_flags(bio); + + let state = state::(bio); + let buf = slice::from_raw_parts_mut(buf as *mut _, len as usize); + match state.stream.read(buf) { + Ok(len) => len as c_int, + Err(err) => { + if err.kind() == io::ErrorKind::WouldBlock { + BIO_set_retry_read(bio); + } + state.error = Some(err); + -1 + } + } +} + +unsafe extern "C" 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, + cmd: c_int, + num: c_long, + ptr: *mut c_void) + -> c_long { + if cmd == BIO_CTRL_FLUSH { + let state = state::(bio); + match state.stream.flush() { + Ok(()) => 1, + Err(err) => { + state.error = Some(err); + 0 + } + } + } else { + 0 + } +} + +unsafe extern "C" fn create(bio: *mut BIO) -> c_int { + (*bio).init = 0; + (*bio).num = 0; + (*bio).ptr = ptr::null_mut(); + (*bio).flags = 0; + 1 +} + +unsafe extern "C" fn destroy(bio: *mut BIO) -> c_int { + if bio.is_null() { + return 0; + } + + assert!((*bio).ptr.is_null()); + 1 +} diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index a26b714a..2f09e4fa 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -28,6 +28,7 @@ use x509::{X509StoreContext, X509FileType, X509}; use crypto::pkey::PKey; pub mod error; +mod bio; #[cfg(test)] mod tests; From 9ee6f1c5785bb170c04a825ef173d4e336c957b2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 9 Dec 2015 21:43:02 -0800 Subject: [PATCH 13/28] IT LIVES --- openssl-sys/src/lib.rs | 3 ++ openssl/src/ssl/bio.rs | 49 ++++++++++++----- openssl/src/ssl/mod.rs | 101 +++++++++++++++++++++++++++++++++++ openssl/src/ssl/tests/mod.rs | 9 +++- 4 files changed, 147 insertions(+), 15 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index f19fa16c..03824e05 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -60,6 +60,9 @@ pub struct BIO_METHOD { pub callback_ctrl: Option c_long>, } +// so we can create static BIO_METHODs +unsafe impl Sync for BIO_METHOD {} + #[repr(C)] pub struct BIO { pub method: *mut BIO_METHOD, diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs index 92479b37..1009c0bc 100644 --- a/openssl/src/ssl/bio.rs +++ b/openssl/src/ssl/bio.rs @@ -1,25 +1,38 @@ use libc::{c_char, c_int, c_long, c_void, strlen}; use ffi::{BIO, BIO_METHOD, BIO_CTRL_FLUSH, BIO_TYPE_NONE, BIO_new}; use ffi_extras::{BIO_clear_retry_flags, BIO_set_retry_read, BIO_set_retry_write}; -use std::any::Any; use std::io; use std::io::prelude::*; -use std::marker::PhantomData; use std::mem; use std::slice; -use std::sync::Mutex; use std::ptr; use ssl::error::SslError; +// "rust" +const NAME: [c_char; 5] = [114, 117, 115, 116, 0]; + +// we use this after removing the stream from the BIO so that we don't have to +// worry about freeing the heap allocated BIO_METHOD after freeing the BIO. +static DESTROY_METHOD: BIO_METHOD = BIO_METHOD { + type_: BIO_TYPE_NONE, + name: &NAME[0], + bwrite: None, + bread: None, + bputs: None, + bgets: None, + ctrl: None, + create: None, + destroy: Some(destroy), + callback_ctrl: None, +}; + pub struct StreamState { pub stream: S, pub error: Option, } -pub fn new_bio(stream: S) -> Result<(*mut BIO, Box), SslError> { - // "rust" - static NAME: [c_char; 5] = [114, 117, 115, 116, 0]; +pub fn new(stream: S) -> Result<(*mut BIO, Box), SslError> { let method = Box::new(BIO_METHOD { type_: BIO_TYPE_NONE, @@ -30,7 +43,7 @@ pub fn new_bio(stream: S) -> Result<(*mut BIO, Box) bgets: None, ctrl: Some(ctrl::), create: Some(create), - destroy: Some(destroy), + destroy: None, // covered in the replacement BIO_METHOD callback_ctrl: None, }); @@ -40,12 +53,9 @@ pub fn new_bio(stream: S) -> Result<(*mut BIO, Box) }); unsafe { - let bio = BIO_new(&*method); - if bio.is_null() { - return Err(SslError::get()); - } - + let bio = try_ssl_null!(BIO_new(&*method)); (*bio).ptr = Box::into_raw(state) as *mut _; + (*bio).init = 1; return Ok((bio, method)); } @@ -59,9 +69,20 @@ pub unsafe fn take_error(bio: *mut BIO) -> Option { pub unsafe fn take_stream(bio: *mut BIO) -> S { let state: Box> = Box::from_raw((*bio).ptr as *mut _); (*bio).ptr = ptr::null_mut(); + (*bio).method = &DESTROY_METHOD as *const _ as *mut _; + (*bio).init = 0; state.stream } +pub unsafe fn get_ref<'a, S: 'a>(bio: *mut BIO) -> &'a S { + let state: &'a StreamState = mem::transmute((*bio).ptr); + &state.stream +} + +pub unsafe fn get_mut<'a, S: 'a>(bio: *mut BIO) -> &'a mut S { + &mut state(bio).stream +} + unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState { mem::transmute((*bio).ptr) } @@ -106,8 +127,8 @@ unsafe extern "C" fn bputs(bio: *mut BIO, s: *const c_char) -> c_int { unsafe extern "C" fn ctrl(bio: *mut BIO, cmd: c_int, - num: c_long, - ptr: *mut c_void) + _num: c_long, + _ptr: *mut c_void) -> c_long { if cmd == BIO_CTRL_FLUSH { let state = state::(bio); diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 2f09e4fa..5d24fc32 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -18,6 +18,7 @@ use std::any::Any; use libc::{c_uchar, c_uint}; #[cfg(any(feature = "npn", feature = "alpn"))] use std::slice; +use std::marker::PhantomData; use bio::{MemBio}; use ffi; @@ -724,6 +725,10 @@ impl Ssl { Ok(ssl) } + fn get_raw_rbio(&self) -> *mut ffi::BIO { + unsafe { ffi::SSL_get_rbio(self.ssl) } + } + fn get_rbio<'a>(&'a self) -> MemBioRef<'a> { unsafe { self.wrap_bio(ffi::SSL_get_rbio(self.ssl)) } } @@ -1345,6 +1350,102 @@ impl Write for SslStream { } } +pub struct SslStreamNg { + ssl: Ssl, + _method: Box, // :( + _p: PhantomData, +} + +impl Drop for SslStreamNg { + fn drop(&mut self) { + unsafe { + let _ = bio::take_stream::(self.ssl.get_raw_rbio()); + } + } +} + +impl SslStreamNg { + fn new_base(ssl: Ssl, stream: S) -> Result { + unsafe { + let (bio, method) = try!(bio::new(stream)); + ffi::SSL_set_bio(ssl.ssl, bio, bio); + + Ok(SslStreamNg { + ssl: ssl, + _method: method, + _p: PhantomData, + }) + } + } + + /// Creates an SSL/TLS client operating over the provided stream. + pub fn connect(ssl: T, stream: S) -> Result { + let ssl = try!(ssl.into_ssl()); + let mut stream = try!(Self::new_base(ssl, stream)); + let ret = stream.ssl.connect(); + if ret > 0 { + Ok(stream) + } else { + Err(stream.make_error(ret)) + } + } + + /// Creates an SSL/TLS server operating over the provided stream. + pub fn accept(ssl: T, stream: S) -> Result { + let ssl = try!(ssl.into_ssl()); + let mut stream = try!(Self::new_base(ssl, stream)); + let ret = stream.ssl.accept(); + if ret > 0 { + Ok(stream) + } else { + Err(stream.make_error(ret)) + } + } + + pub fn get_ref(&self) -> &S { + unsafe { + let bio = self.ssl.get_raw_rbio(); + bio::get_ref(bio) + } + } + + pub fn mut_ref(&mut self) -> &mut S { + unsafe { + let bio = self.ssl.get_raw_rbio(); + bio::get_mut(bio) + } + } + + fn make_error(&mut self, ret: c_int) -> SslError { + match self.ssl.get_error(ret) { + LibSslError::ErrorSsl => SslError::get(), + LibSslError::ErrorSyscall => { + let err = SslError::get(); + let count = match err { + SslError::OpenSslErrors(ref v) => v.len(), + _ => unreachable!(), + }; + if count == 0 { + if ret == 0 { + SslError::StreamError(io::Error::new(io::ErrorKind::ConnectionAborted, + "unexpected EOF observed")) + } else { + let error = unsafe { bio::take_error::(self.ssl.get_raw_rbio()) }; + SslError::StreamError(error.unwrap()) + } + } else { + err + } + } + LibSslError::ErrorWantWrite | LibSslError::ErrorWantRead => { + let error = unsafe { bio::take_error::(self.ssl.get_raw_rbio()) }; + SslError::StreamError(error.unwrap()) + } + err => panic!("unexpected error {:?} with ret {}", err, ret), + } + } +} + pub trait IntoSsl { fn into_ssl(self) -> Result; } diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 025a45a8..d1f34019 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -18,7 +18,7 @@ use ssl::SSL_VERIFY_PEER; use ssl::SslMethod::Sslv23; use ssl::SslMethod; use ssl::error::NonblockingSslError; -use ssl::{SslContext, SslStream, VerifyCallback, NonblockingSslStream}; +use ssl::{SslContext, SslStream, VerifyCallback, NonblockingSslStream, SslStreamNg}; use x509::X509StoreContext; use x509::X509FileType; use x509::X509; @@ -929,3 +929,10 @@ fn test_read_nonblocking() { assert!(bytes_read >= 5); assert_eq!(&input_buffer[..5], b"HTTP/"); } + +#[test] +fn ng_connect() { + let (_s, stream) = Server::new(); + let ctx = SslContext::new(Sslv23).unwrap(); + SslStreamNg::connect(&ctx, stream).unwrap(); +} From 8f56897043f8138980ce3376765b769c764d8701 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 9 Dec 2015 22:02:02 -0800 Subject: [PATCH 14/28] Implement read and write --- openssl-sys-extras/src/lib.rs | 2 + openssl-sys-extras/src/openssl_shim.c | 4 + openssl/src/ssl/mod.rs | 226 +++++++++++++++----------- openssl/src/ssl/tests/mod.rs | 12 ++ 4 files changed, 148 insertions(+), 96 deletions(-) diff --git a/openssl-sys-extras/src/lib.rs b/openssl-sys-extras/src/lib.rs index dfeb06e5..3c114726 100644 --- a/openssl-sys-extras/src/lib.rs +++ b/openssl-sys-extras/src/lib.rs @@ -55,6 +55,8 @@ extern { pub fn BIO_set_retry_read(b: *mut BIO); #[link_name = "BIO_set_retry_write_shim"] pub fn BIO_set_retry_write(b: *mut BIO); + #[link_name = "BIO_flush"] + pub fn BIO_flush(b: *mut BIO) -> c_long; pub fn SSL_CTX_set_options_shim(ctx: *mut SSL_CTX, options: c_long) -> c_long; pub fn SSL_CTX_get_options_shim(ctx: *mut SSL_CTX) -> c_long; pub fn SSL_CTX_clear_options_shim(ctx: *mut SSL_CTX, options: c_long) -> c_long; diff --git a/openssl-sys-extras/src/openssl_shim.c b/openssl-sys-extras/src/openssl_shim.c index 95847ac1..cc42fbf4 100644 --- a/openssl-sys-extras/src/openssl_shim.c +++ b/openssl-sys-extras/src/openssl_shim.c @@ -103,6 +103,10 @@ void BIO_set_retry_write_shim(BIO *b) { BIO_set_retry_write(b); } +long BIO_flush_shim(BIO *b) { + return BIO_flush(b); +} + long SSL_CTX_set_options_shim(SSL_CTX *ctx, long options) { return SSL_CTX_set_options(ctx, options); } diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 5d24fc32..e12d694d 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1350,102 +1350,6 @@ impl Write for SslStream { } } -pub struct SslStreamNg { - ssl: Ssl, - _method: Box, // :( - _p: PhantomData, -} - -impl Drop for SslStreamNg { - fn drop(&mut self) { - unsafe { - let _ = bio::take_stream::(self.ssl.get_raw_rbio()); - } - } -} - -impl SslStreamNg { - fn new_base(ssl: Ssl, stream: S) -> Result { - unsafe { - let (bio, method) = try!(bio::new(stream)); - ffi::SSL_set_bio(ssl.ssl, bio, bio); - - Ok(SslStreamNg { - ssl: ssl, - _method: method, - _p: PhantomData, - }) - } - } - - /// Creates an SSL/TLS client operating over the provided stream. - pub fn connect(ssl: T, stream: S) -> Result { - let ssl = try!(ssl.into_ssl()); - let mut stream = try!(Self::new_base(ssl, stream)); - let ret = stream.ssl.connect(); - if ret > 0 { - Ok(stream) - } else { - Err(stream.make_error(ret)) - } - } - - /// Creates an SSL/TLS server operating over the provided stream. - pub fn accept(ssl: T, stream: S) -> Result { - let ssl = try!(ssl.into_ssl()); - let mut stream = try!(Self::new_base(ssl, stream)); - let ret = stream.ssl.accept(); - if ret > 0 { - Ok(stream) - } else { - Err(stream.make_error(ret)) - } - } - - pub fn get_ref(&self) -> &S { - unsafe { - let bio = self.ssl.get_raw_rbio(); - bio::get_ref(bio) - } - } - - pub fn mut_ref(&mut self) -> &mut S { - unsafe { - let bio = self.ssl.get_raw_rbio(); - bio::get_mut(bio) - } - } - - fn make_error(&mut self, ret: c_int) -> SslError { - match self.ssl.get_error(ret) { - LibSslError::ErrorSsl => SslError::get(), - LibSslError::ErrorSyscall => { - let err = SslError::get(); - let count = match err { - SslError::OpenSslErrors(ref v) => v.len(), - _ => unreachable!(), - }; - if count == 0 { - if ret == 0 { - SslError::StreamError(io::Error::new(io::ErrorKind::ConnectionAborted, - "unexpected EOF observed")) - } else { - let error = unsafe { bio::take_error::(self.ssl.get_raw_rbio()) }; - SslError::StreamError(error.unwrap()) - } - } else { - err - } - } - LibSslError::ErrorWantWrite | LibSslError::ErrorWantRead => { - let error = unsafe { bio::take_error::(self.ssl.get_raw_rbio()) }; - SslError::StreamError(error.unwrap()) - } - err => panic!("unexpected error {:?} with ret {}", err, ret), - } - } -} - pub trait IntoSsl { fn into_ssl(self) -> Result; } @@ -1756,3 +1660,133 @@ impl NonblockingSslStream { } } } + +pub struct SslStreamNg { + ssl: Ssl, + _method: Box, // :( + _p: PhantomData, +} + +impl Drop for SslStreamNg { + fn drop(&mut self) { + unsafe { + let _ = bio::take_stream::(self.ssl.get_raw_rbio()); + } + } +} + +impl SslStreamNg { + fn new_base(ssl: Ssl, stream: S) -> Result { + unsafe { + let (bio, method) = try!(bio::new(stream)); + ffi::SSL_set_bio(ssl.ssl, bio, bio); + + Ok(SslStreamNg { + ssl: ssl, + _method: method, + _p: PhantomData, + }) + } + } + + /// Creates an SSL/TLS client operating over the provided stream. + pub fn connect(ssl: T, stream: S) -> Result { + let ssl = try!(ssl.into_ssl()); + let mut stream = try!(Self::new_base(ssl, stream)); + let ret = stream.ssl.connect(); + if ret > 0 { + Ok(stream) + } else { + Err(stream.make_error(ret)) + } + } + + /// Creates an SSL/TLS server operating over the provided stream. + pub fn accept(ssl: T, stream: S) -> Result { + let ssl = try!(ssl.into_ssl()); + let mut stream = try!(Self::new_base(ssl, stream)); + let ret = stream.ssl.accept(); + if ret > 0 { + Ok(stream) + } else { + Err(stream.make_error(ret)) + } + } +} + +impl SslStreamNg { + pub fn get_ref(&self) -> &S { + unsafe { + let bio = self.ssl.get_raw_rbio(); + bio::get_ref(bio) + } + } + + pub fn get_mut(&mut self) -> &mut S { + unsafe { + let bio = self.ssl.get_raw_rbio(); + bio::get_mut(bio) + } + } + + fn make_error(&mut self, ret: c_int) -> SslError { + match self.ssl.get_error(ret) { + LibSslError::ErrorSsl => SslError::get(), + LibSslError::ErrorSyscall => { + let err = SslError::get(); + let count = match err { + SslError::OpenSslErrors(ref v) => v.len(), + _ => unreachable!(), + }; + if count == 0 { + if ret == 0 { + SslError::StreamError(io::Error::new(io::ErrorKind::ConnectionAborted, + "unexpected EOF observed")) + } else { + let error = unsafe { bio::take_error::(self.ssl.get_raw_rbio()) }; + SslError::StreamError(error.unwrap()) + } + } else { + err + } + } + LibSslError::ErrorWantWrite | LibSslError::ErrorWantRead => { + let error = unsafe { bio::take_error::(self.ssl.get_raw_rbio()) }; + SslError::StreamError(error.unwrap()) + } + err => panic!("unexpected error {:?} with ret {}", err, ret), + } + } +} + +impl Read for SslStreamNg { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let ret = self.ssl.read(buf); + if ret >= 0 { + return Ok(ret as usize); + } + + match self.make_error(ret) { + SslError::StreamError(e) => Err(e), + e => Err(io::Error::new(io::ErrorKind::Other, e)), + } + } +} + +impl Write for SslStreamNg { + fn write(&mut self, buf: &[u8]) -> io::Result { + let ret = self.ssl.write(buf); + if ret > 0 { + return Ok(ret as usize); + } + + match self.make_error(ret) { + SslError::StreamError(e) => Err(e), + e => Err(io::Error::new(io::ErrorKind::Other, e)), + } + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index d1f34019..13d9371c 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -936,3 +936,15 @@ fn ng_connect() { let ctx = SslContext::new(Sslv23).unwrap(); SslStreamNg::connect(&ctx, stream).unwrap(); } + +#[test] +fn ng_get() { + let (_s, stream) = Server::new(); + let ctx = SslContext::new(Sslv23).unwrap(); + let mut stream = SslStreamNg::connect(&ctx, stream).unwrap(); + stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); + let mut resp = String::new(); + stream.read_to_string(&mut resp).unwrap(); + assert!(resp.starts_with("HTTP/1.0 200")); + assert!(resp.ends_with("\r\n\r\n")); +} From 91f8c542f75ff81ce7f3f12f26c469127ff0ab18 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 9 Dec 2015 23:30:29 -0800 Subject: [PATCH 15/28] Replace SslStream implementation! --- openssl-sys/src/lib.rs | 2 + openssl/Cargo.toml | 4 + openssl/build.rs | 16 + openssl/src/c_helpers.c | 5 + openssl/src/ssl/mod.rs | 641 +++++++---------------------------- openssl/src/ssl/tests/mod.rs | 21 +- 6 files changed, 149 insertions(+), 540 deletions(-) create mode 100644 openssl/build.rs create mode 100644 openssl/src/c_helpers.c diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 03824e05..07401abb 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -47,6 +47,8 @@ pub type bio_info_cb = Option; #[repr(C)] +#[derive(Copy, Clone)] +#[allow(raw_pointer_derive)] pub struct BIO_METHOD { pub type_: c_int, pub name: *const c_char, diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 7b616f18..f77d8032 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -8,6 +8,7 @@ repository = "https://github.com/sfackler/rust-openssl" documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.1/openssl" readme = "../README.md" keywords = ["crypto", "tls", "ssl", "dtls"] +build = "build.rs" [features] tlsv1_2 = ["openssl-sys/tlsv1_2"] @@ -30,6 +31,9 @@ libc = "0.2" openssl-sys = { version = "0.7.1", path = "../openssl-sys" } openssl-sys-extras = { version = "0.7.1", path = "../openssl-sys-extras" } +[build-dependencies] +gcc = "0.3" + [dev-dependencies] rustc-serialize = "0.3" net2 = "0.2.16" diff --git a/openssl/build.rs b/openssl/build.rs new file mode 100644 index 00000000..640b024c --- /dev/null +++ b/openssl/build.rs @@ -0,0 +1,16 @@ +extern crate gcc; + +use std::env; +use std::path::PathBuf; + +fn main() { + let mut config = gcc::Config::new(); + + if let Some(paths) = env::var_os("DEP_OPENSSL_INCLUDE") { + for path in env::split_paths(&paths) { + config.include(PathBuf::from(path)); + } + } + + config.file("src/c_helpers.c").compile("libc_helpers.a"); +} diff --git a/openssl/src/c_helpers.c b/openssl/src/c_helpers.c new file mode 100644 index 00000000..3739cfc2 --- /dev/null +++ b/openssl/src/c_helpers.c @@ -0,0 +1,5 @@ +#include + +void rust_SSL_clone(SSL *ssl) { + CRYPTO_add(&ssl->references, 1, CRYPTO_LOCK_SSL); +} diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index e12d694d..5ac6d33e 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -11,7 +11,6 @@ use std::net; use std::path::Path; use std::ptr; use std::sync::{Once, ONCE_INIT, Arc, Mutex}; -use std::ops::{Deref, DerefMut}; use std::cmp; use std::any::Any; #[cfg(any(feature = "npn", feature = "alpn"))] @@ -20,11 +19,10 @@ use libc::{c_uchar, c_uint}; use std::slice; use std::marker::PhantomData; -use bio::{MemBio}; use ffi; use ffi_extras; use dh::DH; -use ssl::error::{NonblockingSslError, SslError, SslSessionClosed, StreamError, OpenSslErrors}; +use ssl::error::{NonblockingSslError, SslError, StreamError, OpenSslErrors}; use x509::{X509StoreContext, X509FileType, X509}; use crypto::pkey::PKey; @@ -33,6 +31,10 @@ mod bio; #[cfg(test)] mod tests; +extern "C" { + fn rust_SSL_clone(ssl: *mut ffi::SSL); +} + static mut VERIFY_IDX: c_int = -1; /// Manually initialize SSL. @@ -677,26 +679,6 @@ impl SslContext { } } -#[allow(dead_code)] -struct MemBioRef<'ssl> { - ssl: &'ssl Ssl, - bio: MemBio, -} - -impl<'ssl> Deref for MemBioRef<'ssl> { - type Target = MemBio; - - fn deref(&self) -> &MemBio { - &self.bio - } -} - -impl<'ssl> DerefMut for MemBioRef<'ssl> { - fn deref_mut(&mut self) -> &mut MemBio { - &mut self.bio - } -} - pub struct Ssl { ssl: *mut ffi::SSL } @@ -718,6 +700,14 @@ impl Drop for Ssl { } } +impl Clone for Ssl { + fn clone(&self) -> Ssl { + unsafe { rust_SSL_clone(self.ssl) }; + Ssl { ssl: self.ssl } + + } +} + impl Ssl { pub fn new(ctx: &SslContext) -> Result { let ssl = try_ssl_null!(unsafe { ffi::SSL_new(ctx.ctx) }); @@ -729,22 +719,6 @@ impl Ssl { unsafe { ffi::SSL_get_rbio(self.ssl) } } - fn get_rbio<'a>(&'a self) -> MemBioRef<'a> { - unsafe { self.wrap_bio(ffi::SSL_get_rbio(self.ssl)) } - } - - fn get_wbio<'a>(&'a self) -> MemBioRef<'a> { - unsafe { self.wrap_bio(ffi::SSL_get_wbio(self.ssl)) } - } - - fn wrap_bio<'a>(&'a self, bio: *mut ffi::BIO) -> MemBioRef<'a> { - assert!(bio != ptr::null_mut()); - MemBioRef { - ssl: self, - bio: MemBio::borrowed(bio) - } - } - fn connect(&self) -> c_int { unsafe { ffi::SSL_connect(self.ssl) } } @@ -925,182 +899,94 @@ make_LibSslError! { ErrorWantAccept = SSL_ERROR_WANT_ACCEPT } -struct IndirectStream { - stream: S, - ssl: Arc, - // Max TLS record size is 16k - buf: Box<[u8; 16 * 1024]>, +/// A stream wrapper which handles SSL encryption for an underlying stream. +pub struct SslStream { + ssl: Ssl, + _method: Box, // :( + _p: PhantomData, } -impl Clone for IndirectStream { - fn clone(&self) -> IndirectStream { - IndirectStream { - stream: self.stream.clone(), - ssl: self.ssl.clone(), - buf: Box::new(*self.buf) - } +unsafe impl Send for SslStream {} + +impl Clone for SslStream { + fn clone(&self) -> SslStream { + let stream = self.get_ref().clone(); + Self::new_base(self.ssl.clone(), stream) } } -impl IndirectStream { - fn try_clone(&self) -> io::Result> { - Ok(IndirectStream { - stream: try!(self.stream.try_clone()), - ssl: self.ssl.clone(), - buf: Box::new(*self.buf) - }) - } -} - -impl IndirectStream { - fn new_base(ssl: T, stream: S) -> Result, SslError> { - let ssl = try!(ssl.into_ssl()); - - let rbio = try!(MemBio::new()); - let wbio = try!(MemBio::new()); - - unsafe { ffi::SSL_set_bio(ssl.ssl, rbio.unwrap(), wbio.unwrap()) } - - Ok(IndirectStream { - stream: stream, - ssl: Arc::new(ssl), - buf: Box::new([0; 16 * 1024]), - }) - } - - fn connect(ssl: T, stream: S) -> Result, SslError> { - let mut ssl = try!(IndirectStream::new_base(ssl, stream)); - try!(ssl.in_retry_wrapper(|ssl| ssl.connect())); - Ok(ssl) - } - - fn accept(ssl: T, stream: S) -> Result, SslError> { - let mut ssl = try!(IndirectStream::new_base(ssl, stream)); - try!(ssl.in_retry_wrapper(|ssl| ssl.accept())); - Ok(ssl) - } - - fn in_retry_wrapper(&mut self, mut blk: F) -> Result - where F: FnMut(&Ssl) -> c_int { - loop { - let ret = blk(&self.ssl); - if ret > 0 { - return Ok(ret); - } - - let e = self.ssl.get_error(ret); - match e { - LibSslError::ErrorWantRead => { - try_ssl_stream!(self.flush()); - let len = try_ssl_stream!(self.stream.read(&mut self.buf[..])); - - - if len == 0 { - let method = self.ssl.get_ssl_method(); - - if method.map(|m| m.is_dtls()).unwrap_or(false) { - return Ok(0); - } else { - self.ssl.get_rbio().set_eof(true); - } - } else { - try_ssl_stream!(self.ssl.get_rbio().write_all(&self.buf[..len])); - } - } - LibSslError::ErrorWantWrite => { try_ssl_stream!(self.flush()) } - LibSslError::ErrorZeroReturn => return Err(SslSessionClosed), - LibSslError::ErrorSsl => return Err(SslError::get()), - LibSslError::ErrorSyscall if ret == 0 => return Ok(0), - err => panic!("unexpected error {:?} with ret {}", err, ret), - } - } - } - - fn write_through(&mut self) -> io::Result<()> { - io::copy(&mut *self.ssl.get_wbio(), &mut self.stream).map(|_| ()) - } -} - -impl Read for IndirectStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - match self.in_retry_wrapper(|ssl| { ssl.read(buf) }) { - Ok(len) => Ok(len as usize), - Err(SslSessionClosed) => Ok(0), - Err(StreamError(e)) => Err(e), - Err(e @ OpenSslErrors(_)) => { - Err(io::Error::new(io::ErrorKind::Other, e)) - } - } - } -} - -impl Write for IndirectStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - let count = match self.in_retry_wrapper(|ssl| ssl.write(buf)) { - Ok(len) => len as usize, - Err(SslSessionClosed) => 0, - Err(StreamError(e)) => return Err(e), - Err(e @ OpenSslErrors(_)) => return Err(io::Error::new(io::ErrorKind::Other, e)), - }; - try!(self.write_through()); - Ok(count) - } - - fn flush(&mut self) -> io::Result<()> { - try!(self.write_through()); - self.stream.flush() - } -} - -#[derive(Clone)] -struct DirectStream { - stream: S, - ssl: Arc, -} - -impl DirectStream { - fn try_clone(&self) -> io::Result> { - Ok(DirectStream { - stream: try!(self.stream.try_clone()), - ssl: self.ssl.clone(), - }) - } -} - -impl DirectStream { - fn new_base(ssl: Ssl, stream: S, sock: c_int) -> Result, SslError> { +impl Drop for SslStream { + fn drop(&mut self) { unsafe { - let bio = try_ssl_null!(ffi::BIO_new_socket(sock, 0)); + let _ = bio::take_stream::(self.ssl.get_raw_rbio()); + } + } +} + +impl fmt::Debug for SslStream where S: fmt::Debug { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("SslStream") + .field("stream", &self.get_ref()) + .field("ssl", &self.ssl()) + .finish() + } +} + +impl SslStream { + fn new_base(ssl: Ssl, stream: S) -> Self { + unsafe { + let (bio, method) = bio::new(stream).unwrap(); ffi::SSL_set_bio(ssl.ssl, bio, bio); - } - Ok(DirectStream { - stream: stream, - ssl: Arc::new(ssl), - }) + SslStream { + ssl: ssl, + _method: method, + _p: PhantomData, + } + } } - fn connect(ssl: Ssl, stream: S, sock: c_int) -> Result, SslError> { - let ssl = try!(DirectStream::new_base(ssl, stream, sock)); - let ret = ssl.ssl.connect(); + /// Creates an SSL/TLS client operating over the provided stream. + pub fn connect(ssl: T, stream: S) -> Result { + let ssl = try!(ssl.into_ssl()); + let mut stream = Self::new_base(ssl, stream); + let ret = stream.ssl.connect(); if ret > 0 { - Ok(ssl) + Ok(stream) } else { - Err(ssl.make_error(ret)) + Err(stream.make_error(ret)) } } - fn accept(ssl: Ssl, stream: S, sock: c_int) -> Result, SslError> { - let ssl = try!(DirectStream::new_base(ssl, stream, sock)); - let ret = ssl.ssl.accept(); + /// Creates an SSL/TLS server operating over the provided stream. + pub fn accept(ssl: T, stream: S) -> Result { + let ssl = try!(ssl.into_ssl()); + let mut stream = Self::new_base(ssl, stream); + let ret = stream.ssl.accept(); if ret > 0 { - Ok(ssl) + Ok(stream) } else { - Err(ssl.make_error(ret)) + Err(stream.make_error(ret)) } } - fn make_error(&self, ret: c_int) -> SslError { + /// ### Deprecated + /// + /// Use `connect`. + pub fn connect_generic(ssl: T, stream: S) -> Result, SslError> { + Self::connect(ssl, stream) + } + + /// ### Deprecated + /// + /// Use `accept`. + pub fn accept_generic(ssl: T, stream: S) -> Result, SslError> { + Self::accept(ssl, stream) + } +} + +impl SslStream { + fn make_error(&mut self, ret: c_int) -> SslError { match self.ssl.get_error(ret) { LibSslError::ErrorSsl => SslError::get(), LibSslError::ErrorSyscall => { @@ -1114,21 +1000,56 @@ impl DirectStream { SslError::StreamError(io::Error::new(io::ErrorKind::ConnectionAborted, "unexpected EOF observed")) } else { - SslError::StreamError(io::Error::last_os_error()) + let error = unsafe { bio::take_error::(self.ssl.get_raw_rbio()) }; + SslError::StreamError(error.unwrap()) } } else { err } } LibSslError::ErrorWantWrite | LibSslError::ErrorWantRead => { - SslError::StreamError(io::Error::last_os_error()) + let error = unsafe { bio::take_error::(self.ssl.get_raw_rbio()) }; + SslError::StreamError(error.unwrap()) } err => panic!("unexpected error {:?} with ret {}", err, ret), } } + /// Returns a reference to the underlying stream. + pub fn get_ref(&self) -> &S { + unsafe { + let bio = self.ssl.get_raw_rbio(); + bio::get_ref(bio) + } + } + + /// Returns a mutable reference to the underlying stream. + /// + /// ## Warning + /// + /// It is inadvisable to read from or write to the underlying stream as it + /// will most likely corrupt the SSL session. + pub fn get_mut(&mut self) -> &mut S { + unsafe { + let bio = self.ssl.get_raw_rbio(); + bio::get_mut(bio) + } + } + + /// Returns the OpenSSL `Ssl` object associated with this stream. + pub fn ssl(&self) -> &Ssl { + &self.ssl + } } -impl Read for DirectStream { +impl SslStream<::std::net::TcpStream> { + /// Like `TcpStream::try_clone`. + pub fn try_clone(&self) -> io::Result> { + let stream = try!(self.get_ref().try_clone()); + Ok(Self::new_base(self.ssl.clone(), stream)) + } +} + +impl Read for SslStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { let ret = self.ssl.read(buf); if ret >= 0 { @@ -1142,7 +1063,7 @@ impl Read for DirectStream { } } -impl Write for DirectStream { +impl Write for SslStream { fn write(&mut self, buf: &[u8]) -> io::Result { let ret = self.ssl.write(buf); if ret > 0 { @@ -1156,197 +1077,7 @@ impl Write for DirectStream { } fn flush(&mut self) -> io::Result<()> { - self.stream.flush() - } -} - -#[derive(Clone)] -enum StreamKind { - Indirect(IndirectStream), - Direct(DirectStream), -} - -impl StreamKind { - fn stream(&self) -> &S { - match *self { - StreamKind::Indirect(ref s) => &s.stream, - StreamKind::Direct(ref s) => &s.stream, - } - } - - fn mut_stream(&mut self) -> &mut S { - match *self { - StreamKind::Indirect(ref mut s) => &mut s.stream, - StreamKind::Direct(ref mut s) => &mut s.stream, - } - } - - fn ssl(&self) -> &Ssl { - match *self { - StreamKind::Indirect(ref s) => &s.ssl, - StreamKind::Direct(ref s) => &s.ssl, - } - } -} - -/// A stream wrapper which handles SSL encryption for an underlying stream. -#[derive(Clone)] -pub struct SslStream { - kind: StreamKind, -} - -impl SslStream { - /// Create a new independently owned handle to the underlying socket. - pub fn try_clone(&self) -> io::Result> { - let kind = match self.kind { - StreamKind::Indirect(ref s) => StreamKind::Indirect(try!(s.try_clone())), - StreamKind::Direct(ref s) => StreamKind::Direct(try!(s.try_clone())) - }; - Ok(SslStream { - kind: kind - }) - } -} - -impl fmt::Debug for SslStream where S: fmt::Debug { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("SslStream") - .field("stream", &self.kind.stream()) - .field("ssl", &self.kind.ssl()) - .finish() - } -} - -#[cfg(unix)] -impl SslStream { - /// Creates an SSL/TLS client operating over the provided stream. - /// - /// Streams passed to this method must implement `AsRawFd` on Unixy - /// platforms and `AsRawSocket` on Windows. Use `connect_generic` for - /// streams that do not. - pub fn connect(ssl: T, stream: S) -> Result, SslError> { - let ssl = try!(ssl.into_ssl()); - let fd = stream.as_raw_fd() as c_int; - let stream = try!(DirectStream::connect(ssl, stream, fd)); - Ok(SslStream { - kind: StreamKind::Direct(stream) - }) - } - - /// Creates an SSL/TLS server operating over the provided stream. - /// - /// Streams passed to this method must implement `AsRawFd` on Unixy - /// platforms and `AsRawSocket` on Windows. Use `accept_generic` for - /// streams that do not. - pub fn accept(ssl: T, stream: S) -> Result, SslError> { - let ssl = try!(ssl.into_ssl()); - let fd = stream.as_raw_fd() as c_int; - let stream = try!(DirectStream::accept(ssl, stream, fd)); - Ok(SslStream { - kind: StreamKind::Direct(stream) - }) - } -} - -#[cfg(windows)] -impl SslStream { - /// Creates an SSL/TLS client operating over the provided stream. - /// - /// Streams passed to this method must implement `AsRawFd` on Unixy - /// platforms and `AsRawSocket` on Windows. Use `connect_generic` for - /// streams that do not. - pub fn connect(ssl: T, stream: S) -> Result, SslError> { - let ssl = try!(ssl.into_ssl()); - let fd = stream.as_raw_socket() as c_int; - let stream = try!(DirectStream::connect(ssl, stream, fd)); - Ok(SslStream { - kind: StreamKind::Direct(stream) - }) - } - - /// Creates an SSL/TLS server operating over the provided stream. - /// - /// Streams passed to this method must implement `AsRawFd` on Unixy - /// platforms and `AsRawSocket` on Windows. Use `accept_generic` for - /// streams that do not. - pub fn accept(ssl: T, stream: S) -> Result, SslError> { - let ssl = try!(ssl.into_ssl()); - let fd = stream.as_raw_socket() as c_int; - let stream = try!(DirectStream::accept(ssl, stream, fd)); - Ok(SslStream { - kind: StreamKind::Direct(stream) - }) - } -} - -impl SslStream { - /// Creates an SSL/TLS client operating over the provided stream. - /// - /// `SslStream`s returned by this method will be less efficient than ones - /// returned by `connect`, so this method should only be used for streams - /// that do not implement `AsRawFd` and `AsRawSocket`. - pub fn connect_generic(ssl: T, stream: S) -> Result, SslError> { - let stream = try!(IndirectStream::connect(ssl, stream)); - Ok(SslStream { - kind: StreamKind::Indirect(stream) - }) - } - - /// Creates an SSL/TLS server operating over the provided stream. - /// - /// `SslStream`s returned by this method will be less efficient than ones - /// returned by `accept`, so this method should only be used for streams - /// that do not implement `AsRawFd` and `AsRawSocket`. - pub fn accept_generic(ssl: T, stream: S) -> Result, SslError> { - let stream = try!(IndirectStream::accept(ssl, stream)); - Ok(SslStream { - kind: StreamKind::Indirect(stream) - }) - } - - /// Returns a reference to the underlying stream. - pub fn get_ref(&self) -> &S { - self.kind.stream() - } - - /// Returns a mutable reference to the underlying stream. - /// - /// ## Warning - /// - /// It is inadvisable to read from or write to the underlying stream as it - /// will most likely corrupt the SSL session. - pub fn get_mut(&mut self) -> &mut S { - self.kind.mut_stream() - } - - /// Returns the OpenSSL `Ssl` object associated with this stream. - pub fn ssl(&self) -> &Ssl { - self.kind.ssl() - } -} - -impl Read for SslStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - match self.kind { - StreamKind::Indirect(ref mut s) => s.read(buf), - StreamKind::Direct(ref mut s) => s.read(buf), - } - } -} - -impl Write for SslStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - match self.kind { - StreamKind::Indirect(ref mut s) => s.write(buf), - StreamKind::Direct(ref mut s) => s.write(buf), - } - } - - fn flush(&mut self) -> io::Result<()> { - match self.kind { - StreamKind::Indirect(ref mut s) => s.flush(), - StreamKind::Direct(ref mut s) => s.flush(), - } + self.get_mut().flush() } } @@ -1660,133 +1391,3 @@ impl NonblockingSslStream { } } } - -pub struct SslStreamNg { - ssl: Ssl, - _method: Box, // :( - _p: PhantomData, -} - -impl Drop for SslStreamNg { - fn drop(&mut self) { - unsafe { - let _ = bio::take_stream::(self.ssl.get_raw_rbio()); - } - } -} - -impl SslStreamNg { - fn new_base(ssl: Ssl, stream: S) -> Result { - unsafe { - let (bio, method) = try!(bio::new(stream)); - ffi::SSL_set_bio(ssl.ssl, bio, bio); - - Ok(SslStreamNg { - ssl: ssl, - _method: method, - _p: PhantomData, - }) - } - } - - /// Creates an SSL/TLS client operating over the provided stream. - pub fn connect(ssl: T, stream: S) -> Result { - let ssl = try!(ssl.into_ssl()); - let mut stream = try!(Self::new_base(ssl, stream)); - let ret = stream.ssl.connect(); - if ret > 0 { - Ok(stream) - } else { - Err(stream.make_error(ret)) - } - } - - /// Creates an SSL/TLS server operating over the provided stream. - pub fn accept(ssl: T, stream: S) -> Result { - let ssl = try!(ssl.into_ssl()); - let mut stream = try!(Self::new_base(ssl, stream)); - let ret = stream.ssl.accept(); - if ret > 0 { - Ok(stream) - } else { - Err(stream.make_error(ret)) - } - } -} - -impl SslStreamNg { - pub fn get_ref(&self) -> &S { - unsafe { - let bio = self.ssl.get_raw_rbio(); - bio::get_ref(bio) - } - } - - pub fn get_mut(&mut self) -> &mut S { - unsafe { - let bio = self.ssl.get_raw_rbio(); - bio::get_mut(bio) - } - } - - fn make_error(&mut self, ret: c_int) -> SslError { - match self.ssl.get_error(ret) { - LibSslError::ErrorSsl => SslError::get(), - LibSslError::ErrorSyscall => { - let err = SslError::get(); - let count = match err { - SslError::OpenSslErrors(ref v) => v.len(), - _ => unreachable!(), - }; - if count == 0 { - if ret == 0 { - SslError::StreamError(io::Error::new(io::ErrorKind::ConnectionAborted, - "unexpected EOF observed")) - } else { - let error = unsafe { bio::take_error::(self.ssl.get_raw_rbio()) }; - SslError::StreamError(error.unwrap()) - } - } else { - err - } - } - LibSslError::ErrorWantWrite | LibSslError::ErrorWantRead => { - let error = unsafe { bio::take_error::(self.ssl.get_raw_rbio()) }; - SslError::StreamError(error.unwrap()) - } - err => panic!("unexpected error {:?} with ret {}", err, ret), - } - } -} - -impl Read for SslStreamNg { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let ret = self.ssl.read(buf); - if ret >= 0 { - return Ok(ret as usize); - } - - match self.make_error(ret) { - SslError::StreamError(e) => Err(e), - e => Err(io::Error::new(io::ErrorKind::Other, e)), - } - } -} - -impl Write for SslStreamNg { - fn write(&mut self, buf: &[u8]) -> io::Result { - let ret = self.ssl.write(buf); - if ret > 0 { - return Ok(ret as usize); - } - - match self.make_error(ret) { - SslError::StreamError(e) => Err(e), - e => Err(io::Error::new(io::ErrorKind::Other, e)), - } - } - - fn flush(&mut self) -> io::Result<()> { - self.get_mut().flush() - } -} diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 13d9371c..025a45a8 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -18,7 +18,7 @@ use ssl::SSL_VERIFY_PEER; use ssl::SslMethod::Sslv23; use ssl::SslMethod; use ssl::error::NonblockingSslError; -use ssl::{SslContext, SslStream, VerifyCallback, NonblockingSslStream, SslStreamNg}; +use ssl::{SslContext, SslStream, VerifyCallback, NonblockingSslStream}; use x509::X509StoreContext; use x509::X509FileType; use x509::X509; @@ -929,22 +929,3 @@ fn test_read_nonblocking() { assert!(bytes_read >= 5); assert_eq!(&input_buffer[..5], b"HTTP/"); } - -#[test] -fn ng_connect() { - let (_s, stream) = Server::new(); - let ctx = SslContext::new(Sslv23).unwrap(); - SslStreamNg::connect(&ctx, stream).unwrap(); -} - -#[test] -fn ng_get() { - let (_s, stream) = Server::new(); - let ctx = SslContext::new(Sslv23).unwrap(); - let mut stream = SslStreamNg::connect(&ctx, stream).unwrap(); - stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); - let mut resp = String::new(); - stream.read_to_string(&mut resp).unwrap(); - assert!(resp.starts_with("HTTP/1.0 200")); - assert!(resp.ends_with("\r\n\r\n")); -} From e9b8627af27b8e239d0008005bd67cc87de671b1 Mon Sep 17 00:00:00 2001 From: Tomoki Aonuma Date: Thu, 10 Dec 2015 19:46:35 +0900 Subject: [PATCH 16/28] Add PBKDF2-HMAC-SHA256 and -SHA512 functions --- openssl-sys/src/lib.rs | 5 +- openssl/src/crypto/pkcs5.rs | 134 ++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 1 deletion(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 0f40bfed..f9f47d5e 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -478,7 +478,10 @@ extern "C" { salt: *const u8, saltlen: c_int, iter: c_int, keylen: c_int, out: *mut u8) -> c_int; - + pub fn PKCS5_PBKDF2_HMAC(pass: *const u8, passlen: c_int, + salt: *const u8, saltlen: c_int, + iter: c_int, digest: *const EVP_MD, keylen: c_int, + out: *mut u8) -> c_int; pub fn RAND_bytes(buf: *mut u8, num: c_int) -> c_int; diff --git a/openssl/src/crypto/pkcs5.rs b/openssl/src/crypto/pkcs5.rs index b5f69732..42966adf 100644 --- a/openssl/src/crypto/pkcs5.rs +++ b/openssl/src/crypto/pkcs5.rs @@ -88,6 +88,40 @@ pub fn pbkdf2_hmac_sha1(pass: &str, salt: &[u8], iter: usize, keylen: usize) -> } } +/// Derives a key from a password and salt using the PBKDF2-HMAC-SHA256 algorithm. +pub fn pbkdf2_hmac_sha256(pass: &str, salt: &[u8], iter: usize, keylen: usize) -> Vec { + pbkdf2_hmac_sha(pass, salt, iter, unsafe { ffi::EVP_sha256() }, keylen) +} + +/// Derives a key from a password and salt using the PBKDF2-HMAC-SHA512 algorithm. +pub fn pbkdf2_hmac_sha512(pass: &str, salt: &[u8], iter: usize, keylen: usize) -> Vec { + pbkdf2_hmac_sha(pass, salt, iter, unsafe { ffi::EVP_sha512() }, keylen) +} + +/// Derives a key from a password and salt using the PBKDF2-HMAC algorithm with a digest function. +fn pbkdf2_hmac_sha(pass: &str, salt: &[u8], iter: usize, digest: *const ffi::EVP_MD, keylen: usize) -> Vec { + unsafe { + assert!(iter >= 1); + assert!(keylen >= 1); + + let mut out = Vec::with_capacity(keylen); + + ffi::init(); + + let r = ffi::PKCS5_PBKDF2_HMAC( + pass.as_ptr(), pass.len() as c_int, + salt.as_ptr(), salt.len() as c_int, + iter as c_int, digest, keylen as c_int, + out.as_mut_ptr()); + + if r != 1 { panic!(); } + + out.set_len(keylen); + + out + } +} + #[cfg(test)] mod tests { use crypto::hash; @@ -183,6 +217,106 @@ mod tests { ); } + // Test vectors from + // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c + #[test] + fn test_pbkdf2_hmac_sha256() { + assert_eq!( + super::pbkdf2_hmac_sha256( + "passwd", + "salt".as_bytes(), + 1, + 16 + ), + vec!( + 0x55_u8, 0xac_u8, 0x04_u8, 0x6e_u8, 0x56_u8, 0xe3_u8, 0x08_u8, + 0x9f_u8, 0xec_u8, 0x16_u8, 0x91_u8, 0xc2_u8, 0x25_u8, 0x44_u8, + 0xb6_u8, 0x05_u8 + ) + ); + + assert_eq!( + super::pbkdf2_hmac_sha256( + "Password", + "NaCl".as_bytes(), + 80000, + 16 + ), + vec!( + 0x4d_u8, 0xdc_u8, 0xd8_u8, 0xf6_u8, 0x0b_u8, 0x98_u8, 0xbe_u8, + 0x21_u8, 0x83_u8, 0x0c_u8, 0xee_u8, 0x5e_u8, 0xf2_u8, 0x27_u8, + 0x01_u8, 0xf9_u8 + ) + ); + } + + // Test vectors from + // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c + #[test] + fn test_pbkdf2_hmac_sha512() { + assert_eq!( + super::pbkdf2_hmac_sha512( + "password", + "NaCL".as_bytes(), + 1, + 64 + ), + vec!( + 0x73_u8, 0xde_u8, 0xcf_u8, 0xa5_u8, 0x8a_u8, 0xa2_u8, 0xe8_u8, + 0x4f_u8, 0x94_u8, 0x77_u8, 0x1a_u8, 0x75_u8, 0x73_u8, 0x6b_u8, + 0xb8_u8, 0x8b_u8, 0xd3_u8, 0xc7_u8, 0xb3_u8, 0x82_u8, 0x70_u8, + 0xcf_u8, 0xb5_u8, 0x0c_u8, 0xb3_u8, 0x90_u8, 0xed_u8, 0x78_u8, + 0xb3_u8, 0x05_u8, 0x65_u8, 0x6a_u8, 0xf8_u8, 0x14_u8, 0x8e_u8, + 0x52_u8, 0x45_u8, 0x2b_u8, 0x22_u8, 0x16_u8, 0xb2_u8, 0xb8_u8, + 0x09_u8, 0x8b_u8, 0x76_u8, 0x1f_u8, 0xc6_u8, 0x33_u8, 0x60_u8, + 0x60_u8, 0xa0_u8, 0x9f_u8, 0x76_u8, 0x41_u8, 0x5e_u8, 0x9f_u8, + 0x71_u8, 0xea_u8, 0x47_u8, 0xf9_u8, 0xe9_u8, 0x06_u8, 0x43_u8, + 0x06_u8 + ) + ); + + assert_eq!( + super::pbkdf2_hmac_sha512( + "pass\0word", + "sa\0lt".as_bytes(), + 1, + 64 + ), + vec!( + 0x71_u8, 0xa0_u8, 0xec_u8, 0x84_u8, 0x2a_u8, 0xbd_u8, 0x5c_u8, + 0x67_u8, 0x8b_u8, 0xcf_u8, 0xd1_u8, 0x45_u8, 0xf0_u8, 0x9d_u8, + 0x83_u8, 0x52_u8, 0x2f_u8, 0x93_u8, 0x36_u8, 0x15_u8, 0x60_u8, + 0x56_u8, 0x3c_u8, 0x4d_u8, 0x0d_u8, 0x63_u8, 0xb8_u8, 0x83_u8, + 0x29_u8, 0x87_u8, 0x10_u8, 0x90_u8, 0xe7_u8, 0x66_u8, 0x04_u8, + 0xa4_u8, 0x9a_u8, 0xf0_u8, 0x8f_u8, 0xe7_u8, 0xc9_u8, 0xf5_u8, + 0x71_u8, 0x56_u8, 0xc8_u8, 0x79_u8, 0x09_u8, 0x96_u8, 0xb2_u8, + 0x0f_u8, 0x06_u8, 0xbc_u8, 0x53_u8, 0x5e_u8, 0x5a_u8, 0xb5_u8, + 0x44_u8, 0x0d_u8, 0xf7_u8, 0xe8_u8, 0x78_u8, 0x29_u8, 0x6f_u8, + 0xa7_u8 + ) + ); + + assert_eq!( + super::pbkdf2_hmac_sha512( + "passwordPASSWORDpassword", + "salt\0\0\0".as_bytes(), + 50, + 64 + ), + vec!( + 0x01_u8, 0x68_u8, 0x71_u8, 0xa4_u8, 0xc4_u8, 0xb7_u8, 0x5f_u8, + 0x96_u8, 0x85_u8, 0x7f_u8, 0xd2_u8, 0xb9_u8, 0xf8_u8, 0xca_u8, + 0x28_u8, 0x02_u8, 0x3b_u8, 0x30_u8, 0xee_u8, 0x2a_u8, 0x39_u8, + 0xf5_u8, 0xad_u8, 0xca_u8, 0xc8_u8, 0xc9_u8, 0x37_u8, 0x5f_u8, + 0x9b_u8, 0xda_u8, 0x1c_u8, 0xcd_u8, 0x1b_u8, 0x6f_u8, 0x0b_u8, + 0x2f_u8, 0xc3_u8, 0xad_u8, 0xda_u8, 0x50_u8, 0x54_u8, 0x12_u8, + 0xe7_u8, 0x9d_u8, 0x89_u8, 0x00_u8, 0x56_u8, 0xc6_u8, 0x2e_u8, + 0x52_u8, 0x4c_u8, 0x7d_u8, 0x51_u8, 0x15_u8, 0x4b_u8, 0x1a_u8, + 0x85_u8, 0x34_u8, 0x57_u8, 0x5b_u8, 0xd0_u8, 0x2d_u8, 0xee_u8, + 0x39_u8 + ) + ); + } #[test] fn test_evp_bytes_to_key_pbkdf1_compatible() { let salt = [ From b6647cc61099eb99747168fb99abe29f88a87b34 Mon Sep 17 00:00:00 2001 From: Tomoki Aonuma Date: Thu, 10 Dec 2015 21:24:58 +0900 Subject: [PATCH 17/28] Put pbkdf2_hmac_{256,512}() behind feature gate PKCS5_PBKDF2_HMAC is not available with openssl-0.9.8 on os x --- .travis.yml | 2 +- openssl-sys/Cargo.toml | 1 + openssl-sys/src/lib.rs | 1 + openssl/Cargo.toml | 1 + openssl/src/crypto/pkcs5.rs | 5 +++++ 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8c394415..ede3f573 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ os: - linux env: global: - - FEATURES="tlsv1_2 tlsv1_1 dtlsv1 dtlsv1_2 sslv2 sslv3 aes_xts aes_ctr npn alpn rfc5114 ecdh_auto" + - FEATURES="tlsv1_2 tlsv1_1 dtlsv1 dtlsv1_2 sslv2 sslv3 aes_xts aes_ctr npn alpn rfc5114 ecdh_auto pkcs5_pbkdf2_hmac" before_install: - (test $TRAVIS_OS_NAME == "osx" || ./openssl/test/build.sh) script: diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 17e4647f..1e025d84 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -23,6 +23,7 @@ aes_ctr = [] npn = [] alpn = [] rfc5114 = [] +pkcs5_pbkdf2_hmac = [] [dependencies] libc = "0.2" diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index f9f47d5e..2a9e9e4f 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -478,6 +478,7 @@ extern "C" { salt: *const u8, saltlen: c_int, iter: c_int, keylen: c_int, out: *mut u8) -> c_int; + #[cfg(feature = "pkcs5_pbkdf2_hmac")] pub fn PKCS5_PBKDF2_HMAC(pass: *const u8, passlen: c_int, salt: *const u8, saltlen: c_int, iter: c_int, digest: *const EVP_MD, keylen: c_int, diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 7b616f18..5397f06e 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -22,6 +22,7 @@ npn = ["openssl-sys/npn"] alpn = ["openssl-sys/alpn"] rfc5114 = ["openssl-sys/rfc5114"] ecdh_auto = ["openssl-sys-extras/ecdh_auto"] +pkcs5_pbkdf2_hmac = ["openssl-sys/pkcs5_pbkdf2_hmac"] [dependencies] bitflags = ">= 0.2, < 0.4" diff --git a/openssl/src/crypto/pkcs5.rs b/openssl/src/crypto/pkcs5.rs index 42966adf..07e86fb1 100644 --- a/openssl/src/crypto/pkcs5.rs +++ b/openssl/src/crypto/pkcs5.rs @@ -89,16 +89,19 @@ pub fn pbkdf2_hmac_sha1(pass: &str, salt: &[u8], iter: usize, keylen: usize) -> } /// Derives a key from a password and salt using the PBKDF2-HMAC-SHA256 algorithm. +#[cfg(feature = "pkcs5_pbkdf2_hmac")] pub fn pbkdf2_hmac_sha256(pass: &str, salt: &[u8], iter: usize, keylen: usize) -> Vec { pbkdf2_hmac_sha(pass, salt, iter, unsafe { ffi::EVP_sha256() }, keylen) } /// Derives a key from a password and salt using the PBKDF2-HMAC-SHA512 algorithm. +#[cfg(feature = "pkcs5_pbkdf2_hmac")] pub fn pbkdf2_hmac_sha512(pass: &str, salt: &[u8], iter: usize, keylen: usize) -> Vec { pbkdf2_hmac_sha(pass, salt, iter, unsafe { ffi::EVP_sha512() }, keylen) } /// Derives a key from a password and salt using the PBKDF2-HMAC algorithm with a digest function. +#[cfg(feature = "pkcs5_pbkdf2_hmac")] fn pbkdf2_hmac_sha(pass: &str, salt: &[u8], iter: usize, digest: *const ffi::EVP_MD, keylen: usize) -> Vec { unsafe { assert!(iter >= 1); @@ -220,6 +223,7 @@ mod tests { // Test vectors from // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c #[test] + #[cfg(feature = "pkcs5_pbkdf2_hmac")] fn test_pbkdf2_hmac_sha256() { assert_eq!( super::pbkdf2_hmac_sha256( @@ -253,6 +257,7 @@ mod tests { // Test vectors from // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c #[test] + #[cfg(feature = "pkcs5_pbkdf2_hmac")] fn test_pbkdf2_hmac_sha512() { assert_eq!( super::pbkdf2_hmac_sha512( From aa37dba0bc139fb9c866b6a57b5028227313df7a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 10 Dec 2015 21:58:22 -0800 Subject: [PATCH 18/28] Make error handling more reliable --- openssl/src/ssl/mod.rs | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 5ac6d33e..bc64d7c8 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1000,20 +1000,30 @@ impl SslStream { SslError::StreamError(io::Error::new(io::ErrorKind::ConnectionAborted, "unexpected EOF observed")) } else { - let error = unsafe { bio::take_error::(self.ssl.get_raw_rbio()) }; - SslError::StreamError(error.unwrap()) + SslError::StreamError(self.get_bio_error()) } } else { err } } + LibSslError::ErrorZeroReturn => SslError::SslSessionClosed, LibSslError::ErrorWantWrite | LibSslError::ErrorWantRead => { - let error = unsafe { bio::take_error::(self.ssl.get_raw_rbio()) }; - SslError::StreamError(error.unwrap()) + SslError::StreamError(self.get_bio_error()) } - err => panic!("unexpected error {:?} with ret {}", err, ret), + err => SslError::StreamError(io::Error::new(io::ErrorKind::Other, + format!("unexpected error {:?}", err))), } } + + 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?") + } + } + /// Returns a reference to the underlying stream. pub fn get_ref(&self) -> &S { unsafe { @@ -1057,6 +1067,7 @@ impl Read for SslStream { } match self.make_error(ret) { + SslError::SslSessionClosed => Ok(0), SslError::StreamError(e) => Err(e), e => Err(io::Error::new(io::ErrorKind::Other, e)), } From 1df131ff810dabd9d0452688bf8956e0af58b06a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Dec 2015 15:01:16 -0800 Subject: [PATCH 19/28] Build out a new error type --- openssl/src/ssl/error.rs | 148 +++++++++++++++++++++++++++++++++++---- openssl/src/ssl/mod.rs | 118 +++++++++++++++++++++++++------ 2 files changed, 231 insertions(+), 35 deletions(-) diff --git a/openssl/src/ssl/error.rs b/openssl/src/ssl/error.rs index d76494f1..9a1a63b2 100644 --- a/openssl/src/ssl/error.rs +++ b/openssl/src/ssl/error.rs @@ -3,12 +3,136 @@ pub use self::OpensslError::*; use libc::c_ulong; use std::error; +use std::error::Error as StdError; use std::fmt; use std::ffi::CStr; use std::io; +use std::str; use ffi; +/// An SSL error. +#[derive(Debug)] +pub enum Error { + /// The SSL session has been closed by the other end + ZeroReturn, + /// An attempt to read data from the underlying socket returned + /// `WouldBlock`. Wait for read readiness and reattempt the operation. + WantRead(io::Error), + /// An attempt to write data from the underlying socket returned + /// `WouldBlock`. Wait for write readiness and reattempt the operation. + WantWrite(io::Error), + #[doc(hidden)] // unused for now + WantX509Lookup, + /// An error reported by the underlying stream. + Stream(io::Error), + /// An error in the OpenSSL library. + Ssl(Vec), +} + +impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + try!(fmt.write_str(self.description())); + match *self { + Error::Stream(ref err) => write!(fmt, ": {}", err), + Error::WantRead(ref err) => write!(fmt, ": {}", err), + Error::WantWrite(ref err) => write!(fmt, ": {}", err), + Error::Ssl(ref errs) => { + let mut first = true; + for err in errs { + if first { + try!(fmt.write_str(": ")); + first = false; + } else { + try!(fmt.write_str(", ")); + } + try!(fmt.write_str(&err.reason())) + } + Ok(()) + } + _ => Ok(()) + } + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + match *self { + Error::ZeroReturn => "The SSL session was closed by the other end", + Error::WantRead(_) => "A read attempt returned a `WouldBlock` error", + Error::WantWrite(_) => "A write attempt returned a `WouldBlock` error", + Error::WantX509Lookup => "The client certificate callback requested to be called again", + Error::Stream(_) => "The underlying stream reported an error", + Error::Ssl(_) => "The OpenSSL library reported an error", + } + } + + fn cause(&self) -> Option<&error::Error> { + match *self { + Error::WantRead(ref err) => Some(err), + Error::WantWrite(ref err) => Some(err), + Error::Stream(ref err) => Some(err), + _ => None + } + } +} + +/// An error reported from OpenSSL. +pub struct OpenSslError(c_ulong); + +impl OpenSslError { + /// Returns the contents of the OpenSSL error stack. + pub fn get_stack() -> Vec { + ffi::init(); + + let mut errs = vec!(); + loop { + match unsafe { ffi::ERR_get_error() } { + 0 => break, + err => errs.push(OpenSslError(err)) + } + } + errs + } + + /// Returns the name of the library reporting the error. + pub fn library(&self) -> &'static str { + get_lib(self.0) + } + + /// Returns the name of the function reporting the error. + pub fn function(&self) -> &'static str { + get_func(self.0) + } + + /// Returns the reason for the error. + pub fn reason(&self) -> &'static str { + get_reason(self.0) + } +} + +impl fmt::Debug for OpenSslError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("OpenSslError") + .field("library", &self.library()) + .field("function", &self.function()) + .field("reason", &self.reason()) + .finish() + } +} + +impl fmt::Display for OpenSslError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(&self.reason()) + } +} + +impl error::Error for OpenSslError { + fn description(&self) -> &str { + "An OpenSSL error" + } +} + /// An SSL error #[derive(Debug)] pub enum SslError { @@ -115,27 +239,27 @@ pub enum OpensslError { } } -fn get_lib(err: c_ulong) -> String { +fn get_lib(err: c_ulong) -> &'static str { unsafe { let cstr = ffi::ERR_lib_error_string(err); - let bytes = CStr::from_ptr(cstr as *const _).to_bytes().to_vec(); - String::from_utf8(bytes).unwrap() + let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); + str::from_utf8(bytes).unwrap() } } -fn get_func(err: c_ulong) -> String { +fn get_func(err: c_ulong) -> &'static str { unsafe { let cstr = ffi::ERR_func_error_string(err); - let bytes = CStr::from_ptr(cstr as *const _).to_bytes().to_vec(); - String::from_utf8(bytes).unwrap() + let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); + str::from_utf8(bytes).unwrap() } } -fn get_reason(err: c_ulong) -> String { +fn get_reason(err: c_ulong) -> &'static str { unsafe { let cstr = ffi::ERR_reason_error_string(err); - let bytes = CStr::from_ptr(cstr as *const _).to_bytes().to_vec(); - String::from_utf8(bytes).unwrap() + let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); + str::from_utf8(bytes).unwrap() } } @@ -161,9 +285,9 @@ impl SslError { fn from_error_code(err: c_ulong) -> OpensslError { ffi::init(); UnknownError { - library: get_lib(err), - function: get_func(err), - reason: get_reason(err) + library: get_lib(err).to_owned(), + function: get_func(err).to_owned(), + reason: get_reason(err).to_owned() } } } diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index bc64d7c8..89c8bbfc 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -22,7 +22,7 @@ use std::marker::PhantomData; use ffi; use ffi_extras; use dh::DH; -use ssl::error::{NonblockingSslError, SslError, StreamError, OpenSslErrors}; +use ssl::error::{NonblockingSslError, SslError, StreamError, OpenSslErrors, OpenSslError}; use x509::{X509StoreContext, X509FileType, X509}; use crypto::pkey::PKey; @@ -31,6 +31,9 @@ mod bio; #[cfg(test)] mod tests; +#[doc(inline)] +pub use ssl::error::Error; + extern "C" { fn rust_SSL_clone(ssl: *mut ffi::SSL); } @@ -954,7 +957,17 @@ impl SslStream { if ret > 0 { Ok(stream) } else { - Err(stream.make_error(ret)) + match stream.make_old_error(ret) { + SslError::StreamError(e) => { + // This is fine - nonblocking sockets will finish the handshake in read/write + if e.kind() == io::ErrorKind::WouldBlock { + Ok(stream) + } else { + Err(SslError::StreamError(e)) + } + } + e => Err(e) + } } } @@ -966,7 +979,17 @@ impl SslStream { if ret > 0 { Ok(stream) } else { - Err(stream.make_error(ret)) + match stream.make_old_error(ret) { + SslError::StreamError(e) => { + // This is fine - nonblocking sockets will finish the handshake in read/write + if e.kind() == io::ErrorKind::WouldBlock { + Ok(stream) + } else { + Err(SslError::StreamError(e)) + } + } + e => Err(e) + } } } @@ -986,7 +1009,31 @@ impl SslStream { } impl SslStream { - fn make_error(&mut self, ret: c_int) -> SslError { + fn make_error(&mut self, ret: c_int) -> Error { + match self.ssl.get_error(ret) { + LibSslError::ErrorSsl => Error::Ssl(OpenSslError::get_stack()), + LibSslError::ErrorSyscall => { + let errs = OpenSslError::get_stack(); + if errs.is_empty() { + if ret == 0 { + Error::Stream(io::Error::new(io::ErrorKind::ConnectionAborted, + "unexpected EOF observed")) + } else { + Error::Stream(self.get_bio_error()) + } + } else { + Error::Ssl(errs) + } + } + LibSslError::ErrorZeroReturn => Error::ZeroReturn, + LibSslError::ErrorWantWrite => Error::WantWrite(self.get_bio_error()), + LibSslError::ErrorWantRead => Error::WantRead(self.get_bio_error()), + err => Error::Stream(io::Error::new(io::ErrorKind::Other, + format!("unexpected error {:?}", err))), + } + } + + fn make_old_error(&mut self, ret: c_int) -> SslError { match self.ssl.get_error(ret) { LibSslError::ErrorSsl => SslError::get(), LibSslError::ErrorSyscall => { @@ -1045,6 +1092,32 @@ impl SslStream { } } + /// Like `read`, but returns an `ssl::Error` rather than an `io::Error`. + /// + /// 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 { + let ret = self.ssl.read(buf); + if ret >= 0 { + Ok(ret as usize) + } else { + Err(self.make_error(ret)) + } + } + + /// Like `write`, but returns an `ssl::Error` rather than an `io::Error`. + /// + /// 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 { + let ret = self.ssl.write(buf); + if ret >= 0 { + Ok(ret as usize) + } else { + Err(self.make_error(ret)) + } + } + /// Returns the OpenSSL `Ssl` object associated with this stream. pub fn ssl(&self) -> &Ssl { &self.ssl @@ -1061,30 +1134,27 @@ impl SslStream<::std::net::TcpStream> { impl Read for SslStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { - let ret = self.ssl.read(buf); - if ret >= 0 { - return Ok(ret as usize); - } - - match self.make_error(ret) { - SslError::SslSessionClosed => Ok(0), - SslError::StreamError(e) => Err(e), - e => Err(io::Error::new(io::ErrorKind::Other, e)), + match self.ssl_read(buf) { + Ok(n) => Ok(n), + Err(Error::ZeroReturn) => Ok(0), + Err(Error::Stream(e)) => Err(e), + Err(Error::WantRead(e)) => Err(e), + Err(Error::WantWrite(e)) => Err(e), + Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)), } } } impl Write for SslStream { fn write(&mut self, buf: &[u8]) -> io::Result { - let ret = self.ssl.write(buf); - if ret > 0 { - return Ok(ret as usize); - } - - match self.make_error(ret) { - SslError::StreamError(e) => Err(e), - e => Err(io::Error::new(io::ErrorKind::Other, e)), - } + self.ssl_write(buf).map_err(|e| { + match e { + Error::Stream(e) => e, + Error::WantRead(e) => e, + Error::WantWrite(e) => e, + e => io::Error::new(io::ErrorKind::Other, e), + } + }) } fn flush(&mut self) -> io::Result<()> { @@ -1174,7 +1244,9 @@ impl MaybeSslStream { } } -/// An SSL stream wrapping a nonblocking socket. +/// # Deprecated +/// +/// Use `SslStream` with `ssl_read` and `ssl_write`. #[derive(Clone)] pub struct NonblockingSslStream { stream: S, From d6ce9afdf31faacaf435380feffcd13bf387255a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Dec 2015 15:46:17 -0800 Subject: [PATCH 20/28] Have NonblockingSslStream delegate to SslStream --- openssl/src/ssl/error.rs | 29 +++-- openssl/src/ssl/mod.rs | 249 +++++++++++++-------------------------- 2 files changed, 102 insertions(+), 176 deletions(-) diff --git a/openssl/src/ssl/error.rs b/openssl/src/ssl/error.rs index 9a1a63b2..52ea6693 100644 --- a/openssl/src/ssl/error.rs +++ b/openssl/src/ssl/error.rs @@ -95,6 +95,11 @@ impl OpenSslError { errs } + /// Returns the raw OpenSSL error code for this error. + pub fn error_code(&self) -> c_ulong { + self.0 + } + /// Returns the name of the library reporting the error. pub fn library(&self) -> &'static str { get_lib(self.0) @@ -239,6 +244,17 @@ pub enum OpensslError { } } +impl OpensslError { + pub fn from_error_code(err: c_ulong) -> OpensslError { + ffi::init(); + UnknownError { + library: get_lib(err).to_owned(), + function: get_func(err).to_owned(), + reason: get_reason(err).to_owned() + } + } +} + fn get_lib(err: c_ulong) -> &'static str { unsafe { let cstr = ffi::ERR_lib_error_string(err); @@ -271,7 +287,7 @@ impl SslError { loop { match unsafe { ffi::ERR_get_error() } { 0 => break, - err => errs.push(SslError::from_error_code(err)) + err => errs.push(OpensslError::from_error_code(err)) } } OpenSslErrors(errs) @@ -279,16 +295,7 @@ impl SslError { /// Creates an `SslError` from the raw numeric error code. pub fn from_error(err: c_ulong) -> SslError { - OpenSslErrors(vec![SslError::from_error_code(err)]) - } - - fn from_error_code(err: c_ulong) -> OpensslError { - ffi::init(); - UnknownError { - library: get_lib(err).to_owned(), - function: get_func(err).to_owned(), - reason: get_reason(err).to_owned() - } + OpenSslErrors(vec![OpensslError::from_error_code(err)]) } } diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 89c8bbfc..0ffa1120 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -10,7 +10,7 @@ use std::str; use std::net; use std::path::Path; use std::ptr; -use std::sync::{Once, ONCE_INIT, Arc, Mutex}; +use std::sync::{Once, ONCE_INIT, Mutex}; use std::cmp; use std::any::Any; #[cfg(any(feature = "npn", feature = "alpn"))] @@ -18,11 +18,16 @@ use libc::{c_uchar, c_uint}; #[cfg(any(feature = "npn", feature = "alpn"))] use std::slice; use std::marker::PhantomData; +#[cfg(unix)] +use std::os::unix::io::{AsRawFd, RawFd}; +#[cfg(windows)] +use std::os::windows::io::{AsRawSocket, RawSocket}; use ffi; use ffi_extras; use dh::DH; -use ssl::error::{NonblockingSslError, SslError, StreamError, OpenSslErrors, OpenSslError}; +use ssl::error::{NonblockingSslError, SslError, StreamError, OpenSslErrors, OpenSslError, + OpensslError}; use x509::{X509StoreContext, X509FileType, X509}; use crypto::pkey::PKey; @@ -935,6 +940,20 @@ impl fmt::Debug for SslStream where S: fmt::Debug { } } +#[cfg(unix)] +impl AsRawFd for SslStream { + fn as_raw_fd(&self) -> RawFd { + self.get_ref().as_raw_fd() + } +} + +#[cfg(windows)] +impl AsRawSocket for NonblockingSslStream { + fn as_raw_fd(&self) -> RawSocket { + self.0.as_raw_socket() + } +} + impl SslStream { fn new_base(ssl: Ssl, stream: S) -> Self { unsafe { @@ -1247,65 +1266,38 @@ impl MaybeSslStream { /// # Deprecated /// /// Use `SslStream` with `ssl_read` and `ssl_write`. -#[derive(Clone)] -pub struct NonblockingSslStream { - stream: S, - ssl: Arc, +pub struct NonblockingSslStream(SslStream); + +impl Clone for NonblockingSslStream { + fn clone(&self) -> Self { + NonblockingSslStream(self.0.clone()) + } +} + +#[cfg(unix)] +impl AsRawFd for NonblockingSslStream { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +#[cfg(windows)] +impl AsRawSocket for NonblockingSslStream { + fn as_raw_fd(&self) -> RawSocket { + self.0.as_raw_socket() + } } impl NonblockingSslStream { pub fn try_clone(&self) -> io::Result> { - Ok(NonblockingSslStream { - stream: try!(self.stream.try_clone()), - ssl: self.ssl.clone(), - }) + self.0.try_clone().map(NonblockingSslStream) } } impl NonblockingSslStream { - fn new_base(ssl: Ssl, stream: S, sock: c_int) -> Result, SslError> { - unsafe { - let bio = try_ssl_null!(ffi::BIO_new_socket(sock, 0)); - ffi_extras::BIO_set_nbio(bio, 1); - ffi::SSL_set_bio(ssl.ssl, bio, bio); - } - - Ok(NonblockingSslStream { - stream: stream, - ssl: Arc::new(ssl), - }) - } - - fn make_error(&self, ret: c_int) -> NonblockingSslError { - match self.ssl.get_error(ret) { - LibSslError::ErrorSsl => NonblockingSslError::SslError(SslError::get()), - LibSslError::ErrorSyscall => { - let err = SslError::get(); - let count = match err { - SslError::OpenSslErrors(ref v) => v.len(), - _ => unreachable!(), - }; - let ssl_error = if count == 0 { - if ret == 0 { - SslError::StreamError(io::Error::new(io::ErrorKind::ConnectionAborted, - "unexpected EOF observed")) - } else { - SslError::StreamError(io::Error::last_os_error()) - } - } else { - err - }; - ssl_error.into() - }, - LibSslError::ErrorWantWrite => NonblockingSslError::WantWrite, - LibSslError::ErrorWantRead => NonblockingSslError::WantRead, - err => panic!("unexpected error {:?} with ret {}", err, ret), - } - } - /// Returns a reference to the underlying stream. pub fn get_ref(&self) -> &S { - &self.stream + self.0.get_ref() } /// Returns a mutable reference to the underlying stream. @@ -1315,117 +1307,50 @@ impl NonblockingSslStream { /// It is inadvisable to read from or write to the underlying stream as it /// will most likely corrupt the SSL session. pub fn get_mut(&mut self) -> &mut S { - &mut self.stream + self.0.get_mut() } /// Returns a reference to the Ssl. pub fn ssl(&self) -> &Ssl { - &self.ssl - } -} - -#[cfg(unix)] -impl NonblockingSslStream { - /// Create a new nonblocking client ssl connection on wrapped `stream`. - /// - /// Note that this method will most likely not actually complete the SSL - /// handshake because doing so requires several round trips; the handshake will - /// be completed in subsequent read/write calls managed by your event loop. - pub fn connect(ssl: T, stream: S) -> Result, SslError> { - let ssl = try!(ssl.into_ssl()); - let fd = stream.as_raw_fd() as c_int; - let ssl = try!(NonblockingSslStream::new_base(ssl, stream, fd)); - let ret = ssl.ssl.connect(); - if ret > 0 { - Ok(ssl) - } else { - // WantRead/WantWrite is okay here; we'll finish the handshake in - // subsequent send/recv calls. - match ssl.make_error(ret) { - NonblockingSslError::WantRead | NonblockingSslError::WantWrite => Ok(ssl), - NonblockingSslError::SslError(other) => Err(other), - } - } - } - - /// Create a new nonblocking server ssl connection on wrapped `stream`. - /// - /// Note that this method will most likely not actually complete the SSL - /// handshake because doing so requires several round trips; the handshake will - /// be completed in subsequent read/write calls managed by your event loop. - pub fn accept(ssl: T, stream: S) -> Result, SslError> { - let ssl = try!(ssl.into_ssl()); - let fd = stream.as_raw_fd() as c_int; - let ssl = try!(NonblockingSslStream::new_base(ssl, stream, fd)); - let ret = ssl.ssl.accept(); - if ret > 0 { - Ok(ssl) - } else { - // WantRead/WantWrite is okay here; we'll finish the handshake in - // subsequent send/recv calls. - match ssl.make_error(ret) { - NonblockingSslError::WantRead | NonblockingSslError::WantWrite => Ok(ssl), - NonblockingSslError::SslError(other) => Err(other), - } - } - } -} - -#[cfg(unix)] -impl ::std::os::unix::io::AsRawFd for NonblockingSslStream { - fn as_raw_fd(&self) -> ::std::os::unix::io::RawFd { - self.stream.as_raw_fd() - } -} - -#[cfg(windows)] -impl NonblockingSslStream { - /// Create a new nonblocking client ssl connection on wrapped `stream`. - /// - /// Note that this method will most likely not actually complete the SSL - /// handshake because doing so requires several round trips; the handshake will - /// be completed in subsequent read/write calls managed by your event loop. - pub fn connect(ssl: T, stream: S) -> Result, SslError> { - let ssl = try!(ssl.into_ssl()); - let fd = stream.as_raw_socket() as c_int; - let ssl = try!(NonblockingSslStream::new_base(ssl, stream, fd)); - let ret = ssl.ssl.connect(); - if ret > 0 { - Ok(ssl) - } else { - // WantRead/WantWrite is okay here; we'll finish the handshake in - // subsequent send/recv calls. - match ssl.make_error(ret) { - NonblockingSslError::WantRead | NonblockingSslError::WantWrite => Ok(ssl), - NonblockingSslError::SslError(other) => Err(other), - } - } - } - - /// Create a new nonblocking server ssl connection on wrapped `stream`. - /// - /// Note that this method will most likely not actually complete the SSL - /// handshake because doing so requires several round trips; the handshake will - /// be completed in subsequent read/write calls managed by your event loop. - pub fn accept(ssl: T, stream: S) -> Result, SslError> { - let ssl = try!(ssl.into_ssl()); - let fd = stream.as_raw_socket() as c_int; - let ssl = try!(NonblockingSslStream::new_base(ssl, stream, fd)); - let ret = ssl.ssl.accept(); - if ret > 0 { - Ok(ssl) - } else { - // WantRead/WantWrite is okay here; we'll finish the handshake in - // subsequent send/recv calls. - match ssl.make_error(ret) { - NonblockingSslError::WantRead | NonblockingSslError::WantWrite => Ok(ssl), - NonblockingSslError::SslError(other) => Err(other), - } - } + self.0.ssl() } } impl NonblockingSslStream { + /// Create a new nonblocking client ssl connection on wrapped `stream`. + /// + /// Note that this method will most likely not actually complete the SSL + /// handshake because doing so requires several round trips; the handshake will + /// be completed in subsequent read/write calls managed by your event loop. + pub fn connect(ssl: T, stream: S) -> Result, SslError> { + SslStream::connect(ssl, stream).map(NonblockingSslStream) + } + + /// Create a new nonblocking server ssl connection on wrapped `stream`. + /// + /// Note that this method will most likely not actually complete the SSL + /// handshake because doing so requires several round trips; the handshake will + /// be completed in subsequent read/write calls managed by your event loop. + pub fn accept(ssl: T, stream: S) -> Result, SslError> { + SslStream::accept(ssl, stream).map(NonblockingSslStream) + } + + fn convert_err(&self, err: Error) -> NonblockingSslError { + match err { + Error::ZeroReturn => SslError::SslSessionClosed.into(), + Error::WantRead(_) => NonblockingSslError::WantRead, + Error::WantWrite(_) => NonblockingSslError::WantWrite, + Error::WantX509Lookup => unreachable!(), + Error::Stream(e) => SslError::StreamError(e).into(), + Error::Ssl(e) => { + SslError::OpenSslErrors(e.iter() + .map(|e| OpensslError::from_error_code(e.error_code())) + .collect()) + .into() + } + } + } + /// Read bytes from the SSL stream into `buf`. /// /// Given the SSL state machine, this method may return either `WantWrite` @@ -1442,11 +1367,10 @@ impl NonblockingSslStream { /// On a return value of `Ok(count)`, count is the number of decrypted /// plaintext bytes copied into the `buf` slice. pub fn read(&mut self, buf: &mut [u8]) -> Result { - let ret = self.ssl.read(buf); - if ret >= 0 { - Ok(ret as usize) - } else { - Err(self.make_error(ret)) + match self.0.ssl_read(buf) { + Ok(n) => Ok(n), + Err(Error::ZeroReturn) => Ok(0), + Err(e) => Err(self.convert_err(e)) } } @@ -1466,11 +1390,6 @@ impl NonblockingSslStream { /// Given a return value of `Ok(count)`, count is the number of plaintext bytes /// from the `buf` slice that were encrypted and written onto the stream. pub fn write(&mut self, buf: &[u8]) -> Result { - let ret = self.ssl.write(buf); - if ret > 0 { - Ok(ret as usize) - } else { - Err(self.make_error(ret)) - } + self.0.ssl_write(buf).map_err(|e| self.convert_err(e)) } } From 63a45ac62220857183e55dd15665b73451580896 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Dec 2015 16:33:58 -0800 Subject: [PATCH 21/28] Fix AsRawSocket impls --- openssl/src/ssl/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 0ffa1120..6def5241 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -949,7 +949,7 @@ impl AsRawFd for SslStream { #[cfg(windows)] impl AsRawSocket for NonblockingSslStream { - fn as_raw_fd(&self) -> RawSocket { + fn as_raw_socket(&self) -> RawSocket { self.0.as_raw_socket() } } @@ -1283,7 +1283,7 @@ impl AsRawFd for NonblockingSslStream { #[cfg(windows)] impl AsRawSocket for NonblockingSslStream { - fn as_raw_fd(&self) -> RawSocket { + fn as_raw_socket(&self) -> RawSocket { self.0.as_raw_socket() } } From ddedda1d03ae149621ac63ea5169b3b3cc7bacac Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Dec 2015 16:47:03 -0800 Subject: [PATCH 22/28] More AsRawSocket fixes --- openssl/src/ssl/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 6def5241..3457fa11 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -948,7 +948,7 @@ impl AsRawFd for SslStream { } #[cfg(windows)] -impl AsRawSocket for NonblockingSslStream { +impl AsRawSocket for SslStream { fn as_raw_socket(&self) -> RawSocket { self.0.as_raw_socket() } From b8c8b770e3668b7a207f3a0a360b6155bd8145ed Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Dec 2015 18:01:21 -0800 Subject: [PATCH 23/28] Yet more AsRawSocket fixes --- openssl/src/ssl/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 3457fa11..c1535900 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -950,7 +950,7 @@ impl AsRawFd for SslStream { #[cfg(windows)] impl AsRawSocket for SslStream { fn as_raw_socket(&self) -> RawSocket { - self.0.as_raw_socket() + self.get_ref().as_raw_socket() } } From 0e34ad4bcf00fd88d98b6d0a64add55b1cd8567a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Dec 2015 18:06:11 -0800 Subject: [PATCH 24/28] Use 1.5.0 instead of nightlies --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 99583432..9cb9ae95 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,8 +10,8 @@ environment: install: - ps: Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-1_0_2e.exe" - Win%BITS%OpenSSL-1_0_2e.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL" - - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" - - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.5.0-${env:TARGET}.exe" + - rust-1.5.0-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin - SET PATH=%PATH%;C:\MinGW\bin - rustc -V From f2fae1f83f0fd94ac6c6e1b22e8a9aaca54f5254 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 14 Dec 2015 23:44:28 -0800 Subject: [PATCH 25/28] Document unused variant No reason to hide it --- openssl/src/ssl/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openssl/src/ssl/error.rs b/openssl/src/ssl/error.rs index 52ea6693..126747d8 100644 --- a/openssl/src/ssl/error.rs +++ b/openssl/src/ssl/error.rs @@ -22,7 +22,7 @@ pub enum Error { /// An attempt to write data from the underlying socket returned /// `WouldBlock`. Wait for write readiness and reattempt the operation. WantWrite(io::Error), - #[doc(hidden)] // unused for now + /// The client certificate callback requested to be called again. WantX509Lookup, /// An error reported by the underlying stream. Stream(io::Error), From 3a0e64dca51f74f6cf1178f6a20949e4063ca9d6 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 15 Dec 2015 19:33:36 -0800 Subject: [PATCH 26/28] Cleanup --- openssl/src/ssl/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index dffcfdb8..6558e1a4 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -315,7 +315,7 @@ extern fn raw_verify_with_data(preverify_ok: c_int, } } -extern fn raw_sni(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_void) +extern fn raw_sni(ssl: *mut ffi::SSL, ad: &mut c_int, _arg: *mut c_void) -> c_int { unsafe { let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); @@ -982,9 +982,11 @@ impl Ssl { /// obtain the context corresponding to the current connection pub fn get_ssl_context(&self) -> SslContext { - let ssl_ctx = unsafe { ffi::SSL_get_SSL_CTX(self.ssl) }; - let count = unsafe { ffi_extras::SSL_CTX_increment_refcount(ssl_ctx) }; - SslContext { ctx: ssl_ctx } + unsafe { + let ssl_ctx = ffi::SSL_get_SSL_CTX(self.ssl); + ffi_extras::SSL_CTX_increment_refcount(ssl_ctx); + SslContext { ctx: ssl_ctx } + } } } From 6d559bf1dad5611f15165645aaad3c465cf6e0fe Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 15 Dec 2015 19:39:24 -0800 Subject: [PATCH 27/28] Cleanup SNI stuff --- openssl-sys-extras/src/lib.rs | 2 -- openssl-sys-extras/src/openssl_shim.c | 5 ----- openssl/src/c_helpers.c | 4 ++++ openssl/src/ssl/mod.rs | 19 ++++++------------- 4 files changed, 10 insertions(+), 20 deletions(-) diff --git a/openssl-sys-extras/src/lib.rs b/openssl-sys-extras/src/lib.rs index f8751d18..08d9e3d2 100644 --- a/openssl-sys-extras/src/lib.rs +++ b/openssl-sys-extras/src/lib.rs @@ -77,6 +77,4 @@ extern { pub fn SSL_CTX_set_tlsext_servername_callback(ssl: *mut SSL_CTX, callback: Option); #[link_name = "SSL_CTX_set_tlsext_servername_arg_shim"] pub fn SSL_CTX_set_tlsext_servername_arg(ssl: *mut SSL_CTX, arg: *const c_void); - #[link_name = "SSL_CTX_increment_refcount_shim"] - pub fn SSL_CTX_increment_refcount(ssl: *mut SSL_CTX) -> c_long; } diff --git a/openssl-sys-extras/src/openssl_shim.c b/openssl-sys-extras/src/openssl_shim.c index 3acd3d50..c3deeebc 100644 --- a/openssl-sys-extras/src/openssl_shim.c +++ b/openssl-sys-extras/src/openssl_shim.c @@ -139,11 +139,6 @@ long SSL_CTX_set_tlsext_servername_arg_shim(SSL_CTX *ctx, void* arg) { return SSL_CTX_set_tlsext_servername_arg(ctx, arg); } -long SSL_CTX_increment_refcount_shim(SSL_CTX *ctx) { - int i = CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX); - return i; -} - #if OPENSSL_VERSION_NUMBER >= 0x10002000L int SSL_CTX_set_ecdh_auto_shim(SSL_CTX *ctx, int onoff) { return SSL_CTX_set_ecdh_auto(ctx, onoff); diff --git a/openssl/src/c_helpers.c b/openssl/src/c_helpers.c index 3739cfc2..402c36ec 100644 --- a/openssl/src/c_helpers.c +++ b/openssl/src/c_helpers.c @@ -3,3 +3,7 @@ void rust_SSL_clone(SSL *ssl) { CRYPTO_add(&ssl->references, 1, CRYPTO_LOCK_SSL); } + +void rust_SSL_CTX_clone(SSL_CTX *ctx) { + CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX); +} diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 6558e1a4..3b22c755 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -41,6 +41,7 @@ pub use ssl::error::Error; extern "C" { fn rust_SSL_clone(ssl: *mut ffi::SSL); + fn rust_SSL_CTX_clone(cxt: *mut ffi::SSL_CTX); } static mut VERIFY_IDX: c_int = -1; @@ -297,20 +298,15 @@ extern fn raw_verify_with_data(preverify_ok: c_int, let verify: Option> = mem::transmute(verify); let data = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::()); - let data: Box = mem::transmute(data); + let data: &T = mem::transmute(data); let ctx = X509StoreContext::new(x509_ctx); let res = match verify { None => preverify_ok, - Some(verify) => verify(preverify_ok != 0, &ctx, &*data) as c_int + Some(verify) => verify(preverify_ok != 0, &ctx, data) as c_int }; - // Since data might be required on the next verification - // it is time to forget about it and avoid dropping - // data will be freed once OpenSSL considers it is time - // to free all context data - mem::forget(data); res } } @@ -321,6 +317,7 @@ extern fn raw_sni(ssl: *mut ffi::SSL, ad: &mut c_int, _arg: *mut c_void) let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, SNI_IDX); let callback: Option = mem::transmute(callback); + rust_SSL_clone(ssl); let mut s = Ssl { ssl: ssl }; let res = match callback { @@ -328,8 +325,6 @@ extern fn raw_sni(ssl: *mut ffi::SSL, ad: &mut c_int, _arg: *mut c_void) Some(callback) => callback(&mut s, ad) }; - // Allows dropping the Ssl instance without calling SSL_FREE on the SSL object - mem::forget(s); res } } @@ -341,6 +336,7 @@ extern fn raw_sni_with_data(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_v let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, SNI_IDX); let callback: Option> = mem::transmute(callback); + rust_SSL_clone(ssl); let mut s = Ssl { ssl: ssl }; let data: &T = mem::transmute(arg); @@ -350,9 +346,6 @@ extern fn raw_sni_with_data(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_v Some(callback) => callback(&mut s, ad, &*data) }; - // Allows dropping the Ssl instance without calling SSL_FREE on the SSL object - mem::forget(s); - // Since data might be required on the next verification // it is time to forget about it and avoid dropping // data will be freed once OpenSSL considers it is time @@ -984,7 +977,7 @@ impl Ssl { pub fn get_ssl_context(&self) -> SslContext { unsafe { let ssl_ctx = ffi::SSL_get_SSL_CTX(self.ssl); - ffi_extras::SSL_CTX_increment_refcount(ssl_ctx); + rust_SSL_CTX_clone(ssl_ctx); SslContext { ctx: ssl_ctx } } } From 13f7cfd9d8d822286cc09495a2eb0f817cf6afa4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 15 Dec 2015 19:41:57 -0800 Subject: [PATCH 28/28] Release v0.7.2 --- README.md | 2 +- openssl-sys-extras/Cargo.toml | 6 ++---- openssl-sys-extras/src/lib.rs | 2 +- openssl-sys/Cargo.toml | 5 ++--- openssl-sys/src/lib.rs | 2 +- openssl/Cargo.toml | 4 ++-- openssl/src/lib.rs | 2 +- 7 files changed, 10 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 83896575..b6dd5651 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/sfackler/rust-openssl.svg?branch=master)](https://travis-ci.org/sfackler/rust-openssl) -[Documentation](https://sfackler.github.io/rust-openssl/doc/v0.7.1/openssl). +[Documentation](https://sfackler.github.io/rust-openssl/doc/v0.7.2/openssl). ## Building diff --git a/openssl-sys-extras/Cargo.toml b/openssl-sys-extras/Cargo.toml index c3d1f565..d0719b02 100644 --- a/openssl-sys-extras/Cargo.toml +++ b/openssl-sys-extras/Cargo.toml @@ -1,13 +1,11 @@ [package] name = "openssl-sys-extras" -version = "0.7.1" +version = "0.7.2" authors = ["Steven Fackler "] license = "MIT" description = "Extra FFI bindings to OpenSSL that require a C shim" repository = "https://github.com/sfackler/rust-openssl" -documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.1/openssl_sys_extras" - -links = "openssl_shim" +documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.2/openssl_sys_extras" build = "build.rs" [features] diff --git a/openssl-sys-extras/src/lib.rs b/openssl-sys-extras/src/lib.rs index 08d9e3d2..85bb4392 100644 --- a/openssl-sys-extras/src/lib.rs +++ b/openssl-sys-extras/src/lib.rs @@ -1,5 +1,5 @@ #![allow(non_upper_case_globals, non_snake_case)] -#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.0")] +#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.2")] extern crate openssl_sys; extern crate libc; diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 1e025d84..d20992c8 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -1,13 +1,12 @@ [package] name = "openssl-sys" -version = "0.7.1" +version = "0.7.2" authors = ["Alex Crichton ", "Steven Fackler "] license = "MIT" description = "FFI bindings to OpenSSL" repository = "https://github.com/sfackler/rust-openssl" -documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.1/openssl_sys" - +documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.2/openssl_sys" links = "openssl" build = "build.rs" diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 1fc6777f..77ba20db 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1,6 +1,6 @@ #![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] #![allow(dead_code)] -#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.1")] +#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.2")] extern crate libc; diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index f3e9f5ce..0d5a4c39 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "openssl" -version = "0.7.1" +version = "0.7.2" authors = ["Steven Fackler "] license = "Apache-2.0" description = "OpenSSL bindings" repository = "https://github.com/sfackler/rust-openssl" -documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.1/openssl" +documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.2/openssl" readme = "../README.md" keywords = ["crypto", "tls", "ssl", "dtls"] build = "build.rs" diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index 4691b6dd..959c11c2 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.1")] +#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.2")] #[macro_use] extern crate bitflags;