diff --git a/README.md b/README.md index d10e478e..2fe4ae6f 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.9/openssl). +[Documentation](https://sfackler.github.io/rust-openssl/doc/v0.7.10/openssl). ## Building diff --git a/openssl-sys-extras/Cargo.toml b/openssl-sys-extras/Cargo.toml index 6ef228a6..c655f6fe 100644 --- a/openssl-sys-extras/Cargo.toml +++ b/openssl-sys-extras/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "openssl-sys-extras" -version = "0.7.9" +version = "0.7.10" 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.9/openssl_sys_extras" +documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.10/openssl_sys_extras" build = "build.rs" [features] @@ -13,7 +13,7 @@ ecdh_auto = [] [dependencies] libc = "0.2" -openssl-sys = { version = "0.7.9", path = "../openssl-sys" } +openssl-sys = { version = "0.7.10", path = "../openssl-sys" } [build-dependencies] gcc = "0.3" diff --git a/openssl-sys-extras/src/lib.rs b/openssl-sys-extras/src/lib.rs index 15f3fbd6..97dc0c2b 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.9")] +#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.10")] extern crate openssl_sys; extern crate libc; diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 35cebfc9..0c166a53 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "openssl-sys" -version = "0.7.9" +version = "0.7.10" 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.9/openssl_sys" +documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.10/openssl_sys" links = "openssl" build = "build.rs" diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 85f434ae..da0beca0 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.9")] +#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.10")] extern crate libc; @@ -259,6 +259,12 @@ pub const SSL_TLSEXT_ERR_ALERT_WARNING: c_int = 1; pub const SSL_TLSEXT_ERR_ALERT_FATAL: c_int = 2; pub const SSL_TLSEXT_ERR_NOACK: c_int = 3; +pub const SSLEAY_VERSION : c_int = 0; +pub const SSLEAY_CFLAGS : c_int = 2; +pub const SSLEAY_BUILT_ON : c_int = 3; +pub const SSLEAY_PLATFORM : c_int = 4; +pub const SSLEAY_DIR : c_int = 5; + #[cfg(any(feature = "npn", feature = "alpn"))] pub const OPENSSL_NPN_UNSUPPORTED: c_int = 0; #[cfg(any(feature = "npn", feature = "alpn"))] @@ -667,6 +673,7 @@ extern "C" { pub fn SSL_CTX_set_verify_depth(ctx: *mut SSL_CTX, depth: c_int); pub fn SSL_CTX_load_verify_locations(ctx: *mut SSL_CTX, CAfile: *const c_char, CApath: *const c_char) -> c_int; + pub fn SSL_CTX_set_default_verify_paths(ctx: *mut SSL_CTX) -> c_int; pub fn SSL_CTX_get_ex_new_index(argl: c_long, argp: *const c_void, new_func: Option, dup_func: Option, @@ -675,6 +682,7 @@ extern "C" { pub fn SSL_CTX_set_ex_data(ctx: *mut SSL_CTX, idx: c_int, data: *mut c_void) -> c_int; pub fn SSL_CTX_get_ex_data(ctx: *mut SSL_CTX, idx: c_int) -> *mut c_void; + pub fn SSL_CTX_set_session_id_context(ssl: *mut SSL_CTX, sid_ctx: *const c_uchar, sid_ctx_len: c_uint) -> c_int; pub fn SSL_CTX_use_certificate_file(ctx: *mut SSL_CTX, cert_file: *const c_char, file_type: c_int) -> c_int; pub fn SSL_CTX_use_certificate_chain_file(ctx: *mut SSL_CTX, cert_chain_file: *const c_char, file_type: c_int) -> c_int; @@ -768,6 +776,9 @@ extern "C" { pub fn d2i_RSA_PUBKEY(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA; pub fn i2d_RSAPrivateKey(k: *mut RSA, buf: *const *mut u8) -> c_int; pub fn d2i_RSAPrivateKey(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA; + + pub fn SSLeay() -> c_long; + pub fn SSLeay_version(key: c_int) -> *const c_char; } pub mod probe; diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 09f84433..08f5a6cd 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "openssl" -version = "0.7.9" +version = "0.7.10" 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.9/openssl" +documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.10/openssl" readme = "../README.md" keywords = ["crypto", "tls", "ssl", "dtls"] build = "build.rs" @@ -30,10 +30,10 @@ nightly = [] [dependencies] bitflags = "0.4" -lazy_static = "0.1" +lazy_static = "0.2" libc = "0.2" -openssl-sys = { version = "0.7.9", path = "../openssl-sys" } -openssl-sys-extras = { version = "0.7.9", path = "../openssl-sys-extras" } +openssl-sys = { version = "0.7.10", path = "../openssl-sys" } +openssl-sys-extras = { version = "0.7.10", path = "../openssl-sys-extras" } [build-dependencies] gcc = "0.3" diff --git a/openssl/src/crypto/pkey.rs b/openssl/src/crypto/pkey.rs index f945276d..ba0a16b6 100644 --- a/openssl/src/crypto/pkey.rs +++ b/openssl/src/crypto/pkey.rs @@ -609,11 +609,19 @@ impl Drop for PKey { impl Clone for PKey { fn clone(&self) -> Self { - unsafe { - let new_evp = ffi::EVP_PKEY_new(); - assert!(ffi::EVP_PKEY_copy_parameters(new_evp, self.evp) == 0); - PKey::from_handle(new_evp, self.parts) + let mut pkey = PKey::from_handle(unsafe { ffi::EVP_PKEY_new() }, self.parts); + // copy by encoding to DER and back + match self.parts { + Parts::Public => { + pkey.load_pub(&self.save_pub()[..]); + }, + Parts::Both => { + pkey.load_priv(&self.save_priv()[..]); + }, + Parts::Neither => { + }, } + pkey } } @@ -874,4 +882,26 @@ mod tests { assert!(old_pkey_n == pkey.get_rsa().n().unwrap()); } + + #[test] + fn test_pkey_clone_copies_private() { + let mut pkey = super::PKey::new(); + pkey.gen(512); + + let pkey2 = pkey.clone(); + + assert!(pkey.get_rsa().q().unwrap() == pkey2.get_rsa().q().unwrap()); + } + + #[test] + fn test_pkey_clone_copies_public() { + let mut pkey = super::PKey::new(); + pkey.gen(512); + let mut pub_key = super::PKey::new(); + pub_key.load_pub(&pkey.save_pub()[..]); + + let pub_key2 = pub_key.clone(); + + assert!(pub_key.get_rsa().n().unwrap() == pub_key2.get_rsa().n().unwrap()); + } } diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index ad982597..63926615 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -1,5 +1,5 @@ -#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.9")] -#![cfg_attr(feature = "nightly", feature(const_fn, recover, panic_propagate))] +#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.10")] +#![cfg_attr(feature = "nightly", feature(const_fn))] #[macro_use] extern crate bitflags; @@ -25,3 +25,4 @@ pub mod dh; pub mod ssl; pub mod x509; pub mod nid; +pub mod version; diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs index 4adbfbe2..e53545d7 100644 --- a/openssl/src/ssl/bio.rs +++ b/openssl/src/ssl/bio.rs @@ -82,12 +82,12 @@ unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState { } #[cfg(feature = "nightly")] -fn recover(f: F) -> Result> where F: FnOnce() -> T { - ::std::panic::recover(::std::panic::AssertRecoverSafe(f)) +fn catch_unwind(f: F) -> Result> where F: FnOnce() -> T { + ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(f)) } #[cfg(not(feature = "nightly"))] -fn recover(f: F) -> Result> where F: FnOnce() -> T { +fn catch_unwind(f: F) -> Result> where F: FnOnce() -> T { Ok(f()) } @@ -97,7 +97,7 @@ unsafe extern "C" fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_ let state = state::(bio); let buf = slice::from_raw_parts(buf as *const _, len as usize); - match recover(|| state.stream.write(buf)) { + match catch_unwind(|| state.stream.write(buf)) { Ok(Ok(len)) => len as c_int, Ok(Err(err)) => { if retriable_error(&err) { @@ -119,7 +119,7 @@ unsafe extern "C" fn bread(bio: *mut BIO, buf: *mut c_char, len: c_int) let state = state::(bio); let buf = slice::from_raw_parts_mut(buf as *mut _, len as usize); - match recover(|| state.stream.read(buf)) { + match catch_unwind(|| state.stream.read(buf)) { Ok(Ok(len)) => len as c_int, Ok(Err(err)) => { if retriable_error(&err) { @@ -154,7 +154,7 @@ unsafe extern "C" fn ctrl(bio: *mut BIO, if cmd == BIO_CTRL_FLUSH { let state = state::(bio); - match recover(|| state.stream.flush()) { + match catch_unwind(|| state.stream.flush()) { Ok(Ok(())) => 1, Ok(Err(err)) => { state.error = Some(err); diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 7b5cf492..4b3a4385 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -612,6 +612,15 @@ impl SslContext { wrap_ssl_result(unsafe { ffi_extras::SSL_CTX_set_tmp_dh(self.ctx, dh.raw()) as i32 }) } + /// Use the default locations of trusted certificates for verification. + /// + /// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR` + /// environment variables if present, or defaults specified at OpenSSL + /// build time otherwise. + pub fn set_default_verify_paths(&mut self) -> Result<(), SslError> { + wrap_ssl_result(unsafe { ffi::SSL_CTX_set_default_verify_paths(self.ctx) }) + } + #[allow(non_snake_case)] /// Specifies the file that contains trusted CA certificates. pub fn set_CA_file>(&mut self, file: P) -> Result<(), SslError> { @@ -621,6 +630,20 @@ impl SslContext { }) } + /// Set the context identifier for sessions + /// + /// This value identifies the server's session cache to a clients, telling them when they're + /// able to reuse sessions. Should be set to a unique value per server, unless multiple servers + /// share a session cache. + /// + /// This value should be set when using client certificates, or each request will fail + /// handshake and need to be restarted. + pub fn set_session_id_context(&mut self, sid_ctx: &[u8]) -> Result<(), SslError> { + wrap_ssl_result(unsafe { + ffi::SSL_CTX_set_session_id_context(self.ctx, sid_ctx.as_ptr(), sid_ctx.len() as u32) + }) + } + /// Specifies the file that contains certificate pub fn set_certificate_file>(&mut self, file: P, @@ -1309,7 +1332,7 @@ impl SslStream { #[cfg(feature = "nightly")] fn check_panic(&mut self) { if let Some(err) = unsafe { bio::take_panic::(self.ssl.get_raw_rbio()) } { - ::std::panic::propagate(err) + ::std::panic::resume_unwind(err) } } diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index be35d7ef..15811d99 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1059,3 +1059,20 @@ fn refcount_ssl_context() { let _new_ctx_b = ssl.set_ssl_context(&new_ctx_a); } } + +#[test] +fn default_verify_paths() { + let mut ctx = SslContext::new(SslMethod::Sslv23).unwrap(); + ctx.set_default_verify_paths().unwrap(); + ctx.set_verify(SSL_VERIFY_PEER, None); + let s = TcpStream::connect("google.com:443").unwrap(); + let mut socket = SslStream::connect(&ctx, s).unwrap(); + + socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); + let mut result = vec![]; + socket.read_to_end(&mut result).unwrap(); + + println!("{}", String::from_utf8_lossy(&result)); + assert!(result.starts_with(b"HTTP/1.0")); + assert!(result.ends_with(b"\r\n") || result.ends_with(b"")); +} diff --git a/openssl/src/version.rs b/openssl/src/version.rs new file mode 100644 index 00000000..323cf1e2 --- /dev/null +++ b/openssl/src/version.rs @@ -0,0 +1,89 @@ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +use ffi; +use std::ffi::CStr; + +/// OPENSSL_VERSION_NUMBER is a numeric release version identifier: +/// +/// `MNNFFPPS: major minor fix patch status` +/// +/// The status nibble has one of the values 0 for development, 1 to e for betas 1 to 14, and f for release. +/// +/// for example +/// +/// `0x000906000 == 0.9.6 dev` +/// `0x000906023 == 0.9.6b beta 3` +/// `0x00090605f == 0.9.6e release` +/// +/// Versions prior to 0.9.3 have identifiers < 0x0930. Versions between 0.9.3 and 0.9.5 had a version identifier with this interpretation: +/// +/// `MMNNFFRBB major minor fix final beta/patch` +/// +/// for example +/// +/// `0x000904100 == 0.9.4 release` +/// `0x000905000 == 0.9.5 dev` +/// +/// Version 0.9.5a had an interim interpretation that is like the current one, except the patch level got the highest bit set, to keep continuity. The number was therefore 0x0090581f +/// +/// The return value of this function can be compared to the macro to make sure that the correct version of the library has been loaded, especially when using DLLs on Windows systems. +pub fn number() -> i64 { + unsafe { ffi::SSLeay() as i64 } +} + + +/// The text variant of the version number and the release date. For example, "OpenSSL 0.9.5a 1 Apr 2000". +pub fn version() -> &'static str { + unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_VERSION)).to_str().unwrap() } +} + +/// The compiler flags set for the compilation process in the form "compiler: ..." if available or +/// "compiler: information not available" otherwise. +pub fn c_flags() -> &'static str { + unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_CFLAGS)).to_str().unwrap() } +} + +/// The date of the build process in the form "built on: ..." if available or "built on: date not available" otherwise. +pub fn built_on() -> &'static str { + unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_BUILT_ON)).to_str().unwrap() } +} + +/// The "Configure" target of the library build in the form "platform: ..." if available or "platform: information not available" otherwise. +pub fn platform() -> &'static str { + unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_PLATFORM)).to_str().unwrap() } +} + +/// The "OPENSSLDIR" setting of the library build in the form "OPENSSLDIR: "..."" if available or "OPENSSLDIR: N/A" otherwise. +pub fn dir() -> &'static str { + unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_DIR)).to_str().unwrap() } +} + +/// This test ensures that we do not segfault when calling the functions of this module +/// and that the strings respect a reasonable format. +#[test] +fn test_versions() { + println!("Number: '{}'", number()); + println!("Version: '{}'", version()); + println!("C flags: '{}'", c_flags()); + println!("Built on: '{}'", built_on()); + println!("Platform: '{}'", platform()); + println!("Dir: '{}'", dir()); + + assert!(number() > 0); + assert!(version().starts_with("OpenSSL")); + assert!(c_flags().starts_with("compiler:")); + assert!(built_on().starts_with("built on:")); + assert!(dir().starts_with("OPENSSLDIR:")); +} \ No newline at end of file