From d5d414b16fe13d65938acd6c601445e1b3e02b55 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Thu, 17 May 2018 03:23:30 -0700 Subject: [PATCH 01/33] Expose max TLS1.3 early data accessors --- openssl-sys/src/openssl/v111.rs | 7 ++++ openssl/src/ssl/mod.rs | 70 +++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/openssl-sys/src/openssl/v111.rs b/openssl-sys/src/openssl/v111.rs index 8574efc8..e284ff98 100644 --- a/openssl-sys/src/openssl/v111.rs +++ b/openssl-sys/src/openssl/v111.rs @@ -82,4 +82,11 @@ extern "C" { cookie_len: size_t ) -> c_int> ); + + pub fn SSL_CTX_set_max_early_data(ctx: *mut ::SSL_CTX, max_early_data: u32) -> c_int; + pub fn SSL_CTX_get_max_early_data(ctx: *const ::SSL_CTX) -> u32; + pub fn SSL_set_max_early_data(ctx: *mut ::SSL, max_early_data: u32) -> c_int; + pub fn SSL_get_max_early_data(ctx: *const ::SSL) -> u32; + pub fn SSL_SESSION_set_max_early_data(ctx: *mut ::SSL_SESSION, max_early_data: u32) -> c_int; + pub fn SSL_SESSION_get_max_early_data(ctx: *const ::SSL_SESSION) -> u32; } diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 8dc605ed..33ffa737 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1489,6 +1489,24 @@ impl SslContextBuilder { } } + /// Sets the maximum amount of early data that will be accepted on incoming connections. + /// + /// Defaults to 0. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_CTX_set_max_early_data`]. + /// + /// [`SSL_CTX_set_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_max_early_data.html + #[cfg(ossl111)] + pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> { + if unsafe { ffi::SSL_CTX_set_max_early_data(self.as_ptr(), bytes) } == 1 { + Ok(()) + } else { + Err(ErrorStack::get()) + } + } + /// Consumes the builder, returning a new `SslContext`. pub fn build(self) -> SslContext { self.0 @@ -1643,6 +1661,18 @@ impl SslContextRef { } } } + + /// Gets the maximum amount of early data that will be accepted on incoming connections. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_CTX_get_max_early_data`]. + /// + /// [`SSL_CTX_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_get_max_early_data.html + #[cfg(ossl111)] + pub fn max_early_data(&self) -> u32 { + unsafe { ffi::SSL_CTX_get_max_early_data(self.as_ptr()) } + } } /// Information about the state of a cipher. @@ -1873,6 +1903,18 @@ impl SslSessionRef { unsafe { compat::SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) } } + /// Gets the maximum amount of early data that can be sent on this session. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_SESSION_get_max_early_data`]. + /// + /// [`SSL_SESSION_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_SESSION_get_max_early_data.html + #[cfg(ossl111)] + pub fn max_early_data(&self) -> u32 { + unsafe { ffi::SSL_SESSION_get_max_early_data(self.as_ptr()) } + } + to_der! { /// Serializes the session into a DER-encoded structure. /// @@ -2594,6 +2636,34 @@ impl SslRef { } } } + + /// Sets the maximum amount of early data that will be accepted on this connection. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_set_max_early_data`]. + /// + /// [`SSL_set_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_set_max_early_data.html + #[cfg(ossl111)] + pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> { + if unsafe { ffi::SSL_set_max_early_data(self.as_ptr(), bytes) } == 1 { + Ok(()) + } else { + Err(ErrorStack::get()) + } + } + + /// Gets the maximum amount of early data that can be sent on this connection. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_get_max_early_data`]. + /// + /// [`SSL_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_get_max_early_data.html + #[cfg(ossl111)] + pub fn max_early_data(&self) -> u32 { + unsafe { ffi::SSL_get_max_early_data(self.as_ptr()) } + } } /// An SSL stream midway through the handshake process. From 69c75a178bbc70dd10d0d69ac8bf9e842cf4ff1f Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Thu, 17 May 2018 13:16:41 -0700 Subject: [PATCH 02/33] Expose early keying material export --- openssl-sys/src/openssl/v111.rs | 10 ++++++++++ openssl/src/ssl/mod.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/openssl-sys/src/openssl/v111.rs b/openssl-sys/src/openssl/v111.rs index e284ff98..4a3f9560 100644 --- a/openssl-sys/src/openssl/v111.rs +++ b/openssl-sys/src/openssl/v111.rs @@ -89,4 +89,14 @@ extern "C" { pub fn SSL_get_max_early_data(ctx: *const ::SSL) -> u32; pub fn SSL_SESSION_set_max_early_data(ctx: *mut ::SSL_SESSION, max_early_data: u32) -> c_int; pub fn SSL_SESSION_get_max_early_data(ctx: *const ::SSL_SESSION) -> u32; + + pub fn SSL_export_keying_material_early( + s: *mut ::SSL, + out: *mut c_uchar, + olen: size_t, + label: *const c_char, + llen: size_t, + context: *const c_uchar, + contextlen: size_t, + ) -> c_int; } diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 33ffa737..78ae2267 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -2498,6 +2498,33 @@ impl SslRef { } } + /// Derives keying material for application use in accordance to RFC 5705. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_export_keying_material_early`]. + /// + /// [`SSL_export_keying_material_early`]: https://www.openssl.org/docs/manmaster/man3/SSL_export_keying_material_early.html + #[cfg(ossl111)] + pub fn export_keying_material_early( + &self, + out: &mut [u8], + label: &str, + context: &[u8], + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_export_keying_material_early( + self.as_ptr(), + out.as_mut_ptr() as *mut c_uchar, + out.len(), + label.as_ptr() as *const c_char, + label.len(), + context.as_ptr() as *const c_uchar, + context.len(), + )).map(|_| ()) + } + } + /// Sets the session to be used. /// /// This should be called before the handshake to attempt to reuse a previously established From e037c0fcb8c44ddd491b6b10e9374203cc0053f0 Mon Sep 17 00:00:00 2001 From: eonil Date: Fri, 18 May 2018 15:31:11 +0900 Subject: [PATCH 03/33] Find path prefix to OpenSSL installed by Homebrew. --- README.md | 14 +++++++------- openssl-sys/build.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 33727d0d..16155fbd 100644 --- a/README.md +++ b/README.md @@ -48,25 +48,25 @@ make -j$(nproc) make install ``` -### OSX +### macOS -Although OpenSSL 0.9.8 is preinstalled on OSX this library is being phased out -of OSX and this crate also does not support that version of OpenSSL. To use this -crate on OSX you'll need to install OpenSSL via some alternate means, typically +Although OpenSSL 0.9.8 is preinstalled on macOS this library is being phased out +of macOS and this crate also does not support that version of OpenSSL. To use this +crate on macOS you'll need to install OpenSSL via some alternate means, typically Homebrew: ```bash brew install openssl ``` -Occasionally an update of XCode or MacOS will cause the linker to fail after compilation, to rectify this you may want to try and run: +Occasionally an update of XCode or macOS will cause the linker to fail after compilation, to rectify this you may want to try and run: ```bash xcode-select --install ``` -If Homebrew is installed to the default location of `/usr/local`, OpenSSL will be -automatically detected. +If you're using latest version of Homebrew which supports `--prefix` command, +OpenSSL will be automatically detected. ### Windows MSVC diff --git a/openssl-sys/build.rs b/openssl-sys/build.rs index 0b8341fa..c5630556 100644 --- a/openssl-sys/build.rs +++ b/openssl-sys/build.rs @@ -104,6 +104,8 @@ fn find_openssl_dir(target: &str) -> OsString { let host = env::var("HOST").unwrap(); if host == target && target.contains("apple-darwin") { + // Check up default Homebrew installation location first + // for quick resolution if possible. let homebrew = Path::new("/usr/local/opt/openssl@1.1"); if homebrew.exists() { return homebrew.to_path_buf().into(); @@ -112,6 +114,22 @@ fn find_openssl_dir(target: &str) -> OsString { if homebrew.exists() { return homebrew.to_path_buf().into(); } + // Calling `brew --prefix ` command usually slow and + // takes seconds, and will be used only as a last resort. + let output = execute_command_and_get_output("brew", &["--prefix", "openssl@1.1"]); + if let Some(ref output) = output { + let homebrew = Path::new(&output); + if homebrew.exists() { + return homebrew.to_path_buf().into(); + } + } + let output = execute_command_and_get_output("brew", &["--prefix", "openssl"]); + if let Some(ref output) = output { + let homebrew = Path::new(&output); + if homebrew.exists() { + return homebrew.to_path_buf().into(); + } + } } try_pkg_config(); @@ -548,3 +566,19 @@ fn determine_mode(libdir: &Path, libs: &[&str]) -> &'static str { // practices with security libs", let's link dynamically. "dylib" } + + + +fn execute_command_and_get_output(cmd: &str, args: &[&str]) -> Option { + let out = Command::new(cmd).args(args).output(); + if let Ok(ref r1) = out { + if r1.status.success() { + let r2 = String::from_utf8(r1.stdout.clone()); + if let Ok(r3) = r2 { + return Some(r3.trim().to_string()); + } + } + } + return None; +} + From d991566f2b1b6803ad214fe6bf531d5870ab43fd Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 19 May 2018 19:43:02 -0700 Subject: [PATCH 04/33] Support min/max version in LibreSSL Their implementations of the accessors don't behave expected with no bounds, so we ignore those bits of the tests. --- openssl-sys/Cargo.toml | 1 + openssl-sys/build/cfgs.rs | 45 +++++++++++++++++++ openssl-sys/{build.rs => build/main.rs} | 36 +++++---------- openssl-sys/src/lib.rs | 27 ++++++----- openssl-sys/src/libressl/mod.rs | 32 ++++++++----- openssl-sys/src/libressl/{v25x.rs => v251.rs} | 4 +- openssl/build.rs | 12 +++++ openssl/src/ec.rs | 18 ++++---- openssl/src/rsa.rs | 11 +++-- openssl/src/ssl/mod.rs | 26 ++++++----- openssl/src/ssl/test.rs | 8 ++-- openssl/src/x509/tests.rs | 13 +++--- systest/build.rs | 43 +++++++++--------- 13 files changed, 175 insertions(+), 101 deletions(-) create mode 100644 openssl-sys/build/cfgs.rs rename openssl-sys/{build.rs => build/main.rs} (95%) rename openssl-sys/src/libressl/{v25x.rs => v251.rs} (94%) diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 1153dd5a..3b76c416 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -9,6 +9,7 @@ repository = "https://github.com/sfackler/rust-openssl" readme = "README.md" categories = ["cryptography", "external-ffi-bindings"] links = "openssl" +build = "build/main.rs" [dependencies] libc = "0.2" diff --git a/openssl-sys/build/cfgs.rs b/openssl-sys/build/cfgs.rs new file mode 100644 index 00000000..3e063aa3 --- /dev/null +++ b/openssl-sys/build/cfgs.rs @@ -0,0 +1,45 @@ +pub fn get(openssl_version: Option, libressl_version: Option) -> Vec<&'static str> { + let mut cfgs = vec![]; + + if let Some(libressl_version) = libressl_version { + cfgs.push("libressl"); + + if libressl_version >= 0x2_05_01_00_0 { + cfgs.push("libressl251"); + } + + if libressl_version >= 0x2_06_01_00_0 { + cfgs.push("libressl261"); + } + + if libressl_version >= 0x2_07_00_00_0 { + cfgs.push("libressl270"); + } + } else { + let openssl_version = openssl_version.unwrap(); + + if openssl_version >= 0x1_00_02_08_0 { + cfgs.push("ossl102h"); + } + + if openssl_version >= 0x1_01_00_07_0 { + cfgs.push("ossl110g"); + } + + if openssl_version >= 0x1_01_01_00_0 { + cfgs.push("ossl111"); + cfgs.push("ossl110"); + } else if openssl_version >= 0x1_01_00_06_0 { + cfgs.push("ossl110"); + cfgs.push("ossl110f"); + } else if openssl_version >= 0x1_01_00_00_0 { + cfgs.push("ossl110"); + } else if openssl_version >= 0x1_00_02_00_0 { + cfgs.push("ossl102"); + } else if openssl_version >= 0x1_00_01_00_0 { + cfgs.push("ossl101"); + } + } + + cfgs +} diff --git a/openssl-sys/build.rs b/openssl-sys/build/main.rs similarity index 95% rename from openssl-sys/build.rs rename to openssl-sys/build/main.rs index c5630556..e2b3108c 100644 --- a/openssl-sys/build.rs +++ b/openssl-sys/build/main.rs @@ -11,6 +11,8 @@ use std::io::{BufWriter, Write}; use std::path::{Path, PathBuf}; use std::process::Command; +mod cfgs; + // The set of `OPENSSL_NO_`s that we care about. const DEFINES: &'static [&'static str] = &[ "OPENSSL_NO_BUF_FREELISTS", @@ -114,7 +116,7 @@ fn find_openssl_dir(target: &str) -> OsString { if homebrew.exists() { return homebrew.to_path_buf().into(); } - // Calling `brew --prefix ` command usually slow and + // Calling `brew --prefix ` command usually slow and // takes seconds, and will be used only as a last resort. let output = execute_command_and_get_output("brew", &["--prefix", "openssl@1.1"]); if let Some(ref output) = output { @@ -427,6 +429,10 @@ See rust-openssl README for more information: } println!("cargo:conf={}", enabled.join(",")); + for cfg in cfgs::get(openssl_version, libressl_version) { + println!("cargo:rustc-cfg={}", cfg); + } + if let Some(libressl_version) = libressl_version { println!("cargo:libressl_version_number={:x}", libressl_version); @@ -445,8 +451,6 @@ See rust-openssl README for more information: _ => version_error(), }; - println!("cargo:rustc-cfg=libressl"); - println!("cargo:rustc-cfg=libressl2{}{}", minor, fix); println!("cargo:libressl=true"); println!("cargo:libressl_version=2{}{}", minor, fix); println!("cargo:version=101"); @@ -455,37 +459,22 @@ See rust-openssl README for more information: let openssl_version = openssl_version.unwrap(); println!("cargo:version_number={:x}", openssl_version); - if openssl_version >= 0x1_00_02_08_0 { - println!("cargo:rustc-cfg=ossl102h"); - } - - if openssl_version >= 0x1_01_00_07_0 { - println!("cargo:rustc-cfg=ossl110g"); - } - if openssl_version >= 0x1_01_02_00_0 { version_error() } else if openssl_version >= 0x1_01_01_00_0 { - println!("cargo:rustc-cfg=ossl111"); - println!("cargo:rustc-cfg=ossl110"); println!("cargo:version=111"); Version::Openssl11x } else if openssl_version >= 0x1_01_00_06_0 { - println!("cargo:rustc-cfg=ossl110"); - println!("cargo:rustc-cfg=ossl110f"); println!("cargo:version=110"); println!("cargo:patch=f"); Version::Openssl11x } else if openssl_version >= 0x1_01_00_00_0 { - println!("cargo:rustc-cfg=ossl110"); println!("cargo:version=110"); Version::Openssl11x } else if openssl_version >= 0x1_00_02_00_0 { - println!("cargo:rustc-cfg=ossl102"); println!("cargo:version=102"); Version::Openssl10x } else if openssl_version >= 0x1_00_01_00_0 { - println!("cargo:rustc-cfg=ossl101"); println!("cargo:version=101"); Version::Openssl10x } else { @@ -542,10 +531,12 @@ fn determine_mode(libdir: &Path, libs: &[&str]) -> &'static str { .map(|e| e.file_name()) .filter_map(|e| e.into_string().ok()) .collect::>(); - let can_static = libs.iter() + let can_static = libs + .iter() .all(|l| files.contains(&format!("lib{}.a", l)) || files.contains(&format!("{}.lib", l))); let can_dylib = libs.iter().all(|l| { - files.contains(&format!("lib{}.so", l)) || files.contains(&format!("{}.dll", l)) + files.contains(&format!("lib{}.so", l)) + || files.contains(&format!("{}.dll", l)) || files.contains(&format!("lib{}.dylib", l)) }); match (can_static, can_dylib) { @@ -567,8 +558,6 @@ fn determine_mode(libdir: &Path, libs: &[&str]) -> &'static str { "dylib" } - - fn execute_command_and_get_output(cmd: &str, args: &[&str]) -> Option { let out = Command::new(cmd).args(args).output(); if let Ok(ref r1) = out { @@ -576,9 +565,8 @@ fn execute_command_and_get_output(cmd: &str, args: &[&str]) -> Option { let r2 = String::from_utf8(r1.stdout.clone()); if let Ok(r3) = r2 { return Some(r3.trim().to_string()); - } + } } } return None; } - diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 61e087d0..e78c24f4 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -236,8 +236,10 @@ pub const EVP_PKEY_OP_VERIFYCTX: c_int = 1 << 7; pub const EVP_PKEY_OP_ENCRYPT: c_int = 1 << 8; pub const EVP_PKEY_OP_DECRYPT: c_int = 1 << 9; -pub const EVP_PKEY_OP_TYPE_SIG: c_int = EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY - | EVP_PKEY_OP_VERIFYRECOVER | EVP_PKEY_OP_SIGNCTX +pub const EVP_PKEY_OP_TYPE_SIG: c_int = EVP_PKEY_OP_SIGN + | EVP_PKEY_OP_VERIFY + | EVP_PKEY_OP_VERIFYRECOVER + | EVP_PKEY_OP_SIGNCTX | EVP_PKEY_OP_VERIFYCTX; pub const EVP_PKEY_OP_TYPE_CRYPT: c_int = EVP_PKEY_OP_ENCRYPT | EVP_PKEY_OP_DECRYPT; @@ -1259,21 +1261,23 @@ pub const SSL_VERIFY_NONE: c_int = 0; pub const SSL_VERIFY_PEER: c_int = 1; pub const SSL_VERIFY_FAIL_IF_NO_PEER_CERT: c_int = 2; -#[cfg(not(any(libressl261, libressl262, libressl26x, libressl27x, ossl101)))] +#[cfg(not(any(libressl261, ossl101)))] pub const SSL_OP_TLSEXT_PADDING: c_ulong = 0x00000010; -#[cfg(any(libressl261, libressl262, libressl26x, libressl27x))] +#[cfg(libressl261)] pub const SSL_OP_TLSEXT_PADDING: c_ulong = 0x0; pub const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: c_ulong = 0x00000800; -#[cfg(not(any(libressl261, libressl262, libressl26x, libressl27x)))] +#[cfg(not(libressl261))] pub const SSL_OP_CRYPTOPRO_TLSEXT_BUG: c_ulong = 0x80000000; -#[cfg(any(libressl261, libressl262, libressl26x, libressl27x))] +#[cfg(libressl261)] pub const SSL_OP_CRYPTOPRO_TLSEXT_BUG: c_ulong = 0x0; pub const SSL_OP_LEGACY_SERVER_CONNECT: c_ulong = 0x00000004; #[cfg(not(any(libressl, ossl110f, ossl111)))] pub const SSL_OP_ALL: c_ulong = 0x80000BFF; #[cfg(any(ossl110f, ossl111))] -pub const SSL_OP_ALL: c_ulong = SSL_OP_CRYPTOPRO_TLSEXT_BUG | SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS - | SSL_OP_LEGACY_SERVER_CONNECT | SSL_OP_TLSEXT_PADDING +pub const SSL_OP_ALL: c_ulong = SSL_OP_CRYPTOPRO_TLSEXT_BUG + | SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS + | SSL_OP_LEGACY_SERVER_CONNECT + | SSL_OP_TLSEXT_PADDING | SSL_OP_SAFARI_ECDHE_ECDSA_BUG; pub const SSL_OP_NO_QUERY_MTU: c_ulong = 0x00001000; pub const SSL_OP_COOKIE_EXCHANGE: c_ulong = 0x00002000; @@ -1289,8 +1293,11 @@ pub const SSL_OP_NO_TLSv1_2: c_ulong = 0x08000000; pub const SSL_OP_NO_SSL_MASK: c_ulong = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2; #[cfg(ossl111)] -pub const SSL_OP_NO_SSL_MASK: c_ulong = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 - | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2 +pub const SSL_OP_NO_SSL_MASK: c_ulong = SSL_OP_NO_SSLv2 + | SSL_OP_NO_SSLv3 + | SSL_OP_NO_TLSv1 + | SSL_OP_NO_TLSv1_1 + | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_3; pub const SSL_FILETYPE_PEM: c_int = X509_FILETYPE_PEM; diff --git a/openssl-sys/src/libressl/mod.rs b/openssl-sys/src/libressl/mod.rs index 366d9502..5ae205bc 100644 --- a/openssl-sys/src/libressl/mod.rs +++ b/openssl-sys/src/libressl/mod.rs @@ -1,19 +1,18 @@ +use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void, size_t}; use std::mem; use std::ptr; use std::sync::{Mutex, MutexGuard}; use std::sync::{Once, ONCE_INIT}; -#[cfg(libressl250)] +#[cfg(not(libressl251))] pub use libressl::v250::*; -#[cfg(not(libressl250))] -pub use libressl::v25x::*; +#[cfg(libressl251)] +pub use libressl::v251::*; -use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void, size_t}; - -#[cfg(libressl250)] +#[cfg(not(libressl251))] mod v250; -#[cfg(not(libressl250))] -mod v25x; +#[cfg(libressl251)] +mod v251; #[repr(C)] pub struct stack_st_ASN1_OBJECT { @@ -337,9 +336,9 @@ pub const SSL_CTRL_OPTIONS: c_int = 32; pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94; -#[cfg(any(libressl261, libressl262, libressl26x, libressl27x))] +#[cfg(libressl261)] pub const SSL_OP_ALL: c_ulong = 0x4; -#[cfg(not(any(libressl261, libressl262, libressl26x, libressl27x)))] +#[cfg(not(libressl261))] pub const SSL_OP_ALL: c_ulong = 0x80000014; pub const SSL_OP_CISCO_ANYCONNECT: c_ulong = 0x0; pub const SSL_OP_NO_COMPRESSION: c_ulong = 0x0; @@ -352,9 +351,9 @@ pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: c_ulong = 0x0; pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: c_ulong = 0x0; pub const SSL_OP_TLS_D5_BUG: c_ulong = 0x0; pub const SSL_OP_TLS_BLOCK_PADDING_BUG: c_ulong = 0x0; -#[cfg(any(libressl261, libressl262, libressl26x, libressl27x))] +#[cfg(libressl261)] pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x0; -#[cfg(not(any(libressl261, libressl262, libressl26x, libressl27x)))] +#[cfg(not(libressl261))] pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x00080000; pub const SSL_OP_SINGLE_DH_USE: c_ulong = 0x00100000; pub const SSL_OP_NO_SSLv2: c_ulong = 0x0; @@ -540,6 +539,15 @@ extern "C" { unsafe extern "C" fn(*mut ::SSL, *mut c_uchar, c_int, *mut c_int) -> *mut SSL_SESSION, >, ); + #[cfg(libressl261)] + pub fn SSL_CTX_set_min_proto_version(ctx: *mut ::SSL_CTX, version: u16) -> c_int; + #[cfg(libressl261)] + pub fn SSL_CTX_set_max_proto_version(ctx: *mut ::SSL_CTX, version: u16) -> c_int; + #[cfg(libressl270)] + pub fn SSL_CTX_get_min_proto_version(ctx: *mut ::SSL_CTX) -> c_int; + #[cfg(libressl270)] + pub fn SSL_CTX_get_max_proto_version(ctx: *mut ::SSL_CTX) -> c_int; + pub fn X509_get_subject_name(x: *mut ::X509) -> *mut ::X509_NAME; pub fn X509_get_issuer_name(x: *mut ::X509) -> *mut ::X509_NAME; pub fn X509_set_notAfter(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; diff --git a/openssl-sys/src/libressl/v25x.rs b/openssl-sys/src/libressl/v251.rs similarity index 94% rename from openssl-sys/src/libressl/v25x.rs rename to openssl-sys/src/libressl/v251.rs index 7e7023ec..541b61db 100644 --- a/openssl-sys/src/libressl/v25x.rs +++ b/openssl-sys/src/libressl/v251.rs @@ -1,4 +1,4 @@ -use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong, time_t}; +use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void, size_t, time_t}; use super::*; @@ -84,6 +84,6 @@ pub struct X509_VERIFY_PARAM { pub purpose: c_int, pub trust: c_int, pub depth: c_int, - policies: *mut stack_st_ASN1_OBJECT, + pub policies: *mut stack_st_ASN1_OBJECT, id: *mut c_void, } diff --git a/openssl/build.rs b/openssl/build.rs index 612322fe..271fb662 100644 --- a/openssl/build.rs +++ b/openssl/build.rs @@ -41,4 +41,16 @@ fn main() { println!("cargo:rustc-cfg=ossl110g"); } } + + if let Ok(version) = env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER") { + let version = u64::from_str_radix(&version, 16).unwrap(); + + if version >= 0x2_06_01_00_0 { + println!("cargo:rustc-cfg=libressl261"); + } + + if version >= 0x2_07_00_00_0 { + println!("cargo:rustc-cfg=libressl270"); + } + } } diff --git a/openssl/src/ec.rs b/openssl/src/ec.rs index c4800c73..573d0c00 100644 --- a/openssl/src/ec.rs +++ b/openssl/src/ec.rs @@ -33,14 +33,14 @@ //! ``` use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; -use std::ptr; use libc::c_int; +use std::ptr; -use {cvt, cvt_n, cvt_p, init}; use bn::{BigNumContextRef, BigNumRef}; use error::ErrorStack; use nid::Nid; use pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public}; +use {cvt, cvt_n, cvt_p, init}; /// Compressed or Uncompressed conversion /// @@ -803,10 +803,10 @@ impl Clone for EcKey { #[cfg(test)] mod test { - use bn::{BigNum, BigNumContext}; - use nid::Nid; - use data_encoding::BASE64URL_NOPAD; use super::*; + use bn::{BigNum, BigNumContext}; + use data_encoding::BASE64URL_NOPAD; + use nid::Nid; #[test] fn key_new_by_curve_name() { @@ -823,7 +823,7 @@ mod test { fn dup() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); - key.clone(); + drop(key.clone()); } #[test] @@ -862,7 +862,8 @@ mod test { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); let mut ctx = BigNumContext::new().unwrap(); - let bytes = key.public_key() + let bytes = key + .public_key() .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx) .unwrap(); @@ -877,7 +878,8 @@ mod test { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); - let dup_key = EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap(); + let dup_key = + EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap(); let res = dup_key.check_key().unwrap(); assert!(res == ()); diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index 0ad55b96..718ae59d 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -751,7 +751,8 @@ mod test { #[test] fn test_to_password() { let key = Rsa::generate(2048).unwrap(); - let pem = key.private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar") + let pem = key + .private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar") .unwrap(); Rsa::private_key_from_pem_passphrase(&pem, b"foobar").unwrap(); assert!(Rsa::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err()); @@ -791,7 +792,8 @@ mod test { k0.private_encrypt(&msg, &mut emesg, Padding::PKCS1) .unwrap(); let mut dmesg = vec![0; k1.size() as usize]; - let len = k1.public_decrypt(&emesg, &mut dmesg, Padding::PKCS1) + let len = k1 + .public_decrypt(&emesg, &mut dmesg, Padding::PKCS1) .unwrap(); assert_eq!(msg, &dmesg[..len]); } @@ -807,7 +809,8 @@ mod test { let mut emesg = vec![0; k0.size() as usize]; k0.public_encrypt(&msg, &mut emesg, Padding::PKCS1).unwrap(); let mut dmesg = vec![0; k1.size() as usize]; - let len = k1.private_decrypt(&emesg, &mut dmesg, Padding::PKCS1) + let len = k1 + .private_decrypt(&emesg, &mut dmesg, Padding::PKCS1) .unwrap(); assert_eq!(msg, &dmesg[..len]); } @@ -883,6 +886,6 @@ mod test { #[test] fn clone() { let key = Rsa::generate(2048).unwrap(); - key.clone(); + drop(key.clone()); } } diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 8dc605ed..adec060c 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1023,15 +1023,15 @@ impl SslContextBuilder { /// /// This corresponds to [`SSL_CTX_set_min_proto_version`]. /// - /// Requires OpenSSL 1.1.0 or newer. + /// Requires OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer. /// /// [`SSL_CTX_set_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html - #[cfg(any(ossl110))] + #[cfg(any(ossl110, libressl261))] pub fn set_min_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_min_proto_version( self.as_ptr(), - version.map_or(0, |v| v.0), + version.map_or(0, |v| v.0 as _), )).map(|_| ()) } } @@ -1043,15 +1043,15 @@ impl SslContextBuilder { /// /// This corresponds to [`SSL_CTX_set_max_proto_version`]. /// - /// Requires OpenSSL 1.1.0 or newer. + /// Requires OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer. /// /// [`SSL_CTX_set_max_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html - #[cfg(any(ossl110))] + #[cfg(any(ossl110, libressl261))] pub fn set_max_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_max_proto_version( self.as_ptr(), - version.map_or(0, |v| v.0), + version.map_or(0, |v| v.0 as _), )).map(|_| ()) } } @@ -1063,10 +1063,10 @@ impl SslContextBuilder { /// /// This corresponds to [`SSL_CTX_get_min_proto_version`]. /// - /// Requires OpenSSL 1.1.0g or newer. + /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. /// /// [`SSL_CTX_get_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html - #[cfg(any(ossl110g))] + #[cfg(any(ossl110g, libressl270))] pub fn min_proto_version(&mut self) -> Option { unsafe { let r = ffi::SSL_CTX_get_min_proto_version(self.as_ptr()); @@ -1085,10 +1085,10 @@ impl SslContextBuilder { /// /// This corresponds to [`SSL_CTX_get_max_proto_version`]. /// - /// Requires OpenSSL 1.1.0g or newer. + /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. /// /// [`SSL_CTX_get_max_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html - #[cfg(any(ossl110g))] + #[cfg(any(ossl110g, libressl270))] pub fn max_proto_version(&mut self) -> Option { unsafe { let r = ffi::SSL_CTX_get_max_proto_version(self.as_ptr()); @@ -2837,7 +2837,8 @@ impl Read for SslStream { } Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {} Err(e) => { - return Err(e.into_io_error() + return Err(e + .into_io_error() .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e))) } } @@ -2852,7 +2853,8 @@ impl Write for SslStream { Ok(n) => return Ok(n), Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {} Err(e) => { - return Err(e.into_io_error() + return Err(e + .into_io_error() .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e))) } } diff --git a/openssl/src/ssl/test.rs b/openssl/src/ssl/test.rs index 2e906728..b90199f0 100644 --- a/openssl/src/ssl/test.rs +++ b/openssl/src/ssl/test.rs @@ -19,7 +19,7 @@ use hash::MessageDigest; use ocsp::{OcspResponse, OcspResponseStatus}; use pkey::PKey; use ssl; -#[cfg(any(ossl110, ossl111))] +#[cfg(any(ossl110, ossl111, libressl261))] use ssl::SslVersion; use ssl::{ Error, HandshakeError, MidHandshakeSslStream, ShutdownResult, Ssl, SslAcceptor, SslConnector, @@ -1315,7 +1315,7 @@ fn keying_export() { } #[test] -#[cfg(any(ossl110))] +#[cfg(any(ossl110, libressl261))] fn no_version_overlap() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = listener.local_addr().unwrap(); @@ -1330,7 +1330,7 @@ fn no_version_overlap() { ctx.set_max_proto_version(Some(SslVersion::TLS1_1)).unwrap(); #[cfg(ossl110g)] assert_eq!(ctx.min_proto_version(), None); - #[cfg(ossl110g)] + #[cfg(any(ossl110g, libressl270))] assert_eq!(ctx.max_proto_version(), Some(SslVersion::TLS1_1)); let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.accept(stream).unwrap_err(); @@ -1339,7 +1339,7 @@ fn no_version_overlap() { let stream = TcpStream::connect(addr).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_min_proto_version(Some(SslVersion::TLS1_2)).unwrap(); - #[cfg(ossl110g)] + #[cfg(any(ossl110g, libressl270))] assert_eq!(ctx.min_proto_version(), Some(SslVersion::TLS1_2)); #[cfg(ossl110g)] assert_eq!(ctx.max_proto_version(), None); diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index 7ef4d160..a3c66e0c 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -7,10 +7,12 @@ use nid::Nid; use pkey::{PKey, Private}; use rsa::Rsa; use stack::Stack; -use x509::{X509, X509Name, X509Req, X509StoreContext, X509VerifyResult}; -use x509::extension::{AuthorityKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage, - SubjectAlternativeName, SubjectKeyIdentifier}; +use x509::extension::{ + AuthorityKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage, SubjectAlternativeName, + SubjectKeyIdentifier, +}; use x509::store::X509StoreBuilder; +use x509::{X509, X509Name, X509Req, X509StoreContext, X509VerifyResult}; fn pkey() -> PKey { let rsa = Rsa::generate(2048).unwrap(); @@ -197,7 +199,8 @@ fn x509_builder() { assert!(pkey.public_eq(&x509.public_key().unwrap())); - let cn = x509.subject_name() + let cn = x509 + .subject_name() .entries_by_nid(Nid::COMMONNAME) .next() .unwrap(); @@ -291,7 +294,7 @@ fn signature() { fn clone_x509() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); - cert.clone(); + drop(cert.clone()); } #[test] diff --git a/systest/build.rs b/systest/build.rs index 98e9ffb3..84c0a1ae 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -2,10 +2,12 @@ extern crate ctest; use std::env; +#[path = "../openssl-sys/build/cfgs.rs"] +mod cfgs; + fn main() { let mut cfg = ctest::TestGenerator::new(); let target = env::var("TARGET").unwrap(); - let mut is_libressl = false; if let Ok(out) = env::var("DEP_OPENSSL_INCLUDE") { cfg.include(&out); @@ -26,21 +28,17 @@ fn main() { cfg.define("WIN32_LEAN_AND_MEAN", None); } - if let Ok(_) = env::var("DEP_OPENSSL_LIBRESSL") { - cfg.cfg("libressl", None); - is_libressl = true; - } else if let Ok(version) = env::var("DEP_OPENSSL_VERSION") { - cfg.cfg(&format!("ossl{}", version), None); - if version == "111" { - cfg.cfg("ossl110", None); - } - } - if let (Ok(version), Ok(patch)) = ( - env::var("DEP_OPENSSL_VERSION"), - env::var("DEP_OPENSSL_PATCH"), - ) { - cfg.cfg(&format!("ossl{}{}", version, patch), None); + let openssl_version = env::var("DEP_OPENSSL_VERSION_NUMBER") + .ok() + .map(|v| u64::from_str_radix(&v, 16).unwrap()); + let libressl_version = env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER") + .ok() + .map(|v| u64::from_str_radix(&v, 16).unwrap()); + + for c in cfgs::get(openssl_version, libressl_version) { + cfg.cfg(c, None); } + if let Ok(vars) = env::var("DEP_OPENSSL_CONF") { for var in vars.split(",") { cfg.cfg("osslconf", Some(var)); @@ -65,7 +63,7 @@ fn main() { .header("openssl/ocsp.h") .header("openssl/evp.h"); - if !is_libressl { + if openssl_version.is_some() { cfg.header("openssl/cms.h"); } @@ -79,7 +77,8 @@ fn main() { } else if s == "_STACK" { format!("struct stack_st") // This logic should really be cleaned up - } else if is_struct && s != "point_conversion_form_t" + } else if is_struct + && s != "point_conversion_form_t" && s.chars().next().unwrap().is_lowercase() { format!("struct {}", s) @@ -111,9 +110,13 @@ fn main() { (s == "GENERAL_NAME" && field == "d") // union }); cfg.skip_signededness(|s| { - s.ends_with("_cb") || s.ends_with("_CB") || s.ends_with("_cb_fn") - || s.starts_with("CRYPTO_") || s == "PasswordCallback" - || s.ends_with("_cb_func") || s.ends_with("_cb_ex") + s.ends_with("_cb") + || s.ends_with("_CB") + || s.ends_with("_cb_fn") + || s.starts_with("CRYPTO_") + || s == "PasswordCallback" + || s.ends_with("_cb_func") + || s.ends_with("_cb_ex") }); cfg.field_name(|_s, field| { if field == "type_" { From 862d78416118cf8854feab92cd0ddb826e83199a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 19 May 2018 21:09:04 -0700 Subject: [PATCH 05/33] Clean up openssl-sys cfgs --- openssl-sys/build/cfgs.rs | 26 +++++------ openssl-sys/src/lib.rs | 82 ++++++++++++++++----------------- openssl-sys/src/openssl/mod.rs | 12 ++--- openssl-sys/src/openssl/v10x.rs | 15 +++--- 4 files changed, 65 insertions(+), 70 deletions(-) diff --git a/openssl-sys/build/cfgs.rs b/openssl-sys/build/cfgs.rs index 3e063aa3..4648f6f5 100644 --- a/openssl-sys/build/cfgs.rs +++ b/openssl-sys/build/cfgs.rs @@ -7,37 +7,35 @@ pub fn get(openssl_version: Option, libressl_version: Option) -> Vec<& if libressl_version >= 0x2_05_01_00_0 { cfgs.push("libressl251"); } - if libressl_version >= 0x2_06_01_00_0 { cfgs.push("libressl261"); } - if libressl_version >= 0x2_07_00_00_0 { cfgs.push("libressl270"); } } else { let openssl_version = openssl_version.unwrap(); + if openssl_version >= 0x1_00_01_00_0 { + cfgs.push("ossl101"); + } + if openssl_version >= 0x1_00_02_00_0 { + cfgs.push("ossl102"); + } if openssl_version >= 0x1_00_02_08_0 { cfgs.push("ossl102h"); } - + if openssl_version >= 0x1_01_00_00_0 { + cfgs.push("ossl110"); + } + if openssl_version >= 0x1_01_00_06_0 { + cfgs.push("ossl110f"); + } if openssl_version >= 0x1_01_00_07_0 { cfgs.push("ossl110g"); } - if openssl_version >= 0x1_01_01_00_0 { cfgs.push("ossl111"); - cfgs.push("ossl110"); - } else if openssl_version >= 0x1_01_00_06_0 { - cfgs.push("ossl110"); - cfgs.push("ossl110f"); - } else if openssl_version >= 0x1_01_00_00_0 { - cfgs.push("ossl110"); - } else if openssl_version >= 0x1_00_02_00_0 { - cfgs.push("ossl102"); - } else if openssl_version >= 0x1_00_01_00_0 { - cfgs.push("ossl101"); } } diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index e78c24f4..dca9d31f 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1261,7 +1261,7 @@ pub const SSL_VERIFY_NONE: c_int = 0; pub const SSL_VERIFY_PEER: c_int = 1; pub const SSL_VERIFY_FAIL_IF_NO_PEER_CERT: c_int = 2; -#[cfg(not(any(libressl261, ossl101)))] +#[cfg(any(ossl102, all(libressl, not(libressl261))))] pub const SSL_OP_TLSEXT_PADDING: c_ulong = 0x00000010; #[cfg(libressl261)] pub const SSL_OP_TLSEXT_PADDING: c_ulong = 0x0; @@ -1271,9 +1271,9 @@ pub const SSL_OP_CRYPTOPRO_TLSEXT_BUG: c_ulong = 0x80000000; #[cfg(libressl261)] pub const SSL_OP_CRYPTOPRO_TLSEXT_BUG: c_ulong = 0x0; pub const SSL_OP_LEGACY_SERVER_CONNECT: c_ulong = 0x00000004; -#[cfg(not(any(libressl, ossl110f, ossl111)))] +#[cfg(not(any(libressl, ossl110f)))] pub const SSL_OP_ALL: c_ulong = 0x80000BFF; -#[cfg(any(ossl110f, ossl111))] +#[cfg(ossl110f)] pub const SSL_OP_ALL: c_ulong = SSL_OP_CRYPTOPRO_TLSEXT_BUG | SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS | SSL_OP_LEGACY_SERVER_CONNECT @@ -1289,7 +1289,7 @@ pub const SSL_OP_NO_TLSv1: c_ulong = 0x04000000; pub const SSL_OP_NO_TLSv1_1: c_ulong = 0x10000000; pub const SSL_OP_NO_TLSv1_2: c_ulong = 0x08000000; -#[cfg(not(any(ossl101, libressl, ossl111)))] +#[cfg(all(ossl102, not(ossl111)))] pub const SSL_OP_NO_SSL_MASK: c_ulong = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2; #[cfg(ossl111)] @@ -1393,35 +1393,35 @@ pub const X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: c_int = 52; pub const X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53; pub const X509_V_ERR_CRL_PATH_VALIDATION_ERROR: c_int = 54; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_SUITE_B_INVALID_VERSION: c_int = 56; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_SUITE_B_INVALID_ALGORITHM: c_int = 57; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_SUITE_B_INVALID_CURVE: c_int = 58; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM: c_int = 59; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED: c_int = 60; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256: c_int = 61; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_HOSTNAME_MISMATCH: c_int = 62; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_EMAIL_MISMATCH: c_int = 63; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_IP_ADDRESS_MISMATCH: c_int = 64; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT: c_uint = 0x1; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_CHECK_FLAG_NO_WILDCARDS: c_uint = 0x2; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS: c_uint = 0x4; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS: c_uint = 0x8; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS: c_uint = 0x10; pub const GEN_OTHERNAME: c_int = 0; @@ -1526,7 +1526,7 @@ pub unsafe fn SSL_CTX_add_extra_chain_cert(ctx: *mut SSL_CTX, x509: *mut X509) - SSL_CTX_ctrl(ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0, x509 as *mut c_void) } -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub unsafe fn SSL_CTX_set0_verify_cert_store(ctx: *mut SSL_CTX, st: *mut X509_STORE) -> c_long { SSL_CTX_ctrl(ctx, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, st as *mut c_void) } @@ -1641,9 +1641,9 @@ extern "C" { pub fn BIO_new_socket(sock: c_int, close_flag: c_int) -> *mut BIO; pub fn BIO_read(b: *mut BIO, buf: *mut c_void, len: c_int) -> c_int; pub fn BIO_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int; - #[cfg(any(ossl101, libressl))] + #[cfg(not(ossl102))] pub fn BIO_new_mem_buf(buf: *mut c_void, len: c_int) -> *mut BIO; - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn BIO_new_mem_buf(buf: *const c_void, len: c_int) -> *mut BIO; pub fn BIO_set_flags(b: *mut BIO, flags: c_int); pub fn BIO_clear_flags(b: *mut BIO, flags: c_int); @@ -1774,11 +1774,11 @@ extern "C" { pub fn DH_new() -> *mut DH; pub fn DH_free(dh: *mut DH); - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn DH_get_1024_160() -> *mut DH; - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn DH_get_2048_224() -> *mut DH; - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn DH_get_2048_256() -> *mut DH; pub fn EC_KEY_new() -> *mut EC_KEY; @@ -2036,13 +2036,13 @@ extern "C" { e: *mut ENGINE, pkey: *mut EVP_PKEY, ) -> c_int; - #[cfg(any(ossl101, libressl))] + #[cfg(not(ossl102))] pub fn EVP_DigestVerifyFinal( ctx: *mut EVP_MD_CTX, sigret: *mut c_uchar, siglen: size_t, ) -> c_int; - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn EVP_DigestVerifyFinal( ctx: *mut EVP_MD_CTX, sigret: *const c_uchar, @@ -2446,14 +2446,14 @@ extern "C" { pub fn SSL_get_ex_data(ssl: *const SSL, idx: c_int) -> *mut c_void; pub fn SSL_get_servername(ssl: *const SSL, name_type: c_int) -> *const c_char; pub fn SSL_get_current_cipher(ssl: *const SSL) -> *const SSL_CIPHER; - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn SSL_get0_param(ssl: *mut SSL) -> *mut X509_VERIFY_PARAM; pub fn SSL_get_verify_result(ssl: *const SSL) -> c_long; pub fn SSL_shutdown(ssl: *mut SSL) -> c_int; pub fn SSL_get_certificate(ssl: *const SSL) -> *mut X509; - #[cfg(any(ossl101, libressl))] + #[cfg(not(ossl102))] pub fn SSL_get_privatekey(ssl: *mut SSL) -> *mut EVP_PKEY; - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn SSL_get_privatekey(ssl: *const SSL) -> *mut EVP_PKEY; pub fn SSL_load_client_CA_file(file: *const c_char) -> *mut stack_st_X509_NAME; pub fn SSL_set_tmp_dh_callback( @@ -2546,9 +2546,9 @@ extern "C" { remove_session_cb: Option, ); - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn SSL_CTX_get0_certificate(ctx: *const SSL_CTX) -> *mut X509; - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn SSL_CTX_get0_privatekey(ctx: *const SSL_CTX) -> *mut EVP_PKEY; pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int; @@ -2599,9 +2599,9 @@ extern "C" { ); pub fn SSL_get_session(s: *const SSL) -> *mut SSL_SESSION; pub fn SSL_set_session(ssl: *mut SSL, session: *mut SSL_SESSION) -> c_int; - #[cfg(not(any(ossl101, libressl, ossl110f, ossl111)))] + #[cfg(all(ossl102, not(ossl110f)))] pub fn SSL_is_server(s: *mut SSL) -> c_int; - #[cfg(any(ossl110f, ossl111))] + #[cfg(ossl110f)] pub fn SSL_is_server(s: *const SSL) -> c_int; pub fn SSL_SESSION_free(s: *mut SSL_SESSION); @@ -2614,14 +2614,14 @@ extern "C" { ) -> *mut SSL_SESSION; pub fn i2d_SSL_SESSION(s: *mut SSL_SESSION, pp: *mut *mut c_uchar) -> c_int; - #[cfg(not(ossl101))] + #[cfg(ossl102)] pub fn SSL_CTX_set_alpn_protos(s: *mut SSL_CTX, data: *const c_uchar, len: c_uint) -> c_int; - #[cfg(not(ossl101))] + #[cfg(ossl102)] pub fn SSL_set_alpn_protos(s: *mut SSL, data: *const c_uchar, len: c_uint) -> c_int; // FIXME should take an Option - #[cfg(not(ossl101))] + #[cfg(ossl102)] pub fn SSL_CTX_set_alpn_select_cb( ssl: *mut SSL_CTX, cb: extern "C" fn( @@ -2634,7 +2634,7 @@ extern "C" { ) -> c_int, arg: *mut c_void, ); - #[cfg(not(ossl101))] + #[cfg(ossl102)] pub fn SSL_get0_alpn_selected(s: *const SSL, data: *mut *const c_uchar, len: *mut c_uint); pub fn X509_add_ext(x: *mut X509, ext: *mut X509_EXTENSION, loc: c_int) -> c_int; @@ -2726,17 +2726,17 @@ extern "C" { pub fn X509_REQ_get_extensions(req: *mut X509_REQ) -> *mut stack_st_X509_EXTENSION; pub fn X509_REQ_sign(x: *mut X509_REQ, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; - #[cfg(not(ossl101))] + #[cfg(ossl102)] pub fn X509_VERIFY_PARAM_free(param: *mut X509_VERIFY_PARAM); - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn X509_VERIFY_PARAM_set_hostflags(param: *mut X509_VERIFY_PARAM, flags: c_uint); - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn X509_VERIFY_PARAM_set1_host( param: *mut X509_VERIFY_PARAM, name: *const c_char, namelen: size_t, ) -> c_int; - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn X509_VERIFY_PARAM_set1_ip( param: *mut X509_VERIFY_PARAM, ip: *const c_uchar, diff --git a/openssl-sys/src/openssl/mod.rs b/openssl-sys/src/openssl/mod.rs index a1e4a345..b65b6129 100644 --- a/openssl-sys/src/openssl/mod.rs +++ b/openssl-sys/src/openssl/mod.rs @@ -1,8 +1,8 @@ use libc::{c_int, c_long, c_uchar, c_uint, c_ulong}; -#[cfg(any(ossl101, ossl102))] +#[cfg(not(ossl110))] mod v10x; -#[cfg(any(ossl101, ossl102))] +#[cfg(not(ossl110))] pub use openssl::v10x::*; #[cfg(ossl110)] @@ -15,7 +15,7 @@ mod v111; #[cfg(ossl111)] pub use openssl::v111::*; -#[cfg(not(ossl101))] +#[cfg(ossl102)] pub const SSL_CTRL_SET_VERIFY_CERT_STORE: c_int = 106; pub const SSL_MODE_SEND_CLIENTHELLO_TIME: c_long = 0x20; @@ -28,9 +28,9 @@ pub const SSL_OP_CISCO_ANYCONNECT: c_ulong = 0x00008000; pub const SSL_OP_NO_COMPRESSION: c_ulong = 0x00020000; pub const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: c_ulong = 0x00040000; pub const SSL_OP_NO_SSLv3: c_ulong = 0x02000000; -#[cfg(not(ossl101))] +#[cfg(ossl102)] pub const SSL_OP_NO_DTLSv1: c_ulong = 0x04000000; -#[cfg(not(ossl101))] +#[cfg(ossl102)] pub const SSL_OP_NO_DTLSv1_2: c_ulong = 0x08000000; pub const X509_V_ERR_UNSPECIFIED: c_int = 1; @@ -55,7 +55,7 @@ pub const CMS_PARTIAL: c_uint = 0x4000; pub const CMS_REUSE_DIGEST: c_uint = 0x8000; pub const CMS_USE_KEYID: c_uint = 0x10000; pub const CMS_DEBUG_DECRYPT: c_uint = 0x20000; -#[cfg(not(ossl101))] +#[cfg(ossl102)] pub const CMS_KEY_PARAM: c_uint = 0x40000; extern "C" { diff --git a/openssl-sys/src/openssl/v10x.rs b/openssl-sys/src/openssl/v10x.rs index 6a4d4346..8ee9c58f 100644 --- a/openssl-sys/src/openssl/v10x.rs +++ b/openssl-sys/src/openssl/v10x.rs @@ -5,7 +5,7 @@ use std::ptr; use std::sync::{Mutex, MutexGuard}; use std::sync::{Once, ONCE_INIT}; -#[cfg(not(ossl101))] +#[cfg(ossl102)] use libc::time_t; use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void, size_t}; @@ -573,9 +573,6 @@ pub struct SSL_CTX { #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl101))] srtp_profiles: *mut c_void, - - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] - srtp_profiles: *mut c_void, #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] alpn_select_cb: *mut c_void, #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] @@ -669,7 +666,7 @@ pub struct SRP_CTX { } #[repr(C)] -#[cfg(not(ossl101))] +#[cfg(ossl102)] pub struct X509_VERIFY_PARAM { pub name: *mut c_char, pub check_time: time_t, @@ -682,7 +679,7 @@ pub struct X509_VERIFY_PARAM { pub id: *mut X509_VERIFY_PARAM_ID, } -#[cfg(not(ossl101))] +#[cfg(ossl102)] pub enum X509_VERIFY_PARAM_ID {} pub enum PKCS12 {} @@ -925,15 +922,15 @@ extern "C" { loc: c_int, set: c_int, ) -> c_int; - #[cfg(not(ossl101))] + #[cfg(ossl102)] pub fn X509_get0_signature( psig: *mut *mut ::ASN1_BIT_STRING, palg: *mut *mut ::X509_ALGOR, x: *const ::X509, ); - #[cfg(not(ossl101))] + #[cfg(ossl102)] pub fn X509_get_signature_nid(x: *const X509) -> c_int; - #[cfg(not(ossl101))] + #[cfg(ossl102)] pub fn X509_ALGOR_get0( paobj: *mut *mut ::ASN1_OBJECT, pptype: *mut c_int, From 9df403043b75e407305f7003636dbe1c55f7d245 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 May 2018 09:23:21 -0700 Subject: [PATCH 06/33] Expose X509_VERIFY_PARAM on libressl --- openssl-sys/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index dca9d31f..8d0790ea 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -2446,7 +2446,7 @@ extern "C" { pub fn SSL_get_ex_data(ssl: *const SSL, idx: c_int) -> *mut c_void; pub fn SSL_get_servername(ssl: *const SSL, name_type: c_int) -> *const c_char; pub fn SSL_get_current_cipher(ssl: *const SSL) -> *const SSL_CIPHER; - #[cfg(ossl102)] + #[cfg(any(ossl102, libressl261))] pub fn SSL_get0_param(ssl: *mut SSL) -> *mut X509_VERIFY_PARAM; pub fn SSL_get_verify_result(ssl: *const SSL) -> c_long; pub fn SSL_shutdown(ssl: *mut SSL) -> c_int; @@ -2726,17 +2726,17 @@ extern "C" { pub fn X509_REQ_get_extensions(req: *mut X509_REQ) -> *mut stack_st_X509_EXTENSION; pub fn X509_REQ_sign(x: *mut X509_REQ, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; - #[cfg(ossl102)] + #[cfg(any(ossl102, libressl261))] pub fn X509_VERIFY_PARAM_free(param: *mut X509_VERIFY_PARAM); - #[cfg(ossl102)] + #[cfg(any(ossl102, libressl261))] pub fn X509_VERIFY_PARAM_set_hostflags(param: *mut X509_VERIFY_PARAM, flags: c_uint); - #[cfg(ossl102)] + #[cfg(any(ossl102, libressl261))] pub fn X509_VERIFY_PARAM_set1_host( param: *mut X509_VERIFY_PARAM, name: *const c_char, namelen: size_t, ) -> c_int; - #[cfg(ossl102)] + #[cfg(any(ossl102, libressl261))] pub fn X509_VERIFY_PARAM_set1_ip( param: *mut X509_VERIFY_PARAM, ip: *const c_uchar, From a6fcef01c0aa71359f583342c813b8db5835178d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 May 2018 11:27:45 -0700 Subject: [PATCH 07/33] Overhaul openssl cfgs Also expose hostname verification on libressl --- openssl-sys/src/lib.rs | 10 +- openssl-sys/src/libressl/mod.rs | 22 ++ openssl-sys/src/openssl/v10x.rs | 22 ++ openssl/Cargo.toml | 2 + openssl/build.rs | 31 +-- openssl/src/asn1.rs | 24 +- openssl/src/bio.rs | 20 +- openssl/src/bn.rs | 55 ++--- openssl/src/dh.rs | 48 ++-- openssl/src/dsa.rs | 50 ++-- openssl/src/ecdsa.rs | 80 +++---- openssl/src/hash.rs | 35 +-- openssl/src/lib.rs | 4 +- openssl/src/rsa.rs | 219 +++++++++-------- openssl/src/sign.rs | 27 ++- openssl/src/ssl/bio.rs | 218 +++++++++-------- openssl/src/ssl/callbacks.rs | 68 ++++-- openssl/src/ssl/connector.rs | 400 ++++++++++++++++---------------- openssl/src/ssl/mod.rs | 239 ++++++++----------- openssl/src/ssl/test.rs | 4 +- openssl/src/stack.rs | 33 +-- openssl/src/symm.rs | 43 ++-- openssl/src/version.rs | 25 +- openssl/src/x509/mod.rs | 174 +++++++------- openssl/src/x509/verify.rs | 2 +- 25 files changed, 953 insertions(+), 902 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 8d0790ea..0f6a4483 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1413,15 +1413,15 @@ pub const X509_V_ERR_EMAIL_MISMATCH: c_int = 63; #[cfg(ossl102)] pub const X509_V_ERR_IP_ADDRESS_MISMATCH: c_int = 64; -#[cfg(ossl102)] +#[cfg(any(ossl102, libressl261))] pub const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT: c_uint = 0x1; -#[cfg(ossl102)] +#[cfg(any(ossl102, libressl261))] pub const X509_CHECK_FLAG_NO_WILDCARDS: c_uint = 0x2; -#[cfg(ossl102)] +#[cfg(any(ossl102, libressl261))] pub const X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS: c_uint = 0x4; -#[cfg(ossl102)] +#[cfg(any(ossl102, libressl261))] pub const X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS: c_uint = 0x8; -#[cfg(ossl102)] +#[cfg(any(ossl102, libressl261))] pub const X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS: c_uint = 0x10; pub const GEN_OTHERNAME: c_int = 0; diff --git a/openssl-sys/src/libressl/mod.rs b/openssl-sys/src/libressl/mod.rs index 5ae205bc..0080fc7d 100644 --- a/openssl-sys/src/libressl/mod.rs +++ b/openssl-sys/src/libressl/mod.rs @@ -447,6 +447,28 @@ pub unsafe fn SSL_session_reused(ssl: *mut ::SSL) -> c_int { ::SSL_ctrl(ssl, SSL_CTRL_GET_SESSION_REUSED, 0, ptr::null_mut()) as c_int } +pub unsafe fn SSL_CTX_get_options(ctx: *const ::SSL_CTX) -> c_ulong { + ::SSL_CTX_ctrl(ctx as *mut _, ::SSL_CTRL_OPTIONS, 0, ptr::null_mut()) as c_ulong +} + +pub unsafe fn SSL_CTX_set_options(ctx: *const ::SSL_CTX, op: c_ulong) -> c_ulong { + ::SSL_CTX_ctrl( + ctx as *mut _, + ::SSL_CTRL_OPTIONS, + op as c_long, + ptr::null_mut(), + ) as c_ulong +} + +pub unsafe fn SSL_CTX_clear_options(ctx: *const ::SSL_CTX, op: c_ulong) -> c_ulong { + ::SSL_CTX_ctrl( + ctx as *mut _, + ::SSL_CTRL_CLEAR_OPTIONS, + op as c_long, + ptr::null_mut(), + ) as c_ulong +} + extern "C" { pub fn BIO_new(type_: *mut BIO_METHOD) -> *mut BIO; pub fn BIO_s_file() -> *mut BIO_METHOD; diff --git a/openssl-sys/src/openssl/v10x.rs b/openssl-sys/src/openssl/v10x.rs index 8ee9c58f..c22bb7fc 100644 --- a/openssl-sys/src/openssl/v10x.rs +++ b/openssl-sys/src/openssl/v10x.rs @@ -807,6 +807,28 @@ pub unsafe fn SSL_session_reused(ssl: *mut ::SSL) -> c_int { ::SSL_ctrl(ssl, SSL_CTRL_GET_SESSION_REUSED, 0, ptr::null_mut()) as c_int } +pub unsafe fn SSL_CTX_get_options(ctx: *const ::SSL_CTX) -> c_ulong { + ::SSL_CTX_ctrl(ctx as *mut _, ::SSL_CTRL_OPTIONS, 0, ptr::null_mut()) as c_ulong +} + +pub unsafe fn SSL_CTX_set_options(ctx: *const ::SSL_CTX, op: c_ulong) -> c_ulong { + ::SSL_CTX_ctrl( + ctx as *mut _, + ::SSL_CTRL_OPTIONS, + op as c_long, + ptr::null_mut(), + ) as c_ulong +} + +pub unsafe fn SSL_CTX_clear_options(ctx: *const ::SSL_CTX, op: c_ulong) -> c_ulong { + ::SSL_CTX_ctrl( + ctx as *mut _, + ::SSL_CTRL_CLEAR_OPTIONS, + op as c_long, + ptr::null_mut(), + ) as c_ulong +} + extern "C" { pub fn BIO_new(type_: *mut BIO_METHOD) -> *mut BIO; pub fn BIO_s_file() -> *mut BIO_METHOD; diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 25aab11d..8ce43b3d 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -18,9 +18,11 @@ v111 = [] [dependencies] bitflags = "1.0" +cfg-if = "0.1" foreign-types = "0.3.1" lazy_static = "1" libc = "0.2" + openssl-sys = { version = "0.9.30", path = "../openssl-sys" } [dev-dependencies] diff --git a/openssl/build.rs b/openssl/build.rs index 271fb662..5a5b86f2 100644 --- a/openssl/build.rs +++ b/openssl/build.rs @@ -1,25 +1,6 @@ use std::env; fn main() { - match env::var("DEP_OPENSSL_VERSION") { - Ok(ref v) if v == "101" => { - println!("cargo:rustc-cfg=ossl101"); - println!("cargo:rustc-cfg=ossl10x"); - } - Ok(ref v) if v == "102" => { - println!("cargo:rustc-cfg=ossl102"); - println!("cargo:rustc-cfg=ossl10x"); - } - Ok(ref v) if v == "110" => { - println!("cargo:rustc-cfg=ossl110"); - } - Ok(ref v) if v == "111" => { - println!("cargo:rustc-cfg=ossl110"); - println!("cargo:rustc-cfg=ossl111"); - } - _ => panic!("Unable to detect OpenSSL version"), - } - if let Ok(_) = env::var("DEP_OPENSSL_LIBRESSL") { println!("cargo:rustc-cfg=libressl"); } @@ -37,9 +18,21 @@ fn main() { if let Ok(version) = env::var("DEP_OPENSSL_VERSION_NUMBER") { let version = u64::from_str_radix(&version, 16).unwrap(); + if version >= 0x1_00_01_00_0 { + println!("cargo:rustc-cfg=ossl101"); + } + if version >= 0x1_00_02_00_0 { + println!("cargo:rustc-cfg=ossl102"); + } + if version >= 0x1_01_00_00_0 { + println!("cargo:rustc-cfg=ossl110"); + } if version >= 0x1_01_00_07_0 { println!("cargo:rustc-cfg=ossl110g"); } + if version >= 0x1_01_01_00_0 { + println!("cargo:rustc-cfg=ossl111"); + } } if let Ok(version) = env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER") { diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index f6917aae..03546a4d 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -32,12 +32,12 @@ use std::ptr; use std::slice; use std::str; -use {cvt, cvt_p}; use bio::MemBio; use bn::BigNum; use error::ErrorStack; use nid::Nid; use string::OpensslString; +use {cvt, cvt_p}; foreign_type_and_impl_send_sync! { type CType = ffi::ASN1_GENERALIZEDTIME; @@ -162,7 +162,7 @@ impl Asn1StringRef { /// /// [`as_utf8`]: struct.Asn1String.html#method.as_utf8 pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(ASN1_STRING_data(self.as_ptr()), self.len()) } + unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr()), self.len()) } } /// Return the length of the Asn1String (number of bytes) @@ -241,11 +241,11 @@ foreign_type_and_impl_send_sync! { impl Asn1BitStringRef { /// Returns the Asn1BitString as a slice pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(ASN1_STRING_data(self.as_ptr() as *mut _), self.len()) } + unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr() as *mut _), self.len()) } } /// Length of Asn1BitString in number of bytes. pub fn len(&self) -> usize { - unsafe { ffi::ASN1_STRING_length(self.as_ptr() as *mut _) as usize } + unsafe { ffi::ASN1_STRING_length(self.as_ptr() as *const _) as usize } } } @@ -296,11 +296,13 @@ impl fmt::Display for Asn1ObjectRef { } } -#[cfg(any(ossl101, ossl102))] -use ffi::ASN1_STRING_data; - -#[cfg(ossl110)] -#[allow(bad_style)] -unsafe fn ASN1_STRING_data(s: *mut ffi::ASN1_STRING) -> *mut ::libc::c_uchar { - ffi::ASN1_STRING_get0_data(s) as *mut _ +cfg_if! { + if #[cfg(ossl110)] { + use ffi::ASN1_STRING_get0_data; + } else { + #[allow(bad_style)] + unsafe fn ASN1_STRING_get0_data(s: *mut ffi::ASN1_STRING) -> *const ::libc::c_uchar { + ffi::ASN1_STRING_data(s) + } + } } diff --git a/openssl/src/bio.rs b/openssl/src/bio.rs index 56ba1f3d..51724e3f 100644 --- a/openssl/src/bio.rs +++ b/openssl/src/bio.rs @@ -1,8 +1,8 @@ +use ffi; +use libc::c_int; use std::marker::PhantomData; use std::ptr; use std::slice; -use libc::c_int; -use ffi; use cvt_p; use error::ErrorStack; @@ -68,11 +68,13 @@ impl MemBio { } } -#[cfg(not(ossl101))] -use ffi::BIO_new_mem_buf; - -#[cfg(ossl101)] -#[allow(bad_style)] -unsafe fn BIO_new_mem_buf(buf: *const ::libc::c_void, len: ::libc::c_int) -> *mut ffi::BIO { - ffi::BIO_new_mem_buf(buf as *mut _, len) +cfg_if! { + if #[cfg(ossl102)] { + use ffi::BIO_new_mem_buf; + } else { + #[allow(bad_style)] + unsafe fn BIO_new_mem_buf(buf: *const ::libc::c_void, len: ::libc::c_int) -> *mut ffi::BIO { + ffi::BIO_new_mem_buf(buf as *mut _, len) + } + } } diff --git a/openssl/src/bn.rs b/openssl/src/bn.rs index fe662e85..15dd7368 100644 --- a/openssl/src/bn.rs +++ b/openssl/src/bn.rs @@ -30,28 +30,39 @@ use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::cmp::Ordering; use std::ffi::CString; -use std::{fmt, ptr}; use std::ops::{Add, Deref, Div, Mul, Neg, Rem, Shl, Shr, Sub}; +use std::{fmt, ptr}; -use {cvt, cvt_n, cvt_p}; use asn1::Asn1Integer; use error::ErrorStack; use string::OpensslString; +use {cvt, cvt_n, cvt_p}; -#[cfg(ossl10x)] -use ffi::{get_rfc2409_prime_1024 as BN_get_rfc2409_prime_1024, - get_rfc2409_prime_768 as BN_get_rfc2409_prime_768, - get_rfc3526_prime_1536 as BN_get_rfc3526_prime_1536, - get_rfc3526_prime_2048 as BN_get_rfc3526_prime_2048, - get_rfc3526_prime_3072 as BN_get_rfc3526_prime_3072, - get_rfc3526_prime_4096 as BN_get_rfc3526_prime_4096, - get_rfc3526_prime_6144 as BN_get_rfc3526_prime_6144, - get_rfc3526_prime_8192 as BN_get_rfc3526_prime_8192}; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ + BN_get_rfc2409_prime_1024, BN_get_rfc2409_prime_768, BN_get_rfc3526_prime_1536, + BN_get_rfc3526_prime_2048, BN_get_rfc3526_prime_3072, BN_get_rfc3526_prime_4096, + BN_get_rfc3526_prime_6144, BN_get_rfc3526_prime_8192, BN_is_negative, + }; + } else { + use ffi::{ + get_rfc2409_prime_1024 as BN_get_rfc2409_prime_1024, + get_rfc2409_prime_768 as BN_get_rfc2409_prime_768, + get_rfc3526_prime_1536 as BN_get_rfc3526_prime_1536, + get_rfc3526_prime_2048 as BN_get_rfc3526_prime_2048, + get_rfc3526_prime_3072 as BN_get_rfc3526_prime_3072, + get_rfc3526_prime_4096 as BN_get_rfc3526_prime_4096, + get_rfc3526_prime_6144 as BN_get_rfc3526_prime_6144, + get_rfc3526_prime_8192 as BN_get_rfc3526_prime_8192, + }; -#[cfg(ossl110)] -use ffi::{BN_get_rfc2409_prime_1024, BN_get_rfc2409_prime_768, BN_get_rfc3526_prime_1536, - BN_get_rfc3526_prime_2048, BN_get_rfc3526_prime_3072, BN_get_rfc3526_prime_4096, - BN_get_rfc3526_prime_6144, BN_get_rfc3526_prime_8192}; + #[allow(bad_style)] + unsafe fn BN_is_negative(bn: *const ffi::BIGNUM) -> c_int { + (*bn).neg + } + } +} /// Options for the most significant bits of a randomly generated `BigNum`. pub struct MsbOption(c_int); @@ -361,17 +372,7 @@ impl BigNumRef { /// Returns `true` if `self` is negative. pub fn is_negative(&self) -> bool { - self._is_negative() - } - - #[cfg(ossl10x)] - fn _is_negative(&self) -> bool { - unsafe { (*self.as_ptr()).neg == 1 } - } - - #[cfg(ossl110)] - fn _is_negative(&self) -> bool { - unsafe { ffi::BN_is_negative(self.as_ptr()) == 1 } + unsafe { BN_is_negative(self.as_ptr()) == 1 } } /// Returns the number of significant bits in `self`. @@ -1218,7 +1219,7 @@ macro_rules! delegate { $t::$m(self.deref(), oth.deref()) } } - } + }; } impl<'a, 'b> Add<&'b BigNumRef> for &'a BigNumRef { diff --git a/openssl/src/dh.rs b/openssl/src/dh.rs index a90b10b8..730a5180 100644 --- a/openssl/src/dh.rs +++ b/openssl/src/dh.rs @@ -4,9 +4,9 @@ use foreign_types::{ForeignType, ForeignTypeRef}; use std::mem; use std::ptr; -use {cvt, cvt_p}; use bn::BigNum; use pkey::{HasParams, Params}; +use {cvt, cvt_p}; generic_foreign_type_and_impl_send_sync! { type CType = ffi::DH; @@ -48,12 +48,7 @@ impl Dh { pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result, ErrorStack> { unsafe { let dh = Dh::from_ptr(cvt_p(ffi::DH_new())?); - cvt(compat::DH_set0_pqg( - dh.0, - p.as_ptr(), - q.as_ptr(), - g.as_ptr(), - ))?; + cvt(DH_set0_pqg(dh.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; mem::forget((p, g, q)); Ok(dh) } @@ -111,34 +106,29 @@ impl Dh { } } -#[cfg(ossl110)] -mod compat { - pub use ffi::DH_set0_pqg; -} - -#[cfg(ossl10x)] -#[allow(bad_style)] -mod compat { - use ffi; - use libc::c_int; - - pub unsafe fn DH_set0_pqg( - dh: *mut ffi::DH, - p: *mut ffi::BIGNUM, - q: *mut ffi::BIGNUM, - g: *mut ffi::BIGNUM, - ) -> c_int { - (*dh).p = p; - (*dh).q = q; - (*dh).g = g; - 1 +cfg_if! { + if #[cfg(ossl110)] { + use ffi::DH_set0_pqg; + } else { + #[allow(bad_style)] + unsafe fn DH_set0_pqg( + dh: *mut ffi::DH, + p: *mut ffi::BIGNUM, + q: *mut ffi::BIGNUM, + g: *mut ffi::BIGNUM, + ) -> ::libc::c_int { + (*dh).p = p; + (*dh).q = q; + (*dh).g = g; + 1 + } } } #[cfg(test)] mod tests { - use dh::Dh; use bn::BigNum; + use dh::Dh; use ssl::{SslContext, SslMethod}; #[test] diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index 0a14ccc3..abc2e297 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -11,10 +11,10 @@ use libc::c_int; use std::fmt; use std::ptr; -use {cvt, cvt_p}; use bn::BigNumRef; use error::ErrorStack; use pkey::{HasParams, HasPublic, Private, Public}; +use {cvt, cvt_p}; generic_foreign_type_and_impl_send_sync! { type CType = ffi::DSA; @@ -101,7 +101,8 @@ where /// Returns the DSA prime parameter of `self`. pub fn p(&self) -> &BigNumRef { unsafe { - let p = compat::pqg(self.as_ptr())[0]; + let mut p = ptr::null(); + DSA_get0_pqg(self.as_ptr(), &mut p, ptr::null_mut(), ptr::null_mut()); BigNumRef::from_ptr(p as *mut _) } } @@ -109,7 +110,8 @@ where /// Returns the DSA sub-prime parameter of `self`. pub fn q(&self) -> &BigNumRef { unsafe { - let q = compat::pqg(self.as_ptr())[1]; + let mut q = ptr::null(); + DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), &mut q, ptr::null_mut()); BigNumRef::from_ptr(q as *mut _) } } @@ -117,7 +119,8 @@ where /// Returns the DSA base parameter of `self`. pub fn g(&self) -> &BigNumRef { unsafe { - let g = compat::pqg(self.as_ptr())[2]; + let mut g = ptr::null(); + DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut g); BigNumRef::from_ptr(g as *mut _) } } @@ -184,24 +187,27 @@ impl fmt::Debug for Dsa { } } -#[cfg(ossl110)] -mod compat { - use std::ptr; - use ffi::{self, BIGNUM, DSA}; - - pub unsafe fn pqg(d: *const DSA) -> [*const BIGNUM; 3] { - let (mut p, mut q, mut g) = (ptr::null(), ptr::null(), ptr::null()); - ffi::DSA_get0_pqg(d, &mut p, &mut q, &mut g); - [p, q, g] - } -} - -#[cfg(ossl10x)] -mod compat { - use ffi::{BIGNUM, DSA}; - - pub unsafe fn pqg(d: *const DSA) -> [*const BIGNUM; 3] { - [(*d).p, (*d).q, (*d).g] +cfg_if! { + if #[cfg(ossl110)] { + use ffi::DSA_get0_pqg; + } else { + #[allow(bad_style)] + unsafe fn DSA_get0_pqg( + d: *mut ffi::DSA, + p: *mut *const ffi::BIGNUM, + q: *mut *const ffi::BIGNUM, + g: *mut *const ffi::BIGNUM) + { + if !p.is_null() { + *p = (*d).p; + } + if !q.is_null() { + *q = (*d).q; + } + if !g.is_null() { + *g = (*d).g; + } + } } } diff --git a/openssl/src/ecdsa.rs b/openssl/src/ecdsa.rs index 120f6531..d07dfda4 100644 --- a/openssl/src/ecdsa.rs +++ b/openssl/src/ecdsa.rs @@ -3,12 +3,13 @@ use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::mem; +use std::ptr; use bn::{BigNum, BigNumRef}; -use {cvt, cvt_n, cvt_p}; use ec::EcKeyRef; use error::ErrorStack; use pkey::{Private, Public}; +use {cvt_n, cvt_p}; foreign_type_and_impl_send_sync! { type CType = ffi::ECDSA_SIG; @@ -53,7 +54,7 @@ impl EcdsaSig { pub fn from_private_components(r: BigNum, s: BigNum) -> Result { unsafe { let sig = cvt_p(ffi::ECDSA_SIG_new())?; - cvt(compat::set_numbers(sig, r.as_ptr(), s.as_ptr()))?; + ECDSA_SIG_set0(sig, r.as_ptr(), s.as_ptr()); mem::forget((r, s)); Ok(EcdsaSig::from_ptr(sig as *mut _)) } @@ -83,8 +84,9 @@ impl EcdsaSig { /// [`ECDSA_SIG_get0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_get0.html pub fn r(&self) -> &BigNumRef { unsafe { - let xs = compat::get_numbers(self.as_ptr()); - BigNumRef::from_ptr(xs[0] as *mut _) + let mut r = ptr::null(); + ECDSA_SIG_get0(self.as_ptr(), &mut r, ptr::null_mut()); + BigNumRef::from_ptr(r as *mut _) } } @@ -95,53 +97,50 @@ impl EcdsaSig { /// [`ECDSA_SIG_get0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_get0.html pub fn s(&self) -> &BigNumRef { unsafe { - let xs = compat::get_numbers(self.as_ptr()); - BigNumRef::from_ptr(xs[1] as *mut _) + let mut s = ptr::null(); + ECDSA_SIG_get0(self.as_ptr(), ptr::null_mut(), &mut s); + BigNumRef::from_ptr(s as *mut _) } } } -#[cfg(ossl110)] -mod compat { - use std::ptr; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ECDSA_SIG_set0, ECDSA_SIG_get0}; + } else { + #[allow(bad_style)] + unsafe fn ECDSA_SIG_set0( + sig: *mut ffi::ECDSA_SIG, + r: *mut ffi::BIGNUM, + s: *mut ffi::BIGNUM, + ) -> c_int { + (*sig).r = r; + (*sig).s = s; + 1 + } - use libc::c_int; - use ffi::{self, BIGNUM, ECDSA_SIG}; - - pub unsafe fn set_numbers(sig: *mut ECDSA_SIG, r: *mut BIGNUM, s: *mut BIGNUM) -> c_int { - ffi::ECDSA_SIG_set0(sig, r, s) + #[allow(bad_style)] + unsafe fn ECDSA_SIG_get0( + sig: *const ffi::ECDSA_SIG, + pr: *mut *const ffi::BIGNUM, + ps: *mut *const ffi::BIGNUM) + { + if !pr.is_null() { + (*pr) = (*sig).r; + } + if !ps.is_null() { + (*ps) = (*sig).s; + } + } } - - pub unsafe fn get_numbers(sig: *mut ECDSA_SIG) -> [*const BIGNUM; 2] { - let (mut r, mut s) = (ptr::null(), ptr::null()); - ffi::ECDSA_SIG_get0(sig, &mut r, &mut s); - [r, s] - } -} - -#[cfg(ossl10x)] -mod compat { - use libc::c_int; - use ffi::{BIGNUM, ECDSA_SIG}; - - pub unsafe fn set_numbers(sig: *mut ECDSA_SIG, r: *mut BIGNUM, s: *mut BIGNUM) -> c_int { - (*sig).r = r; - (*sig).s = s; - 1 - } - - pub unsafe fn get_numbers(sig: *mut ECDSA_SIG) -> [*const BIGNUM; 2] { - [(*sig).r, (*sig).s] - } - } #[cfg(test)] mod test { - use nid::Nid; + use super::*; use ec::EcGroup; use ec::EcKey; - use super::*; + use nid::Nid; #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] static CURVE_IDENTIFER: Nid = Nid::X9_62_PRIME192V1; @@ -171,7 +170,8 @@ mod test { assert!(verification); // Signature will not be verified using the incorrect data but the correct public key - let verification2 = res.verify(String::from("hello2").as_bytes(), &public_key) + let verification2 = res + .verify(String::from("hello2").as_bytes(), &public_key) .unwrap(); assert!(verification2 == false); diff --git a/openssl/src/hash.rs b/openssl/src/hash.rs index 726ebe9c..582a2ada 100644 --- a/openssl/src/hash.rs +++ b/openssl/src/hash.rs @@ -1,22 +1,27 @@ -use std::io::prelude::*; -use std::io; -use std::ops::{Deref, DerefMut}; -use std::fmt; use ffi; +use std::fmt; +use std::io; +use std::io::prelude::*; +use std::ops::{Deref, DerefMut}; -#[cfg(ossl110)] -use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; -#[cfg(any(ossl101, ossl102))] -use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; + } else { + use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; + } +} -use {cvt, cvt_p}; use error::ErrorStack; +use {cvt, cvt_p}; #[derive(Copy, Clone)] pub struct MessageDigest(*const ffi::EVP_MD); impl MessageDigest { - pub unsafe fn from_ptr(x: *const ffi::EVP_MD) -> Self { MessageDigest(x) } + pub unsafe fn from_ptr(x: *const ffi::EVP_MD) -> Self { + MessageDigest(x) + } pub fn md5() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_md5()) } @@ -382,12 +387,10 @@ mod tests { #[test] fn test_sha256() { - let tests = [ - ( - "616263", - "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", - ), - ]; + let tests = [( + "616263", + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", + )]; for test in tests.iter() { hash_test(MessageDigest::sha256(), test); diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index a66a7743..d74ce65f 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -3,6 +3,8 @@ #[macro_use] extern crate bitflags; #[macro_use] +extern crate cfg_if; +#[macro_use] extern crate foreign_types; #[macro_use] extern crate lazy_static; @@ -53,8 +55,8 @@ pub mod pkcs5; pub mod pkey; pub mod rand; pub mod rsa; -pub mod sign; pub mod sha; +pub mod sign; pub mod ssl; pub mod stack; pub mod string; diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index 718ae59d..92a5799e 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -189,7 +189,8 @@ where /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn d(&self) -> &BigNumRef { unsafe { - let d = compat::key(self.as_ptr())[2]; + let mut d = ptr::null(); + RSA_get0_key(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut d); BigNumRef::from_ptr(d as *mut _) } } @@ -201,7 +202,8 @@ where /// [`RSA_get0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn p(&self) -> Option<&BigNumRef> { unsafe { - let p = compat::factors(self.as_ptr())[0]; + let mut p = ptr::null(); + RSA_get0_factors(self.as_ptr(), &mut p, ptr::null_mut()); if p.is_null() { None } else { @@ -217,7 +219,8 @@ where /// [`RSA_get0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn q(&self) -> Option<&BigNumRef> { unsafe { - let q = compat::factors(self.as_ptr())[1]; + let mut q = ptr::null(); + RSA_get0_factors(self.as_ptr(), ptr::null_mut(), &mut q); if q.is_null() { None } else { @@ -233,7 +236,8 @@ where /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn dmp1(&self) -> Option<&BigNumRef> { unsafe { - let dp = compat::crt_params(self.as_ptr())[0]; + let mut dp = ptr::null(); + RSA_get0_crt_params(self.as_ptr(), &mut dp, ptr::null_mut(), ptr::null_mut()); if dp.is_null() { None } else { @@ -249,7 +253,8 @@ where /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn dmq1(&self) -> Option<&BigNumRef> { unsafe { - let dq = compat::crt_params(self.as_ptr())[1]; + let mut dq = ptr::null(); + RSA_get0_crt_params(self.as_ptr(), ptr::null_mut(), &mut dq, ptr::null_mut()); if dq.is_null() { None } else { @@ -265,7 +270,8 @@ where /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn iqmp(&self) -> Option<&BigNumRef> { unsafe { - let qi = compat::crt_params(self.as_ptr())[2]; + let mut qi = ptr::null(); + RSA_get0_crt_params(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut qi); if qi.is_null() { None } else { @@ -391,7 +397,8 @@ where /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn n(&self) -> &BigNumRef { unsafe { - let n = compat::key(self.as_ptr())[0]; + let mut n = ptr::null(); + RSA_get0_key(self.as_ptr(), &mut n, ptr::null_mut(), ptr::null_mut()); BigNumRef::from_ptr(n as *mut _) } } @@ -403,7 +410,8 @@ where /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn e(&self) -> &BigNumRef { unsafe { - let e = compat::key(self.as_ptr())[1]; + let mut e = ptr::null(); + RSA_get0_key(self.as_ptr(), ptr::null_mut(), &mut e, ptr::null_mut()); BigNumRef::from_ptr(e as *mut _) } } @@ -421,15 +429,10 @@ impl Rsa { /// [`RSA_set0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_key.html pub fn from_public_components(n: BigNum, e: BigNum) -> Result, ErrorStack> { unsafe { - let rsa = Rsa::from_ptr(cvt_p(ffi::RSA_new())?); - cvt(compat::set_key( - rsa.0, - n.as_ptr(), - e.as_ptr(), - ptr::null_mut(), - ))?; + let rsa = cvt_p(ffi::RSA_new())?; + RSA_set0_key(rsa, n.as_ptr(), e.as_ptr(), ptr::null_mut()); mem::forget((n, e)); - Ok(rsa) + Ok(Rsa::from_ptr(rsa)) } } @@ -498,10 +501,12 @@ impl RsaPrivateKeyBuilder { /// [`RSA_set0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_key.html pub fn new(n: BigNum, e: BigNum, d: BigNum) -> Result { unsafe { - let rsa = Rsa::from_ptr(cvt_p(ffi::RSA_new())?); - cvt(compat::set_key(rsa.0, n.as_ptr(), e.as_ptr(), d.as_ptr()))?; + let rsa = cvt_p(ffi::RSA_new())?; + RSA_set0_key(rsa, n.as_ptr(), e.as_ptr(), d.as_ptr()); mem::forget((n, e, d)); - Ok(RsaPrivateKeyBuilder { rsa }) + Ok(RsaPrivateKeyBuilder { + rsa: Rsa::from_ptr(rsa), + }) } } @@ -512,9 +517,10 @@ impl RsaPrivateKeyBuilder { /// This correspond to [`RSA_set0_factors`]. /// /// [`RSA_set0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_factors.html + // FIXME should be infallible pub fn set_factors(self, p: BigNum, q: BigNum) -> Result { unsafe { - cvt(compat::set_factors(self.rsa.0, p.as_ptr(), q.as_ptr()))?; + RSA_set0_factors(self.rsa.as_ptr(), p.as_ptr(), q.as_ptr()); mem::forget((p, q)); } Ok(self) @@ -528,6 +534,7 @@ impl RsaPrivateKeyBuilder { /// This correspond to [`RSA_set0_crt_params`]. /// /// [`RSA_set0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_crt_params.html + // FIXME should be infallible pub fn set_crt_params( self, dmp1: BigNum, @@ -535,12 +542,12 @@ impl RsaPrivateKeyBuilder { iqmp: BigNum, ) -> Result { unsafe { - cvt(compat::set_crt_params( - self.rsa.0, + RSA_set0_crt_params( + self.rsa.as_ptr(), dmp1.as_ptr(), dmq1.as_ptr(), iqmp.as_ptr(), - ))?; + ); mem::forget((dmp1, dmq1, iqmp)); } Ok(self) @@ -637,89 +644,99 @@ impl fmt::Debug for Rsa { } } -#[cfg(ossl110)] -mod compat { - use std::ptr; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ + RSA_get0_key, RSA_get0_factors, RSA_get0_crt_params, RSA_set0_key, RSA_set0_factors, + RSA_set0_crt_params, + }; + } else { + #[allow(bad_style)] + unsafe fn RSA_get0_key( + r: *const ffi::RSA, + n: *mut *const ffi::BIGNUM, + e: *mut *const ffi::BIGNUM, + d: *mut *const ffi::BIGNUM, + ) { + if !n.is_null() { + *n = (*r).n; + } + if !e.is_null() { + *e = (*r).e; + } + if !d.is_null() { + *d = (*r).d; + } + } - use ffi::{self, BIGNUM, RSA}; - use libc::c_int; + #[allow(bad_style)] + unsafe fn RSA_get0_factors( + r: *const ffi::RSA, + p: *mut *const ffi::BIGNUM, + q: *mut *const ffi::BIGNUM, + ) { + if !p.is_null() { + *p = (*r).p; + } + if !q.is_null() { + *q = (*r).q; + } + } - pub unsafe fn key(r: *const RSA) -> [*const BIGNUM; 3] { - let (mut n, mut e, mut d) = (ptr::null(), ptr::null(), ptr::null()); - ffi::RSA_get0_key(r, &mut n, &mut e, &mut d); - [n, e, d] - } + #[allow(bad_style)] + unsafe fn RSA_get0_crt_params( + r: *const ffi::RSA, + dmp1: *mut *const ffi::BIGNUM, + dmq1: *mut *const ffi::BIGNUM, + iqmp: *mut *const ffi::BIGNUM, + ) { + if !dmp1.is_null() { + *dmp1 = (*r).dmp1; + } + if !dmq1.is_null() { + *dmq1 = (*r).dmq1; + } + if !iqmp.is_null() { + *iqmp = (*r).iqmp; + } + } - pub unsafe fn factors(r: *const RSA) -> [*const BIGNUM; 2] { - let (mut p, mut q) = (ptr::null(), ptr::null()); - ffi::RSA_get0_factors(r, &mut p, &mut q); - [p, q] - } + #[allow(bad_style)] + unsafe fn RSA_set0_key( + r: *mut ffi::RSA, + n: *mut ffi::BIGNUM, + e: *mut ffi::BIGNUM, + d: *mut ffi::BIGNUM, + ) -> c_int { + (*r).n = n; + (*r).e = e; + (*r).d = d; + 1 + } - pub unsafe fn crt_params(r: *const RSA) -> [*const BIGNUM; 3] { - let (mut dp, mut dq, mut qi) = (ptr::null(), ptr::null(), ptr::null()); - ffi::RSA_get0_crt_params(r, &mut dp, &mut dq, &mut qi); - [dp, dq, qi] - } + #[allow(bad_style)] + unsafe fn RSA_set0_factors( + r: *mut ffi::RSA, + p: *mut ffi::BIGNUM, + q: *mut ffi::BIGNUM, + ) -> c_int { + (*r).p = p; + (*r).q = q; + 1 + } - pub unsafe fn set_key(r: *mut RSA, n: *mut BIGNUM, e: *mut BIGNUM, d: *mut BIGNUM) -> c_int { - ffi::RSA_set0_key(r, n, e, d) - } - - pub unsafe fn set_factors(r: *mut RSA, p: *mut BIGNUM, q: *mut BIGNUM) -> c_int { - ffi::RSA_set0_factors(r, p, q) - } - - pub unsafe fn set_crt_params( - r: *mut RSA, - dmp1: *mut BIGNUM, - dmq1: *mut BIGNUM, - iqmp: *mut BIGNUM, - ) -> c_int { - ffi::RSA_set0_crt_params(r, dmp1, dmq1, iqmp) - } -} - -#[cfg(ossl10x)] -mod compat { - use ffi::{BIGNUM, RSA}; - use libc::c_int; - - pub unsafe fn key(r: *const RSA) -> [*const BIGNUM; 3] { - [(*r).n, (*r).e, (*r).d] - } - - pub unsafe fn factors(r: *const RSA) -> [*const BIGNUM; 2] { - [(*r).p, (*r).q] - } - - pub unsafe fn crt_params(r: *const RSA) -> [*const BIGNUM; 3] { - [(*r).dmp1, (*r).dmq1, (*r).iqmp] - } - - pub unsafe fn set_key(r: *mut RSA, n: *mut BIGNUM, e: *mut BIGNUM, d: *mut BIGNUM) -> c_int { - (*r).n = n; - (*r).e = e; - (*r).d = d; - 1 // TODO: is this right? should it be 0? what's success? - } - - pub unsafe fn set_factors(r: *mut RSA, p: *mut BIGNUM, q: *mut BIGNUM) -> c_int { - (*r).p = p; - (*r).q = q; - 1 // TODO: is this right? should it be 0? what's success? - } - - pub unsafe fn set_crt_params( - r: *mut RSA, - dmp1: *mut BIGNUM, - dmq1: *mut BIGNUM, - iqmp: *mut BIGNUM, - ) -> c_int { - (*r).dmp1 = dmp1; - (*r).dmq1 = dmq1; - (*r).iqmp = iqmp; - 1 // TODO: is this right? should it be 0? what's success? + #[allow(bad_style)] + unsafe fn RSA_set0_crt_params( + r: *mut ffi::RSA, + dmp1: *mut ffi::BIGNUM, + dmq1: *mut ffi::BIGNUM, + iqmp: *mut ffi::BIGNUM, + ) -> c_int { + (*r).dmp1 = dmp1; + (*r).dmq1 = dmq1; + (*r).iqmp = iqmp; + 1 + } } } diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs index c8032686..849831ed 100644 --- a/openssl/src/sign.rs +++ b/openssl/src/sign.rs @@ -63,21 +63,24 @@ //! ``` use ffi; use foreign_types::ForeignTypeRef; +use libc::c_int; use std::io::{self, Write}; use std::marker::PhantomData; use std::ptr; -use libc::c_int; -use {cvt, cvt_p}; +use error::ErrorStack; use hash::MessageDigest; use pkey::{HasPrivate, HasPublic, PKeyRef}; -use error::ErrorStack; use rsa::Padding; +use {cvt, cvt_p}; -#[cfg(ossl110)] -use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; -#[cfg(any(ossl101, ossl102))] -use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; + } else { + use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; + } +} /// Salt lengths that must be used with `set_rsa_pss_saltlen`. pub struct RsaPssSaltlen(c_int); @@ -459,7 +462,7 @@ impl<'a> Verifier<'a> { pub fn verify(&self, signature: &[u8]) -> Result { unsafe { let r = - EVP_DigestVerifyFinal(self.md_ctx, signature.as_ptr() as *const _, signature.len()); + EVP_DigestVerifyFinal(self.md_ctx, signature.as_ptr() as *mut _, signature.len()); match r { 1 => Ok(true), 0 => { @@ -501,12 +504,12 @@ mod test { use hex::{self, FromHex}; use std::iter; - use hash::MessageDigest; - use sign::{RsaPssSaltlen, Signer, Verifier}; use ec::{EcGroup, EcKey}; + use hash::MessageDigest; use nid::Nid; - use rsa::{Padding, Rsa}; use pkey::PKey; + use rsa::{Padding, Rsa}; + use sign::{RsaPssSaltlen, Signer, Verifier}; const INPUT: &'static str = "65794a68624763694f694a53557a49314e694a392e65794a7063334d694f694a71623255694c41304b49434a6c\ @@ -673,7 +676,7 @@ mod test { signer.update(data as &[u8]).unwrap(); let expected = vec![ - 136, 101, 61, 167, 61, 30, 248, 234, 124, 166, 196, 157, 203, 52, 171, 19 + 136, 101, 61, 167, 61, 30, 248, 234, 124, 166, 196, 157, 203, 52, 171, 19, ]; assert_eq!(signer.sign_to_vec().unwrap(), expected); } diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs index 4b792a75..1a149b6d 100644 --- a/openssl/src/ssl/bio.rs +++ b/openssl/src/ssl/bio.rs @@ -1,11 +1,13 @@ +use ffi::{ + self, BIO_clear_retry_flags, BIO_new, BIO_set_retry_read, BIO_set_retry_write, BIO, + BIO_CTRL_FLUSH, +}; use libc::{c_char, c_int, c_long, c_void, strlen}; -use ffi::{BIO, BIO_CTRL_FLUSH, BIO_new, 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::mem; -use std::panic::{AssertUnwindSafe, catch_unwind}; +use std::panic::{catch_unwind, AssertUnwindSafe}; use std::ptr; use std::slice; @@ -19,11 +21,11 @@ pub struct StreamState { } /// Safe wrapper for BIO_METHOD -pub struct BioMethod(compat::BIO_METHOD); +pub struct BioMethod(BIO_METHOD); impl BioMethod { fn new() -> BioMethod { - BioMethod(compat::BIO_METHOD::new::()) + BioMethod(BIO_METHOD::new::()) } } @@ -41,8 +43,8 @@ pub fn new(stream: S) -> Result<(*mut BIO, BioMethod), ErrorSta unsafe { let bio = cvt_p(BIO_new(method.0.get()))?; - compat::BIO_set_data(bio, Box::into_raw(state) as *mut _); - compat::BIO_set_init(bio, 1); + BIO_set_data(bio, Box::into_raw(state) as *mut _); + BIO_set_init(bio, 1); return Ok((bio, method)); } @@ -59,7 +61,7 @@ pub unsafe fn take_panic(bio: *mut BIO) -> Option> { } pub unsafe fn get_ref<'a, S: 'a>(bio: *mut BIO) -> &'a S { - let state: &'a StreamState = mem::transmute(compat::BIO_get_data(bio)); + let state: &'a StreamState = mem::transmute(BIO_get_data(bio)); &state.stream } @@ -68,7 +70,7 @@ pub unsafe fn get_mut<'a, S: 'a>(bio: *mut BIO) -> &'a mut S { } unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState { - &mut *(compat::BIO_get_data(bio) as *mut _) + &mut *(BIO_get_data(bio) as *mut _) } unsafe extern "C" fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int { @@ -117,8 +119,7 @@ unsafe extern "C" fn bread(bio: *mut BIO, buf: *mut c_char, len: c_int) fn retriable_error(err: &io::Error) -> bool { match err.kind() { - io::ErrorKind::WouldBlock | - io::ErrorKind::NotConnected => true, + io::ErrorKind::WouldBlock | io::ErrorKind::NotConnected => true, _ => false, } } @@ -153,10 +154,10 @@ unsafe extern "C" fn ctrl( } unsafe extern "C" fn create(bio: *mut BIO) -> c_int { - compat::BIO_set_init(bio, 0); - compat::BIO_set_num(bio, 0); - compat::BIO_set_data(bio, ptr::null_mut()); - compat::BIO_set_flags(bio, 0); + BIO_set_init(bio, 0); + BIO_set_num(bio, 0); + BIO_set_data(bio, ptr::null_mut()); + BIO_set_flags(bio, 0); 1 } @@ -165,115 +166,110 @@ unsafe extern "C" fn destroy(bio: *mut BIO) -> c_int { return 0; } - let data = compat::BIO_get_data(bio); + let data = BIO_get_data(bio); assert!(!data.is_null()); Box::>::from_raw(data as *mut _); - compat::BIO_set_data(bio, ptr::null_mut()); - compat::BIO_set_init(bio, 0); + BIO_set_data(bio, ptr::null_mut()); + BIO_set_init(bio, 0); 1 } -#[cfg(ossl110)] -#[allow(bad_style)] -mod compat { - use std::io::{Read, Write}; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{BIO_get_data, BIO_set_data, BIO_set_flags, BIO_set_init}; - use libc::c_int; - use ffi; - pub use ffi::{BIO_set_init, BIO_set_flags, BIO_set_data, BIO_get_data}; + #[allow(bad_style)] + unsafe fn BIO_set_num(_bio: *mut ffi::BIO, _num: c_int) {} - pub unsafe fn BIO_set_num(_bio: *mut ffi::BIO, _num: c_int) {} + #[allow(bad_style)] + struct BIO_METHOD(*mut ffi::BIO_METHOD); - pub struct BIO_METHOD(*mut ffi::BIO_METHOD); + impl BIO_METHOD { + fn new() -> BIO_METHOD { + unsafe { + let ptr = ffi::BIO_meth_new(ffi::BIO_TYPE_NONE, b"rust\0".as_ptr() as *const _); + assert!(!ptr.is_null()); + let ret = BIO_METHOD(ptr); + assert!(ffi::BIO_meth_set_write(ptr, bwrite::) != 0); + assert!(ffi::BIO_meth_set_read(ptr, bread::) != 0); + assert!(ffi::BIO_meth_set_puts(ptr, bputs::) != 0); + assert!(ffi::BIO_meth_set_ctrl(ptr, ctrl::) != 0); + assert!(ffi::BIO_meth_set_create(ptr, create) != 0); + assert!(ffi::BIO_meth_set_destroy(ptr, destroy::) != 0); + return ret; + } + } - impl BIO_METHOD { - pub fn new() -> BIO_METHOD { - unsafe { - let ptr = ffi::BIO_meth_new(ffi::BIO_TYPE_NONE, b"rust\0".as_ptr() as *const _); - assert!(!ptr.is_null()); - let ret = BIO_METHOD(ptr); - assert!(ffi::BIO_meth_set_write(ptr, super::bwrite::) != 0); - assert!(ffi::BIO_meth_set_read(ptr, super::bread::) != 0); - assert!(ffi::BIO_meth_set_puts(ptr, super::bputs::) != 0); - assert!(ffi::BIO_meth_set_ctrl(ptr, super::ctrl::) != 0); - assert!(ffi::BIO_meth_set_create(ptr, super::create) != 0); - assert!(ffi::BIO_meth_set_destroy(ptr, super::destroy::) != 0); - return ret; + fn get(&self) -> *mut ffi::BIO_METHOD { + self.0 } } - pub fn get(&self) -> *mut ffi::BIO_METHOD { - self.0 - } - } - - impl Drop for BIO_METHOD { - fn drop(&mut self) { - unsafe { - ffi::BIO_meth_free(self.0); + impl Drop for BIO_METHOD { + fn drop(&mut self) { + unsafe { + ffi::BIO_meth_free(self.0); + } } } + } else { + #[allow(bad_style)] + struct BIO_METHOD(*mut ffi::BIO_METHOD); + + impl BIO_METHOD { + fn new() -> BIO_METHOD { + let ptr = Box::new(ffi::BIO_METHOD { + type_: ffi::BIO_TYPE_NONE, + name: b"rust\0".as_ptr() as *const _, + bwrite: Some(bwrite::), + bread: Some(bread::), + bputs: Some(bputs::), + bgets: None, + ctrl: Some(ctrl::), + create: Some(create), + destroy: Some(destroy::), + callback_ctrl: None, + }); + + BIO_METHOD(Box::into_raw(ptr)) + } + + fn get(&self) -> *mut ffi::BIO_METHOD { + self.0 + } + } + + impl Drop for BIO_METHOD { + fn drop(&mut self) { + unsafe { + Box::::from_raw(self.0); + } + } + } + + #[allow(bad_style)] + unsafe fn BIO_set_init(bio: *mut ffi::BIO, init: c_int) { + (*bio).init = init; + } + + #[allow(bad_style)] + unsafe fn BIO_set_flags(bio: *mut ffi::BIO, flags: c_int) { + (*bio).flags = flags; + } + + #[allow(bad_style)] + unsafe fn BIO_get_data(bio: *mut ffi::BIO) -> *mut c_void { + (*bio).ptr + } + + #[allow(bad_style)] + unsafe fn BIO_set_data(bio: *mut ffi::BIO, data: *mut c_void) { + (*bio).ptr = data; + } + + #[allow(bad_style)] + unsafe fn BIO_set_num(bio: *mut ffi::BIO, num: c_int) { + (*bio).num = num; + } } } - -#[cfg(ossl10x)] -#[allow(bad_style)] -mod compat { - use std::io::{Read, Write}; - - use ffi; - use libc::{c_int, c_void}; - - pub struct BIO_METHOD(*mut ffi::BIO_METHOD); - - impl BIO_METHOD { - pub fn new() -> BIO_METHOD { - let ptr = Box::new(ffi::BIO_METHOD { - type_: ffi::BIO_TYPE_NONE, - name: b"rust\0".as_ptr() as *const _, - bwrite: Some(super::bwrite::), - bread: Some(super::bread::), - bputs: Some(super::bputs::), - bgets: None, - ctrl: Some(super::ctrl::), - create: Some(super::create), - destroy: Some(super::destroy::), - callback_ctrl: None, - }); - - BIO_METHOD(Box::into_raw(ptr)) - } - - pub fn get(&self) -> *mut ffi::BIO_METHOD { - self.0 - } - } - - impl Drop for BIO_METHOD { - fn drop(&mut self) { - unsafe { - Box::::from_raw(self.0); - } - } - } - - pub unsafe fn BIO_set_init(bio: *mut ffi::BIO, init: c_int) { - (*bio).init = init; - } - - pub unsafe fn BIO_set_flags(bio: *mut ffi::BIO, flags: c_int) { - (*bio).flags = flags; - } - - pub unsafe fn BIO_get_data(bio: *mut ffi::BIO) -> *mut c_void { - (*bio).ptr - } - - pub unsafe fn BIO_set_data(bio: *mut ffi::BIO, data: *mut c_void) { - (*bio).ptr = data; - } - - pub unsafe fn BIO_set_num(bio: *mut ffi::BIO, num: c_int) { - (*bio).num = num; - } -} diff --git a/openssl/src/ssl/callbacks.rs b/openssl/src/ssl/callbacks.rs index fd5b7ef5..6ec9aef9 100644 --- a/openssl/src/ssl/callbacks.rs +++ b/openssl/src/ssl/callbacks.rs @@ -13,11 +13,11 @@ use std::str; use std::sync::Arc; use dh::Dh; -#[cfg(any(ossl101, ossl102))] +#[cfg(all(ossl101, not(ossl110)))] use ec::EcKey; use error::ErrorStack; use pkey::Params; -#[cfg(any(ossl102, ossl110))] +#[cfg(ossl102)] use ssl::AlpnError; #[cfg(ossl111)] use ssl::ExtensionContext; @@ -37,7 +37,8 @@ where // raw pointer shenanigans to break the borrow of ctx // the callback can't mess with its own ex_data slot so this is safe - let verify = ctx.ex_data(ssl_idx) + let verify = ctx + .ex_data(ssl_idx) .expect("BUG: store context missing ssl") .ssl_context() .ex_data(verify_idx) @@ -66,7 +67,8 @@ where let ssl = SslRef::from_ptr_mut(ssl); let callback_idx = SslContext::cached_ex_index::(); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(callback_idx) .expect("BUG: psk callback missing") as *const F; let hint = if hint != ptr::null() { @@ -96,7 +98,8 @@ where let ssl_idx = X509StoreContext::ssl_idx().expect("BUG: store context ssl index missing"); let callback_idx = Ssl::cached_ex_index::>(); - let callback = ctx.ex_data(ssl_idx) + let callback = ctx + .ex_data(ssl_idx) .expect("BUG: store context missing ssl") .ex_data(callback_idx) .expect("BUG: ssl verify callback missing") @@ -112,7 +115,8 @@ where { unsafe { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: sni callback missing") as *const F; let mut alert = SslAlert(*al); @@ -140,7 +144,8 @@ where { unsafe { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: alpn callback missing") as *const F; let protos = slice::from_raw_parts(inbuf as *const u8, inlen as usize); @@ -165,7 +170,8 @@ where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: tmp dh callback missing") as *const F; @@ -182,7 +188,7 @@ where } } -#[cfg(any(ossl101, ossl102))] +#[cfg(all(ossl101, not(ossl110)))] pub unsafe extern "C" fn raw_tmp_ecdh( ssl: *mut ffi::SSL, is_export: c_int, @@ -192,7 +198,8 @@ where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: tmp ecdh callback missing") as *const F; @@ -218,7 +225,8 @@ where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ex_data(Ssl::cached_ex_index::>()) + let callback = ssl + .ex_data(Ssl::cached_ex_index::>()) .expect("BUG: ssl tmp dh callback missing") .clone(); @@ -235,7 +243,7 @@ where } } -#[cfg(any(ossl101, ossl102))] +#[cfg(all(ossl101, not(ossl110)))] pub unsafe extern "C" fn raw_tmp_ecdh_ssl( ssl: *mut ffi::SSL, is_export: c_int, @@ -245,7 +253,8 @@ where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ex_data(Ssl::cached_ex_index::>()) + let callback = ssl + .ex_data(Ssl::cached_ex_index::>()) .expect("BUG: ssl tmp ecdh callback missing") .clone(); @@ -267,7 +276,8 @@ where F: Fn(&mut SslRef) -> Result + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: ocsp callback missing") as *const F; let ret = (*callback)(ssl); @@ -301,7 +311,8 @@ where F: Fn(&mut SslRef, SslSession) + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: new session callback missing") as *const F; let session = SslSession::from_ptr(session); @@ -319,7 +330,8 @@ pub unsafe extern "C" fn raw_remove_session( F: Fn(&SslContextRef, &SslSessionRef) + 'static + Sync + Send, { let ctx = SslContextRef::from_ptr(ctx); - let callback = ctx.ex_data(SslContext::cached_ex_index::()) + let callback = ctx + .ex_data(SslContext::cached_ex_index::()) .expect("BUG: remove session callback missing"); let session = SslSessionRef::from_ptr(session); @@ -341,7 +353,8 @@ where F: Fn(&mut SslRef, &[u8]) -> Option + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: get session callback missing") as *const F; let data = slice::from_raw_parts(data as *const u8, len as usize); @@ -363,7 +376,8 @@ where F: Fn(&SslRef, &str) + 'static + Sync + Send, { let ssl = SslRef::from_ptr(ssl as *mut _); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: get session callback missing"); let line = CStr::from_ptr(line).to_bytes(); @@ -382,7 +396,8 @@ where F: Fn(&mut SslRef, &mut [u8]) -> Result + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: stateless cookie generate callback missing") as *const F; let slice = slice::from_raw_parts_mut(cookie as *mut u8, ffi::SSL_COOKIE_LENGTH as usize); @@ -408,7 +423,8 @@ where F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: stateless cookie verify callback missing") as *const F; let slice = slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len as usize); @@ -425,7 +441,8 @@ where { unsafe { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: cookie generate callback missing") as *const F; // We subtract 1 from DTLS1_COOKIE_LENGTH as the ostensible value, 256, is erroneous but retained for @@ -461,7 +478,8 @@ where { unsafe { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: cookie verify callback missing") as *const F; let slice = @@ -494,7 +512,8 @@ where { unsafe { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: custom ext add callback missing") as *const F; let ectx = ExtensionContext::from_bits_truncate(context); @@ -570,7 +589,8 @@ where { unsafe { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: custom ext parse callback missing") as *const F; let ectx = ExtensionContext::from_bits_truncate(context); diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 9966a5a0..f10a0e23 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -3,16 +3,22 @@ use std::ops::{Deref, DerefMut}; use dh::Dh; use error::ErrorStack; -use ssl::{HandshakeError, Ssl, SslContext, SslContextBuilder, SslMethod, SslMode, SslOptions, - SslRef, SslStream, SslVerifyMode}; +use ssl::{ + HandshakeError, Ssl, SslContext, SslContextBuilder, SslMethod, SslMode, SslOptions, SslRef, + SslStream, SslVerifyMode, +}; use version; fn ctx(method: SslMethod) -> Result { let mut ctx = SslContextBuilder::new(method)?; - let mut opts = SslOptions::ALL | SslOptions::NO_COMPRESSION | SslOptions::NO_SSLV2 - | SslOptions::NO_SSLV3 | SslOptions::SINGLE_DH_USE - | SslOptions::SINGLE_ECDH_USE | SslOptions::CIPHER_SERVER_PREFERENCE; + let mut opts = SslOptions::ALL + | SslOptions::NO_COMPRESSION + | SslOptions::NO_SSLV2 + | SslOptions::NO_SSLV3 + | SslOptions::SINGLE_DH_USE + | SslOptions::SINGLE_ECDH_USE + | SslOptions::CIPHER_SERVER_PREFERENCE; opts &= !SslOptions::DONT_INSERT_EMPTY_FRAGMENTS; ctx.set_options(opts); @@ -23,7 +29,7 @@ fn ctx(method: SslMethod) -> Result { // This is quite a useful optimization for saving memory, but historically // caused CVEs in OpenSSL pre-1.0.1h, according to // https://bugs.python.org/issue25672 - if version::number() >= 0x1000108f { + if version::number() >= 0x1_00_01_08_0 { mode |= SslMode::RELEASE_BUFFERS; } @@ -277,226 +283,228 @@ impl DerefMut for SslAcceptorBuilder { } } -#[cfg(ossl101)] -fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { - use ec::EcKey; - use nid::Nid; - - let curve = EcKey::from_curve_name(Nid::X9_62_PRIME256V1)?; - ctx.set_tmp_ecdh(&curve) -} - -#[cfg(ossl102)] -fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { - ctx.set_ecdh_auto(true) -} - -#[cfg(ossl110)] -fn setup_curves(_: &mut SslContextBuilder) -> Result<(), ErrorStack> { - Ok(()) -} - -#[cfg(any(ossl102, ossl110))] -fn setup_verify(ctx: &mut SslContextBuilder) { - ctx.set_verify(SslVerifyMode::PEER); -} - -#[cfg(ossl101)] -fn setup_verify(ctx: &mut SslContextBuilder) { - ctx.set_verify_callback(SslVerifyMode::PEER, verify::verify_callback); -} - -#[cfg(any(ossl102, ossl110))] -fn setup_verify_hostname(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { - use x509::verify::X509CheckFlags; - - let param = ssl.param_mut(); - param.set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS); - match domain.parse() { - Ok(ip) => param.set_ip(ip), - Err(_) => param.set_host(domain), - } -} - -#[cfg(ossl101)] -fn setup_verify_hostname(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { - let domain = domain.to_string(); - ssl.set_ex_data(*verify::HOSTNAME_IDX, domain); - Ok(()) -} - -#[cfg(ossl101)] -mod verify { - use std::net::IpAddr; - use std::str; - - use ex_data::Index; - use nid::Nid; - use x509::{GeneralName, X509NameRef, X509Ref, X509StoreContext, X509StoreContextRef, - X509VerifyResult}; - use stack::Stack; - use ssl::Ssl; - - lazy_static! { - pub static ref HOSTNAME_IDX: Index = Ssl::new_ex_index().unwrap(); - } - - pub fn verify_callback(preverify_ok: bool, x509_ctx: &mut X509StoreContextRef) -> bool { - if !preverify_ok || x509_ctx.error_depth() != 0 { - return preverify_ok; +cfg_if! { + if #[cfg(ossl110)] { + fn setup_curves(_: &mut SslContextBuilder) -> Result<(), ErrorStack> { + Ok(()) } - - let ok = match ( - x509_ctx.current_cert(), - X509StoreContext::ssl_idx() - .ok() - .and_then(|idx| x509_ctx.ex_data(idx)) - .and_then(|ssl| ssl.ex_data(*HOSTNAME_IDX)), - ) { - (Some(x509), Some(domain)) => verify_hostname(domain, &x509), - _ => true, - }; - - if !ok { - x509_ctx.set_error(X509VerifyResult::APPLICATION_VERIFICATION); + } else if #[cfg(any(ossl102, libressl))] { + fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { + ctx.set_ecdh_auto(true) } + } else { + fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { + use ec::EcKey; + use nid::Nid; - ok - } - - fn verify_hostname(domain: &str, cert: &X509Ref) -> bool { - match cert.subject_alt_names() { - Some(names) => verify_subject_alt_names(domain, names), - None => verify_subject_name(domain, &cert.subject_name()), + let curve = EcKey::from_curve_name(Nid::X9_62_PRIME256V1)?; + ctx.set_tmp_ecdh(&curve) } } +} - fn verify_subject_alt_names(domain: &str, names: Stack) -> bool { - let ip = domain.parse(); +cfg_if! { + if #[cfg(any(ossl102, libressl261))] { + fn setup_verify(ctx: &mut SslContextBuilder) { + ctx.set_verify(SslVerifyMode::PEER); + } - for name in &names { - match ip { - Ok(ip) => { - if let Some(actual) = name.ipaddress() { - if matches_ip(&ip, actual) { - return true; - } - } - } - Err(_) => { - if let Some(pattern) = name.dnsname() { - if matches_dns(pattern, domain) { - return true; - } - } - } + fn setup_verify_hostname(ssl: &mut SslRef, domain: &str) -> Result<(), ErrorStack> { + use x509::verify::X509CheckFlags; + + let param = ssl.param_mut(); + param.set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS); + match domain.parse() { + Ok(ip) => param.set_ip(ip), + Err(_) => param.set_host(domain), } } + } else { + fn setup_verify(ctx: &mut SslContextBuilder) { + ctx.set_verify_callback(SslVerifyMode::PEER, verify::verify_callback); + } - false - } + fn setup_verify_hostname(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { + let domain = domain.to_string(); + ssl.set_ex_data(*verify::HOSTNAME_IDX, domain); + Ok(()) + } - fn verify_subject_name(domain: &str, subject_name: &X509NameRef) -> bool { - match subject_name.entries_by_nid(Nid::COMMONNAME).next() { - Some(pattern) => { - let pattern = match str::from_utf8(pattern.data().as_slice()) { - Ok(pattern) => pattern, - Err(_) => return false, + mod verify { + use std::net::IpAddr; + use std::str; + + use ex_data::Index; + use nid::Nid; + use ssl::Ssl; + use stack::Stack; + use x509::{ + GeneralName, X509NameRef, X509Ref, X509StoreContext, X509StoreContextRef, + X509VerifyResult, + }; + + lazy_static! { + pub static ref HOSTNAME_IDX: Index = Ssl::new_ex_index().unwrap(); + } + + pub fn verify_callback(preverify_ok: bool, x509_ctx: &mut X509StoreContextRef) -> bool { + if !preverify_ok || x509_ctx.error_depth() != 0 { + return preverify_ok; + } + + let ok = match ( + x509_ctx.current_cert(), + X509StoreContext::ssl_idx() + .ok() + .and_then(|idx| x509_ctx.ex_data(idx)) + .and_then(|ssl| ssl.ex_data(*HOSTNAME_IDX)), + ) { + (Some(x509), Some(domain)) => verify_hostname(domain, &x509), + _ => true, }; - // Unlike SANs, IP addresses in the subject name don't have a - // different encoding. - match domain.parse::() { - Ok(ip) => pattern - .parse::() - .ok() - .map_or(false, |pattern| pattern == ip), - Err(_) => matches_dns(pattern, domain), + if !ok { + x509_ctx.set_error(X509VerifyResult::APPLICATION_VERIFICATION); + } + + ok + } + + fn verify_hostname(domain: &str, cert: &X509Ref) -> bool { + match cert.subject_alt_names() { + Some(names) => verify_subject_alt_names(domain, names), + None => verify_subject_name(domain, &cert.subject_name()), } } - None => false, - } - } - fn matches_dns(mut pattern: &str, mut hostname: &str) -> bool { - // first strip trailing . off of pattern and hostname to normalize - if pattern.ends_with('.') { - pattern = &pattern[..pattern.len() - 1]; - } - if hostname.ends_with('.') { - hostname = &hostname[..hostname.len() - 1]; - } + fn verify_subject_alt_names(domain: &str, names: Stack) -> bool { + let ip = domain.parse(); - matches_wildcard(pattern, hostname).unwrap_or_else(|| pattern == hostname) - } + for name in &names { + match ip { + Ok(ip) => { + if let Some(actual) = name.ipaddress() { + if matches_ip(&ip, actual) { + return true; + } + } + } + Err(_) => { + if let Some(pattern) = name.dnsname() { + if matches_dns(pattern, domain) { + return true; + } + } + } + } + } - fn matches_wildcard(pattern: &str, hostname: &str) -> Option { - // internationalized domains can't involved in wildcards - if pattern.starts_with("xn--") { - return None; - } + false + } - let wildcard_location = match pattern.find('*') { - Some(l) => l, - None => return None, - }; + fn verify_subject_name(domain: &str, subject_name: &X509NameRef) -> bool { + match subject_name.entries_by_nid(Nid::COMMONNAME).next() { + Some(pattern) => { + let pattern = match str::from_utf8(pattern.data().as_slice()) { + Ok(pattern) => pattern, + Err(_) => return false, + }; - let mut dot_idxs = pattern.match_indices('.').map(|(l, _)| l); - let wildcard_end = match dot_idxs.next() { - Some(l) => l, - None => return None, - }; + // Unlike SANs, IP addresses in the subject name don't have a + // different encoding. + match domain.parse::() { + Ok(ip) => pattern + .parse::() + .ok() + .map_or(false, |pattern| pattern == ip), + Err(_) => matches_dns(pattern, domain), + } + } + None => false, + } + } - // Never match wildcards if the pattern has less than 2 '.'s (no *.com) - // - // This is a bit dubious, as it doesn't disallow other TLDs like *.co.uk. - // Chrome has a black- and white-list for this, but Firefox (via NSS) does - // the same thing we do here. - // - // The Public Suffix (https://www.publicsuffix.org/) list could - // potentially be used here, but it's both huge and updated frequently - // enough that management would be a PITA. - if dot_idxs.next().is_none() { - return None; - } + fn matches_dns(mut pattern: &str, mut hostname: &str) -> bool { + // first strip trailing . off of pattern and hostname to normalize + if pattern.ends_with('.') { + pattern = &pattern[..pattern.len() - 1]; + } + if hostname.ends_with('.') { + hostname = &hostname[..hostname.len() - 1]; + } - // Wildcards can only be in the first component - if wildcard_location > wildcard_end { - return None; - } + matches_wildcard(pattern, hostname).unwrap_or_else(|| pattern == hostname) + } - let hostname_label_end = match hostname.find('.') { - Some(l) => l, - None => return None, - }; + fn matches_wildcard(pattern: &str, hostname: &str) -> Option { + // internationalized domains can't involved in wildcards + if pattern.starts_with("xn--") { + return None; + } - // check that the non-wildcard parts are identical - if pattern[wildcard_end..] != hostname[hostname_label_end..] { - return Some(false); - } + let wildcard_location = match pattern.find('*') { + Some(l) => l, + None => return None, + }; - let wildcard_prefix = &pattern[..wildcard_location]; - let wildcard_suffix = &pattern[wildcard_location + 1..wildcard_end]; + let mut dot_idxs = pattern.match_indices('.').map(|(l, _)| l); + let wildcard_end = match dot_idxs.next() { + Some(l) => l, + None => return None, + }; - let hostname_label = &hostname[..hostname_label_end]; + // Never match wildcards if the pattern has less than 2 '.'s (no *.com) + // + // This is a bit dubious, as it doesn't disallow other TLDs like *.co.uk. + // Chrome has a black- and white-list for this, but Firefox (via NSS) does + // the same thing we do here. + // + // The Public Suffix (https://www.publicsuffix.org/) list could + // potentially be used here, but it's both huge and updated frequently + // enough that management would be a PITA. + if dot_idxs.next().is_none() { + return None; + } - // check the prefix of the first label - if !hostname_label.starts_with(wildcard_prefix) { - return Some(false); - } + // Wildcards can only be in the first component + if wildcard_location > wildcard_end { + return None; + } - // and the suffix - if !hostname_label[wildcard_prefix.len()..].ends_with(wildcard_suffix) { - return Some(false); - } + let hostname_label_end = match hostname.find('.') { + Some(l) => l, + None => return None, + }; - Some(true) - } + // check that the non-wildcard parts are identical + if pattern[wildcard_end..] != hostname[hostname_label_end..] { + return Some(false); + } - fn matches_ip(expected: &IpAddr, actual: &[u8]) -> bool { - match *expected { - IpAddr::V4(ref addr) => actual == addr.octets(), - IpAddr::V6(ref addr) => actual == addr.octets(), + let wildcard_prefix = &pattern[..wildcard_location]; + let wildcard_suffix = &pattern[wildcard_location + 1..wildcard_end]; + + let hostname_label = &hostname[..hostname_label_end]; + + // check the prefix of the first label + if !hostname_label.starts_with(wildcard_prefix) { + return Some(false); + } + + // and the suffix + if !hostname_label[wildcard_prefix.len()..].ends_with(wildcard_suffix) { + return Some(false); + } + + Some(true) + } + + fn matches_ip(expected: &IpAddr, actual: &[u8]) -> bool { + match *expected { + IpAddr::V4(ref addr) => actual == addr.octets(), + IpAddr::V6(ref addr) => actual == addr.octets(), + } + } } } } diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index adec060c..ce9c4b1d 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -78,7 +78,7 @@ use std::str; use std::sync::{Arc, Mutex}; use dh::{Dh, DhRef}; -#[cfg(any(ossl101, ossl102))] +#[cfg(all(ossl101, not(ossl110)))] use ec::EcKey; use ec::EcKeyRef; use error::ErrorStack; @@ -91,10 +91,10 @@ use ssl::bio::BioMethod; use ssl::callbacks::*; use ssl::error::InnerError; use stack::{Stack, StackRef}; -#[cfg(any(ossl102, ossl110))] +#[cfg(ossl102)] use x509::store::X509Store; use x509::store::{X509StoreBuilderRef, X509StoreRef}; -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] use x509::verify::X509VerifyParamRef; use x509::{X509, X509Name, X509Ref, X509StoreContextRef, X509VerifyResult}; use {cvt, cvt_n, cvt_p, init}; @@ -284,7 +284,7 @@ impl SslMethod { /// This corresponds to `TLS_method` on OpenSSL 1.1.0 and `SSLv23_method` /// on OpenSSL 1.0.x. pub fn tls() -> SslMethod { - SslMethod(compat::tls_method()) + unsafe { SslMethod(TLS_method()) } } /// Support all versions of the DTLS protocol. @@ -292,7 +292,7 @@ impl SslMethod { /// This corresponds to `DTLS_method` on OpenSSL 1.1.0 and `DTLSv1_method` /// on OpenSSL 1.0.x. pub fn dtls() -> SslMethod { - SslMethod(compat::dtls_method()) + unsafe { SslMethod(DTLS_method()) } } /// Constructs an `SslMethod` from a pointer to the underlying OpenSSL value. @@ -767,7 +767,7 @@ impl SslContextBuilder { /// Requires OpenSSL 1.0.1 or 1.0.2. /// /// This corresponds to `SSL_CTX_set_tmp_ecdh_callback`. - #[cfg(any(ossl101, ossl102))] + #[cfg(all(ossl101, not(ossl110)))] pub fn set_tmp_ecdh_callback(&mut self, callback: F) where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, @@ -976,7 +976,7 @@ impl SslContextBuilder { /// This corresponds to [`SSL_CTX_set_ecdh_auto`]. /// /// [`SSL_CTX_set_ecdh_auto`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_ecdh_auto.html - #[cfg(any(ossl102, libressl))] + #[cfg(any(libressl, all(ossl102, not(ossl110))))] pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) } } @@ -992,7 +992,7 @@ impl SslContextBuilder { /// /// [`SSL_CTX_set_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html pub fn set_options(&mut self, option: SslOptions) -> SslOptions { - let bits = unsafe { compat::SSL_CTX_set_options(self.as_ptr(), option.bits()) }; + let bits = unsafe { ffi::SSL_CTX_set_options(self.as_ptr(), option.bits()) }; SslOptions { bits } } @@ -1002,7 +1002,7 @@ impl SslContextBuilder { /// /// [`SSL_CTX_get_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html pub fn options(&self) -> SslOptions { - let bits = unsafe { compat::SSL_CTX_get_options(self.as_ptr()) }; + let bits = unsafe { ffi::SSL_CTX_get_options(self.as_ptr()) }; SslOptions { bits } } @@ -1012,7 +1012,7 @@ impl SslContextBuilder { /// /// [`SSL_CTX_clear_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html pub fn clear_options(&mut self, option: SslOptions) -> SslOptions { - let bits = unsafe { compat::SSL_CTX_clear_options(self.as_ptr(), option.bits()) }; + let bits = unsafe { ffi::SSL_CTX_clear_options(self.as_ptr(), option.bits()) }; SslOptions { bits } } @@ -1514,7 +1514,7 @@ foreign_type_and_impl_send_sync! { impl Clone for SslContext { fn clone(&self) -> Self { unsafe { - compat::SSL_CTX_up_ref(self.as_ptr()); + SSL_CTX_up_ref(self.as_ptr()); SslContext::from_ptr(self.as_ptr()) } } @@ -1547,7 +1547,7 @@ impl SslContext { { unsafe { ffi::init(); - let idx = cvt_n(compat::get_new_idx(free_data_box::))?; + let idx = cvt_n(get_new_idx(free_data_box::))?; Ok(Index::from_raw(idx)) } } @@ -1833,7 +1833,7 @@ impl ToOwned for SslSessionRef { fn to_owned(&self) -> SslSession { unsafe { - compat::SSL_SESSION_up_ref(self.as_ptr()); + SSL_SESSION_up_ref(self.as_ptr()); SslSession(self.as_ptr()) } } @@ -1859,7 +1859,7 @@ impl SslSessionRef { /// /// [`SSL_SESSION_get_master_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_SESSION_get_master_key.html pub fn master_key_len(&self) -> usize { - unsafe { compat::SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) } + unsafe { SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) } } /// Copies the master key into the provided buffer. @@ -1870,7 +1870,7 @@ impl SslSessionRef { /// /// [`SSL_SESSION_get_master_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_SESSION_get_master_key.html pub fn master_key(&self, buf: &mut [u8]) -> usize { - unsafe { compat::SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) } + unsafe { SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) } } to_der! { @@ -1926,7 +1926,7 @@ impl Ssl { { unsafe { ffi::init(); - let idx = cvt_n(compat::get_new_ssl_idx(free_data_box::))?; + let idx = cvt_n(get_new_ssl_idx(free_data_box::))?; Ok(Index::from_raw(idx)) } } @@ -2091,7 +2091,7 @@ impl SslRef { /// This corresponds to `SSL_set_tmp_ecdh_callback`. /// /// [`SslContextBuilder::set_tmp_ecdh_callback`]: struct.SslContextBuilder.html#method.set_tmp_ecdh_callback - #[cfg(any(ossl101, ossl102))] + #[cfg(any(all(ossl101, not(ossl110))))] pub fn set_tmp_ecdh_callback(&mut self, callback: F) where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, @@ -2111,7 +2111,7 @@ impl SslRef { /// /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh /// [`SSL_set_ecdh_auto`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_ecdh_auto.html - #[cfg(ossl102)] + #[cfg(all(ossl102, not(ossl110)))] pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) } } @@ -2363,7 +2363,7 @@ impl SslRef { /// This corresponds to [`SSL_get0_param`]. /// /// [`SSL_get0_param`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get0_param.html - #[cfg(any(ossl102, ossl110))] + #[cfg(any(ossl102, libressl261))] pub fn param_mut(&mut self) -> &mut X509VerifyParamRef { unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) } } @@ -2541,7 +2541,7 @@ impl SslRef { /// /// [`SSL_is_server`]: https://www.openssl.org/docs/manmaster/man3/SSL_is_server.html pub fn is_server(&self) -> bool { - unsafe { compat::SSL_is_server(self.as_ptr()) != 0 } + unsafe { SSL_is_server(self.as_ptr()) != 0 } } /// Sets the extra data at the specified index. @@ -2987,133 +2987,88 @@ pub enum ShutdownResult { Received, } -#[cfg(ossl110)] -mod compat { - use std::ptr; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ + SSL_CTX_up_ref, + SSL_SESSION_get_master_key, SSL_SESSION_up_ref, SSL_is_server, TLS_method, DTLS_method, + }; - use ffi; - use libc::c_int; + pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { + ffi::CRYPTO_get_ex_new_index( + ffi::CRYPTO_EX_INDEX_SSL_CTX, + 0, + ptr::null_mut(), + None, + None, + Some(f), + ) + } - pub use ffi::{ - SSL_CTX_clear_options, SSL_CTX_get_options, SSL_CTX_set_options, SSL_CTX_up_ref, - SSL_SESSION_get_master_key, SSL_SESSION_up_ref, SSL_is_server, - }; + pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int { + ffi::CRYPTO_get_ex_new_index( + ffi::CRYPTO_EX_INDEX_SSL, + 0, + ptr::null_mut(), + None, + None, + Some(f), + ) + } + } else { + use ffi::{SSLv23_method as TLS_method, DTLSv1_method as DTLS_method}; - pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { - ffi::CRYPTO_get_ex_new_index( - ffi::CRYPTO_EX_INDEX_SSL_CTX, - 0, - ptr::null_mut(), - None, - None, - Some(f), - ) - } + pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { + ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)) + } - pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int { - ffi::CRYPTO_get_ex_new_index( - ffi::CRYPTO_EX_INDEX_SSL, - 0, - ptr::null_mut(), - None, - None, - Some(f), - ) - } + pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int { + ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)) + } - pub fn tls_method() -> *const ffi::SSL_METHOD { - unsafe { ffi::TLS_method() } - } + #[allow(bad_style)] + pub unsafe fn SSL_CTX_up_ref(ssl: *mut ffi::SSL_CTX) -> c_int { + ffi::CRYPTO_add_lock( + &mut (*ssl).references, + 1, + ffi::CRYPTO_LOCK_SSL_CTX, + "mod.rs\0".as_ptr() as *const _, + line!() as c_int, + ); + 0 + } - pub fn dtls_method() -> *const ffi::SSL_METHOD { - unsafe { ffi::DTLS_method() } - } -} - -#[cfg(ossl10x)] -#[allow(bad_style)] -mod compat { - use std::ptr; - - use ffi; - use libc::{self, c_int, c_long, c_uchar, c_ulong, size_t}; - - pub unsafe fn SSL_CTX_get_options(ctx: *const ffi::SSL_CTX) -> c_ulong { - ffi::SSL_CTX_ctrl(ctx as *mut _, ffi::SSL_CTRL_OPTIONS, 0, ptr::null_mut()) as c_ulong - } - - pub unsafe fn SSL_CTX_set_options(ctx: *const ffi::SSL_CTX, op: c_ulong) -> c_ulong { - ffi::SSL_CTX_ctrl( - ctx as *mut _, - ffi::SSL_CTRL_OPTIONS, - op as c_long, - ptr::null_mut(), - ) as c_ulong - } - - pub unsafe fn SSL_CTX_clear_options(ctx: *const ffi::SSL_CTX, op: c_ulong) -> c_ulong { - ffi::SSL_CTX_ctrl( - ctx as *mut _, - ffi::SSL_CTRL_CLEAR_OPTIONS, - op as c_long, - ptr::null_mut(), - ) as c_ulong - } - - pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { - ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)) - } - - pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int { - ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)) - } - - pub unsafe fn SSL_CTX_up_ref(ssl: *mut ffi::SSL_CTX) -> libc::c_int { - ffi::CRYPTO_add_lock( - &mut (*ssl).references, - 1, - ffi::CRYPTO_LOCK_SSL_CTX, - "mod.rs\0".as_ptr() as *const _, - line!() as libc::c_int, - ); - 0 - } - - pub unsafe fn SSL_SESSION_get_master_key( - session: *const ffi::SSL_SESSION, - out: *mut c_uchar, - mut outlen: size_t, - ) -> size_t { - if outlen == 0 { - return (*session).master_key_length as size_t; - } - if outlen > (*session).master_key_length as size_t { - outlen = (*session).master_key_length as size_t; - } - ptr::copy_nonoverlapping((*session).master_key.as_ptr(), out, outlen); - outlen - } - - pub fn tls_method() -> *const ffi::SSL_METHOD { - unsafe { ffi::SSLv23_method() } - } - - pub fn dtls_method() -> *const ffi::SSL_METHOD { - unsafe { ffi::DTLSv1_method() } - } - - pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int { - (*s).server - } - - pub unsafe fn SSL_SESSION_up_ref(ses: *mut ffi::SSL_SESSION) -> c_int { - ffi::CRYPTO_add_lock( - &mut (*ses).references, - 1, - ffi::CRYPTO_LOCK_SSL_CTX, - "mod.rs\0".as_ptr() as *const _, - line!() as libc::c_int, - ); - 0 + #[allow(bad_style)] + pub unsafe fn SSL_SESSION_get_master_key( + session: *const ffi::SSL_SESSION, + out: *mut c_uchar, + mut outlen: usize, + ) -> usize { + if outlen == 0 { + return (*session).master_key_length as usize; + } + if outlen > (*session).master_key_length as usize { + outlen = (*session).master_key_length as usize; + } + ptr::copy_nonoverlapping((*session).master_key.as_ptr(), out, outlen); + outlen + } + + #[allow(bad_style)] + pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int { + (*s).server + } + + #[allow(bad_style)] + pub unsafe fn SSL_SESSION_up_ref(ses: *mut ffi::SSL_SESSION) -> c_int { + ffi::CRYPTO_add_lock( + &mut (*ses).references, + 1, + ffi::CRYPTO_LOCK_SSL_CTX, + "mod.rs\0".as_ptr() as *const _, + line!() as c_int, + ); + 0 + } } } diff --git a/openssl/src/ssl/test.rs b/openssl/src/ssl/test.rs index b90199f0..f2dc4a65 100644 --- a/openssl/src/ssl/test.rs +++ b/openssl/src/ssl/test.rs @@ -1063,7 +1063,7 @@ fn tmp_dh_callback() { } #[test] -#[cfg(any(all(ossl101, not(libressl)), ossl102))] +#[cfg(all(ossl101, not(ossl110)))] fn tmp_ecdh_callback() { use ec::EcKey; use nid::Nid; @@ -1137,7 +1137,7 @@ fn tmp_dh_callback_ssl() { } #[test] -#[cfg(any(all(ossl101, not(libressl)), ossl102))] +#[cfg(all(ossl101, not(ossl110)))] fn tmp_ecdh_callback_ssl() { use ec::EcKey; use nid::Nid; diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs index d8589352..4d5c0a13 100644 --- a/openssl/src/stack.rs +++ b/openssl/src/stack.rs @@ -1,23 +1,30 @@ -use foreign_types::{ForeignTypeRef, ForeignType, Opaque}; +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; use libc::c_int; use std::borrow::Borrow; use std::convert::AsRef; use std::iter; use std::marker::PhantomData; use std::mem; -use ffi; -use {cvt, cvt_p}; use error::ErrorStack; use std::ops::{Deref, DerefMut, Index, IndexMut}; +use {cvt, cvt_p}; -#[cfg(ossl10x)] -use ffi::{sk_pop as OPENSSL_sk_pop, sk_free as OPENSSL_sk_free, sk_num as OPENSSL_sk_num, - sk_value as OPENSSL_sk_value, _STACK as OPENSSL_STACK, - sk_new_null as OPENSSL_sk_new_null, sk_push as OPENSSL_sk_push}; -#[cfg(ossl110)] -use ffi::{OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value, OPENSSL_STACK, - OPENSSL_sk_new_null, OPENSSL_sk_push}; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ + OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value, OPENSSL_STACK, + OPENSSL_sk_new_null, OPENSSL_sk_push, + }; + } else { + use ffi::{ + sk_pop as OPENSSL_sk_pop, sk_free as OPENSSL_sk_free, sk_num as OPENSSL_sk_num, + sk_value as OPENSSL_sk_value, _STACK as OPENSSL_STACK, + sk_new_null as OPENSSL_sk_new_null, sk_push as OPENSSL_sk_push, + }; + } +} /// Trait implemented by types which can be placed in a stack. /// @@ -87,7 +94,7 @@ impl ForeignType for Stack { assert!( !ptr.is_null(), "Must not instantiate a Stack from a null-ptr - use Stack::new() in \ - that case" + that case" ); Stack(ptr) } @@ -218,9 +225,7 @@ impl StackRef { /// Pushes a value onto the top of the stack. pub fn push(&mut self, data: T) -> Result<(), ErrorStack> { unsafe { - cvt( - OPENSSL_sk_push(self.as_stack(), data.as_ptr() as *mut _), - )?; + cvt(OPENSSL_sk_push(self.as_stack(), data.as_ptr() as *mut _))?; mem::forget(data); Ok(()) } diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs index 904fb8de..33655874 100644 --- a/openssl/src/symm.rs +++ b/openssl/src/symm.rs @@ -52,14 +52,14 @@ //! println!("Decrypted: '{}'", output_string); //! ``` +use ffi; +use libc::c_int; use std::cmp; use std::ptr; -use libc::c_int; -use ffi; -use {cvt, cvt_p}; use error::ErrorStack; use nid::Nid; +use {cvt, cvt_p}; #[derive(Copy, Clone)] pub enum Mode { @@ -718,34 +718,31 @@ pub fn decrypt_aead( Ok(out) } -#[cfg(ossl110)] -use ffi::{EVP_CIPHER_block_size, EVP_CIPHER_iv_length, EVP_CIPHER_key_length}; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{EVP_CIPHER_block_size, EVP_CIPHER_iv_length, EVP_CIPHER_key_length}; + } else { + #[allow(bad_style)] + pub unsafe fn EVP_CIPHER_iv_length(ptr: *const ffi::EVP_CIPHER) -> c_int { + (*ptr).iv_len + } -#[cfg(ossl10x)] -#[allow(bad_style)] -mod compat { - use libc::c_int; - use ffi::EVP_CIPHER; + #[allow(bad_style)] + pub unsafe fn EVP_CIPHER_block_size(ptr: *const ffi::EVP_CIPHER) -> c_int { + (*ptr).block_size + } - pub unsafe fn EVP_CIPHER_iv_length(ptr: *const EVP_CIPHER) -> c_int { - (*ptr).iv_len - } - - pub unsafe fn EVP_CIPHER_block_size(ptr: *const EVP_CIPHER) -> c_int { - (*ptr).block_size - } - - pub unsafe fn EVP_CIPHER_key_length(ptr: *const EVP_CIPHER) -> c_int { - (*ptr).key_len + #[allow(bad_style)] + pub unsafe fn EVP_CIPHER_key_length(ptr: *const ffi::EVP_CIPHER) -> c_int { + (*ptr).key_len + } } } -#[cfg(ossl10x)] -use self::compat::*; #[cfg(test)] mod tests { - use hex::{self, FromHex}; use super::*; + use hex::{self, FromHex}; // Test vectors from FIPS-197: // http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf diff --git a/openssl/src/version.rs b/openssl/src/version.rs index 7254d7ba..dc8508d1 100644 --- a/openssl/src/version.rs +++ b/openssl/src/version.rs @@ -13,15 +13,21 @@ use std::ffi::CStr; -#[cfg(ossl10x)] -use ffi::{SSLEAY_VERSION as OPENSSL_VERSION, SSLEAY_CFLAGS as OPENSSL_CFLAGS, - SSLEAY_BUILT_ON as OPENSSL_BUILT_ON, SSLEAY_PLATFORM as OPENSSL_PLATFORM, - SSLEAY_DIR as OPENSSL_DIR, SSLeay as OpenSSL_version_num, - SSLeay_version as OpenSSL_version}; - -#[cfg(ossl110)] -use ffi::{OPENSSL_VERSION, OPENSSL_CFLAGS, OPENSSL_BUILT_ON, OPENSSL_PLATFORM, OPENSSL_DIR, - OpenSSL_version_num, OpenSSL_version}; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ + OPENSSL_VERSION, OPENSSL_CFLAGS, OPENSSL_BUILT_ON, OPENSSL_PLATFORM, OPENSSL_DIR, + OpenSSL_version_num, OpenSSL_version, + }; + } else { + use ffi::{ + SSLEAY_VERSION as OPENSSL_VERSION, SSLEAY_CFLAGS as OPENSSL_CFLAGS, + SSLEAY_BUILT_ON as OPENSSL_BUILT_ON, SSLEAY_PLATFORM as OPENSSL_PLATFORM, + SSLEAY_DIR as OPENSSL_DIR, SSLeay as OpenSSL_version_num, + SSLeay_version as OpenSSL_version, + }; + } +} /// OPENSSL_VERSION_NUMBER is a numeric release version identifier: /// @@ -51,7 +57,6 @@ pub fn number() -> i64 { unsafe { OpenSSL_version_num() 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 { diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index c1ae3b16..19760f25 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -7,9 +7,9 @@ //! Internet protocols, including SSL/TLS, which is the basis for HTTPS, //! the secure protocol for browsing the web. -use libc::{c_int, c_long}; use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::{c_int, c_long}; use std::error::Error; use std::ffi::{CStr, CString}; use std::fmt; @@ -20,7 +20,6 @@ use std::ptr; use std::slice; use std::str; -use {cvt, cvt_n, cvt_p}; use asn1::{Asn1BitStringRef, Asn1IntegerRef, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef}; use bio::MemBioSlice; use conf::ConfRef; @@ -29,18 +28,12 @@ use ex_data::Index; use hash::MessageDigest; use nid::Nid; use pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public}; +use ssl::SslRef; use stack::{Stack, StackRef, Stackable}; use string::OpensslString; -use ssl::SslRef; +use {cvt, cvt_n, cvt_p}; -#[cfg(ossl10x)] -use ffi::{ASN1_STRING_data, X509_STORE_CTX_get_chain, X509_set_notAfter, X509_set_notBefore}; -#[cfg(ossl110)] -use ffi::{ASN1_STRING_get0_data as ASN1_STRING_data, - X509_STORE_CTX_get0_chain as X509_STORE_CTX_get_chain, - X509_set1_notAfter as X509_set_notAfter, X509_set1_notBefore as X509_set_notBefore}; - -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] pub mod verify; pub mod extension; @@ -215,7 +208,7 @@ impl X509StoreContextRef { /// [`X509_STORE_CTX_get0_chain`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get0_chain.html pub fn chain(&self) -> Option<&StackRef> { unsafe { - let chain = X509_STORE_CTX_get_chain(self.as_ptr()); + let chain = X509_STORE_CTX_get0_chain(self.as_ptr()); if chain.is_null() { None @@ -240,12 +233,12 @@ impl X509Builder { /// Sets the notAfter constraint on the certificate. pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> { - unsafe { cvt(X509_set_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) } + unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) } } /// Sets the notBefore constraint on the certificate. pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> { - unsafe { cvt(X509_set_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) } + unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) } } /// Sets the version of the certificate. @@ -474,7 +467,7 @@ impl X509Ref { /// Returns the certificate's Not After validity period. pub fn not_after(&self) -> &Asn1TimeRef { unsafe { - let date = compat::X509_get_notAfter(self.as_ptr()); + let date = X509_getm_notAfter(self.as_ptr()); assert!(!date.is_null()); Asn1TimeRef::from_ptr(date) } @@ -483,7 +476,7 @@ impl X509Ref { /// Returns the certificate's Not Before validity period. pub fn not_before(&self) -> &Asn1TimeRef { unsafe { - let date = compat::X509_get_notBefore(self.as_ptr()); + let date = X509_getm_notBefore(self.as_ptr()); assert!(!date.is_null()); Asn1TimeRef::from_ptr(date) } @@ -493,7 +486,7 @@ impl X509Ref { pub fn signature(&self) -> &Asn1BitStringRef { unsafe { let mut signature = ptr::null(); - compat::X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr()); + X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr()); assert!(!signature.is_null()); Asn1BitStringRef::from_ptr(signature as *mut _) } @@ -503,7 +496,7 @@ impl X509Ref { pub fn signature_algorithm(&self) -> &X509AlgorithmRef { unsafe { let mut algor = ptr::null(); - compat::X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr()); + X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr()); assert!(!algor.is_null()); X509AlgorithmRef::from_ptr(algor as *mut _) } @@ -564,7 +557,7 @@ impl ToOwned for X509Ref { fn to_owned(&self) -> X509 { unsafe { - compat::X509_up_ref(self.as_ptr()); + X509_up_ref(self.as_ptr()); X509::from_ptr(self.as_ptr()) } } @@ -1054,7 +1047,7 @@ impl X509ReqRef { /// /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_version.html pub fn version(&self) -> i32 { - unsafe { compat::X509_REQ_get_version(self.as_ptr()) as i32 } + unsafe { X509_REQ_get_version(self.as_ptr()) as i32 } } /// Returns the subject name of the certificate request. @@ -1064,7 +1057,7 @@ impl X509ReqRef { /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_subject_name.html pub fn subject_name(&self) -> &X509NameRef { unsafe { - let name = compat::X509_REQ_get_subject_name(self.as_ptr()); + let name = X509_REQ_get_subject_name(self.as_ptr()); assert!(!name.is_null()); X509NameRef::from_ptr(name) } @@ -1172,7 +1165,7 @@ impl GeneralNameRef { return None; } - let ptr = ASN1_STRING_data((*self.as_ptr()).d as *mut _); + let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d as *mut _); let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _); let slice = slice::from_raw_parts(ptr as *const u8, len as usize); @@ -1205,7 +1198,7 @@ impl GeneralNameRef { return None; } - let ptr = ASN1_STRING_data((*self.as_ptr()).d as *mut _); + let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d as *mut _); let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _); Some(slice::from_raw_parts(ptr as *const u8, len as usize)) @@ -1232,79 +1225,86 @@ impl X509AlgorithmRef { pub fn object(&self) -> &Asn1ObjectRef { unsafe { let mut oid = ptr::null(); - compat::X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr()); + X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr()); assert!(!oid.is_null()); Asn1ObjectRef::from_ptr(oid as *mut _) } } } -#[cfg(ossl110)] -mod compat { - pub use ffi::X509_getm_notAfter as X509_get_notAfter; - pub use ffi::X509_getm_notBefore as X509_get_notBefore; - pub use ffi::X509_up_ref; - pub use ffi::X509_REQ_get_version; - pub use ffi::X509_REQ_get_subject_name; - pub use ffi::X509_get0_signature; - pub use ffi::X509_ALGOR_get0; -} +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ + X509_ALGOR_get0, X509_REQ_get_subject_name, X509_REQ_get_version, + X509_get0_signature, X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, + ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter, + X509_set1_notBefore, + }; + } else { + use ffi::{ + ASN1_STRING_data as ASN1_STRING_get0_data, + X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain, + X509_set_notAfter as X509_set1_notAfter, + X509_set_notBefore as X509_set1_notBefore, + }; -#[cfg(ossl10x)] -#[allow(bad_style)] -mod compat { - use libc::{c_int, c_void}; - use ffi; - - pub unsafe fn X509_get_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { - (*(*(*x).cert_info).validity).notAfter - } - - pub unsafe fn X509_get_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { - (*(*(*x).cert_info).validity).notBefore - } - - pub unsafe fn X509_up_ref(x: *mut ffi::X509) { - ffi::CRYPTO_add_lock( - &mut (*x).references, - 1, - ffi::CRYPTO_LOCK_X509, - "mod.rs\0".as_ptr() as *const _, - line!() as c_int, - ); - } - - pub unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long { - ::ffi::ASN1_INTEGER_get((*(*x).req_info).version) - } - - pub unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME { - (*(*x).req_info).subject - } - - pub unsafe fn X509_get0_signature( - psig: *mut *const ffi::ASN1_BIT_STRING, - palg: *mut *const ffi::X509_ALGOR, - x: *const ffi::X509, - ) { - if !psig.is_null() { - *psig = (*x).signature; + #[allow(bad_style)] + unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { + (*(*(*x).cert_info).validity).notAfter } - if !palg.is_null() { - *palg = (*x).sig_alg; - } - } - pub unsafe fn X509_ALGOR_get0( - paobj: *mut *const ffi::ASN1_OBJECT, - pptype: *mut c_int, - pval: *mut *mut c_void, - alg: *const ffi::X509_ALGOR, - ) { - if !paobj.is_null() { - *paobj = (*alg).algorithm; + #[allow(bad_style)] + unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { + (*(*(*x).cert_info).validity).notBefore + } + + #[allow(bad_style)] + unsafe fn X509_up_ref(x: *mut ffi::X509) { + ffi::CRYPTO_add_lock( + &mut (*x).references, + 1, + ffi::CRYPTO_LOCK_X509, + "mod.rs\0".as_ptr() as *const _, + line!() as c_int, + ); + } + + #[allow(bad_style)] + unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long { + ffi::ASN1_INTEGER_get((*(*x).req_info).version) + } + + #[allow(bad_style)] + unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME { + (*(*x).req_info).subject + } + + #[allow(bad_style)] + unsafe fn X509_get0_signature( + psig: *mut *const ffi::ASN1_BIT_STRING, + palg: *mut *const ffi::X509_ALGOR, + x: *const ffi::X509, + ) { + if !psig.is_null() { + *psig = (*x).signature; + } + if !palg.is_null() { + *palg = (*x).sig_alg; + } + } + + #[allow(bad_style)] + unsafe fn X509_ALGOR_get0( + paobj: *mut *const ffi::ASN1_OBJECT, + pptype: *mut c_int, + pval: *mut *mut ::libc::c_void, + alg: *const ffi::X509_ALGOR, + ) { + if !paobj.is_null() { + *paobj = (*alg).algorithm; + } + assert!(pptype.is_null()); + assert!(pval.is_null()); } - assert!(pptype.is_null()); - assert!(pval.is_null()); } } diff --git a/openssl/src/x509/verify.rs b/openssl/src/x509/verify.rs index b90c8f58..2eabe38c 100644 --- a/openssl/src/x509/verify.rs +++ b/openssl/src/x509/verify.rs @@ -1,6 +1,6 @@ -use libc::c_uint; use ffi; use foreign_types::ForeignTypeRef; +use libc::c_uint; use std::net::IpAddr; use cvt; From 4c1fdf1d81e20ee2130e883bb9065af0d1d4de2a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 May 2018 12:52:49 -0700 Subject: [PATCH 08/33] Support ALPN on libressl Closes #690 --- openssl-sys/src/lib.rs | 8 ++++---- openssl/src/ssl/callbacks.rs | 9 ++++++--- openssl/src/ssl/mod.rs | 19 ++++++++++--------- openssl/src/ssl/test.rs | 10 +++++----- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 0f6a4483..04a50855 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -2614,14 +2614,14 @@ extern "C" { ) -> *mut SSL_SESSION; pub fn i2d_SSL_SESSION(s: *mut SSL_SESSION, pp: *mut *mut c_uchar) -> c_int; - #[cfg(ossl102)] + #[cfg(any(ossl102, libressl261))] pub fn SSL_CTX_set_alpn_protos(s: *mut SSL_CTX, data: *const c_uchar, len: c_uint) -> c_int; - #[cfg(ossl102)] + #[cfg(any(ossl102, libressl261))] pub fn SSL_set_alpn_protos(s: *mut SSL, data: *const c_uchar, len: c_uint) -> c_int; // FIXME should take an Option - #[cfg(ossl102)] + #[cfg(any(ossl102, libressl261))] pub fn SSL_CTX_set_alpn_select_cb( ssl: *mut SSL_CTX, cb: extern "C" fn( @@ -2634,7 +2634,7 @@ extern "C" { ) -> c_int, arg: *mut c_void, ); - #[cfg(ossl102)] + #[cfg(any(ossl102, libressl261))] pub fn SSL_get0_alpn_selected(s: *const SSL, data: *mut *const c_uchar, len: *mut c_uint); pub fn X509_add_ext(x: *mut X509, ext: *mut X509_EXTENSION, loc: c_int) -> c_int; diff --git a/openssl/src/ssl/callbacks.rs b/openssl/src/ssl/callbacks.rs index 6ec9aef9..b23c60e7 100644 --- a/openssl/src/ssl/callbacks.rs +++ b/openssl/src/ssl/callbacks.rs @@ -1,9 +1,12 @@ use ffi; use foreign_types::ForeignType; use foreign_types::ForeignTypeRef; +#[cfg(not(osslconf = "OPENSSL_NO_PSK"))] +use libc::c_char; #[cfg(ossl111)] use libc::size_t; -use libc::{c_char, c_int, c_uchar, c_uint, c_void}; +use libc::{c_int, c_uchar, c_uint, c_void}; +#[cfg(not(osslconf = "OPENSSL_NO_PSK"))] use std::ffi::CStr; use std::mem; use std::ptr; @@ -17,7 +20,7 @@ use dh::Dh; use ec::EcKey; use error::ErrorStack; use pkey::Params; -#[cfg(ossl102)] +#[cfg(any(ossl102, libressl261))] use ssl::AlpnError; #[cfg(ossl111)] use ssl::ExtensionContext; @@ -130,7 +133,7 @@ where } } -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] pub extern "C" fn raw_alpn_select( ssl: *mut ffi::SSL, out: *mut *const c_uchar, diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index ce9c4b1d..08475888 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -85,6 +85,7 @@ use error::ErrorStack; use ex_data::Index; #[cfg(ossl111)] use hash::MessageDigest; +#[cfg(ossl110)] use nid::Nid; use pkey::{HasPrivate, PKeyRef, Params, Private}; use ssl::bio::BioMethod; @@ -506,12 +507,12 @@ impl SslAlert { /// An error returned from an ALPN selection callback. /// -/// Requires OpenSSL 1.0.2 or newer. -#[cfg(any(ossl102, ossl110))] +/// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. +#[cfg(any(ossl102, libressl261))] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct AlpnError(c_int); -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] impl AlpnError { /// Terminate the handshake with a fatal alert. /// @@ -1109,10 +1110,10 @@ impl SslContextBuilder { /// /// This corresponds to [`SSL_CTX_set_alpn_protos`]. /// - /// Requires OpenSSL 1.0.2 or newer. + /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. /// /// [`SSL_CTX_set_alpn_protos`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_alpn_protos.html - #[cfg(any(ossl102, ossl110))] + #[cfg(any(ossl102, libressl261))] pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> { unsafe { assert!(protocols.len() <= c_uint::max_value() as usize); @@ -1140,12 +1141,12 @@ impl SslContextBuilder { /// /// This corresponds to [`SSL_CTX_set_alpn_select_cb`]. /// - /// Requires OpenSSL 1.0.2 or newer. + /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. /// /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos /// [`select_next_proto`]: fn.select_next_proto.html /// [`SSL_CTX_set_alpn_select_cb`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_alpn_protos.html - #[cfg(any(ossl102, ossl110))] + #[cfg(any(ossl102, libressl261))] pub fn set_alpn_select_callback(&mut self, callback: F) where F: for<'a> Fn(&mut SslRef, &'a [u8]) -> Result<&'a [u8], AlpnError> + 'static + Sync + Send, @@ -2283,12 +2284,12 @@ impl SslRef { /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client /// to interpret it. /// - /// Requires OpenSSL 1.0.2 or newer. + /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. /// /// This corresponds to [`SSL_get0_alpn_selected`]. /// /// [`SSL_get0_alpn_selected`]: https://www.openssl.org/docs/manmaster/man3/SSL_get0_next_proto_negotiated.html - #[cfg(any(ossl102, ossl110))] + #[cfg(any(ossl102, libressl261))] pub fn selected_alpn_protocol(&self) -> Option<&[u8]> { unsafe { let mut data: *const c_uchar = ptr::null(); diff --git a/openssl/src/ssl/test.rs b/openssl/src/ssl/test.rs index f2dc4a65..0d418d2c 100644 --- a/openssl/src/ssl/test.rs +++ b/openssl/src/ssl/test.rs @@ -481,7 +481,7 @@ fn test_state() { /// Tests that connecting with the client using ALPN, but the server not does not /// break the existing connection behavior. #[test] -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] fn test_connect_with_unilateral_alpn() { let (_s, stream) = Server::new(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); @@ -503,7 +503,7 @@ fn test_connect_with_unilateral_alpn() { /// Tests that when both the client as well as the server use ALPN and their /// lists of supported protocols have an overlap, the correct protocol is chosen. #[test] -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] fn test_connect_with_alpn_successful_multiple_matching() { let (_s, stream) = Server::new_alpn(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); @@ -526,7 +526,7 @@ fn test_connect_with_alpn_successful_multiple_matching() { /// lists of supported protocols have an overlap -- with only ONE protocol /// being valid for both. #[test] -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] fn test_connect_with_alpn_successful_single_match() { let (_s, stream) = Server::new_alpn(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); @@ -548,7 +548,7 @@ fn test_connect_with_alpn_successful_single_match() { /// Tests that when the `SslStream` is created as a server stream, the protocols /// are correctly advertised to the client. #[test] -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] fn test_alpn_server_advertise_multiple() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let localhost = listener.local_addr().unwrap(); @@ -624,7 +624,7 @@ fn test_alpn_server_select_none_fatal() { } #[test] -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] fn test_alpn_server_select_none() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let localhost = listener.local_addr().unwrap(); From 3ab1cc7a8f259ecc858bbc6fe28d9611802d0591 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 May 2018 15:24:38 -0700 Subject: [PATCH 09/33] Make Stack Sync + Send --- openssl/src/stack.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs index 4d5c0a13..ac1e2a13 100644 --- a/openssl/src/stack.rs +++ b/openssl/src/stack.rs @@ -40,15 +40,8 @@ pub trait Stackable: ForeignType { /// An owned stack of `T`. pub struct Stack(*mut T::StackType); -impl Stack { - pub fn new() -> Result, ErrorStack> { - unsafe { - ffi::init(); - let ptr = cvt_p(OPENSSL_sk_new_null())?; - Ok(Stack(ptr as *mut _)) - } - } -} +unsafe impl Send for Stack {} +unsafe impl Sync for Stack {} impl Drop for Stack { fn drop(&mut self) { @@ -59,6 +52,16 @@ impl Drop for Stack { } } +impl Stack { + pub fn new() -> Result, ErrorStack> { + unsafe { + ffi::init(); + let ptr = cvt_p(OPENSSL_sk_new_null())?; + Ok(Stack(ptr as *mut _)) + } + } +} + impl iter::IntoIterator for Stack { type IntoIter = IntoIter; type Item = T; @@ -164,6 +167,9 @@ impl ExactSizeIterator for IntoIter {} pub struct StackRef(Opaque, PhantomData); +unsafe impl Send for StackRef {} +unsafe impl Sync for StackRef {} + impl ForeignTypeRef for StackRef { type CType = T::StackType; } From f0347fbce8b09754bedd187cbb8a9c12d17ac92d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 May 2018 19:37:19 -0700 Subject: [PATCH 10/33] Improve error Display impls --- openssl/src/ssl/error.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/openssl/src/ssl/error.rs b/openssl/src/ssl/error.rs index 18e44cd6..b7e29c15 100644 --- a/openssl/src/ssl/error.rs +++ b/openssl/src/ssl/error.rs @@ -99,17 +99,18 @@ impl fmt::Display for Error { Some(_) => fmt.write_str("a nonblocking read call would have blocked"), None => fmt.write_str("the operation should be retried"), }, + ErrorCode::WANT_WRITE => match self.io_error() { + Some(_) => fmt.write_str("a nonblocking write call would have blocked"), + None => fmt.write_str("the operation should be retried"), + }, ErrorCode::SYSCALL => match self.io_error() { - Some(err) => write!(fmt, "the inner stream returned an error: {}", err), + Some(err) => write!(fmt, "{}", err), None => fmt.write_str("unexpected EOF"), }, - ErrorCode::SSL => { - fmt.write_str("OpenSSL error")?; - if let Some(ref err) = self.ssl_error() { - write!(fmt, ": {}", err)? - } - Ok(()) - } + ErrorCode::SSL => match self.ssl_error() { + Some(e) => write!(fmt, "{}", e), + None => fmt.write_str("OpenSSL error"), + }, ErrorCode(code) => write!(fmt, "unknown error code {}", code), } } From a2be3535b59534216936d00bdc8297b0f6c6c6c1 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 May 2018 20:43:33 -0700 Subject: [PATCH 11/33] Changelog --- CHANGELOG.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0734265..5d9bd633 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,28 @@ ## [Unreleased] +## [v0.10.8] - 2018-05-20 + +### Fixed + +* `openssl-sys` will now detect Homebrew-installed OpenSSL when installed to a non-default + directory. +* The `X509_V_ERR_INVALID_CALL`, `X509_V_ERR_STORE_LOOKUP`, and + `X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION` constants in `openssl-sys` are now only present when + building against 1.1.0g and up rather than 1.1.0. +* `SslContextBuilder::max_proto_version` and `SslContextBuilder::min_proto_version` have been moved + to `SslContextRef` and are only present when building against 1.1.0g and up rather than 1.1.0. + +### Added + +* Added `CmsContentInfo::sign`. +* Added `Clone` and `ToOwned` implementations to `Rsa` and `RsaRef` respectively. +* The `min_proto_version` and `max_proto_version` methods are available when linking against + LibreSSL 2.6.1 and up in addition to OpenSSL. +* `X509VerifyParam` is available when linking against LibreSSL 2.6.1 and up in addition to OpenSSL. +* ALPN support is available when linking against LibreSSL 2.6.1 and up in addition to OpenSSL. +* `Stack` and `StackRef` are now `Sync` and `Send`. + ## [v0.10.7] - 2018-04-30 ### Added @@ -183,7 +205,8 @@ Look at the [release tags] for information about older releases. -[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.7...master +[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.8...master +[v0.10.8]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.8...openssl-v0.10.8 [v0.10.7]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.6...openssl-v0.10.7 [v0.10.6]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.5...openssl-v0.10.6 [v0.10.5]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.4...openssl-v0.10.5 From b976b5fd52b62ecbd447551c562c2524f7f071da Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 May 2018 20:47:00 -0700 Subject: [PATCH 12/33] Move proto version accessors to SslContextRef Add a Derf impl for SslContextBuilder so existing use still works. --- openssl/src/ssl/mod.rs | 96 +++++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 08475888..e62c1dc9 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1057,50 +1057,6 @@ impl SslContextBuilder { } } - /// Gets the minimum supported protocol version. - /// - /// A value of `None` indicates that all versions down the the lowest version supported by - /// OpenSSL are enabled. - /// - /// This corresponds to [`SSL_CTX_get_min_proto_version`]. - /// - /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. - /// - /// [`SSL_CTX_get_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html - #[cfg(any(ossl110g, libressl270))] - pub fn min_proto_version(&mut self) -> Option { - unsafe { - let r = ffi::SSL_CTX_get_min_proto_version(self.as_ptr()); - if r == 0 { - None - } else { - Some(SslVersion(r)) - } - } - } - - /// Gets the maximum supported protocol version. - /// - /// A value of `None` indicates that all versions down the the highest version supported by - /// OpenSSL are enabled. - /// - /// This corresponds to [`SSL_CTX_get_max_proto_version`]. - /// - /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. - /// - /// [`SSL_CTX_get_max_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html - #[cfg(any(ossl110g, libressl270))] - pub fn max_proto_version(&mut self) -> Option { - unsafe { - let r = ffi::SSL_CTX_get_max_proto_version(self.as_ptr()); - if r == 0 { - None - } else { - Some(SslVersion(r)) - } - } - } - /// Sets the protocols to sent to the server for Application Layer Protocol Negotiation (ALPN). /// /// The input must be in ALPN "wire format". It consists of a sequence of supported protocol @@ -1496,6 +1452,14 @@ impl SslContextBuilder { } } +impl Deref for SslContextBuilder { + type Target = SslContextRef; + + fn deref(&self) -> &SslContextRef { + &self.0 + } +} + foreign_type_and_impl_send_sync! { type CType = ffi::SSL_CTX; fn drop = ffi::SSL_CTX_free; @@ -1644,6 +1608,50 @@ impl SslContextRef { } } } + + /// Gets the minimum supported protocol version. + /// + /// A value of `None` indicates that all versions down the the lowest version supported by + /// OpenSSL are enabled. + /// + /// This corresponds to [`SSL_CTX_get_min_proto_version`]. + /// + /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. + /// + /// [`SSL_CTX_get_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html + #[cfg(any(ossl110g, libressl270))] + pub fn min_proto_version(&self) -> Option { + unsafe { + let r = ffi::SSL_CTX_get_min_proto_version(self.as_ptr()); + if r == 0 { + None + } else { + Some(SslVersion(r)) + } + } + } + + /// Gets the maximum supported protocol version. + /// + /// A value of `None` indicates that all versions down the the highest version supported by + /// OpenSSL are enabled. + /// + /// This corresponds to [`SSL_CTX_get_max_proto_version`]. + /// + /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. + /// + /// [`SSL_CTX_get_max_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html + #[cfg(any(ossl110g, libressl270))] + pub fn max_proto_version(&self) -> Option { + unsafe { + let r = ffi::SSL_CTX_get_max_proto_version(self.as_ptr()); + if r == 0 { + None + } else { + Some(SslVersion(r)) + } + } + } } /// Information about the state of a cipher. From 7a7f98a32c4b7d9bc4b9b6d60e13764a0e4e6d7e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 May 2018 20:55:20 -0700 Subject: [PATCH 13/33] Revert "Move proto version accessors to SslContextRef" --- openssl/src/ssl/mod.rs | 96 +++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 52 deletions(-) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index e62c1dc9..08475888 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1057,6 +1057,50 @@ impl SslContextBuilder { } } + /// Gets the minimum supported protocol version. + /// + /// A value of `None` indicates that all versions down the the lowest version supported by + /// OpenSSL are enabled. + /// + /// This corresponds to [`SSL_CTX_get_min_proto_version`]. + /// + /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. + /// + /// [`SSL_CTX_get_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html + #[cfg(any(ossl110g, libressl270))] + pub fn min_proto_version(&mut self) -> Option { + unsafe { + let r = ffi::SSL_CTX_get_min_proto_version(self.as_ptr()); + if r == 0 { + None + } else { + Some(SslVersion(r)) + } + } + } + + /// Gets the maximum supported protocol version. + /// + /// A value of `None` indicates that all versions down the the highest version supported by + /// OpenSSL are enabled. + /// + /// This corresponds to [`SSL_CTX_get_max_proto_version`]. + /// + /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. + /// + /// [`SSL_CTX_get_max_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html + #[cfg(any(ossl110g, libressl270))] + pub fn max_proto_version(&mut self) -> Option { + unsafe { + let r = ffi::SSL_CTX_get_max_proto_version(self.as_ptr()); + if r == 0 { + None + } else { + Some(SslVersion(r)) + } + } + } + /// Sets the protocols to sent to the server for Application Layer Protocol Negotiation (ALPN). /// /// The input must be in ALPN "wire format". It consists of a sequence of supported protocol @@ -1452,14 +1496,6 @@ impl SslContextBuilder { } } -impl Deref for SslContextBuilder { - type Target = SslContextRef; - - fn deref(&self) -> &SslContextRef { - &self.0 - } -} - foreign_type_and_impl_send_sync! { type CType = ffi::SSL_CTX; fn drop = ffi::SSL_CTX_free; @@ -1608,50 +1644,6 @@ impl SslContextRef { } } } - - /// Gets the minimum supported protocol version. - /// - /// A value of `None` indicates that all versions down the the lowest version supported by - /// OpenSSL are enabled. - /// - /// This corresponds to [`SSL_CTX_get_min_proto_version`]. - /// - /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. - /// - /// [`SSL_CTX_get_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html - #[cfg(any(ossl110g, libressl270))] - pub fn min_proto_version(&self) -> Option { - unsafe { - let r = ffi::SSL_CTX_get_min_proto_version(self.as_ptr()); - if r == 0 { - None - } else { - Some(SslVersion(r)) - } - } - } - - /// Gets the maximum supported protocol version. - /// - /// A value of `None` indicates that all versions down the the highest version supported by - /// OpenSSL are enabled. - /// - /// This corresponds to [`SSL_CTX_get_max_proto_version`]. - /// - /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. - /// - /// [`SSL_CTX_get_max_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html - #[cfg(any(ossl110g, libressl270))] - pub fn max_proto_version(&self) -> Option { - unsafe { - let r = ffi::SSL_CTX_get_max_proto_version(self.as_ptr()); - if r == 0 { - None - } else { - Some(SslVersion(r)) - } - } - } } /// Information about the state of a cipher. From 58c273845fe04a7bc4378beb369a7d477f43144e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 May 2018 20:56:35 -0700 Subject: [PATCH 14/33] Fix changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d9bd633..4b84c4b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,8 +11,8 @@ * The `X509_V_ERR_INVALID_CALL`, `X509_V_ERR_STORE_LOOKUP`, and `X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION` constants in `openssl-sys` are now only present when building against 1.1.0g and up rather than 1.1.0. -* `SslContextBuilder::max_proto_version` and `SslContextBuilder::min_proto_version` have been moved - to `SslContextRef` and are only present when building against 1.1.0g and up rather than 1.1.0. +* `SslContextBuilder::max_proto_version` and `SslContextBuilder::min_proto_version` are only present + when building against 1.1.0g and up rather than 1.1.0. ### Added From 25df3c8b51cedf9dc126bd2f179668002c701816 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 May 2018 21:02:12 -0700 Subject: [PATCH 15/33] Release openssl-sys 0.9.31 --- openssl-sys/Cargo.toml | 2 +- openssl/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 3b76c416..08f838ec 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl-sys" -version = "0.9.30" +version = "0.9.31" authors = ["Alex Crichton ", "Steven Fackler "] license = "MIT" diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 8ce43b3d..e7157136 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -23,7 +23,7 @@ foreign-types = "0.3.1" lazy_static = "1" libc = "0.2" -openssl-sys = { version = "0.9.30", path = "../openssl-sys" } +openssl-sys = { version = "0.9.31", path = "../openssl-sys" } [dev-dependencies] tempdir = "0.3" From b187eb0ee3b3460bcb4069514e1d2b0f22204758 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 May 2018 21:03:16 -0700 Subject: [PATCH 16/33] Release openssl v0.10.8 --- openssl/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index e7157136..00d5e54f 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl" -version = "0.10.7" +version = "0.10.8" authors = ["Steven Fackler "] license = "Apache-2.0" description = "OpenSSL bindings" From 677617bc0bb9185bf90da74b3636b6878a884a0f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 May 2018 21:04:34 -0700 Subject: [PATCH 17/33] Fix changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b84c4b4..6beffb27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -206,7 +206,7 @@ Look at the [release tags] for information about older releases. [Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.8...master -[v0.10.8]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.8...openssl-v0.10.8 +[v0.10.8]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.7...openssl-v0.10.8 [v0.10.7]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.6...openssl-v0.10.7 [v0.10.6]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.5...openssl-v0.10.6 [v0.10.5]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.4...openssl-v0.10.5 From 2e478fdcf47bcb69a098bd6c3ab6227b53d45a24 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Thu, 17 May 2018 15:17:40 -0700 Subject: [PATCH 18/33] Expose early I/O --- openssl-sys/src/lib.rs | 3 ++ openssl-sys/src/openssl/v111.rs | 6 +++ openssl/src/ssl/mod.rs | 90 ++++++++++++++++++++++++++++++++- 3 files changed, 98 insertions(+), 1 deletion(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 61e087d0..a48f6a85 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -2832,4 +2832,7 @@ extern "C" { pub fn EVP_MD_size(md: *const EVP_MD) -> c_int; pub fn EVP_get_cipherbyname(name: *const c_char) -> *const EVP_CIPHER; + + pub fn SSL_set_connect_state(s: *mut SSL); + pub fn SSL_set_accept_state(s: *mut SSL); } diff --git a/openssl-sys/src/openssl/v111.rs b/openssl-sys/src/openssl/v111.rs index 4a3f9560..36682663 100644 --- a/openssl-sys/src/openssl/v111.rs +++ b/openssl-sys/src/openssl/v111.rs @@ -55,6 +55,9 @@ pub const SSL_EXT_TLS1_3_CERTIFICATE: c_uint = 0x1000; pub const SSL_EXT_TLS1_3_NEW_SESSION_TICKET: c_uint = 0x2000; pub const SSL_EXT_TLS1_3_CERTIFICATE_REQUEST: c_uint = 0x4000; +pub const SSL_READ_EARLY_DATA_ERROR: c_int = 0; +pub const SSL_READ_EARLY_DATA_SUCCESS: c_int = 1; +pub const SSL_READ_EARLY_DATA_FINISH: c_int = 2; extern "C" { pub fn SSL_CTX_set_keylog_callback(ctx: *mut ::SSL_CTX, cb: SSL_CTX_keylog_cb_func); @@ -99,4 +102,7 @@ extern "C" { context: *const c_uchar, contextlen: size_t, ) -> c_int; + + pub fn SSL_write_early_data(s: *mut ::SSL, buf: *const c_void, num: size_t, written: *mut size_t) -> c_int; + pub fn SSL_read_early_data(s: *mut ::SSL, buf: *mut c_void, num: size_t, readbytes: *mut size_t) -> c_int; } diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 78ae2267..623db801 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -2500,6 +2500,9 @@ impl SslRef { /// Derives keying material for application use in accordance to RFC 5705. /// + /// This function is only usable with TLSv1.3, wherein there is no distinction between an empty context and no + /// context. Therefore, unlike `export_keying_material`, `context` must always be supplied. + /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_export_keying_material_early`]. @@ -3001,6 +3004,24 @@ where } } + /// Configure as an outgoing stream from a client. + /// + /// This corresponds to [`SSL_set_connect_state`]. + /// + /// [`SSL_set_connect_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_connect_state.html + pub fn set_connect_state(&mut self) { + unsafe { ffi::SSL_set_connect_state(self.inner.ssl.as_ptr()) } + } + + /// Configure as an incoming stream to a server. + /// + /// This corresponds to [`SSL_set_accept_state`]. + /// + /// [`SSL_set_accept_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_accept_state.html + pub fn set_accept_state(&mut self) { + unsafe { ffi::SSL_set_accept_state(self.inner.ssl.as_ptr()) } + } + /// See `Ssl::connect` pub fn connect(self) -> Result, HandshakeError> { let mut stream = self.inner; @@ -3041,7 +3062,74 @@ where } } - // Future work: early IO methods + /// Initiates the handshake. + /// + /// This will fail if `set_accept_state` or `set_connect_state` was not called first. + /// + /// This corresponds to [`SSL_do_handshake`]. + /// + /// [`SSL_do_handshake`]: https://www.openssl.org/docs/manmaster/man3/SSL_do_handshake.html + pub fn handshake(self) -> Result, HandshakeError> { + let mut stream = self.inner; + let ret = unsafe { ffi::SSL_do_handshake(stream.ssl.as_ptr()) }; + if ret > 0 { + Ok(stream) + } else { + let error = stream.make_error(ret); + match error.code() { + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { + Err(HandshakeError::WouldBlock(MidHandshakeSslStream { stream, error })) + } + _ => Err(HandshakeError::Failure(MidHandshakeSslStream { stream, error })), + } + } + } + + /// Read application data transmitted by a client before handshake + /// completion. + /// + /// Useful for reducing latency, but vulnerable to replay attacks. Call + /// `set_accept_state` first. + /// + /// Returns `Ok(0)` if all early data has been read. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_read_early_data`]. + /// + /// [`SSL_read_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_read_early_data.html + #[cfg(ossl111)] + pub fn read_early_data(&mut self, buf: &mut [u8]) -> Result { + let mut read = 0; + let ret = unsafe { ffi::SSL_read_early_data(self.inner.ssl.as_ptr(), buf.as_ptr() as *mut c_void, buf.len(), &mut read) }; + match ret { + ffi::SSL_READ_EARLY_DATA_ERROR => Err(self.inner.make_error(ret)), + ffi::SSL_READ_EARLY_DATA_SUCCESS => Ok(read), + ffi::SSL_READ_EARLY_DATA_FINISH => Ok(0), + _ => unreachable!(), + } + } + + /// Send data to the server without blocking on handshake completion. + /// + /// Useful for reducing latency, but vulnerable to replay attacks. Call + /// `set_connect_state` first. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_write_early_data`]. + /// + /// [`SSL_write_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_write_early_data.html + #[cfg(ossl111)] + pub fn write_early_data(&mut self, buf: &[u8]) -> Result { + let mut written = 0; + let ret = unsafe { ffi::SSL_write_early_data(self.inner.ssl.as_ptr(), buf.as_ptr() as *const c_void, buf.len(), &mut written) }; + if ret > 0 { + Ok(written as usize) + } else { + Err(self.inner.make_error(ret)) + } + } } impl SslStreamBuilder { From c0876cc8c65cf61d99006ce5e502a9a2d1acd70b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 24 May 2018 20:00:28 -0700 Subject: [PATCH 19/33] Add bindings to SSL_get_finished and SSL_get_peer_finished These are used for the tls-unique SCRAM channel binding mode. --- openssl-sys/src/lib.rs | 2 ++ openssl/src/ssl/mod.rs | 52 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index bc8f44e1..fda47fd0 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -2603,6 +2603,8 @@ extern "C" { pub fn SSL_is_server(s: *mut SSL) -> c_int; #[cfg(ossl110f)] pub fn SSL_is_server(s: *const SSL) -> c_int; + pub fn SSL_get_finished(s: *const SSL, buf: *mut c_void, count: size_t) -> size_t; + pub fn SSL_get_peer_finished(s: *const SSL, buf: *mut c_void, count: size_t) -> size_t; pub fn SSL_SESSION_free(s: *mut SSL_SESSION); pub fn SSL_SESSION_get_id(s: *const SSL_SESSION, len: *mut c_uint) -> *const c_uchar; diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 444a50cc..017ba54c 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -2695,6 +2695,29 @@ impl SslRef { pub fn max_early_data(&self) -> u32 { unsafe { ffi::SSL_get_max_early_data(self.as_ptr()) } } + + /// Copies the contents of the last Finished message sent to the peer into the provided buffer. + /// + /// The total size of the message is returned, so this can be used to determine the size of the + /// buffer required. + /// + /// This corresponds to `SSL_get_finished`. + pub fn finished(&self, buf: &mut [u8]) -> usize { + unsafe { ffi::SSL_get_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) } + } + + /// Copies the contents of the last Finished message received from the peer into the provided + /// buffer. + /// + /// The total size of the message is returned, so this can be used to determine the size of the + /// buffer required. + /// + /// This corresponds to `SSL_get_finished`. + pub fn peer_finished(&self, buf: &mut [u8]) -> usize { + unsafe { + ffi::SSL_get_peer_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) + } + } } /// An SSL stream midway through the handshake process. @@ -3080,10 +3103,13 @@ where } else { let error = stream.make_error(ret); match error.code() { - ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { - Err(HandshakeError::WouldBlock(MidHandshakeSslStream { stream, error })) - } - _ => Err(HandshakeError::Failure(MidHandshakeSslStream { stream, error })), + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => Err(HandshakeError::WouldBlock( + MidHandshakeSslStream { stream, error }, + )), + _ => Err(HandshakeError::Failure(MidHandshakeSslStream { + stream, + error, + })), } } } @@ -3104,7 +3130,14 @@ where #[cfg(ossl111)] pub fn read_early_data(&mut self, buf: &mut [u8]) -> Result { let mut read = 0; - let ret = unsafe { ffi::SSL_read_early_data(self.inner.ssl.as_ptr(), buf.as_ptr() as *mut c_void, buf.len(), &mut read) }; + let ret = unsafe { + ffi::SSL_read_early_data( + self.inner.ssl.as_ptr(), + buf.as_ptr() as *mut c_void, + buf.len(), + &mut read, + ) + }; match ret { ffi::SSL_READ_EARLY_DATA_ERROR => Err(self.inner.make_error(ret)), ffi::SSL_READ_EARLY_DATA_SUCCESS => Ok(read), @@ -3126,7 +3159,14 @@ where #[cfg(ossl111)] pub fn write_early_data(&mut self, buf: &[u8]) -> Result { let mut written = 0; - let ret = unsafe { ffi::SSL_write_early_data(self.inner.ssl.as_ptr(), buf.as_ptr() as *const c_void, buf.len(), &mut written) }; + let ret = unsafe { + ffi::SSL_write_early_data( + self.inner.ssl.as_ptr(), + buf.as_ptr() as *const c_void, + buf.len(), + &mut written, + ) + }; if ret > 0 { Ok(written as usize) } else { From 3cd33cdd8bc4e18c01bc1f848de9956758bc37fb Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 24 May 2018 20:18:33 -0700 Subject: [PATCH 20/33] Don't panic on bogus servernames Also add a second version of the method to avoid filtering out non-utf8 names. Closes #930 --- openssl/src/ssl/mod.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 017ba54c..e24c3498 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -2366,14 +2366,38 @@ impl SslRef { /// /// This corresponds to [`SSL_get_servername`]. /// + /// # Note + /// + /// While the SNI specification requires that servernames be valid domain names (and therefore + /// ASCII), OpenSSL does not enforce this restriction. If the servername provided by the client + /// is not valid UTF-8, this function will return `None`. The `servername_raw` method returns + /// the raw bytes and does not have this restriction. + /// /// [`SSL_get_servername`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername.html + // FIXME maybe rethink in 0.11? pub fn servername(&self, type_: NameType) -> Option<&str> { + self.servername_raw(type_) + .and_then(|b| str::from_utf8(b).ok()) + } + + /// Returns the servername sent by the client via Server Name Indication (SNI). + /// + /// It is only useful on the server side. + /// + /// This corresponds to [`SSL_get_servername`]. + /// + /// # Note + /// + /// Unlike `servername`, this method does not require the name be valid UTF-8. + /// + /// [`SSL_get_servername`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername.html + pub fn servername_raw(&self, type_: NameType) -> Option<&[u8]> { unsafe { let name = ffi::SSL_get_servername(self.as_ptr(), type_.0); if name == ptr::null() { None } else { - Some(str::from_utf8(CStr::from_ptr(name as *const _).to_bytes()).unwrap()) + Some(CStr::from_ptr(name as *const _).to_bytes()) } } } From 772e1c003f57cdbc6258580cb2059999aa51b4f2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 24 May 2018 21:06:11 -0700 Subject: [PATCH 21/33] Add some digest support --- openssl-sys/src/lib.rs | 7 +++++++ openssl/src/hash.rs | 31 ++++++++++++++++++++++++++++--- openssl/src/nid.rs | 28 ++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index fda47fd0..e7bd046e 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1453,6 +1453,10 @@ pub unsafe fn BIO_set_retry_write(b: *mut BIO) { BIO_set_flags(b, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY) } +pub unsafe fn EVP_get_digestbynid(type_: c_int) -> *const EVP_MD { + EVP_get_digestbyname(OBJ_nid2sn(type_)) +} + // EVP_PKEY_CTX_ctrl macros pub unsafe fn EVP_PKEY_CTX_set_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad: c_int) -> c_int { EVP_PKEY_CTX_ctrl( @@ -2103,6 +2107,8 @@ extern "C" { no_name: c_int, ) -> c_int; pub fn OBJ_nid2sn(nid: c_int) -> *const c_char; + pub fn OBJ_find_sigid_algs(signid: c_int, pdig_nid: *mut c_int, ppkey_nid: *mut c_int) + -> c_int; pub fn OCSP_BASICRESP_new() -> *mut OCSP_BASICRESP; pub fn OCSP_BASICRESP_free(r: *mut OCSP_BASICRESP); @@ -2840,6 +2846,7 @@ extern "C" { ); pub fn EVP_MD_size(md: *const EVP_MD) -> c_int; + pub fn EVP_get_digestbyname(name: *const c_char) -> *const EVP_MD; pub fn EVP_get_cipherbyname(name: *const c_char) -> *const EVP_CIPHER; pub fn SSL_set_connect_state(s: *mut SSL); diff --git a/openssl/src/hash.rs b/openssl/src/hash.rs index 582a2ada..49797df8 100644 --- a/openssl/src/hash.rs +++ b/openssl/src/hash.rs @@ -4,6 +4,10 @@ use std::io; use std::io::prelude::*; use std::ops::{Deref, DerefMut}; +use error::ErrorStack; +use nid::Nid; +use {cvt, cvt_p}; + cfg_if! { if #[cfg(ossl110)] { use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; @@ -12,9 +16,6 @@ cfg_if! { } } -use error::ErrorStack; -use {cvt, cvt_p}; - #[derive(Copy, Clone)] pub struct MessageDigest(*const ffi::EVP_MD); @@ -23,6 +24,22 @@ impl MessageDigest { MessageDigest(x) } + /// Returns the `MessageDigest` corresponding to an `Nid`. + /// + /// This corresponds to [`EVP_get_digestbynid`]. + /// + /// [`EVP_get_digestbynid`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestInit.html + pub fn from_nid(type_: Nid) -> Option { + unsafe { + let ptr = ffi::EVP_get_digestbynid(type_.as_raw()); + if ptr.is_null() { + None + } else { + Some(MessageDigest(ptr)) + } + } + } + pub fn md5() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_md5()) } } @@ -405,4 +422,12 @@ mod tests { hash_test(MessageDigest::ripemd160(), test); } } + + #[test] + fn from_nid() { + assert_eq!( + MessageDigest::from_nid(Nid::SHA256).unwrap().as_ptr(), + MessageDigest::sha256().as_ptr() + ); + } } diff --git a/openssl/src/nid.rs b/openssl/src/nid.rs index 7c041236..78ffac96 100644 --- a/openssl/src/nid.rs +++ b/openssl/src/nid.rs @@ -1,6 +1,7 @@ //! A collection of numerical identifiers for OpenSSL objects. use ffi; use libc::c_int; +use std::ptr; /// A numerical identifier for an OpenSSL object. /// @@ -42,6 +43,20 @@ impl Nid { self.0 } + /// Returns the `Nid` of the digest algorithm associated with a signature ID. + /// + /// This corresponds to `OBJ_find_sigid_algs`. + pub fn digest_algorithm(&self) -> Option { + unsafe { + let mut digest = 0; + if ffi::OBJ_find_sigid_algs(self.0, &mut digest, ptr::null_mut()) == 1 { + Some(Nid(digest)) + } else { + None + } + } + } + pub const UNDEF: Nid = Nid(ffi::NID_undef); pub const ITU_T: Nid = Nid(ffi::NID_itu_t); pub const CCITT: Nid = Nid(ffi::NID_ccitt); @@ -991,3 +1006,16 @@ impl Nid { pub const AES_192_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_192_cbc_hmac_sha1); pub const AES_256_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_256_cbc_hmac_sha1); } + +#[cfg(test)] +mod test { + use super::Nid; + + #[test] + fn signature_digest() { + assert_eq!( + Nid::SHA256WITHRSAENCRYPTION.digest_algorithm(), + Some(Nid::SHA256) + ); + } +} From a774c0c5f2867b33735bec9e1cb6c9870a5ece08 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 24 May 2018 20:35:06 -0700 Subject: [PATCH 22/33] Rename X509Ref::fingerprint to X509Ref::digest and avoid allocating --- openssl/src/hash.rs | 4 ++-- openssl/src/pkcs12.rs | 27 ++++++++++++++------------- openssl/src/ssl/test.rs | 12 ++++++------ openssl/src/x509/mod.rs | 30 +++++++++++++++++++++--------- openssl/src/x509/tests.rs | 8 ++++---- 5 files changed, 47 insertions(+), 34 deletions(-) diff --git a/openssl/src/hash.rs b/openssl/src/hash.rs index 49797df8..dd4d136c 100644 --- a/openssl/src/hash.rs +++ b/openssl/src/hash.rs @@ -251,8 +251,8 @@ impl Drop for Hasher { /// store the digest data. #[derive(Copy)] pub struct DigestBytes { - buf: [u8; ffi::EVP_MAX_MD_SIZE as usize], - len: usize, + pub(crate) buf: [u8; ffi::EVP_MAX_MD_SIZE as usize], + pub(crate) len: usize, } impl Clone for DigestBytes { diff --git a/openssl/src/pkcs12.rs b/openssl/src/pkcs12.rs index d71a1d82..b98848c8 100644 --- a/openssl/src/pkcs12.rs +++ b/openssl/src/pkcs12.rs @@ -3,15 +3,15 @@ use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; -use std::ptr; use std::ffi::CString; +use std::ptr; -use {cvt, cvt_p}; -use pkey::{HasPrivate, PKey, PKeyRef, Private}; use error::ErrorStack; -use x509::{X509, X509Ref}; -use stack::Stack; use nid::Nid; +use pkey::{HasPrivate, PKey, PKeyRef, Private}; +use stack::Stack; +use x509::{X509, X509Ref}; +use {cvt, cvt_p}; foreign_type_and_impl_send_sync! { type CType = ffi::PKCS12; @@ -172,7 +172,8 @@ impl Pkcs12Builder { let friendly_name = CString::new(friendly_name).unwrap(); let pkey = pkey.as_ptr(); let cert = cert.as_ptr(); - let ca = self.ca + let ca = self + .ca .as_ref() .map(|ca| ca.as_ptr()) .unwrap_or(ptr::null_mut()); @@ -206,11 +207,11 @@ mod test { use hex; use asn1::Asn1Time; - use rsa::Rsa; - use pkey::PKey; use nid::Nid; - use x509::{X509, X509Name}; + use pkey::PKey; + use rsa::Rsa; use x509::extension::KeyUsage; + use x509::{X509, X509Name}; use super::*; @@ -221,14 +222,14 @@ mod test { let parsed = pkcs12.parse("mypass").unwrap(); assert_eq!( - hex::encode(parsed.cert.fingerprint(MessageDigest::sha1()).unwrap()), + hex::encode(parsed.cert.digest(MessageDigest::sha1()).unwrap()), "59172d9313e84459bcff27f967e79e6e9217e584" ); let chain = parsed.chain.unwrap(); assert_eq!(chain.len(), 1); assert_eq!( - hex::encode(chain[0].fingerprint(MessageDigest::sha1()).unwrap()), + hex::encode(chain[0].digest(MessageDigest::sha1()).unwrap()), "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875" ); } @@ -279,8 +280,8 @@ mod test { let parsed = pkcs12.parse("mypass").unwrap(); assert_eq!( - parsed.cert.fingerprint(MessageDigest::sha1()).unwrap(), - cert.fingerprint(MessageDigest::sha1()).unwrap() + &*parsed.cert.digest(MessageDigest::sha1()).unwrap(), + &*cert.digest(MessageDigest::sha1()).unwrap() ); assert!(parsed.pkey.public_eq(&pkey)); } diff --git a/openssl/src/ssl/test.rs b/openssl/src/ssl/test.rs index 0d418d2c..f5ec7b29 100644 --- a/openssl/src/ssl/test.rs +++ b/openssl/src/ssl/test.rs @@ -295,8 +295,8 @@ run_test!(verify_callback_data, |method, stream| { match cert { None => false, Some(cert) => { - let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap(); - fingerprint == node_id + let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); + node_id == &*fingerprint } } }); @@ -323,8 +323,8 @@ run_test!(ssl_verify_callback, |method, stream| { match x509.current_cert() { None => false, Some(cert) => { - let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap(); - fingerprint == node_id + let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); + node_id == &*fingerprint } } }); @@ -424,10 +424,10 @@ run_test!(get_peer_certificate, |method, stream| { let ctx = SslContext::builder(method).unwrap(); let stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap(); let cert = stream.ssl().peer_certificate().unwrap(); - let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap(); + let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; let node_id = Vec::from_hex(node_hash_str).unwrap(); - assert_eq!(node_id, fingerprint) + assert_eq!(node_id, &*fingerprint) }); #[test] diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 19760f25..5c1bb23f 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -25,7 +25,7 @@ use bio::MemBioSlice; use conf::ConfRef; use error::ErrorStack; use ex_data::Index; -use hash::MessageDigest; +use hash::{DigestBytes, MessageDigest}; use nid::Nid; use pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public}; use ssl::SslRef; @@ -447,23 +447,35 @@ impl X509Ref { } } - /// Returns certificate fingerprint calculated using provided hash - pub fn fingerprint(&self, hash_type: MessageDigest) -> Result, ErrorStack> { + /// Returns a digest of the DER representation of the certificate. + /// + /// This corresponds to [`X509_digest`]. + /// + /// [`X509_digest`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_digest.html + pub fn digest(&self, hash_type: MessageDigest) -> Result { unsafe { - let evp = hash_type.as_ptr(); + let mut digest = DigestBytes { + buf: [0; ffi::EVP_MAX_MD_SIZE as usize], + len: ffi::EVP_MAX_MD_SIZE as usize, + }; let mut len = ffi::EVP_MAX_MD_SIZE; - let mut buf = vec![0u8; len as usize]; cvt(ffi::X509_digest( self.as_ptr(), - evp, - buf.as_mut_ptr() as *mut _, + hash_type.as_ptr(), + digest.buf.as_mut_ptr() as *mut _, &mut len, ))?; - buf.truncate(len as usize); - Ok(buf) + digest.len = len as usize; + + Ok(digest) } } + #[deprecated(since = "0.10.9", note = "renamed to digest")] + pub fn fingerprint(&self, hash_type: MessageDigest) -> Result, ErrorStack> { + self.digest(hash_type).map(|b| b.to_vec()) + } + /// Returns the certificate's Not After validity period. pub fn not_after(&self) -> &Asn1TimeRef { unsafe { diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index a3c66e0c..42859c97 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -23,12 +23,12 @@ fn pkey() -> PKey { fn test_cert_loading() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); - let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap(); + let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); let hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; let hash_vec = Vec::from_hex(hash_str).unwrap(); - assert_eq!(fingerprint, hash_vec); + assert_eq!(hash_vec, &*fingerprint); } #[test] @@ -250,11 +250,11 @@ fn test_stack_from_pem() { assert_eq!(certs.len(), 2); assert_eq!( - hex::encode(certs[0].fingerprint(MessageDigest::sha1()).unwrap()), + hex::encode(certs[0].digest(MessageDigest::sha1()).unwrap()), "59172d9313e84459bcff27f967e79e6e9217e584" ); assert_eq!( - hex::encode(certs[1].fingerprint(MessageDigest::sha1()).unwrap()), + hex::encode(certs[1].digest(MessageDigest::sha1()).unwrap()), "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875" ); } From b8de619fbe20dd08849c5364a222d5bc117d9072 Mon Sep 17 00:00:00 2001 From: Marco Huenseler Date: Thu, 24 May 2018 12:01:47 +0200 Subject: [PATCH 23/33] Get Nid string representations --- openssl-sys/src/lib.rs | 1 + openssl/src/nid.rs | 69 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index e7bd046e..f2a77cab 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -2106,6 +2106,7 @@ extern "C" { a: *const ASN1_OBJECT, no_name: c_int, ) -> c_int; + pub fn OBJ_nid2ln(nid: c_int) -> *const c_char; pub fn OBJ_nid2sn(nid: c_int) -> *const c_char; pub fn OBJ_find_sigid_algs(signid: c_int, pdig_nid: *mut c_int, ppkey_nid: *mut c_int) -> c_int; diff --git a/openssl/src/nid.rs b/openssl/src/nid.rs index 78ffac96..ceefece5 100644 --- a/openssl/src/nid.rs +++ b/openssl/src/nid.rs @@ -3,6 +3,9 @@ use ffi; use libc::c_int; use std::ptr; +use std::ffi::CStr; +use std::str; + /// A numerical identifier for an OpenSSL object. /// /// Objects in OpenSSL can have a short name, a long name, and @@ -57,6 +60,38 @@ impl Nid { } } + /// Return the string representation of a `Nid` (long) + /// This corresponds to [`OBJ_nid2ln`] + /// + /// [`OBJ_nid2ln`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_nid2ln.html + pub fn to_long_name(&self) -> Option<&'static str> { + unsafe { + let s = ffi::OBJ_nid2ln(self.0); + if s.is_null() { + None + } + else { + Some(str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()) + } + } + } + + /// Return the string representation of a `Nid` (short) + /// This corresponds to [`OBJ_nid2sn`] + /// + /// [`OBJ_nid2sn`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_nid2sn.html + pub fn to_short_name(&self) -> Option<&'static str> { + unsafe { + let s = ffi::OBJ_nid2sn(self.0); + if s.is_null() { + None + } + else { + Some(str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()) + } + } + } + pub const UNDEF: Nid = Nid(ffi::NID_undef); pub const ITU_T: Nid = Nid(ffi::NID_itu_t); pub const CCITT: Nid = Nid(ffi::NID_ccitt); @@ -1018,4 +1053,38 @@ mod test { Some(Nid::SHA256) ); } + + #[test] + fn test_long_name_conversion() { + let common_name = Nid::COMMONNAME; + let organizational_unit_name = Nid::ORGANIZATIONALUNITNAME; + let aes256_cbc_hmac_sha1 = Nid::AES_256_CBC_HMAC_SHA1; + let id_cmc_lrapopwitness = Nid::ID_CMC_LRAPOPWITNESS; + let ms_ctl_sign = Nid::MS_CTL_SIGN; + let undefined_nid = Nid::from_raw(118); + + assert_eq!(common_name.to_long_name(), Some("commonName")); + assert_eq!(organizational_unit_name.to_long_name(), Some("organizationalUnitName")); + assert_eq!(aes256_cbc_hmac_sha1.to_long_name(), Some("aes-256-cbc-hmac-sha1")); + assert_eq!(id_cmc_lrapopwitness.to_long_name(), Some("id-cmc-lraPOPWitness")); + assert_eq!(ms_ctl_sign.to_long_name(), Some("Microsoft Trust List Signing")); + assert_eq!(undefined_nid.to_long_name(), None); + } + + #[test] + fn test_short_name_conversion() { + let common_name = Nid::COMMONNAME; + let organizational_unit_name = Nid::ORGANIZATIONALUNITNAME; + let aes256_cbc_hmac_sha1 = Nid::AES_256_CBC_HMAC_SHA1; + let id_cmc_lrapopwitness = Nid::ID_CMC_LRAPOPWITNESS; + let ms_ctl_sign = Nid::MS_CTL_SIGN; + let undefined_nid = Nid::from_raw(118); + + assert_eq!(common_name.to_short_name(), Some("CN")); + assert_eq!(organizational_unit_name.to_short_name(), Some("OU")); + assert_eq!(aes256_cbc_hmac_sha1.to_short_name(), Some("AES-256-CBC-HMAC-SHA1")); + assert_eq!(id_cmc_lrapopwitness.to_short_name(), Some("id-cmc-lraPOPWitness")); + assert_eq!(ms_ctl_sign.to_short_name(), Some("msCTLSign")); + assert_eq!(undefined_nid.to_long_name(), None); + } } From 2977f6ed308473869a29d2507c6124778827bd0d Mon Sep 17 00:00:00 2001 From: Marco Huenseler Date: Mon, 28 May 2018 11:57:59 +0200 Subject: [PATCH 24/33] rewrite Nid::{long_name,short_name} to return Results instead of Options --- openssl/src/nid.rs | 51 ++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/openssl/src/nid.rs b/openssl/src/nid.rs index ceefece5..23068406 100644 --- a/openssl/src/nid.rs +++ b/openssl/src/nid.rs @@ -1,11 +1,14 @@ //! A collection of numerical identifiers for OpenSSL objects. use ffi; -use libc::c_int; +use libc::{c_int,c_char}; use std::ptr; use std::ffi::CStr; use std::str; +use error::ErrorStack; +use cvt_p; + /// A numerical identifier for an OpenSSL object. /// /// Objects in OpenSSL can have a short name, a long name, and @@ -64,15 +67,10 @@ impl Nid { /// This corresponds to [`OBJ_nid2ln`] /// /// [`OBJ_nid2ln`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_nid2ln.html - pub fn to_long_name(&self) -> Option<&'static str> { + pub fn long_name(&self) -> Result<&'static str, ErrorStack> { unsafe { - let s = ffi::OBJ_nid2ln(self.0); - if s.is_null() { - None - } - else { - Some(str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()) - } + cvt_p(ffi::OBJ_nid2ln(self.0) as *mut c_char) + .map(|nameptr| str::from_utf8(CStr::from_ptr(nameptr).to_bytes()).unwrap()) } } @@ -80,15 +78,10 @@ impl Nid { /// This corresponds to [`OBJ_nid2sn`] /// /// [`OBJ_nid2sn`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_nid2sn.html - pub fn to_short_name(&self) -> Option<&'static str> { + pub fn short_name(&self) -> Result<&'static str, ErrorStack> { unsafe { - let s = ffi::OBJ_nid2sn(self.0); - if s.is_null() { - None - } - else { - Some(str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()) - } + cvt_p(ffi::OBJ_nid2sn(self.0) as *mut c_char) + .map(|nameptr| str::from_utf8(CStr::from_ptr(nameptr).to_bytes()).unwrap()) } } @@ -1063,12 +1056,12 @@ mod test { let ms_ctl_sign = Nid::MS_CTL_SIGN; let undefined_nid = Nid::from_raw(118); - assert_eq!(common_name.to_long_name(), Some("commonName")); - assert_eq!(organizational_unit_name.to_long_name(), Some("organizationalUnitName")); - assert_eq!(aes256_cbc_hmac_sha1.to_long_name(), Some("aes-256-cbc-hmac-sha1")); - assert_eq!(id_cmc_lrapopwitness.to_long_name(), Some("id-cmc-lraPOPWitness")); - assert_eq!(ms_ctl_sign.to_long_name(), Some("Microsoft Trust List Signing")); - assert_eq!(undefined_nid.to_long_name(), None); + assert_eq!(common_name.long_name().unwrap(), "commonName"); + assert_eq!(organizational_unit_name.long_name().unwrap(), "organizationalUnitName"); + assert_eq!(aes256_cbc_hmac_sha1.long_name().unwrap(), "aes-256-cbc-hmac-sha1"); + assert_eq!(id_cmc_lrapopwitness.long_name().unwrap(), "id-cmc-lraPOPWitness"); + assert_eq!(ms_ctl_sign.long_name().unwrap(), "Microsoft Trust List Signing"); + assert!(undefined_nid.long_name().is_err(), "undefined_nid should not return a valid value"); } #[test] @@ -1080,11 +1073,11 @@ mod test { let ms_ctl_sign = Nid::MS_CTL_SIGN; let undefined_nid = Nid::from_raw(118); - assert_eq!(common_name.to_short_name(), Some("CN")); - assert_eq!(organizational_unit_name.to_short_name(), Some("OU")); - assert_eq!(aes256_cbc_hmac_sha1.to_short_name(), Some("AES-256-CBC-HMAC-SHA1")); - assert_eq!(id_cmc_lrapopwitness.to_short_name(), Some("id-cmc-lraPOPWitness")); - assert_eq!(ms_ctl_sign.to_short_name(), Some("msCTLSign")); - assert_eq!(undefined_nid.to_long_name(), None); + assert_eq!(common_name.short_name().unwrap(), "CN"); + assert_eq!(organizational_unit_name.short_name().unwrap(), "OU"); + assert_eq!(aes256_cbc_hmac_sha1.short_name().unwrap(), "AES-256-CBC-HMAC-SHA1"); + assert_eq!(id_cmc_lrapopwitness.short_name().unwrap(), "id-cmc-lraPOPWitness"); + assert_eq!(ms_ctl_sign.short_name().unwrap(), "msCTLSign"); + assert!(undefined_nid.short_name().is_err(), "undefined_nid should not return a valid value"); } } From 3456add537d03aef8a5becc9cbaa77910a1ecb3f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 29 May 2018 21:53:22 -0700 Subject: [PATCH 25/33] Add SslRef::verified_chain --- openssl-sys/src/openssl/v110.rs | 1 + openssl/src/ssl/mod.rs | 34 +++++++++++++++++++++++++-------- openssl/src/x509/store.rs | 10 ++++------ 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/openssl-sys/src/openssl/v110.rs b/openssl-sys/src/openssl/v110.rs index 4f1aa1c1..47d2bee4 100644 --- a/openssl-sys/src/openssl/v110.rs +++ b/openssl-sys/src/openssl/v110.rs @@ -280,6 +280,7 @@ extern "C" { ); pub fn SSL_get_client_random(ssl: *const SSL, out: *mut c_uchar, len: size_t) -> size_t; pub fn SSL_get_server_random(ssl: *const SSL, out: *mut c_uchar, len: size_t) -> size_t; + pub fn SSL_get0_verified_chain(ssl: *const SSL) -> *mut stack_st_X509; pub fn X509_getm_notAfter(x: *const ::X509) -> *mut ::ASN1_TIME; pub fn X509_getm_notBefore(x: *const ::X509) -> *mut ::ASN1_TIME; pub fn X509_get0_signature( diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index e24c3498..0f3f9624 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1822,7 +1822,7 @@ impl SslCipherRef { } } -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::SSL_SESSION; fn drop = ffi::SSL_SESSION_free; @@ -1837,9 +1837,6 @@ foreign_type! { pub struct SslSessionRef; } -unsafe impl Sync for SslSession {} -unsafe impl Send for SslSession {} - impl Clone for SslSession { fn clone(&self) -> SslSession { SslSessionRef::to_owned(self) @@ -1927,7 +1924,7 @@ impl SslSessionRef { } } -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::SSL; fn drop = ffi::SSL_free; @@ -1945,9 +1942,6 @@ foreign_type! { pub struct SslRef; } -unsafe impl Sync for Ssl {} -unsafe impl Send for Ssl {} - impl fmt::Debug for Ssl { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, fmt) @@ -2254,6 +2248,30 @@ impl SslRef { } } + /// Returns the verified certificate chani of the peer, including the leaf certificate. + /// + /// If verification was not successful (i.e. [`verify_result`] does not return + /// [`X509VerifyResult::OK`]), this chain may be incomplete or invalid. + /// + /// Requires OpenSSL 1.1.0 or newer. + /// + /// This corresponds to [`SSL_get0_verified_chain`]. + /// + /// [`verify_result`]: #method.verify_result + /// [`X509VerifyResult::OK`]: ../x509/struct.X509VerifyResult.html#associatedconstant.OK + /// [`SSL_get0_verified_chain`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get0_verified_chain.html + #[cfg(ossl110)] + pub fn verified_chain(&self) -> Option<&StackRef> { + unsafe { + let ptr = ffi::SSL_get0_verified_chain(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(StackRef::from_ptr(ptr)) + } + } + } + /// Like [`SslContext::certificate`]. /// /// This corresponds to `SSL_get_certificate`. diff --git a/openssl/src/x509/store.rs b/openssl/src/x509/store.rs index 4d6bc9ab..f533d9c7 100644 --- a/openssl/src/x509/store.rs +++ b/openssl/src/x509/store.rs @@ -44,11 +44,11 @@ use ffi; use foreign_types::ForeignTypeRef; use std::mem; -use {cvt, cvt_p}; use error::ErrorStack; use x509::X509; +use {cvt, cvt_p}; -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::X509_STORE; fn drop = ffi::X509_STORE_free; @@ -82,9 +82,7 @@ impl X509StoreBuilderRef { /// Adds a certificate to the certificate store. // FIXME should take an &X509Ref pub fn add_cert(&mut self, cert: X509) -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::X509_STORE_add_cert(self.as_ptr(), cert.as_ptr())).map(|_| ()) - } + unsafe { cvt(ffi::X509_STORE_add_cert(self.as_ptr(), cert.as_ptr())).map(|_| ()) } } /// Load certificates from their default locations. @@ -97,7 +95,7 @@ impl X509StoreBuilderRef { } } -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::X509_STORE; fn drop = ffi::X509_STORE_free; From fb1b9b414084aac35611bc2149bde0ae1175090a Mon Sep 17 00:00:00 2001 From: Axel Rasmussen Date: Wed, 30 May 2018 18:30:51 -0700 Subject: [PATCH 26/33] Add an openssl-sys binding for RSA_padding_check_PKCS1_type_2. This padding check implementation is useful for certain types of RSA decryption, notably the type performed by Yubico's PIV library. --- openssl-sys/src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index f2a77cab..aaeb9713 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -2365,6 +2365,14 @@ extern "C" { k: *mut RSA, ) -> c_int; + pub fn RSA_padding_check_PKCS1_type_2( + to: *mut c_uchar, + tlen: c_int, + f: *const c_uchar, + fl: c_int, + rsa_len: c_int, + ) -> c_int; + pub fn DSA_new() -> *mut DSA; pub fn DSA_free(dsa: *mut DSA); pub fn DSA_size(dsa: *const DSA) -> c_int; From 15cb335e66d518a25950ff40906676f982b64a2b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 1 Jun 2018 19:38:52 -0700 Subject: [PATCH 27/33] Fix use-after-free in cms Closes #941 --- openssl/src/cms.rs | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/openssl/src/cms.rs b/openssl/src/cms.rs index 6ee62fd0..5781a01f 100644 --- a/openssl/src/cms.rs +++ b/openssl/src/cms.rs @@ -138,22 +138,14 @@ impl CmsContentInfo { flags: CMSOptions, ) -> Result { unsafe { - let signcert = match signcert { - Some(cert) => cert.as_ptr(), - None => ptr::null_mut(), - }; - let pkey = match pkey { - Some(pkey) => pkey.as_ptr(), - None => ptr::null_mut(), - }; - let data_bio_ptr = match data { - Some(data) => MemBioSlice::new(data)?.as_ptr(), - None => ptr::null_mut(), - }; - let certs = match certs { - Some(certs) => certs.as_ptr(), - None => ptr::null_mut(), + let signcert = signcert.map_or(ptr::null_mut(), |p| p.as_ptr()); + let pkey = pkey.map_or(ptr::null_mut(), |p| p.as_ptr()); + let data_bio = match data { + Some(data) => Some(MemBioSlice::new(data)?), + None => None, }; + let data_bio_ptr = data_bio.as_ref().map_or(ptr::null_mut(), |p| p.as_ptr()); + let certs = certs.map_or(ptr::null_mut(), |p| p.as_ptr()); let cms = cvt_p(ffi::CMS_sign( signcert, From c2145384a956e176612f5088cee53e7afe449f1e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 1 Jun 2018 20:07:13 -0700 Subject: [PATCH 28/33] Fix types --- openssl/src/cms.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/openssl/src/cms.rs b/openssl/src/cms.rs index 5781a01f..d8d64c00 100644 --- a/openssl/src/cms.rs +++ b/openssl/src/cms.rs @@ -13,8 +13,8 @@ use bio::{MemBio, MemBioSlice}; use error::ErrorStack; use libc::c_uint; use pkey::{HasPrivate, PKeyRef}; -use stack::Stack; -use x509::X509; +use stack::StackRef; +use x509::{X509, X509Ref}; use {cvt, cvt_p}; bitflags! { @@ -130,13 +130,16 @@ impl CmsContentInfo { /// OpenSSL documentation at [`CMS_sign`] /// /// [`CMS_sign`]: https://www.openssl.org/docs/manmaster/man3/CMS_sign.html - pub fn sign( - signcert: Option<&X509>, + pub fn sign( + signcert: Option<&X509Ref>, pkey: Option<&PKeyRef>, - certs: Option<&Stack>, + certs: Option<&StackRef>, data: Option<&[u8]>, flags: CMSOptions, - ) -> Result { + ) -> Result + where + T: HasPrivate, + { unsafe { let signcert = signcert.map_or(ptr::null_mut(), |p| p.as_ptr()); let pkey = pkey.map_or(ptr::null_mut(), |p| p.as_ptr()); From 10b2a34529110b3eaddcad0e17456929037e5d09 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 1 Jun 2018 20:36:19 -0700 Subject: [PATCH 29/33] Adjust Nid signature algorithm APIs --- openssl/src/nid.rs | 75 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 19 deletions(-) diff --git a/openssl/src/nid.rs b/openssl/src/nid.rs index 23068406..6c300c89 100644 --- a/openssl/src/nid.rs +++ b/openssl/src/nid.rs @@ -1,13 +1,23 @@ //! A collection of numerical identifiers for OpenSSL objects. use ffi; -use libc::{c_int,c_char}; -use std::ptr; +use libc::{c_char, c_int}; use std::ffi::CStr; use std::str; -use error::ErrorStack; use cvt_p; +use error::ErrorStack; + +/// The digest and public-key algorithms associated with a signature. +pub struct SignatureAlgorithms { + /// The signature's digest. + /// + /// If the signature does not specify a digest, this will be `NID::UNDEF`. + pub digest: Nid, + + /// The signature's public-key. + pub pkey: Nid, +} /// A numerical identifier for an OpenSSL object. /// @@ -49,14 +59,18 @@ impl Nid { self.0 } - /// Returns the `Nid` of the digest algorithm associated with a signature ID. + /// Returns the `Nid`s of the digest and public key algorithms associated with a signature ID. /// /// This corresponds to `OBJ_find_sigid_algs`. - pub fn digest_algorithm(&self) -> Option { + pub fn signature_algorithms(&self) -> Option { unsafe { let mut digest = 0; - if ffi::OBJ_find_sigid_algs(self.0, &mut digest, ptr::null_mut()) == 1 { - Some(Nid(digest)) + let mut pkey = 0; + if ffi::OBJ_find_sigid_algs(self.0, &mut digest, &mut pkey) == 1 { + Some(SignatureAlgorithms { + digest: Nid(digest), + pkey: Nid(pkey), + }) } else { None } @@ -1041,10 +1055,9 @@ mod test { #[test] fn signature_digest() { - assert_eq!( - Nid::SHA256WITHRSAENCRYPTION.digest_algorithm(), - Some(Nid::SHA256) - ); + let algs = Nid::SHA256WITHRSAENCRYPTION.signature_algorithms().unwrap(); + assert_eq!(algs.digest, Nid::SHA256,); + assert_eq!(algs.pkey, Nid::RSAENCRYPTION); } #[test] @@ -1057,11 +1070,26 @@ mod test { let undefined_nid = Nid::from_raw(118); assert_eq!(common_name.long_name().unwrap(), "commonName"); - assert_eq!(organizational_unit_name.long_name().unwrap(), "organizationalUnitName"); - assert_eq!(aes256_cbc_hmac_sha1.long_name().unwrap(), "aes-256-cbc-hmac-sha1"); - assert_eq!(id_cmc_lrapopwitness.long_name().unwrap(), "id-cmc-lraPOPWitness"); - assert_eq!(ms_ctl_sign.long_name().unwrap(), "Microsoft Trust List Signing"); - assert!(undefined_nid.long_name().is_err(), "undefined_nid should not return a valid value"); + assert_eq!( + organizational_unit_name.long_name().unwrap(), + "organizationalUnitName" + ); + assert_eq!( + aes256_cbc_hmac_sha1.long_name().unwrap(), + "aes-256-cbc-hmac-sha1" + ); + assert_eq!( + id_cmc_lrapopwitness.long_name().unwrap(), + "id-cmc-lraPOPWitness" + ); + assert_eq!( + ms_ctl_sign.long_name().unwrap(), + "Microsoft Trust List Signing" + ); + assert!( + undefined_nid.long_name().is_err(), + "undefined_nid should not return a valid value" + ); } #[test] @@ -1075,9 +1103,18 @@ mod test { assert_eq!(common_name.short_name().unwrap(), "CN"); assert_eq!(organizational_unit_name.short_name().unwrap(), "OU"); - assert_eq!(aes256_cbc_hmac_sha1.short_name().unwrap(), "AES-256-CBC-HMAC-SHA1"); - assert_eq!(id_cmc_lrapopwitness.short_name().unwrap(), "id-cmc-lraPOPWitness"); + assert_eq!( + aes256_cbc_hmac_sha1.short_name().unwrap(), + "AES-256-CBC-HMAC-SHA1" + ); + assert_eq!( + id_cmc_lrapopwitness.short_name().unwrap(), + "id-cmc-lraPOPWitness" + ); assert_eq!(ms_ctl_sign.short_name().unwrap(), "msCTLSign"); - assert!(undefined_nid.short_name().is_err(), "undefined_nid should not return a valid value"); + assert!( + undefined_nid.short_name().is_err(), + "undefined_nid should not return a valid value" + ); } } From bf5772eb54a90a5fcd4cc1c16a98ce1f1c733184 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 1 Jun 2018 20:45:19 -0700 Subject: [PATCH 30/33] changelog --- CHANGELOG.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6beffb27..3091a4fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,28 @@ ## [Unreleased] +## [v0.10.9] - 2018-06-01 + +### Fixed + +* Fixed a use-after-free in `CmsContentInfo::sign`. +* `SslRef::servername` now returns `None` rather than panicking on a non-UTF8 name. + +### Added + +* Added `MessageDigest::from_nid`. +* Added `Nid::signature_algorithms`, `Nid::long_name`, and `Nid::short_name`. +* Added early data and early keying material export support for TLS 1.3. +* Added `SslRef::verified_chain`. +* Added `SslRef::servername_raw` which returns a `&[u8]` rather than `&str`. +* Added `SslRef::finished` and `SslRef::peer_finished`. +* Added `X509Ref::digest` to replace `X509Ref::fingerprint`. +* `X509StoreBuilder` and `X509Store` now implement `Sync` and `Send`. + +### Deprecated + +* `X509Ref::fingerprint` has been deprecated in favor of `X509Ref::digest`. + ## [v0.10.8] - 2018-05-20 ### Fixed @@ -205,7 +227,8 @@ Look at the [release tags] for information about older releases. -[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.8...master +[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.9...master +[v0.10.9]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.8...openssl-v0.10.9 [v0.10.8]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.7...openssl-v0.10.8 [v0.10.7]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.6...openssl-v0.10.7 [v0.10.6]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.5...openssl-v0.10.6 From a3a26051156da0278478319294a37db30bf2d9da Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 1 Jun 2018 20:47:46 -0700 Subject: [PATCH 31/33] fix build on older rustc --- openssl/src/nid.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openssl/src/nid.rs b/openssl/src/nid.rs index 6c300c89..6f480254 100644 --- a/openssl/src/nid.rs +++ b/openssl/src/nid.rs @@ -1056,7 +1056,7 @@ mod test { #[test] fn signature_digest() { let algs = Nid::SHA256WITHRSAENCRYPTION.signature_algorithms().unwrap(); - assert_eq!(algs.digest, Nid::SHA256,); + assert_eq!(algs.digest, Nid::SHA256); assert_eq!(algs.pkey, Nid::RSAENCRYPTION); } From 52f581ffc955a16060e3e20215f2c0e76946634b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 1 Jun 2018 20:56:46 -0700 Subject: [PATCH 32/33] Release openssl-sys v0.9.32 --- openssl-sys/Cargo.toml | 2 +- openssl/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 08f838ec..9e53ce64 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl-sys" -version = "0.9.31" +version = "0.9.32" authors = ["Alex Crichton ", "Steven Fackler "] license = "MIT" diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 00d5e54f..b1d764ce 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -23,7 +23,7 @@ foreign-types = "0.3.1" lazy_static = "1" libc = "0.2" -openssl-sys = { version = "0.9.31", path = "../openssl-sys" } +openssl-sys = { version = "0.9.32", path = "../openssl-sys" } [dev-dependencies] tempdir = "0.3" From 83767b861e1fd84d29e8684e2695e3e4fbc5a83a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 1 Jun 2018 20:59:26 -0700 Subject: [PATCH 33/33] Release openssl v0.10.9 --- openssl/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index b1d764ce..81568472 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl" -version = "0.10.8" +version = "0.10.9" authors = ["Steven Fackler "] license = "Apache-2.0" description = "OpenSSL bindings"