From 43c951f743e68fac5f45119eda7c994882a1d489 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 30 Sep 2016 00:43:05 -0700 Subject: [PATCH] Add support for OpenSSL 1.1.0 This commit is relatively major refactoring of the `openssl-sys` crate as well as the `openssl` crate itself. The end goal here was to support OpenSSL 1.1.0, and lots of other various tweaks happened along the way. The major new features are: * OpenSSL 1.1.0 is supported * OpenSSL 0.9.8 is no longer supported (aka all OSX users by default) * All FFI bindings are verified with the `ctest` crate (same way as the `libc` crate) * CI matrixes are vastly expanded to include 32/64 of all platforms, more OpenSSL version coverage, as well as ARM coverage on Linux * The `c_helpers` module is completely removed along with the `gcc` dependency. * The `openssl-sys` build script was completely rewritten * Now uses `OPENSSL_DIR` to find the installation, not include/lib env vars. * Better error messages for mismatched versions. * Better error messages for failing to find OpenSSL on a platform (more can be done here) * Probing of OpenSSL build-time configuration to inform the API of the `*-sys` crate. * Many Cargo features have been removed as they're now enabled by default. As this is a breaking change to both the `openssl` and `openssl-sys` crates this will necessitate a major version bump of both. There's still a few more API questions remaining but let's hash that out on a PR! Closes #452 --- .travis.yml | 104 +++-- Cargo.toml | 2 +- README.md | 112 +++--- appveyor.yml | 48 ++- openssl-sys/Cargo.toml | 26 -- openssl-sys/build.rs | 386 +++++++++++++++---- openssl-sys/src/lib.rs | 720 +++++++++-------------------------- openssl-sys/src/ossl10x.rs | 569 +++++++++++++++++++++++++++ openssl-sys/src/ossl110.rs | 146 +++++++ openssl-sys/src/probe.rs | 77 ---- openssl/Cargo.toml | 43 +-- openssl/build.rs | 37 +- openssl/src/bn/mod.rs | 68 ++-- openssl/src/c_helpers.c | 67 ---- openssl/src/c_helpers.rs | 15 - openssl/src/crypto/dsa.rs | 56 ++- openssl/src/crypto/hash.rs | 22 +- openssl/src/crypto/hmac.rs | 130 +++++-- openssl/src/crypto/mod.rs | 1 - openssl/src/crypto/pkcs12.rs | 34 +- openssl/src/crypto/pkcs5.rs | 7 +- openssl/src/crypto/rsa.rs | 159 ++++++-- openssl/src/crypto/symm.rs | 30 +- openssl/src/dh/mod.rs | 59 ++- openssl/src/error.rs | 5 +- openssl/src/lib.rs | 5 +- openssl/src/macros.rs | 14 + openssl/src/ssl/bio.rs | 176 ++++++--- openssl/src/ssl/mod.rs | 350 +++++++++-------- openssl/src/ssl/tests/mod.rs | 124 +++--- openssl/src/version.rs | 31 +- openssl/src/x509/mod.rs | 132 +++++-- openssl/src/x509/tests.rs | 2 - openssl/test/build.sh | 35 +- openssl/test/run.sh | 33 +- systest/Cargo.toml | 12 + systest/build.rs | 110 ++++++ systest/src/main.rs | 9 + 38 files changed, 2513 insertions(+), 1443 deletions(-) create mode 100644 openssl-sys/src/ossl10x.rs create mode 100644 openssl-sys/src/ossl110.rs delete mode 100644 openssl-sys/src/probe.rs delete mode 100644 openssl/src/c_helpers.c delete mode 100644 openssl/src/c_helpers.rs create mode 100644 systest/Cargo.toml create mode 100644 systest/build.rs create mode 100644 systest/src/main.rs diff --git a/.travis.yml b/.travis.yml index 0d76be3d..347a23c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,28 +1,86 @@ language: rust -sudo: false -addons: - apt: - packages: - - gcc-arm-linux-gnueabihf -rust: -- nightly -- 1.9.0 -os: -- osx -- linux +sudo: required +rust: stable +dist: trusty + env: - matrix: - - TEST_FEATURES=false - - TEST_FEATURES=true + global: + - TARGET=x86_64-unknown-linux-gnu matrix: - # include: - # - os: linux - # env: TARGET=arm-unknown-linux-gnueabihf TEST_FEATURES=true - # rust: 1.7.0 - exclude: - - os: osx - env: TEST_FEATURES=true + include: + # ARM-bit version compat + - env: > + TARGET=arm-unknown-linux-gnueabihf + BUILD_OPENSSL_VERSION=1.0.2h + CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc + QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf + RUST_TEST_THREADS=1 + addons: + apt: + packages: + - gcc-arm-linux-gnueabihf + - qemu-user-static + - libc6-dev-armhf-cross + - binfmt-support + - env: > + TARGET=arm-unknown-linux-gnueabihf + BUILD_OPENSSL_VERSION=1.1.0b + CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc + QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf + RUST_TEST_THREADS=1 + addons: + apt: + packages: + - gcc-arm-linux-gnueabihf + - qemu-user-static + - libc6-dev-armhf-cross + - binfmt-support + + # Minimum version supported + - rust: 1.9.0 + + # beta/nightly channels + - rust: beta + - rust: nightly + + # 64-bit version compat + - env: BUILD_OPENSSL_VERSION=1.0.1u + - env: BUILD_OPENSSL_VERSION=1.0.2h + - env: BUILD_OPENSSL_VERSION=1.1.0b + + # 32-bit version compat + - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.1u + addons: + apt: + packages: + - gcc-multilib + - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.2h + addons: + apt: + packages: + - gcc-multilib + - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.1.0b + addons: + apt: + packages: + - gcc-multilib + + # osx 32/64 + - os: osx + env: TARGET=x86_64-apple-darwin + - os: osx + env: TARGET=i686-apple-darwin + install: brew uninstall openssl && brew install openssl --universal + + before_install: -- ./openssl/test/build.sh + - ./openssl/test/build.sh + - curl https://static.rust-lang.org/rustup.sh | + sh -s -- --add-target=$TARGET --disable-sudo -y --prefix=`rustc --print sysroot` script: -- ./openssl/test/run.sh + - ./openssl/test/run.sh + +cache: + cargo: true + directories: + - $HOME/openssl diff --git a/Cargo.toml b/Cargo.toml index 0bd2c005..2ef99c17 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["openssl", "openssl-sys"] +members = ["openssl", "openssl-sys", "systest"] diff --git a/README.md b/README.md index d919cff1..54f208b4 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,16 @@ ## Building -rust-openssl depends on both the OpenSSL runtime libraries and headers. +rust-openssl depends on the OpenSSL runtime libraries version 1.0.1 or above. +Currently the libraries need to be present in the build environment before this +crate is compiled, and some instructions of how to do this are in the sections +below. ### Linux -On Linux, you can install OpenSSL via your package manager. The headers are -sometimes provided in a separate package than the runtime libraries - look for -something like `openssl-devel` or `libssl-dev`. +On Linux, you can typically install OpenSSL via your package manager. The +headers are sometimes provided in a separate package than the runtime libraries +- look for something like `openssl-devel` or `libssl-dev`. ```bash # On Ubuntu @@ -23,79 +26,78 @@ sudo pacman -S openssl sudo dnf install openssl-devel ``` +If installation via a package manager is not possible, or if you're cross +compiling to a separate target, you'll typically need to compile OpenSSL from +source. That can normally be done with: + +``` +curl -O https://www.openssl.org/source/openssl-1.1.0b.tar.gz +tar xf openssl-1.1.0b.tar.gz +cd openssl-1.1.0b +export CC=... +./Configure --prefix=... linux-x86_64 -fPIC +make -j$(nproc) +make install +``` + ### OSX -OpenSSL 0.9.8 is preinstalled on OSX. Some features are only available when -linking against OpenSSL 1.0.0 or greater; see below on how to point -rust-openssl to a separate installation. OSX releases starting at 10.11, "El -Capitan", no longer include OpenSSL headers which will prevent the `openssl` -crate from compiling. +Although OpenSSL 0.9.8 is preinstalled on OSX this library is being phased out +of OSX and this crate also does not support this version of OpenSSL. To use this +crate on OSX you'll need to install OpenSSL via some alternate means, typically +homebrew: -For OSX 10.11 you can use brew to install OpenSSL and then set the environment variables -as described below. ```bash brew install openssl -export OPENSSL_INCLUDE_DIR=`brew --prefix openssl`/include -export OPENSSL_LIB_DIR=`brew --prefix openssl`/lib ``` -May be necessary clean the repository with `cargo clean` before build again. +### Windows MSVC -### Windows +On MSVC it's unfortunately not always a trivial process acquiring OpenSSL. +Perhaps the easiest way to do this right now is to download [precompiled +binaries] and install them on your system. Currently it's recommended to +install the 1.1.0b light installation if you're choosing this route. -On Windows, consider building with [mingw-w64](http://mingw-w64.org/). -Build script will try to find mingw in `PATH` environment variable to provide -Cargo with location where openssl libs from mingw-w64 package may be found. +[precompiled binaries]: http://slproweb.com/products/Win32OpenSSL.html -mingw-w64 can be easily installed by using [MSYS2](http://msys2.github.io/). Install MSYS2 according to the instructions, and then, from an MSYS2 Shell, install mingw-w64: +Once a precompiled binary is installed you can configure this crate to find the +installation via an environment variable: -32-bit: -```bash -pacman -S mingw-w64-i686-gcc -``` - -64-bit -```bash -pacman -S mingw-w64-x86_64-gcc +``` +set OPENSSL_DIR=C:\OpenSSL-Win64 ``` -and then install the mingw-w64 toolchain. +After that, you're just a `cargo build` away! -32-bit: -```bash -pacman -S mingw-w64-i686-toolchain +### Windows GNU (MinGW) + +The easiest way to acquire OpenSSL when working with MinGW is to ensure you're +using [MSYS2](http://msys2.github.io) and to then execute: + +``` +# 32-bit +pacman -S mingw-w64-i686-openssl + +# 64-bit +pacman -S mingw-w64-x86_64-openssl ``` -64-bit: -```bash -pacman -S mingw-w64-x86_64-toolchain -``` - -Alternatively, install OpenSSL from [here][1]. Cargo will not be able to find OpenSSL if it's -installed to the default location. You can either copy the `include/openssl` -directory, `libssl32.dll`, and `libeay32.dll` to locations that Cargo can find -or pass the location to Cargo via environment variables: - -```bash -env OPENSSL_LIB_DIR=C:/OpenSSL-Win64 OPENSSL_INCLUDE_DIR=C:/OpenSSL-Win64/include cargo build -``` +And after that, a `cargo build` should be all you need! ### Manual configuration rust-openssl's build script will by default attempt to locate OpenSSL via -pkg-config. This will not work in some situations, for example, on systems that -don't have pkg-config, when cross compiling, or when using a copy of OpenSSL +pkg-config or other system-specific mechanisms. This will not work in some +situations however, for example cross compiling or when using a copy of OpenSSL other than the normal system install. The build script can be configured via environment variables: -* `OPENSSL_LIB_DIR` - If specified, a directory that will be used to find - OpenSSL runtime libraries. -* `OPENSSL_INCLUDE_DIR` - If specified, a directory that will be used to find - OpenSSL headers. + +* `OPENSSL_DIR` - If specified, a directory that will be used to find + OpenSSL installation. It's expected that under this directory the `include` + folder has header files and a `lib` folder has the runtime libraries. * `OPENSSL_STATIC` - If specified, OpenSSL libraries will be statically rather - than dynamically linked. + than dynamically linked. -If either `OPENSSL_LIB_DIR` or `OPENSSL_INCLUDE_DIR` are specified, then the -build script will skip the pkg-config step. - -[1]: http://slproweb.com/products/Win32OpenSSL.html +If `OPENSSL_DIR` is specified, then the build script will skip the pkg-config +step. diff --git a/appveyor.yml b/appveyor.yml index 4cd6c231..9a7a3dc7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,25 +1,43 @@ environment: - OPENSSL_INCLUDE_DIR: C:\OpenSSL\include - OPENSSL_LIB_DIR: C:\OpenSSL\lib - OPENSSL_LIBS: ssleay32:libeay32 matrix: - - TARGET: i686-pc-windows-gnu - BITS: 32 - - TARGET: x86_64-pc-windows-msvc - BITS: 64 + # 1.1.0, 64/32 bit + - TARGET: i686-pc-windows-gnu + BITS: 32 + MSYS2: 1 + OPENSSL_VERSION: 1_1_0b + - TARGET: x86_64-pc-windows-msvc + BITS: 64 + OPENSSL_VERSION: 1_1_0b + OPENSSL_DIR: C:\OpenSSL + + # 1.0.2, 64/32 bit + - TARGET: x86_64-pc-windows-gnu + BITS: 64 + MSYS2: 1 + OPENSSL_VERSION: 1_0_2j + - TARGET: i686-pc-windows-msvc + BITS: 32 + OPENSSL_VERSION: 1_0_2j + OPENSSL_DIR: C:\OpenSSL install: - - ps: Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-1_0_2h.exe" - - Win%BITS%OpenSSL-1_0_2h.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL" - - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.9.0-${env:TARGET}.exe" - - rust-1.9.0-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" - - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin - - SET PATH=%PATH%;C:\MinGW\bin + # install OpenSSL + - ps: Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-${env:OPENSSL_VERSION}.exe" + - Win%BITS%OpenSSL-%OPENSSL_VERSION%.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL" + + # Install Rust + - curl -sSf -o rustup-init.exe https://win.rustup.rs/ + - rustup-init.exe -y --default-host %TARGET% + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - if defined MSYS2 set PATH=C:\msys64\mingw%BITS%\bin;%PATH% - rustc -V - cargo -V build: false -# Don't run doctests due to rust-lang/cargo#1592 test_script: - - cargo test --lib --manifest-path openssl/Cargo.toml + - cargo run --manifest-path systest/Cargo.toml --target %TARGET% + - cargo test --manifest-path openssl/Cargo.toml --target %TARGET% +cache: + - target + - C:\Users\appveyor\.cargo\registry diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index dcdf9d1a..d44dcfc1 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -10,38 +10,12 @@ documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.17/openssl_sys links = "openssl" build = "build.rs" -[features] -tlsv1_2 = [] -tlsv1_1 = [] -dtlsv1 = [] -dtlsv1_2 = [] -sslv2 = [] -sslv3 = [] -aes_xts = [] -aes_ctr = [] -npn = [] -alpn = [] -rfc5114 = [] -pkcs5_pbkdf2_hmac = [] -ecdh_auto = [] -hmac_clone = [] - [dependencies] libc = "0.2" [build-dependencies] pkg-config = "0.3" -[target.le32-unknown-nacl.dependencies] -libressl-pnacl-sys = "2.1.0" -[target.x86_64-unknown-nacl.dependencies] -libressl-pnacl-sys = "2.1.0" -[target.i686-unknown-nacl.dependencies] -libressl-pnacl-sys = "2.1.0" -[target.arm-unknown-nacl.dependencies] -libressl-pnacl-sys = "2.1.0" - -# Only here to make sure we link to these in a static build on Windows [target.'cfg(windows)'.dependencies] user32-sys = "0.2" gdi32-sys = "0.2" diff --git a/openssl-sys/build.rs b/openssl-sys/build.rs index 0e3a76d2..9f5b3877 100644 --- a/openssl-sys/build.rs +++ b/openssl-sys/build.rs @@ -1,86 +1,344 @@ extern crate pkg_config; +use std::collections::HashSet; use std::env; +use std::ffi::OsString; +use std::fs::File; +use std::io::Read; +use std::path::{Path, PathBuf}; fn main() { let target = env::var("TARGET").unwrap(); - // libressl_pnacl_sys links the libs needed. - if target.ends_with("nacl") { return; } + let openssl_dir = env::var_os("OPENSSL_DIR").unwrap_or_else(|| { + find_openssl_dir(&target) + }); - let lib_dir = env::var("OPENSSL_LIB_DIR").ok(); - let include_dir = env::var("OPENSSL_INCLUDE_DIR").ok(); - - if lib_dir.is_none() && include_dir.is_none() { - // rustc doesn't seem to work with pkg-config's output in mingw64 - if !target.contains("windows") { - if let Ok(info) = pkg_config::find_library("openssl") { - // avoid empty include paths as they are not supported by GCC - if info.include_paths.len() > 0 { - let paths = env::join_paths(info.include_paths).unwrap(); - println!("cargo:include={}", paths.to_str().unwrap()); - } - return; - } - } - if let Some(mingw_paths) = get_mingw_in_path() { - for path in mingw_paths { - println!("cargo:rustc-link-search=native={}", path); - } - } + let lib_dir = Path::new(&openssl_dir).join("lib"); + let include_dir = Path::new(&openssl_dir).join("include"); + if !Path::new(&lib_dir).exists() { + panic!("OpenSSL library directory does not exist: {}", + lib_dir.to_string_lossy()); } - let libs_env = env::var("OPENSSL_LIBS").ok(); - let libs = match libs_env { - Some(ref v) => v.split(":").collect(), - None => if target.contains("windows") { - if get_mingw_in_path().is_some() && lib_dir.is_none() && include_dir.is_none() { - vec!["ssleay32", "eay32"] - } else { - vec!["ssl32", "eay32"] - } - } else { - vec!["ssl", "crypto"] - } - }; + if !Path::new(&include_dir).exists() { + panic!("OpenSSL include directory does not exist: {}", + include_dir.to_string_lossy()); + } - let mode = if env::var_os("OPENSSL_STATIC").is_some() { - "static" + println!("cargo:rustc-link-search=native={}", lib_dir.to_string_lossy()); + println!("cargo:include={}", include_dir.to_string_lossy()); + + let version = validate_headers(&[include_dir.clone().into()], + &[lib_dir.clone().into()]); + + let libs = if (version.contains("0x10001") || + version.contains("0x10002")) && + target.contains("windows") { + ["ssleay32", "libeay32"] + } else if target.contains("windows") { + ["libssl", "libcrypto"] } else { - "dylib" + ["ssl", "crypto"] }; - if let Some(lib_dir) = lib_dir { - println!("cargo:rustc-link-search=native={}", lib_dir); - } - - for lib in libs { - println!("cargo:rustc-link-lib={}={}", mode, lib); - } - - if let Some(include_dir) = include_dir { - println!("cargo:include={}", include_dir); + let kind = determine_mode(Path::new(&lib_dir), &libs); + for lib in libs.iter() { + println!("cargo:rustc-link-lib={}={}", kind, lib); } } -fn get_mingw_in_path() -> Option> { - match env::var_os("PATH") { - Some(env_path) => { - let paths: Vec = env::split_paths(&env_path).filter_map(|path| { - use std::ascii::AsciiExt; +fn find_openssl_dir(target: &str) -> OsString { + let host = env::var("HOST").unwrap(); - match path.to_str() { - Some(path_str) => { - if path_str.to_ascii_lowercase().contains("mingw") { - Some(path_str.to_string()) - } else { None } - }, - None => None + if host.contains("apple-darwin") && target.contains("apple-darwin") { + let homebrew = Path::new("/usr/local/opt/openssl"); + if homebrew.exists() { + return homebrew.to_path_buf().into() + } + let homebrew = Path::new("/usr/local/opt/openssl@1.1"); + if homebrew.exists() { + return homebrew.to_path_buf().into() + } + } + + try_pkg_config(); + + let mut msg = format!(" + +Could not find directory of OpenSSL installation, and this `-sys` crate cannot +proceed without this knowledge. If OpenSSL is installed and this crate had +trouble finding it, you can set the `OPENSSL_DIR` environment variable for the +compilation process. + +If you're in a situation where you think the directory *should* be found +automatically, please open a bug at https://github.com/sfackler/rust-openssl +and include information about your system as well as this message. + + $HOST = {} + $TARGET = {} + openssl-sys = {} + +", + host, target, env!("CARGO_PKG_VERSION")); + + if host.contains("apple-darwin") && target.contains("apple-darwin") { + let system = Path::new("/usr/lib/libssl.0.9.8.dylib"); + if system.exists() { + msg.push_str(&format!(" + +It looks like you're compiling on macOS, where the system contains a version of +OpenSSL 0.9.8. This crate no longer supports OpenSSL 0.9.8. + +As a consumer of this crate, you can fix this error by using Homebrew to +install the `openssl` package, or as a maintainer you can use the openssl-sys +0.7 crate for support with OpenSSL 0.9.8. + +Unfortunately though the compile cannot continue, so aborting. + +")); + } + } + + if host.contains("windows") && target.contains("windows-gnu") { + msg.push_str(&format!(" +It looks like you're compiling for MinGW but you may not have either OpenSSL or +pkg-config installed. You can install these two dependencies with: + + pacman -S openssl pkg-config + +and try building this crate again. + +" +)); + } + + if host.contains("windows") && target.contains("windows-msvc") { + msg.push_str(&format!(" +It looks like you're compiling for MSVC but we couldn't detect an OpenSSL +installation. If there isn't one installed then you can try the rust-openssl +README for more information about how to download precompiled binaries of +OpenSSL: + + https://github.com/sfackler/rust-openssl#windows + +" +)); + } + + panic!(msg); +} + +/// Attempt to find OpenSSL through pkg-config. +/// +/// Note that if this succeeds then the function does not return as pkg-config +/// typically tells us all the information that we need. +fn try_pkg_config() { + let target = env::var("TARGET").unwrap(); + let host = env::var("HOST").unwrap(); + + // If we're going to windows-gnu we can use pkg-config, but only so long as + // we're coming from a windows host. + // + // Otherwise if we're going to windows we probably can't use pkg-config. + if target.contains("windows-gnu") && host.contains("windows") { + env::set_var("PKG_CONFIG_ALLOW_CROSS", "1"); + } else if target.contains("windows") { + return + } + + // We're going to be looking at header files, so show us all the system + // cflags dirs for showing us lots of `-I`. + env::set_var("PKG_CONFIG_ALLOW_SYSTEM_CFLAGS", "1"); + + let lib = match pkg_config::find_library("openssl") { + Ok(lib) => lib, + Err(_) => return, + }; + + if lib.include_paths.len() == 0 { + panic!(" + +Used pkg-config to discover the OpenSSL installation, but pkg-config did not +return any include paths for the installation. This crate needs to take a peek +at the header files so it cannot proceed unless they're found. + +You can try fixing this by setting the `OPENSSL_DIR` environment variable +pointing to your OpenSSL installation. + +"); + } + + validate_headers(&lib.include_paths, &lib.link_paths); + + for include in lib.include_paths.iter() { + println!("cargo:include={}", include.display()); + } + + std::process::exit(0); +} + +/// Validates the header files found in `include_dir` and then returns the +/// version string of OpenSSL. +fn validate_headers(include_dirs: &[PathBuf], + libdirs: &[PathBuf]) -> String { + // This `*-sys` crate only works with OpenSSL 1.0.1, 1.0.2, and 1.1.0. To + // correctly expose the right API from this crate, take a look at + // `opensslv.h` to see what version OpenSSL claims to be. + let mut version_header = String::new(); + let mut include = include_dirs.iter() + .map(|p| p.join("openssl/opensslv.h")) + .filter(|p| p.exists()); + let mut f = match include.next() { + Some(f) => File::open(f).unwrap(), + None => { + panic!("failed to open header file at `openssl/opensslv.h` to learn + about OpenSSL's version number, looked inside:\n\n{:#?}\n\n", + include_dirs); + } + }; + f.read_to_string(&mut version_header).unwrap(); + + // Do a bit of string parsing to find `#define OPENSSL_VERSION_NUMBER ...` + let version_line = version_header.lines().find(|l| { + l.contains("define ") && l.contains("OPENSSL_VERSION_NUMBER") + }).and_then(|line| { + let start = match line.find("0x") { + Some(start) => start, + None => return None, + }; + Some(line[start..].trim()) + }); + let version_text = match version_line { + Some(text) => text, + None => { + panic!("header file at `{}` did not include `OPENSSL_VERSION_NUMBER` \ + that this crate recognized, failed to learn about the \ + OpenSSL version number"); + } + }; + if version_text.contains("0x10001") { + println!("cargo:rustc-cfg=ossl101"); + println!("cargo:is_101=1"); + } else if version_text.contains("0x10002") { + println!("cargo:rustc-cfg=ossl102"); + println!("cargo:is_102=1"); + } else if version_text.contains("0x10100") { + println!("cargo:rustc-cfg=ossl110"); + println!("cargo:is_110=1"); + } else { + panic!(" + +This crate is only compatible with OpenSSL 1.0.1, 1.0.2, and 1.1.0, but a +different version of OpenSSL was found: + + {} + +The build is now aborting due to this version mismatch. + +", version_text); + } + + // OpenSSL has a number of build-time configuration options which affect + // various structs and such. Since OpenSSL 1.1.0 this isn't really a problem + // as the library is much more FFI-friendly, but 1.0.{1,2} suffer this problem. + // + // To handle all this conditional compilation we slurp up the configuration + // file of OpenSSL, `opensslconf.h`, and then dump out everything it defines + // as our own #[cfg] directives. That way the `ossl10x.rs` bindings can + // account for compile differences and such. + if version_text.contains("0x1000") { + let mut conf_header = String::new(); + let mut include = include_dirs.iter() + .map(|p| p.join("openssl/opensslconf.h")) + .filter(|p| p.exists()); + let mut f = match include.next() { + Some(f) => File::open(f).unwrap(), + None => { + // It's been seen that on linux the include dir printed out by + // `pkg-config` doesn't actually have opensslconf.h. Instead + // it's in an architecture-specific include directory. + // + // Try to detect that case to see if it exists. + let mut libdirs = libdirs.iter().map(|p| { + p.iter() + .map(|p| if p == "lib" {"include".as_ref()} else {p}) + .collect::() + }).map(|p| { + p.join("openssl/opensslconf.h") + }).filter(|p| p.exists()); + match libdirs.next() { + Some(f) => File::open(f).unwrap(), + None => { + panic!("failed to open header file at + `openssl/opensslconf.h` to learn about \ + OpenSSL's version number, looked \ + inside:\n\n{:#?}\n\n", + include_dirs); + } } - }).collect(); + } + }; + f.read_to_string(&mut conf_header).unwrap(); - if paths.len() > 0 { Some(paths) } else { None } - }, - None => None + // Look for `#define OPENSSL_FOO`, print out everything as our own + // #[cfg] flag. + for line in conf_header.lines() { + let i = match line.find("define ") { + Some(i) => i, + None => continue, + }; + let var = line[i + "define ".len()..].trim(); + if var.starts_with("OPENSSL") && !var.contains(" ") { + println!("cargo:rustc-cfg=osslconf=\"{}\"", var); + } + } } + + return version_text.to_string() +} + +/// Given a libdir for OpenSSL (where artifacts are located) as well as the name +/// of the libraries we're linking to, figure out whether we should link them +/// statically or dynamically. +fn determine_mode(libdir: &Path, libs: &[&str]) -> &'static str { + // First see if a mode was explicitly requested + let kind = env::var("OPENSSL_STATIC").ok(); + match kind.as_ref().map(|s| &s[..]) { + Some("0") => return "dylib", + Some(_) => return "static", + None => {} + } + + // Next, see what files we actually have to link against, and see what our + // possibilities even are. + let files = libdir.read_dir().unwrap() + .map(|e| e.unwrap()) + .map(|e| e.file_name()) + .filter_map(|e| e.into_string().ok()) + .collect::>(); + 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{}.dylib", l)) + }); + match (can_static, can_dylib) { + (true, false) => return "static", + (false, true) => return "dylib", + (false, false) => { + panic!("OpenSSL libdir at `{}` does not contain the required files \ + to either statically or dynamically link OpenSSL", + libdir.display()); + } + (true, true) => {} + } + + // Ok, we've got not explicit preference and can *either* link statically or + // link dynamically. In the interest of "security upgrades" and/or "best + // practices with security libs", let's link dynamically. + "dylib" } diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index b7a61c52..1c1df579 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1,64 +1,45 @@ #![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] -#![allow(dead_code)] +#![allow(dead_code, overflowing_literals)] #![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.17")] extern crate libc; -#[cfg(target_os = "nacl")] -extern crate libressl_pnacl_sys; - use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t, FILE}; -use std::mem; use std::ptr; -use std::sync::{Mutex, MutexGuard}; -use std::sync::{Once, ONCE_INIT}; -pub type ASN1_INTEGER = c_void; -pub type ASN1_STRING = c_void; -pub type ASN1_TIME = c_void; -pub type ASN1_TYPE = c_void; -pub type BN_CTX = c_void; -pub type BN_GENCB = c_void; -pub type COMP_METHOD = c_void; -pub type DH = c_void; -pub type ENGINE = c_void; -pub type EVP_CIPHER_CTX = c_void; -pub type EVP_MD = c_void; -pub type EVP_PKEY_CTX = c_void; -pub type SSL = c_void; -pub type SSL_CIPHER = c_void; -pub type SSL_CTX = c_void; -pub type SSL_METHOD = c_void; -pub type X509 = c_void; -pub type X509_CRL = c_void; -pub type X509_EXTENSION = c_void; -pub type X509_NAME = c_void; -pub type X509_NAME_ENTRY = c_void; -pub type X509_REQ = c_void; -pub type X509_STORE_CTX = c_void; -pub type bio_st = c_void; -#[repr(C)] -pub struct PKCS12(c_void); +#[cfg(any(ossl101, ossl102))] +mod ossl10x; +#[cfg(any(ossl101, ossl102))] +pub use ossl10x::*; -#[repr(C)] -pub struct stack_st_X509 { - pub stack: _STACK, -} +#[cfg(ossl110)] +mod ossl110; +#[cfg(ossl110)] +pub use ossl110::*; -#[repr(C)] -pub struct stack_st_X509_EXTENSION { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_GENERAL_NAME { - pub stack: _STACK, -} - -#[repr(C)] -pub struct stack_st_void { - pub stack: _STACK, -} +pub enum ASN1_INTEGER {} +pub enum ASN1_STRING {} +pub enum ASN1_TIME {} +pub enum ASN1_TYPE {} +pub enum BN_CTX {} +pub enum BN_GENCB {} +pub enum COMP_METHOD {} +pub enum ENGINE {} +pub enum EVP_CIPHER_CTX {} +pub enum EVP_MD {} +pub enum EVP_PKEY_CTX {} +pub enum SSL {} +pub enum SSL_CIPHER {} +pub enum SSL_METHOD {} +pub enum X509_CRL {} +pub enum X509_EXTENSION {} +pub enum X509_NAME {} +pub enum X509_NAME_ENTRY {} +pub enum X509_REQ {} +pub enum X509_STORE_CTX {} +pub enum bio_st {} +pub enum PKCS12 {} +pub enum DH_METHOD {} pub type bio_info_cb = Option; +pub enum RSA_METHOD {} +pub enum BN_MONT_CTX {} +pub enum BN_BLINDING {} +pub enum DSA_METHOD {} +pub enum EVP_PKEY_ASN1_METHOD {} + #[repr(C)] -#[derive(Copy, Clone)] -pub struct BIO_METHOD { +pub struct GENERAL_NAME { pub type_: c_int, - pub name: *const c_char, - pub bwrite: Option c_int>, - pub bread: Option c_int>, - pub bputs: Option c_int>, - pub bgets: Option c_int>, - pub ctrl: Option c_long>, - pub create: Option c_int>, - pub destroy: Option c_int>, - pub callback_ctrl: Option c_long>, -} - -// so we can create static BIO_METHODs -unsafe impl Sync for BIO_METHOD {} - -#[repr(C)] -pub struct _STACK { - pub num: c_int, - pub data: *mut *mut c_char, - pub sorted: c_int, - pub num_alloc: c_int, - pub comp: Option, -} - -#[repr(C)] -pub struct RSA { - pub pad: c_int, - pub version: c_long, - pub meth: *const c_void, - - pub engine: *mut c_void, - pub n: *mut BIGNUM, - pub e: *mut BIGNUM, - pub d: *mut BIGNUM, - pub p: *mut BIGNUM, - pub q: *mut BIGNUM, - pub dmp1: *mut BIGNUM, - pub dmq1: *mut BIGNUM, - pub iqmp: *mut BIGNUM, - - pub ex_data: *mut c_void, - pub references: c_int, - pub flags: c_int, - - pub _method_mod_n: *mut c_void, - pub _method_mod_p: *mut c_void, - pub _method_mod_q: *mut c_void, - - pub bignum_data: *mut c_char, - pub blinding: *mut c_void, - pub mt_blinding: *mut c_void, -} - -#[repr(C)] -pub struct DSA { - pub pad: c_int, - pub version: c_long, - pub write_params: c_int, - - pub p: *mut BIGNUM, - pub q: *mut BIGNUM, - pub g: *mut BIGNUM, - pub pub_key: *mut BIGNUM, - pub priv_key: *mut BIGNUM, - pub kinv: *mut BIGNUM, - pub r: *mut BIGNUM, - - pub flags: c_int, - pub _method_mont_p: *mut c_void, - pub references: c_int, - pub ex_data: *mut c_void, - pub meth: *const c_void, - pub engine: *const c_void, -} - -#[repr(C)] -pub struct EVP_PKEY { - pub type_: c_int, - pub save_type: c_int, - pub references: c_int, - pub ameth: *const c_void, - pub engine: *mut ENGINE, - pub pkey: *mut c_void, - pub save_parameters: c_int, - pub attributes: *mut c_void, -} - -#[repr(C)] -pub struct BIO { - pub method: *mut BIO_METHOD, - pub callback: Option c_long>, - pub cb_arg: *mut c_char, - pub init: c_int, - pub shutdown: c_int, - pub flags: c_int, - pub retry_reason: c_int, - pub num: c_int, - pub ptr: *mut c_void, - pub next_bio: *mut BIO, - pub prev_bio: *mut BIO, - pub references: c_int, - pub num_read: c_ulong, - pub num_write: c_ulong, - pub ex_data: CRYPTO_EX_DATA, -} - -#[repr(C)] -pub struct CRYPTO_EX_DATA { - pub sk: *mut stack_st_void, - pub dummy: c_int, -} - -#[repr(C)] -pub struct EVP_MD_CTX { - digest: *mut EVP_MD, - engine: *mut c_void, - flags: c_ulong, - md_data: *mut c_void, - pctx: *mut EVP_PKEY_CTX, - update: *mut c_void -} - -impl Copy for EVP_MD_CTX {} -impl Clone for EVP_MD_CTX { - fn clone(&self) -> EVP_MD_CTX { *self } -} - -#[repr(C)] -pub struct EVP_CIPHER { - pub nid: c_int, - pub block_size: c_int, - pub key_len: c_int, - pub iv_len: c_int, - pub flags: c_ulong, - pub init: Option c_int>, - pub do_cipher: Option c_int>, - pub cleanup: Option c_int>, - pub ctx_size: c_int, - pub set_asn1_parameters: Option c_int>, - pub get_asn1_parameters: Option c_int>, - pub ctrl: Option c_int>, - pub app_data: *mut c_void, -} - -impl Copy for EVP_CIPHER {} -impl Clone for EVP_CIPHER { - fn clone(&self) -> EVP_CIPHER { *self } -} - -#[repr(C)] -pub struct HMAC_CTX { - md: *mut EVP_MD, - md_ctx: EVP_MD_CTX, - i_ctx: EVP_MD_CTX, - o_ctx: EVP_MD_CTX, - key_length: c_uint, - key: [c_uchar; 128] -} - -impl Copy for HMAC_CTX {} -impl Clone for HMAC_CTX { - fn clone(&self) -> HMAC_CTX { *self } + pub d: *mut c_void, } #[repr(C)] @@ -264,35 +73,10 @@ pub struct X509V3_CTX { // Maybe more here } -#[repr(C)] -pub struct GENERAL_NAME { - pub type_: c_int, - pub d: *mut c_void, -} - -impl Copy for GENERAL_NAME {} -impl Clone for GENERAL_NAME { - fn clone(&self) -> GENERAL_NAME { *self } -} - -impl Copy for X509V3_CTX {} -impl Clone for X509V3_CTX { - fn clone(&self) -> X509V3_CTX { *self } -} - -#[repr(C)] -pub struct BIGNUM { - pub d: *mut c_void, - pub top: c_int, - pub dmax: c_int, - pub neg: c_int, - pub flags: c_int, -} - -impl Copy for BIGNUM {} -impl Clone for BIGNUM { - fn clone(&self) -> BIGNUM { *self } -} +#[cfg(target_pointer_width = "64")] +pub type BN_ULONG = libc::c_ulonglong; +#[cfg(target_pointer_width = "32")] +pub type BN_ULONG = c_uint; pub type CRYPTO_EX_new = extern "C" fn(parent: *mut c_void, ptr: *mut c_void, ad: *const CRYPTO_EX_DATA, idx: c_int, @@ -348,15 +132,11 @@ pub const RSA_X931_PADDING: c_int = 5; pub const SSL_CTRL_SET_TMP_DH: c_int = 3; pub const SSL_CTRL_EXTRA_CHAIN_CERT: c_int = 14; -pub const SSL_CTRL_OPTIONS: c_int = 32; pub const SSL_CTRL_MODE: c_int = 33; pub const SSL_CTRL_SET_READ_AHEAD: c_int = 41; pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_CB: c_int = 53; pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG: c_int = 54; pub const SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55; -pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; -#[cfg(feature = "ecdh_auto")] -pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94; pub const SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER: c_long = 2; pub const SSL_MODE_AUTO_RETRY: c_long = 4; @@ -374,30 +154,21 @@ 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; -pub const SSL_OP_MICROSOFT_SESS_ID_BUG: c_long = 0x00000001; -pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: c_long = 0x00000002; -pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: c_long = 0x00000008; -pub const SSL_OP_TLSEXT_PADDING: c_long = 0x00000010; -pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: c_long = 0x00000020; -pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: c_long = 0x00000080; -pub const SSL_OP_TLS_D5_BUG: c_long = 0x00000100; -pub const SSL_OP_TLS_BLOCK_PADDING_BUG: c_long = 0x00000200; -pub const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: c_long = 0x00000800; -pub const SSL_OP_ALL: c_long = 0x80000BFF; -pub const SSL_OP_NO_QUERY_MTU: c_long = 0x00001000; -pub const SSL_OP_COOKIE_EXCHANGE: c_long = 0x00002000; -pub const SSL_OP_NO_TICKET: c_long = 0x00004000; -pub const SSL_OP_CISCO_ANYCONNECT: c_long = 0x00008000; -pub const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION: c_long = 0x00010000; -pub const SSL_OP_NO_COMPRESSION: c_long = 0x00020000; -pub const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: c_long = 0x00040000; -pub const SSL_OP_SINGLE_ECDH_USE: c_long = 0x00080000; -pub const SSL_OP_SINGLE_DH_USE: c_long = 0x00100000; -pub const SSL_OP_CIPHER_SERVER_PREFERENCE: c_long = 0x00400000; -pub const SSL_OP_TLS_ROLLBACK_BUG: c_long = 0x00800000; -pub const SSL_OP_NO_SSLv2: c_long = 0x01000000; -pub const SSL_OP_NO_SSLv3: c_long = 0x02000000; -pub const SSL_OP_NO_TLSv1: c_long = 0x04000000; +#[cfg(not(ossl101))] +pub const SSL_OP_TLSEXT_PADDING: c_ulong = 0x00000010; +pub const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: c_ulong = 0x00000800; +pub const SSL_OP_ALL: c_ulong = 0x80000BFF; +pub const SSL_OP_NO_QUERY_MTU: c_ulong = 0x00001000; +pub const SSL_OP_COOKIE_EXCHANGE: c_ulong = 0x00002000; +pub const SSL_OP_NO_TICKET: c_ulong = 0x00004000; +pub const SSL_OP_CISCO_ANYCONNECT: c_ulong = 0x00008000; +pub const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION: c_ulong = 0x00010000; +pub const SSL_OP_NO_COMPRESSION: c_ulong = 0x00020000; +pub const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: c_ulong = 0x00040000; +pub const SSL_OP_CIPHER_SERVER_PREFERENCE: c_ulong = 0x00400000; +pub const SSL_OP_TLS_ROLLBACK_BUG: c_ulong = 0x00800000; +pub const SSL_OP_NO_SSLv3: c_ulong = 0x02000000; +pub const SSL_OP_NO_TLSv1: c_ulong = 0x04000000; // Intentionally not bound since they conflict with SSL_OP_PKCS1_CHECK_1 and // SSL_OP_PKCS1_CHECK_2 on 0.9.8 :( @@ -410,24 +181,15 @@ pub const SSL_OP_NO_SSL_MASK: c_long = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2; */ -pub const TLSEXT_NAMETYPE_host_name: c_long = 0; +pub const TLSEXT_NAMETYPE_host_name: c_int = 0; pub const SSL_TLSEXT_ERR_OK: c_int = 0; pub const SSL_TLSEXT_ERR_ALERT_WARNING: c_int = 1; pub const SSL_TLSEXT_ERR_ALERT_FATAL: c_int = 2; pub const SSL_TLSEXT_ERR_NOACK: c_int = 3; -pub const SSLEAY_VERSION : c_int = 0; -pub const SSLEAY_CFLAGS : c_int = 2; -pub const SSLEAY_BUILT_ON : c_int = 3; -pub const SSLEAY_PLATFORM : c_int = 4; -pub const SSLEAY_DIR : c_int = 5; - -#[cfg(any(feature = "npn", feature = "alpn"))] pub const OPENSSL_NPN_UNSUPPORTED: c_int = 0; -#[cfg(any(feature = "npn", feature = "alpn"))] pub const OPENSSL_NPN_NEGOTIATED: c_int = 1; -#[cfg(any(feature = "npn", feature = "alpn"))] pub const OPENSSL_NPN_NO_OVERLAP: c_int = 2; pub const V_ASN1_GENERALIZEDTIME: c_int = 24; @@ -501,59 +263,6 @@ pub const GEN_URI: c_int = 6; pub const GEN_IPADD: c_int = 7; pub const GEN_RID: c_int = 8; -static mut MUTEXES: *mut Vec> = 0 as *mut Vec>; -static mut GUARDS: *mut Vec>> = 0 as *mut Vec>>; - -unsafe extern fn locking_function(mode: c_int, n: c_int, _file: *const c_char, - _line: c_int) { - let mutex = &(*MUTEXES)[n as usize]; - - if mode & CRYPTO_LOCK != 0 { - (*GUARDS)[n as usize] = Some(mutex.lock().unwrap()); - } else { - &(*GUARDS)[n as usize].take(); - } -} - -pub fn init() { - static INIT: Once = ONCE_INIT; - - INIT.call_once(|| { - unsafe { - SSL_library_init(); - SSL_load_error_strings(); - OPENSSL_add_all_algorithms_noconf(); - - let num_locks = CRYPTO_num_locks(); - let mut mutexes = Box::new(Vec::new()); - for _ in 0..num_locks { - mutexes.push(Mutex::new(())); - } - MUTEXES = mem::transmute(mutexes); - let guards: Box>>> = - Box::new((0..num_locks).map(|_| None).collect()); - GUARDS = mem::transmute(guards); - - CRYPTO_set_locking_callback(locking_function); - set_id_callback(); - } - }) -} - -#[cfg(unix)] -fn set_id_callback() { - unsafe extern "C" fn thread_id() -> c_ulong { - libc::pthread_self() as c_ulong - } - - unsafe { - CRYPTO_set_id_callback(thread_id); - } -} - -#[cfg(not(unix))] -fn set_id_callback() {} - // macros pub unsafe fn BIO_get_mem_data(b: *mut BIO, pp: *mut *mut c_char) -> c_long { BIO_ctrl(b, BIO_CTRL_INFO, 0, pp as *mut c_void) @@ -575,18 +284,6 @@ pub unsafe fn SSL_CTX_set_mode(ctx: *mut SSL_CTX, op: c_long) -> c_long { SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, op, ptr::null_mut()) } -pub unsafe fn SSL_CTX_set_options(ctx: *mut SSL_CTX, op: c_long) -> c_long { - SSL_CTX_ctrl(ctx, SSL_CTRL_OPTIONS, op, ptr::null_mut()) -} - -pub unsafe fn SSL_CTX_clear_options(ctx: *mut SSL_CTX, op: c_long) -> c_long { - SSL_CTX_ctrl(ctx, SSL_CTRL_CLEAR_OPTIONS, op, ptr::null_mut()) -} - -pub unsafe fn SSL_CTX_get_options(ctx: *mut SSL_CTX) -> c_long { - SSL_CTX_ctrl(ctx, SSL_CTRL_OPTIONS, 0, ptr::null_mut()) -} - pub unsafe fn SSL_CTX_set_read_ahead(ctx: *mut SSL_CTX, m: c_long) -> c_long { SSL_CTX_ctrl(ctx, SSL_CTRL_SET_READ_AHEAD, m, ptr::null_mut()) } @@ -599,11 +296,6 @@ 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(feature = "ecdh_auto")] -pub unsafe fn SSL_CTX_set_ecdh_auto(ctx: *mut SSL_CTX, onoff: c_long) -> c_long { - SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, ptr::null_mut()) -} - pub unsafe fn SSL_CTX_set_tlsext_servername_callback(ctx: *mut SSL_CTX, cb: Option) -> c_long { @@ -611,23 +303,12 @@ pub unsafe fn SSL_CTX_set_tlsext_servername_callback(ctx: *mut SSL_CTX, } pub unsafe fn SSL_set_tlsext_host_name(s: *mut SSL, name: *mut c_char) -> c_long { - SSL_ctrl(s, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, name as *mut c_void) + SSL_ctrl(s, SSL_CTRL_SET_TLSEXT_HOSTNAME, + TLSEXT_NAMETYPE_host_name as c_long, + name as *mut c_void) } -pub unsafe fn EVP_CIPHER_block_size(e: *const EVP_CIPHER) -> c_int { - (*e).block_size -} - -pub unsafe fn EVP_CIPHER_key_length(e: *const EVP_CIPHER) -> c_int { - (*e).key_len -} - -pub unsafe fn EVP_CIPHER_iv_length(e: *const EVP_CIPHER) -> c_int { - (*e).iv_len -} - -// True functions -extern "C" { +extern { pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; pub fn ASN1_TIME_free(tm: *mut ASN1_TIME); @@ -635,116 +316,101 @@ extern "C" { pub fn BIO_ctrl(b: *mut BIO, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; pub fn BIO_free_all(b: *mut BIO); - pub fn BIO_new(type_: *const BIO_METHOD) -> *mut BIO; pub fn BIO_new_fp(stream: *mut FILE, close_flag: c_int) -> *mut BIO; 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; - pub fn BIO_s_file() -> *const BIO_METHOD; - pub fn BIO_s_mem() -> *const BIO_METHOD; 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); pub fn BN_new() -> *mut BIGNUM; - pub fn BN_dup(n: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_dup(n: *const BIGNUM) -> *mut BIGNUM; pub fn BN_clear_free(bn: *mut BIGNUM); pub fn BN_CTX_new() -> *mut BN_CTX; pub fn BN_CTX_free(ctx: *mut BN_CTX); - pub fn BN_num_bits(bn: *mut BIGNUM) -> c_int; + pub fn BN_num_bits(bn: *const BIGNUM) -> c_int; pub fn BN_set_negative(bn: *mut BIGNUM, n: c_int); - pub fn BN_set_word(bn: *mut BIGNUM, n: c_ulong) -> c_int; + pub fn BN_set_word(bn: *mut BIGNUM, n: BN_ULONG) -> c_int; /* Arithmetic operations on BIGNUMs */ - pub fn BN_add(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; - pub fn BN_div(dv: *mut BIGNUM, rem: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_exp(r: *mut BIGNUM, a: *mut BIGNUM, p: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_gcd(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_mod_add(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_mod_exp(r: *mut BIGNUM, a: *mut BIGNUM, p: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_mod_inverse(r: *mut BIGNUM, a: *mut BIGNUM, n: *mut BIGNUM, ctx: *mut BN_CTX) -> *const BIGNUM; - pub fn BN_mod_mul(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_mod_sqr(r: *mut BIGNUM, a: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_mod_sub(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_mul(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_nnmod(rem: *mut BIGNUM, a: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_add_word(r: *mut BIGNUM, w: c_ulong) -> c_int; - pub fn BN_sub_word(r: *mut BIGNUM, w: c_ulong) -> c_int; - pub fn BN_mul_word(r: *mut BIGNUM, w: c_ulong) -> c_int; - pub fn BN_div_word(r: *mut BIGNUM, w: c_ulong) -> c_ulong; - pub fn BN_mod_word(r: *const BIGNUM, w: c_ulong) -> c_ulong; - pub fn BN_sqr(r: *mut BIGNUM, a: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_sub(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; + pub fn BN_add(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM) -> c_int; + pub fn BN_div(dv: *mut BIGNUM, rem: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_exp(r: *mut BIGNUM, a: *const BIGNUM, p: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_gcd(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_mod_add(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM, m: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_mod_exp(r: *mut BIGNUM, a: *const BIGNUM, p: *const BIGNUM, m: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_mod_inverse(r: *mut BIGNUM, a: *const BIGNUM, n: *const BIGNUM, ctx: *mut BN_CTX) -> *mut BIGNUM; + pub fn BN_mod_mul(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM, m: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_mod_sqr(r: *mut BIGNUM, a: *const BIGNUM, m: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_mod_sub(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM, m: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_mul(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_nnmod(rem: *mut BIGNUM, a: *const BIGNUM, m: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_add_word(r: *mut BIGNUM, w: BN_ULONG) -> c_int; + pub fn BN_sub_word(r: *mut BIGNUM, w: BN_ULONG) -> c_int; + pub fn BN_mul_word(r: *mut BIGNUM, w: BN_ULONG) -> c_int; + pub fn BN_div_word(r: *mut BIGNUM, w: BN_ULONG) -> BN_ULONG; + pub fn BN_mod_word(r: *const BIGNUM, w: BN_ULONG) -> BN_ULONG; + pub fn BN_sqr(r: *mut BIGNUM, a: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_sub(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM) -> c_int; /* Bit operations on BIGNUMs */ pub fn BN_clear_bit(a: *mut BIGNUM, n: c_int) -> c_int; - pub fn BN_is_bit_set(a: *mut BIGNUM, n: c_int) -> c_int; - pub fn BN_lshift(r: *mut BIGNUM, a: *mut BIGNUM, n: c_int) -> c_int; - pub fn BN_lshift1(r: *mut BIGNUM, a: *mut BIGNUM) -> c_int; + pub fn BN_is_bit_set(a: *const BIGNUM, n: c_int) -> c_int; + pub fn BN_lshift(r: *mut BIGNUM, a: *const BIGNUM, n: c_int) -> c_int; + pub fn BN_lshift1(r: *mut BIGNUM, a: *const BIGNUM) -> c_int; pub fn BN_mask_bits(a: *mut BIGNUM, n: c_int) -> c_int; - pub fn BN_rshift(r: *mut BIGNUM, a: *mut BIGNUM, n: c_int) -> c_int; + pub fn BN_rshift(r: *mut BIGNUM, a: *const BIGNUM, n: c_int) -> c_int; pub fn BN_set_bit(a: *mut BIGNUM, n: c_int) -> c_int; - pub fn BN_rshift1(r: *mut BIGNUM, a: *mut BIGNUM) -> c_int; + pub fn BN_rshift1(r: *mut BIGNUM, a: *const BIGNUM) -> c_int; /* Comparisons on BIGNUMs */ - pub fn BN_cmp(a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; - pub fn BN_ucmp(a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; + pub fn BN_cmp(a: *const BIGNUM, b: *const BIGNUM) -> c_int; + pub fn BN_ucmp(a: *const BIGNUM, b: *const BIGNUM) -> c_int; /* Prime handling */ - pub fn BN_generate_prime_ex(r: *mut BIGNUM, bits: c_int, safe: c_int, add: *mut BIGNUM, rem: *mut BIGNUM, cb: *const c_void) -> c_int; - pub fn BN_is_prime_ex(p: *mut BIGNUM, checks: c_int, ctx: *mut BN_CTX, cb: *const c_void) -> c_int; - pub fn BN_is_prime_fasttest_ex(p: *mut BIGNUM, checks: c_int, ctx: *mut BN_CTX, do_trial_division: c_int, cb: *const c_void) -> c_int; + pub fn BN_generate_prime_ex(r: *mut BIGNUM, bits: c_int, safe: c_int, add: *const BIGNUM, rem: *const BIGNUM, cb: *mut BN_GENCB) -> c_int; + pub fn BN_is_prime_ex(p: *const BIGNUM, checks: c_int, ctx: *mut BN_CTX, cb: *mut BN_GENCB) -> c_int; + pub fn BN_is_prime_fasttest_ex(p: *const BIGNUM, checks: c_int, ctx: *mut BN_CTX, do_trial_division: c_int, cb: *mut BN_GENCB) -> c_int; /* Random number handling */ pub fn BN_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int; pub fn BN_pseudo_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int; - pub fn BN_rand_range(r: *mut BIGNUM, range: *mut BIGNUM) -> c_int; - pub fn BN_pseudo_rand_range(r: *mut BIGNUM, range: *mut BIGNUM) -> c_int; + pub fn BN_rand_range(r: *mut BIGNUM, range: *const BIGNUM) -> c_int; + pub fn BN_pseudo_rand_range(r: *mut BIGNUM, range: *const BIGNUM) -> c_int; /* Conversion from/to binary representation */ pub fn BN_bin2bn(s: *const u8, size: c_int, ret: *mut BIGNUM) -> *mut BIGNUM; - pub fn BN_bn2bin(a: *mut BIGNUM, to: *mut u8) -> c_int; + pub fn BN_bn2bin(a: *const BIGNUM, to: *mut u8) -> c_int; /* Conversion from/to decimal string representation */ - pub fn BN_dec2bn(a: *const *mut BIGNUM, s: *const c_char) -> c_int; - pub fn BN_bn2dec(a: *mut BIGNUM) -> *const c_char; + pub fn BN_dec2bn(a: *mut *mut BIGNUM, s: *const c_char) -> c_int; + pub fn BN_bn2dec(a: *const BIGNUM) -> *mut c_char; /* Conversion from/to hexidecimal string representation */ - pub fn BN_hex2bn(a: *const *mut BIGNUM, s: *const c_char) -> c_int; - pub fn BN_bn2hex(a: *mut BIGNUM) -> *const c_char; + pub fn BN_hex2bn(a: *mut *mut BIGNUM, s: *const c_char) -> c_int; + pub fn BN_bn2hex(a: *const BIGNUM) -> *mut c_char; - pub fn CRYPTO_num_locks() -> c_int; - pub fn CRYPTO_set_locking_callback(func: unsafe extern "C" fn(mode: c_int, - n: c_int, - file: *const c_char, - line: c_int)); - pub fn CRYPTO_set_id_callback(func: unsafe extern "C" fn() -> c_ulong); - pub fn CRYPTO_free(buf: *mut c_void); pub fn CRYPTO_memcmp(a: *const c_void, b: *const c_void, len: size_t) -> c_int; pub fn DH_free(dh: *mut DH); - #[cfg(feature = "rfc5114")] + #[cfg(not(ossl101))] pub fn DH_get_1024_160() -> *mut DH; - #[cfg(feature = "rfc5114")] + #[cfg(not(ossl101))] pub fn DH_get_2048_224() -> *mut DH; - #[cfg(feature = "rfc5114")] + #[cfg(not(ossl101))] pub fn DH_get_2048_256() -> *mut DH; - // FIXME delete on next version bump - pub fn DH_new_from_params(p: *mut BIGNUM, g: *mut BIGNUM, q: *mut BIGNUM) -> *mut DH; - pub fn ERR_get_error() -> c_ulong; pub fn ERR_lib_error_string(err: c_ulong) -> *const c_char; pub fn ERR_func_error_string(err: c_ulong) -> *const c_char; pub fn ERR_reason_error_string(err: c_ulong) -> *const c_char; - pub fn ERR_load_crypto_strings(); - pub fn EVP_md5() -> *const EVP_MD; pub fn EVP_ripemd160() -> *const EVP_MD; pub fn EVP_sha1() -> *const EVP_MD; @@ -755,9 +421,7 @@ extern "C" { pub fn EVP_aes_128_cbc() -> *const EVP_CIPHER; pub fn EVP_aes_128_ecb() -> *const EVP_CIPHER; - #[cfg(feature = "aes_xts")] pub fn EVP_aes_128_xts() -> *const EVP_CIPHER; - #[cfg(feature = "aes_ctr")] pub fn EVP_aes_128_ctr() -> *const EVP_CIPHER; // fn EVP_aes_128_gcm() -> EVP_CIPHER; pub fn EVP_aes_128_cfb1() -> *const EVP_CIPHER; @@ -765,9 +429,7 @@ extern "C" { pub fn EVP_aes_128_cfb8() -> *const EVP_CIPHER; pub fn EVP_aes_256_cbc() -> *const EVP_CIPHER; pub fn EVP_aes_256_ecb() -> *const EVP_CIPHER; - #[cfg(feature = "aes_xts")] pub fn EVP_aes_256_xts() -> *const EVP_CIPHER; - #[cfg(feature = "aes_ctr")] pub fn EVP_aes_256_ctr() -> *const EVP_CIPHER; // fn EVP_aes_256_gcm() -> EVP_CIPHER; pub fn EVP_aes_256_cfb1() -> *const EVP_CIPHER; @@ -792,35 +454,34 @@ extern "C" { pub fn EVP_CipherInit_ex(ctx: *mut EVP_CIPHER_CTX, type_: *const EVP_CIPHER, impl_: *mut ENGINE, - key: *mut c_uchar, - iv: *mut c_uchar, + key: *const c_uchar, + iv: *const c_uchar, enc: c_int) -> c_int; pub fn EVP_CipherUpdate(ctx: *mut EVP_CIPHER_CTX, outbuf: *mut u8, - outlen: &mut c_int, inbuf: *const u8, inlen: c_int) -> c_int; - pub fn EVP_CipherFinal(ctx: *mut EVP_CIPHER_CTX, res: *mut u8, len: &mut c_int) -> c_int; + outlen: *mut c_int, inbuf: *const u8, inlen: c_int) -> c_int; + pub fn EVP_CipherFinal(ctx: *mut EVP_CIPHER_CTX, res: *mut u8, len: *mut c_int) -> c_int; pub fn EVP_DigestInit(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD) -> c_int; - pub fn EVP_DigestInit_ex(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD, imple: *const ENGINE) -> c_int; - pub fn EVP_DigestUpdate(ctx: *mut EVP_MD_CTX, data: *const u8, n: c_uint) -> c_int; + pub fn EVP_DigestInit_ex(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD, imple: *mut ENGINE) -> c_int; + pub fn EVP_DigestUpdate(ctx: *mut EVP_MD_CTX, data: *const c_void, n: size_t) -> c_int; pub fn EVP_DigestFinal(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32) -> c_int; pub fn EVP_DigestFinal_ex(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32) -> c_int; - pub fn EVP_MD_CTX_create() -> *mut EVP_MD_CTX; + #[cfg_attr(any(ossl101, ossl102), link_name = "EVP_MD_CTX_create")] + pub fn EVP_MD_CTX_new() -> *mut EVP_MD_CTX; pub fn EVP_MD_CTX_copy_ex(dst: *mut EVP_MD_CTX, src: *const EVP_MD_CTX) -> c_int; - pub fn EVP_MD_CTX_destroy(ctx: *mut EVP_MD_CTX); + #[cfg_attr(any(ossl101, ossl102), link_name = "EVP_MD_CTX_destroy")] + pub fn EVP_MD_CTX_free(ctx: *mut EVP_MD_CTX); pub fn EVP_PKEY_new() -> *mut EVP_PKEY; pub fn EVP_PKEY_free(k: *mut EVP_PKEY); - pub fn EVP_PKEY_assign(pkey: *mut EVP_PKEY, typ: c_int, key: *const c_void) -> c_int; + pub fn EVP_PKEY_assign(pkey: *mut EVP_PKEY, typ: c_int, key: *mut c_void) -> c_int; pub fn EVP_PKEY_copy_parameters(to: *mut EVP_PKEY, from: *const EVP_PKEY) -> c_int; pub fn EVP_PKEY_get1_RSA(k: *mut EVP_PKEY) -> *mut RSA; pub fn EVP_PKEY_set1_RSA(k: *mut EVP_PKEY, r: *mut RSA) -> c_int; pub fn EVP_PKEY_cmp(a: *const EVP_PKEY, b: *const EVP_PKEY) -> c_int; - pub fn HMAC_CTX_init(ctx: *mut HMAC_CTX); - pub fn HMAC_CTX_cleanup(ctx: *mut HMAC_CTX); - #[cfg(feature = "hmac_clone")] - pub fn HMAC_CTX_copy(dst: *mut HMAC_CTX, src: *const HMAC_CTX) -> c_int; + pub fn HMAC_CTX_copy(dst: *mut HMAC_CTX, src: *mut HMAC_CTX) -> c_int; pub fn PEM_read_bio_DHparams(bio: *mut BIO, out: *mut *mut DH, callback: Option, user_data: *mut c_void) -> *mut DH; @@ -845,7 +506,7 @@ extern "C" { kstr: *mut c_uchar, klen: c_int, callback: Option, user_data: *mut c_void) -> c_int; - pub fn PEM_write_bio_RSAPublicKey(bp: *mut BIO, rsa: *mut RSA) -> c_int; + pub fn PEM_write_bio_RSAPublicKey(bp: *mut BIO, rsa: *const RSA) -> c_int; pub fn PEM_write_bio_RSA_PUBKEY(bp: *mut BIO, rsa: *mut RSA) -> c_int; pub fn PEM_read_bio_DSAPrivateKey(bp: *mut BIO, dsa: *mut *mut DSA, callback: Option, @@ -862,13 +523,12 @@ extern "C" { pub fn PEM_write_bio_X509(bio: *mut BIO, x509: *mut X509) -> c_int; pub fn PEM_write_bio_X509_REQ(bio: *mut BIO, x509: *mut X509_REQ) -> c_int; - pub fn PKCS5_PBKDF2_HMAC_SHA1(pass: *const u8, passlen: c_int, + pub fn PKCS5_PBKDF2_HMAC_SHA1(pass: *const c_char, passlen: c_int, salt: *const u8, saltlen: c_int, iter: c_int, keylen: c_int, out: *mut u8) -> c_int; - #[cfg(feature = "pkcs5_pbkdf2_hmac")] - pub fn PKCS5_PBKDF2_HMAC(pass: *const u8, passlen: c_int, - salt: *const u8, saltlen: c_int, + pub fn PKCS5_PBKDF2_HMAC(pass: *const c_char, passlen: c_int, + salt: *const c_uchar, saltlen: c_int, iter: c_int, digest: *const EVP_MD, keylen: c_int, out: *mut u8) -> c_int; @@ -877,7 +537,6 @@ extern "C" { pub fn RSA_new() -> *mut RSA; pub fn RSA_free(rsa: *mut RSA); - pub fn RSA_generate_key(modsz: c_int, e: c_ulong, cb: *const c_void, cbarg: *const c_void) -> *mut RSA; pub fn RSA_generate_key_ex(rsa: *mut RSA, bits: c_int, e: *mut BIGNUM, cb: *mut BN_GENCB) -> c_int; pub fn RSA_private_decrypt(flen: c_int, from: *const u8, to: *mut u8, k: *mut RSA, pad: c_int) -> c_int; @@ -889,7 +548,7 @@ extern "C" { pad: c_int) -> c_int; pub fn RSA_sign(t: c_int, m: *const u8, mlen: c_uint, sig: *mut u8, siglen: *mut c_uint, k: *mut RSA) -> c_int; - pub fn RSA_size(k: *mut RSA) -> c_int; + pub fn RSA_size(k: *const RSA) -> c_int; pub fn RSA_verify(t: c_int, m: *const u8, mlen: c_uint, sig: *const u8, siglen: c_uint, k: *mut RSA) -> c_int; @@ -898,75 +557,51 @@ extern "C" { pub fn DSA_size(dsa: *const DSA) -> c_int; pub fn DSA_generate_parameters_ex(dsa: *mut DSA, bits: c_int, seed: *const c_uchar, seed_len: c_int, counter_ref: *mut c_int, h_ret: *mut c_ulong, - cb: *const c_void) -> c_int; + cb: *mut BN_GENCB) -> c_int; pub fn DSA_generate_key(dsa: *mut DSA) -> c_int; pub fn DSA_sign(dummy: c_int, dgst: *const c_uchar, len: c_int, sigret: *mut c_uchar, siglen: *mut c_uint, dsa: *mut DSA) -> c_int; pub fn DSA_verify(dummy: c_int, dgst: *const c_uchar, len: c_int, sigbuf: *const c_uchar, siglen: c_int, dsa: *mut DSA) -> c_int; - pub fn SSL_library_init() -> c_int; - pub fn SSL_load_error_strings(); - pub fn OPENSSL_add_all_algorithms_noconf(); - - #[cfg(feature = "sslv2")] - pub fn SSLv2_method() -> *const SSL_METHOD; - pub fn SSLv3_method() -> *const SSL_METHOD; - pub fn TLSv1_method() -> *const SSL_METHOD; - #[cfg(feature = "tlsv1_1")] - pub fn TLSv1_1_method() -> *const SSL_METHOD; - #[cfg(feature = "tlsv1_2")] - pub fn TLSv1_2_method() -> *const SSL_METHOD; - #[cfg(feature = "dtlsv1")] - pub fn DTLSv1_method() -> *const SSL_METHOD; - #[cfg(feature = "dtlsv1_2")] - pub fn DTLSv1_2_method() -> *const SSL_METHOD; - pub fn SSLv23_method() -> *const SSL_METHOD; - pub fn SSL_new(ctx: *mut SSL_CTX) -> *mut SSL; pub fn SSL_pending(ssl: *const SSL) -> c_int; pub fn SSL_free(ssl: *mut SSL); pub fn SSL_set_bio(ssl: *mut SSL, rbio: *mut BIO, wbio: *mut BIO); - pub fn SSL_get_rbio(ssl: *mut SSL) -> *mut BIO; - pub fn SSL_get_wbio(ssl: *mut SSL) -> *mut BIO; + pub fn SSL_get_rbio(ssl: *const SSL) -> *mut BIO; + pub fn SSL_get_wbio(ssl: *const SSL) -> *mut BIO; pub fn SSL_accept(ssl: *mut SSL) -> c_int; pub fn SSL_connect(ssl: *mut SSL) -> c_int; pub fn SSL_do_handshake(ssl: *mut SSL) -> c_int; pub fn SSL_ctrl(ssl: *mut SSL, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; - pub fn SSL_get_error(ssl: *mut SSL, ret: c_int) -> c_int; + pub fn SSL_get_error(ssl: *const SSL, ret: c_int) -> c_int; pub fn SSL_read(ssl: *mut SSL, buf: *mut c_void, num: c_int) -> c_int; pub fn SSL_write(ssl: *mut SSL, buf: *const c_void, num: c_int) -> c_int; pub fn SSL_get_ex_data_X509_STORE_CTX_idx() -> c_int; - pub fn SSL_get_SSL_CTX(ssl: *mut SSL) -> *mut SSL_CTX; + pub fn SSL_get_SSL_CTX(ssl: *const SSL) -> *mut SSL_CTX; pub fn SSL_set_SSL_CTX(ssl: *mut SSL, ctx: *mut SSL_CTX) -> *mut SSL_CTX; pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const COMP_METHOD; - pub fn SSL_get_peer_certificate(ssl: *mut SSL) -> *mut X509; + pub fn SSL_get_peer_certificate(ssl: *const SSL) -> *mut X509; pub fn SSL_get_ssl_method(ssl: *mut SSL) -> *const SSL_METHOD; - pub fn SSL_get_version(ssl: *mut SSL) -> *const c_char; - pub fn SSL_state_string(ssl: *mut SSL) -> *const c_char; - pub fn SSL_state_string_long(ssl: *mut SSL) -> *const c_char; + pub fn SSL_get_version(ssl: *const SSL) -> *const c_char; + pub fn SSL_state_string(ssl: *const SSL) -> *const c_char; + pub fn SSL_state_string_long(ssl: *const SSL) -> *const c_char; pub fn SSL_set_verify(ssl: *mut SSL, mode: c_int, verify_callback: Option c_int>); - pub fn SSL_get_ex_new_index(argl: c_long, argp: *const c_void, - new_func: Option, - dup_func: Option, - free_func: Option) - -> c_int; pub fn SSL_set_ex_data(ssl: *mut SSL, idx: c_int, data: *mut c_void) -> c_int; - pub fn SSL_get_ex_data(ssl: *mut SSL, idx: c_int) -> *mut c_void; + 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_long) -> *const c_char; + pub fn SSL_get_servername(ssl: *const SSL, name_type: c_int) -> *const c_char; pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char; pub fn SSL_get_current_cipher(ssl: *const SSL) -> *const SSL_CIPHER; pub fn SSL_CIPHER_get_name(cipher: *const SSL_CIPHER) -> *const c_char; - pub fn SSL_CIPHER_get_bits(cipher: *const SSL_CIPHER, alg_bits: *const c_int) -> c_int; - pub fn SSL_CIPHER_get_version(cipher: *const SSL_CIPHER) -> *const c_char; - pub fn SSL_CIPHER_description(cipher: *const SSL_CIPHER, buf: *mut c_char, size: c_int) -> *const c_char; + pub fn SSL_CIPHER_get_bits(cipher: *const SSL_CIPHER, alg_bits: *mut c_int) -> c_int; + pub fn SSL_CIPHER_description(cipher: *const SSL_CIPHER, buf: *mut c_char, size: c_int) -> *mut c_char; pub fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX; pub fn SSL_CTX_free(ctx: *mut SSL_CTX); @@ -978,34 +613,27 @@ extern "C" { pub fn SSL_CTX_load_verify_locations(ctx: *mut SSL_CTX, CAfile: *const c_char, CApath: *const c_char) -> c_int; pub fn SSL_CTX_set_default_verify_paths(ctx: *mut SSL_CTX) -> c_int; - pub fn SSL_CTX_get_ex_new_index(argl: c_long, argp: *const c_void, - new_func: Option, - dup_func: Option, - free_func: Option) - -> c_int; pub fn SSL_CTX_set_ex_data(ctx: *mut SSL_CTX, idx: c_int, data: *mut c_void) -> c_int; - pub fn SSL_CTX_get_ex_data(ctx: *mut SSL_CTX, idx: c_int) -> *mut c_void; + pub fn SSL_CTX_get_ex_data(ctx: *const SSL_CTX, idx: c_int) -> *mut c_void; pub fn SSL_CTX_set_session_id_context(ssl: *mut SSL_CTX, sid_ctx: *const c_uchar, sid_ctx_len: c_uint) -> c_int; pub fn SSL_CTX_use_certificate_file(ctx: *mut SSL_CTX, cert_file: *const c_char, file_type: c_int) -> c_int; - pub fn SSL_CTX_use_certificate_chain_file(ctx: *mut SSL_CTX, cert_chain_file: *const c_char, file_type: c_int) -> c_int; + pub fn SSL_CTX_use_certificate_chain_file(ctx: *mut SSL_CTX, cert_chain_file: *const c_char) -> c_int; pub fn SSL_CTX_use_certificate(ctx: *mut SSL_CTX, cert: *mut X509) -> c_int; pub fn SSL_CTX_use_PrivateKey_file(ctx: *mut SSL_CTX, key_file: *const c_char, file_type: c_int) -> c_int; pub fn SSL_CTX_use_PrivateKey(ctx: *mut SSL_CTX, key: *mut EVP_PKEY) -> c_int; - pub fn SSL_CTX_check_private_key(ctx: *mut SSL_CTX) -> c_int; + pub fn SSL_CTX_check_private_key(ctx: *const SSL_CTX) -> c_int; pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int; - #[cfg(feature = "npn")] pub fn SSL_CTX_set_next_protos_advertised_cb(ssl: *mut SSL_CTX, cb: extern "C" fn(ssl: *mut SSL, out: *mut *const c_uchar, outlen: *mut c_uint, arg: *mut c_void) -> c_int, arg: *mut c_void); - #[cfg(feature = "npn")] pub fn SSL_CTX_set_next_proto_select_cb(ssl: *mut SSL_CTX, cb: extern "C" fn(ssl: *mut SSL, out: *mut *mut c_uchar, @@ -1014,59 +642,49 @@ extern "C" { inlen: c_uint, arg: *mut c_void) -> c_int, arg: *mut c_void); - #[cfg(any(feature = "alpn", feature = "npn"))] pub fn SSL_select_next_proto(out: *mut *mut c_uchar, outlen: *mut c_uchar, inbuf: *const c_uchar, inlen: c_uint, client: *const c_uchar, client_len: c_uint) -> c_int; - #[cfg(feature = "npn")] pub fn SSL_get0_next_proto_negotiated(s: *const SSL, data: *mut *const c_uchar, len: *mut c_uint); - #[cfg(feature = "alpn")] + #[cfg(not(ossl101))] pub fn SSL_CTX_set_alpn_protos(s: *mut SSL_CTX, data: *const c_uchar, len: c_uint) -> c_int; - #[cfg(feature = "alpn")] + #[cfg(not(ossl101))] pub fn SSL_set_alpn_protos(s: *mut SSL, data: *const c_uchar, len: c_uint) -> c_int; - #[cfg(feature = "alpn")] + #[cfg(not(ossl101))] pub fn SSL_CTX_set_alpn_select_cb(ssl: *mut SSL_CTX, - cb: extern "C" fn(ssl: *mut SSL, - out: *mut *mut c_uchar, - outlen: *mut c_uchar, - inbuf: *const c_uchar, - inlen: c_uint, - arg: *mut c_void) -> c_int, - arg: *mut c_void); - #[cfg(feature = "alpn")] + cb: extern fn(ssl: *mut SSL, + out: *mut *const c_uchar, + outlen: *mut c_uchar, + inbuf: *const c_uchar, + inlen: c_uint, + arg: *mut c_void) -> c_int, + arg: *mut c_void); + #[cfg(not(ossl101))] 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; - pub fn X509_digest(x: *mut X509, digest: *const EVP_MD, buf: *mut c_char, len: *mut c_uint) -> c_int; + pub fn X509_digest(x: *const X509, digest: *const EVP_MD, buf: *mut c_uchar, len: *mut c_uint) -> c_int; pub fn X509_free(x: *mut X509); pub fn X509_REQ_free(x: *mut X509_REQ); pub fn X509_get_serialNumber(x: *mut X509) -> *mut ASN1_INTEGER; - pub fn X509_get_subject_name(x: *mut X509) -> *mut X509_NAME; pub fn X509_gmtime_adj(time: *mut ASN1_TIME, adj: c_long) -> *mut ASN1_TIME; pub fn X509_new() -> *mut X509; pub fn X509_set_issuer_name(x: *mut X509, name: *mut X509_NAME) -> c_int; - pub fn X509_set_notAfter(x: *mut X509, tm: *const ASN1_TIME) -> c_int; - pub fn X509_set_notBefore(x: *mut X509, tm: *const ASN1_TIME) -> c_int; - pub fn X509_set_version(x: *mut X509, version: c_ulong) -> c_int; + pub fn X509_set_version(x: *mut X509, version: c_long) -> c_int; pub fn X509_set_pubkey(x: *mut X509, pkey: *mut EVP_PKEY) -> c_int; pub fn X509_sign(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; pub fn X509_get_pubkey(x: *mut X509) -> *mut EVP_PKEY; pub fn X509_to_X509_REQ(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> *mut X509_REQ; - pub fn X509_get_ext_d2i(x: *mut X509, nid: c_int, crit: *mut c_int, idx: *mut c_int) -> *mut c_void; pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION); - pub fn X509_NAME_add_entry_by_txt(x: *mut X509, field: *const c_char, ty: c_int, bytes: *const c_char, len: c_int, loc: c_int, set: c_int) -> c_int; + pub fn X509_NAME_add_entry_by_txt(x: *mut X509_NAME, field: *const c_char, ty: c_int, bytes: *const c_uchar, len: c_int, loc: c_int, set: c_int) -> c_int; pub fn X509_NAME_get_index_by_NID(n: *mut X509_NAME, nid: c_int, last_pos: c_int) ->c_int; - pub fn X509_NAME_get_entry(n: *mut X509_NAME, loc: c_int) -> *mut X509_NAME_ENTRY; - pub fn X509_NAME_ENTRY_get_data(ne: *mut X509_NAME_ENTRY) -> *mut ASN1_STRING; - pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_char, s: *mut ASN1_STRING) -> c_int; - pub fn ASN1_STRING_length(x: *mut ASN1_STRING) -> c_int; - pub fn ASN1_STRING_data(x: *mut ASN1_STRING) -> *mut c_uchar; + pub fn ASN1_STRING_length(x: *const ASN1_STRING) -> c_int; pub fn X509_STORE_CTX_get_current_cert(ct: *mut X509_STORE_CTX) -> *mut X509; pub fn X509_STORE_CTX_get_error(ctx: *mut X509_STORE_CTX) -> c_int; @@ -1080,14 +698,14 @@ extern "C" { pub fn X509_REQ_add_extensions(req: *mut X509_REQ, exts: *mut stack_st_X509_EXTENSION) -> c_int; pub fn X509_REQ_sign(x: *mut X509_REQ, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; - pub fn d2i_X509(a: *mut *mut X509, pp: *mut *mut c_uchar, length: c_long) -> *mut X509; + pub fn d2i_X509(a: *mut *mut X509, pp: *mut *const c_uchar, length: c_long) -> *mut X509; pub fn i2d_X509_bio(b: *mut BIO, x: *mut X509) -> c_int; pub fn i2d_X509_REQ_bio(b: *mut BIO, x: *mut X509_REQ) -> c_int; - pub fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *const *mut u8) -> c_int; - pub fn d2i_RSA_PUBKEY(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA; - pub fn i2d_RSAPrivateKey(k: *mut RSA, buf: *const *mut u8) -> c_int; - pub fn d2i_RSAPrivateKey(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA; + pub fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *mut *mut u8) -> c_int; + pub fn d2i_RSA_PUBKEY(k: *mut *mut RSA, buf: *mut *const u8, len: c_long) -> *mut RSA; + pub fn i2d_RSAPrivateKey(k: *const RSA, buf: *mut *mut u8) -> c_int; + pub fn d2i_RSAPrivateKey(k: *mut *mut RSA, buf: *mut *const u8, len: c_long) -> *mut RSA; pub fn d2i_PKCS12(a: *mut *mut PKCS12, pp: *mut *const u8, length: c_long) -> *mut PKCS12; pub fn PKCS12_parse(p12: *mut PKCS12, @@ -1098,14 +716,18 @@ extern "C" { -> c_int; pub fn PKCS12_free(p12: *mut PKCS12); - pub fn sk_free(st: *mut _STACK); - pub fn sk_pop_free(st: *mut _STACK, free: Option); - pub fn sk_pop(st: *mut _STACK) -> *mut c_char; - pub fn GENERAL_NAME_free(name: *mut GENERAL_NAME); - pub fn SSLeay() -> c_long; - pub fn SSLeay_version(key: c_int) -> *const c_char; + pub fn HMAC_Init_ex(ctx: *mut HMAC_CTX, + key: *const c_void, + len: c_int, + md: *const EVP_MD, + impl_: *mut ENGINE) -> c_int; + pub fn HMAC_Update(ctx: *mut HMAC_CTX, + data: *const c_uchar, + len: size_t) -> c_int; + pub fn HMAC_Final(ctx: *mut HMAC_CTX, + md: *mut c_uchar, + len: *mut c_uint) -> c_int; + pub fn DH_new() -> *mut DH; } - -pub mod probe; diff --git a/openssl-sys/src/ossl10x.rs b/openssl-sys/src/ossl10x.rs new file mode 100644 index 00000000..8420846a --- /dev/null +++ b/openssl-sys/src/ossl10x.rs @@ -0,0 +1,569 @@ +use std::sync::{Mutex, MutexGuard}; +use std::sync::{Once, ONCE_INIT}; +use std::mem; + +use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong}; + +#[repr(C)] +pub struct stack_st_X509 { + pub stack: _STACK, +} + +#[repr(C)] +pub struct stack_st_X509_ATTRIBUTE { + pub stack: _STACK, +} + +#[repr(C)] +pub struct stack_st_X509_EXTENSION { + pub stack: _STACK, +} + +#[repr(C)] +pub struct stack_st_GENERAL_NAME { + pub stack: _STACK, +} + +#[repr(C)] +pub struct stack_st_void { + pub stack: _STACK, +} + +#[repr(C)] +pub struct _STACK { + pub num: c_int, + pub data: *mut *mut c_char, + pub sorted: c_int, + pub num_alloc: c_int, + pub comp: Option c_int>, +} + +#[repr(C)] +pub struct BIO_METHOD { + pub type_: c_int, + pub name: *const c_char, + pub bwrite: Option c_int>, + pub bread: Option c_int>, + pub bputs: Option c_int>, + pub bgets: Option c_int>, + pub ctrl: Option c_long>, + pub create: Option c_int>, + pub destroy: Option c_int>, + pub callback_ctrl: Option c_long>, +} + +#[repr(C)] +pub struct RSA { + pub pad: c_int, + pub version: c_long, + pub meth: *const ::RSA_METHOD, + + pub engine: *mut ::ENGINE, + pub n: *mut ::BIGNUM, + pub e: *mut ::BIGNUM, + pub d: *mut ::BIGNUM, + pub p: *mut ::BIGNUM, + pub q: *mut ::BIGNUM, + pub dmp1: *mut ::BIGNUM, + pub dmq1: *mut ::BIGNUM, + pub iqmp: *mut ::BIGNUM, + + pub ex_data: ::CRYPTO_EX_DATA, + pub references: c_int, + pub flags: c_int, + + pub _method_mod_n: *mut ::BN_MONT_CTX, + pub _method_mod_p: *mut ::BN_MONT_CTX, + pub _method_mod_q: *mut ::BN_MONT_CTX, + + pub bignum_data: *mut c_char, + pub blinding: *mut ::BN_BLINDING, + pub mt_blinding: *mut ::BN_BLINDING, +} + +#[repr(C)] +pub struct DSA { + pub pad: c_int, + pub version: c_long, + pub write_params: c_int, + + pub p: *mut ::BIGNUM, + pub q: *mut ::BIGNUM, + pub g: *mut ::BIGNUM, + pub pub_key: *mut ::BIGNUM, + pub priv_key: *mut ::BIGNUM, + pub kinv: *mut ::BIGNUM, + pub r: *mut ::BIGNUM, + + pub flags: c_int, + pub method_mont_p: *mut ::BN_MONT_CTX, + pub references: c_int, + pub ex_data: ::CRYPTO_EX_DATA, + pub meth: *const ::DSA_METHOD, + pub engine: *mut ::ENGINE, +} + +#[repr(C)] +pub struct EVP_PKEY { + pub type_: c_int, + pub save_type: c_int, + pub references: c_int, + pub ameth: *const ::EVP_PKEY_ASN1_METHOD, + pub engine: *mut ::ENGINE, + pub pkey: *mut c_void, + pub save_parameters: c_int, + pub attributes: *mut stack_st_X509_ATTRIBUTE, +} + +#[repr(C)] +pub struct BIO { + pub method: *mut ::BIO_METHOD, + pub callback: Option c_long>, + pub cb_arg: *mut c_char, + pub init: c_int, + pub shutdown: c_int, + pub flags: c_int, + pub retry_reason: c_int, + pub num: c_int, + pub ptr: *mut c_void, + pub next_bio: *mut ::BIO, + pub prev_bio: *mut ::BIO, + pub references: c_int, + pub num_read: c_ulong, + pub num_write: c_ulong, + pub ex_data: ::CRYPTO_EX_DATA, +} + +#[repr(C)] +pub struct CRYPTO_EX_DATA { + pub sk: *mut ::stack_st_void, + pub dummy: c_int, +} + +#[repr(C)] +pub struct EVP_MD_CTX { + digest: *mut ::EVP_MD, + engine: *mut ::ENGINE, + flags: c_ulong, + md_data: *mut c_void, + pctx: *mut ::EVP_PKEY_CTX, + update: *mut c_void +} + +#[repr(C)] +pub struct EVP_CIPHER { + pub nid: c_int, + pub block_size: c_int, + pub key_len: c_int, + pub iv_len: c_int, + pub flags: c_ulong, + pub init: Option c_int>, + pub do_cipher: Option c_int>, + pub cleanup: Option c_int>, + pub ctx_size: c_int, + pub set_asn1_parameters: Option c_int>, + pub get_asn1_parameters: Option c_int>, + pub ctrl: Option c_int>, + pub app_data: *mut c_void, +} + +#[repr(C)] +pub struct HMAC_CTX { + md: *mut ::EVP_MD, + md_ctx: ::EVP_MD_CTX, + i_ctx: ::EVP_MD_CTX, + o_ctx: ::EVP_MD_CTX, + key_length: c_uint, + key: [c_uchar; 128] +} + +#[repr(C)] +pub struct BIGNUM { + pub d: *mut ::BN_ULONG, + pub top: c_int, + pub dmax: c_int, + pub neg: c_int, + pub flags: c_int, +} + +#[repr(C)] +pub struct DH { + pub pad: c_int, + pub version: c_int, + pub p: *mut ::BIGNUM, + pub g: *mut ::BIGNUM, + pub length: c_long, + pub pub_key: *mut ::BIGNUM, + pub priv_key: *mut ::BIGNUM, + pub flags: c_int, + pub method_mont_p: *mut ::BN_MONT_CTX, + pub q: *mut ::BIGNUM, + pub j: *mut ::BIGNUM, + pub seed: *mut c_uchar, + pub seedlen: c_int, + pub counter: *mut ::BIGNUM, + pub references: c_int, + pub ex_data: ::CRYPTO_EX_DATA, + pub meth: *const ::DH_METHOD, + pub engine: *mut ::ENGINE, +} + +#[repr(C)] +pub struct X509 { + pub cert_info: *mut X509_CINF, + sig_alg: *mut c_void, + signature: *mut c_void, + pub valid: c_int, + pub references: c_int, + pub name: *mut c_char, + pub ex_data: ::CRYPTO_EX_DATA, + pub ex_pathlen: c_long, + pub ex_pcpathlen: c_long, + pub ex_flags: c_ulong, + pub ex_kusage: c_ulong, + pub ex_xkusage: c_ulong, + pub ex_nscert: c_ulong, + skid: *mut c_void, + akid: *mut c_void, + policy_cache: *mut c_void, + crldp: *mut c_void, + altname: *mut c_void, + nc: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_RFC3779"))] + rfc3779_addr: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_RFC3779"))] + rfc3779_asid: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_SHA"))] + sha1_hash: [c_uchar; 20], + aux: *mut c_void, +} + +#[repr(C)] +pub struct X509_CINF { + version: *mut c_void, + serialNumber: *mut c_void, + signature: *mut c_void, + issuer: *mut c_void, + pub validity: *mut X509_VAL, + subject: *mut c_void, + key: *mut c_void, + issuerUID: *mut c_void, + subjectUID: *mut c_void, + pub extensions: *mut stack_st_X509_EXTENSION, + enc: ASN1_ENCODING, +} + +#[repr(C)] +pub struct ASN1_ENCODING { + pub enc: *mut c_uchar, + pub len: c_long, + pub modified: c_int, +} + +#[repr(C)] +pub struct X509_VAL { + pub notBefore: *mut ::ASN1_TIME, + pub notAfter: *mut ::ASN1_TIME, +} + +#[repr(C)] +pub struct SSL_CTX { + method: *mut c_void, + cipher_list: *mut c_void, + cipher_list_by_id: *mut c_void, + cert_store: *mut c_void, + sessions: *mut c_void, + session_cache_size: c_ulong, + session_cache_head: *mut c_void, + session_cache_tail: *mut c_void, + session_cache_mode: c_int, + session_timeout: c_long, + new_session_cb: *mut c_void, + remove_session_cb: *mut c_void, + get_session_cb: *mut c_void, + stats: [c_int; 11], + pub references: c_int, + app_verify_callback: *mut c_void, + app_verify_arg: *mut c_void, + default_passwd_callback: *mut c_void, + default_passwd_callback_userdata: *mut c_void, + client_cert_cb: *mut c_void, + app_gen_cookie_cb: *mut c_void, + app_verify_cookie_cb: *mut c_void, + ex_dat: ::CRYPTO_EX_DATA, + rsa_md5: *mut c_void, + md5: *mut c_void, + sha1: *mut c_void, + extra_certs: *mut c_void, + comp_methods: *mut c_void, + info_callback: *mut c_void, + client_CA: *mut c_void, + options: c_ulong, + mode: c_ulong, + max_cert_list: c_long, + cert: *mut c_void, + read_ahead: c_int, + msg_callback: *mut c_void, + msg_callback_arg: *mut c_void, + verify_mode: c_int, + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; 32], + default_verify_callback: *mut c_void, + generate_session_id: *mut c_void, + param: *mut c_void, + quiet_shutdown: c_int, + max_send_fragment: c_uint, + + #[cfg(not(osslconf = "OPENSSL_NO_ENGINE"))] + client_cert_engine: *mut c_void, + + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_servername_callback: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsect_servername_arg: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick_key_name: [c_uchar; 16], + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick_hmac_key: [c_uchar; 16], + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick_aes_key: [c_uchar; 16], + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ticket_key_cb: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_status_cb: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_status_arg: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_opaque_prf_input_callback: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_opaque_prf_input_callback_arg: *mut c_void, + + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_identity_hint: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_client_callback: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_server_callback: *mut c_void, + + #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] + freelist_max_len: c_uint, + #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] + wbuf_freelist: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] + rbuf_freelist: *mut c_void, + + #[cfg(not(osslconf = "OPENSSL_NO_SRP"))] + srp_ctx: SRP_CTX, + + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] + next_protos_advertised_cb: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] + next_protos_advertised_cb_arg: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] + next_proto_select_cb: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] + next_proto_select_cb_arg: *mut c_void, + + #[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))] + alpn_select_cb_arg: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_client_proto_list: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_client_proto_list_len: c_uint, + + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC"), ossl102))] + tlsext_ecpointformatlist_length: size_t, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC"), ossl102))] + tlsext_ecpointformatlist: *mut c_uchar, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC"), ossl102))] + tlsext_ellipticcurvelist_length: size_t, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC"), ossl102))] + tlsext_ellipticcurvelist: *mut c_uchar, +} + +#[repr(C)] +pub struct SRP_CTX { + SRP_cb_arg: *mut c_void, + TLS_ext_srp_username_callback: *mut c_void, + SRP_verify_param_callback: *mut c_void, + SRP_give_srp_client_pwd_callback: *mut c_void, + login: *mut c_void, + N: *mut c_void, + g: *mut c_void, + s: *mut c_void, + B: *mut c_void, + A: *mut c_void, + a: *mut c_void, + b: *mut c_void, + v: *mut c_void, + info: *mut c_void, + stringth: c_int, + srp_Mask: c_ulong, +} + +pub const SSL_CTRL_OPTIONS: c_int = 32; +pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; +#[cfg(ossl102)] +pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94; + +pub const SSL_OP_MICROSOFT_SESS_ID_BUG: c_ulong = 0x00000001; +pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: c_ulong = 0x00000002; +pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: c_ulong = 0x00000008; +pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: c_ulong = 0x00000020; +pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: c_ulong = 0x00000080; +pub const SSL_OP_TLS_D5_BUG: c_ulong = 0x00000100; +pub const SSL_OP_TLS_BLOCK_PADDING_BUG: c_ulong = 0x00000200; +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 = 0x01000000; + +pub const SSLEAY_VERSION : c_int = 0; +pub const SSLEAY_CFLAGS : c_int = 2; +pub const SSLEAY_BUILT_ON : c_int = 3; +pub const SSLEAY_PLATFORM : c_int = 4; +pub const SSLEAY_DIR : c_int = 5; + +pub const CRYPTO_LOCK_X509: c_int = 3; +pub const CRYPTO_LOCK_SSL_CTX: c_int = 12; + +static mut MUTEXES: *mut Vec> = 0 as *mut Vec>; +static mut GUARDS: *mut Vec>> = 0 as *mut Vec>>; + +unsafe extern fn locking_function(mode: c_int, n: c_int, _file: *const c_char, + _line: c_int) { + let mutex = &(*MUTEXES)[n as usize]; + + if mode & ::CRYPTO_LOCK != 0 { + (*GUARDS)[n as usize] = Some(mutex.lock().unwrap()); + } else { + &(*GUARDS)[n as usize].take(); + } +} + +pub fn init() { + static INIT: Once = ONCE_INIT; + + INIT.call_once(|| { + unsafe { + SSL_library_init(); + SSL_load_error_strings(); + OPENSSL_add_all_algorithms_noconf(); + + let num_locks = ::CRYPTO_num_locks(); + let mut mutexes = Box::new(Vec::new()); + for _ in 0..num_locks { + mutexes.push(Mutex::new(())); + } + MUTEXES = mem::transmute(mutexes); + let guards: Box>>> = + Box::new((0..num_locks).map(|_| None).collect()); + GUARDS = mem::transmute(guards); + + CRYPTO_set_locking_callback(locking_function); + set_id_callback(); + } + }) +} + +#[cfg(unix)] +fn set_id_callback() { + unsafe extern fn thread_id() -> c_ulong { + ::libc::pthread_self() as c_ulong + } + + unsafe { + CRYPTO_set_id_callback(thread_id); + } +} + +#[cfg(not(unix))] +fn set_id_callback() {} + +extern { + pub fn BIO_new(type_: *mut BIO_METHOD) -> *mut BIO; + pub fn BIO_s_file() -> *mut BIO_METHOD; + pub fn BIO_s_mem() -> *mut BIO_METHOD; + pub fn CRYPTO_free(buf: *mut c_void); + pub fn CRYPTO_num_locks() -> c_int; + pub fn CRYPTO_set_locking_callback(func: unsafe extern "C" fn(mode: c_int, + n: c_int, + file: *const c_char, + line: c_int)); + pub fn CRYPTO_set_id_callback(func: unsafe extern "C" fn() -> c_ulong); + + pub fn ERR_load_crypto_strings(); + + pub fn RSA_generate_key(modsz: c_int, + e: c_ulong, + cb: Option, + cbarg: *mut c_void) -> *mut RSA; + + pub fn SSL_library_init() -> c_int; + pub fn SSL_load_error_strings(); + pub fn OPENSSL_add_all_algorithms_noconf(); + pub fn HMAC_CTX_init(ctx: *mut ::HMAC_CTX); + pub fn HMAC_CTX_cleanup(ctx: *mut ::HMAC_CTX); + pub fn SSLv3_method() -> *const ::SSL_METHOD; + pub fn TLSv1_method() -> *const ::SSL_METHOD; + pub fn SSLv23_method() -> *const ::SSL_METHOD; + pub fn TLSv1_1_method() -> *const ::SSL_METHOD; + pub fn TLSv1_2_method() -> *const ::SSL_METHOD; + pub fn DTLSv1_method() -> *const ::SSL_METHOD; + #[cfg(ossl102)] + pub fn DTLSv1_2_method() -> *const ::SSL_METHOD; + pub fn SSL_get_ex_new_index(argl: c_long, argp: *mut c_void, + new_func: Option<::CRYPTO_EX_new>, + dup_func: Option<::CRYPTO_EX_dup>, + free_func: Option<::CRYPTO_EX_free>) + -> c_int; + pub fn SSL_CIPHER_get_version(cipher: *const ::SSL_CIPHER) -> *mut c_char; + pub fn SSL_CTX_get_ex_new_index(argl: c_long, argp: *mut c_void, + new_func: Option<::CRYPTO_EX_new>, + dup_func: Option<::CRYPTO_EX_dup>, + free_func: Option<::CRYPTO_EX_free>) + -> c_int; + pub fn X509_get_subject_name(x: *mut ::X509) -> *mut ::X509_NAME; + pub fn X509_set_notAfter(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; + pub fn X509_set_notBefore(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; + pub fn X509_get_ext_d2i(x: *mut ::X509, nid: c_int, crit: *mut c_int, idx: *mut c_int) -> *mut c_void; + pub fn X509_NAME_get_entry(n: *mut ::X509_NAME, loc: c_int) -> *mut ::X509_NAME_ENTRY; + pub fn X509_NAME_ENTRY_get_data(ne: *mut ::X509_NAME_ENTRY) -> *mut ::ASN1_STRING; + pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: *mut ::ASN1_STRING) -> c_int; + pub fn ASN1_STRING_data(x: *mut ::ASN1_STRING) -> *mut c_uchar; + pub fn CRYPTO_add_lock(pointer: *mut c_int, + amount: c_int, + type_: c_int, + file: *const c_char, + line: c_int) -> c_int; + + pub fn sk_free(st: *mut _STACK); + pub fn sk_pop_free(st: *mut _STACK, free: Option); + pub fn sk_pop(st: *mut _STACK) -> *mut c_void; + + pub fn SSLeay() -> c_ulong; + pub fn SSLeay_version(key: c_int) -> *const c_char; +} diff --git a/openssl-sys/src/ossl110.rs b/openssl-sys/src/ossl110.rs new file mode 100644 index 00000000..62a66cd5 --- /dev/null +++ b/openssl-sys/src/ossl110.rs @@ -0,0 +1,146 @@ +use libc::{c_int, c_void, c_char, c_uchar, c_ulong, c_long}; + +pub enum stack_st_X509 {} +pub enum stack_st_X509_ATTRIBUTE {} +pub enum stack_st_X509_EXTENSION {} +pub enum stack_st_GENERAL_NAME {} +pub enum stack_st_void {} +pub enum _STACK {} +pub enum BIO_METHOD {} +pub enum RSA {} +pub enum DSA {} +pub enum EVP_PKEY {} +pub enum BIO {} +pub enum CRYPTO_EX_DATA {} +pub enum EVP_MD_CTX {} +pub enum EVP_CIPHER {} +pub enum HMAC_CTX {} +pub enum BIGNUM {} +pub enum OPENSSL_STACK {} +pub enum DH {} +pub enum X509 {} +pub enum SSL_CTX {} + +pub const SSL_OP_MICROSOFT_SESS_ID_BUG: c_ulong = 0x00000000; +pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: c_ulong = 0x00000000; +pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: c_ulong = 0x00000000; +pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: c_ulong = 0x00000000; +pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: c_ulong = 0x00000000; +pub const SSL_OP_TLS_D5_BUG: c_ulong = 0x00000000; +pub const SSL_OP_TLS_BLOCK_PADDING_BUG: c_ulong = 0x00000000; +pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x00000000; +pub const SSL_OP_SINGLE_DH_USE: c_ulong = 0x00000000; +pub const SSL_OP_NO_SSLv2: c_ulong = 0x00000000; + +pub const OPENSSL_VERSION: c_int = 0; +pub const OPENSSL_CFLAGS: c_int = 1; +pub const OPENSSL_BUILT_ON: c_int = 2; +pub const OPENSSL_PLATFORM: c_int = 3; +pub const OPENSSL_DIR: c_int = 4; + +pub const CRYPTO_EX_INDEX_SSL: c_int = 0; +pub const CRYPTO_EX_INDEX_SSL_CTX: c_int = 1; + +pub fn init() {} + +extern { + pub fn BIO_new(type_: *const BIO_METHOD) -> *mut BIO; + pub fn BIO_s_file() -> *const BIO_METHOD; + pub fn BIO_s_mem() -> *const BIO_METHOD; + pub fn CRYPTO_free(buf: *mut c_void, file: *const c_char, line: c_int); + pub fn HMAC_CTX_new() -> *mut HMAC_CTX; + pub fn HMAC_CTX_free(ctx: *mut HMAC_CTX); + pub fn TLS_method() -> *const ::SSL_METHOD; + pub fn DTLS_method() -> *const ::SSL_METHOD; + pub fn SSL_CIPHER_get_version(cipher: *const ::SSL_CIPHER) -> *const c_char; + pub fn X509_get_subject_name(x: *const ::X509) -> *mut ::X509_NAME; + pub fn X509_set1_notAfter(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; + pub fn X509_set1_notBefore(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; + pub fn X509_get_ext_d2i(x: *const ::X509, nid: c_int, crit: *mut c_int, idx: *mut c_int) -> *mut c_void; + pub fn X509_NAME_get_entry(n: *const ::X509_NAME, loc: c_int) -> *mut ::X509_NAME_ENTRY; + pub fn X509_NAME_ENTRY_get_data(ne: *const ::X509_NAME_ENTRY) -> *mut ::ASN1_STRING; + pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: *const ::ASN1_STRING) -> c_int; + pub fn BN_is_negative(b: *const ::BIGNUM) -> c_int; + pub fn EVP_CIPHER_key_length(cipher: *const EVP_CIPHER) -> c_int; + pub fn EVP_CIPHER_block_size(cipher: *const EVP_CIPHER) -> c_int; + pub fn EVP_CIPHER_iv_length(cipher: *const EVP_CIPHER) -> c_int; + pub fn DSA_get0_pqg(d: *const ::DSA, + p: *mut *const ::BIGNUM, + q: *mut *const ::BIGNUM, + q: *mut *const ::BIGNUM); + pub fn DSA_get0_key(d: *const ::DSA, + pub_key: *mut *const ::BIGNUM, + priv_key: *mut *const ::BIGNUM); + pub fn RSA_get0_key(r: *const ::RSA, + n: *mut *const ::BIGNUM, + e: *mut *const ::BIGNUM, + d: *mut *const ::BIGNUM); + pub fn RSA_get0_factors(r: *const ::RSA, + p: *mut *const ::BIGNUM, + q: *mut *const ::BIGNUM); + pub fn RSA_set0_key(r: *mut ::RSA, + n: *mut ::BIGNUM, + e: *mut ::BIGNUM, + d: *mut ::BIGNUM) -> c_int; + pub fn RSA_set0_factors(r: *mut ::RSA, + p: *mut ::BIGNUM, + q: *mut ::BIGNUM) -> c_int; + pub fn RSA_set0_crt_params(r: *mut ::RSA, + dmp1: *mut ::BIGNUM, + dmq1: *mut ::BIGNUM, + iqmp: *mut ::BIGNUM) -> c_int; + pub fn ASN1_STRING_get0_data(x: *const ::ASN1_STRING) -> *const c_uchar; + pub fn OPENSSL_sk_num(stack: *const ::OPENSSL_STACK) -> c_int; + pub fn OPENSSL_sk_value(stack: *const ::OPENSSL_STACK, + idx: c_int) -> *mut c_void; + pub fn SSL_CTX_get_options(ctx: *const ::SSL_CTX) -> c_ulong; + pub fn SSL_CTX_set_options(ctx: *mut ::SSL_CTX, op: c_ulong) -> c_ulong; + pub fn SSL_CTX_clear_options(ctx: *mut ::SSL_CTX, op: c_ulong) -> c_ulong; + pub fn X509_getm_notAfter(x: *const ::X509) -> *mut ::ASN1_TIME; + pub fn X509_getm_notBefore(x: *const ::X509) -> *mut ::ASN1_TIME; + pub fn DH_set0_pqg(dh: *mut ::DH, + p: *mut ::BIGNUM, + q: *mut ::BIGNUM, + g: *mut ::BIGNUM) -> c_int; + pub fn BIO_set_init(a: *mut ::BIO, init: c_int); + pub fn BIO_set_data(a: *mut ::BIO, data: *mut c_void); + pub fn BIO_get_data(a: *mut ::BIO) -> *mut c_void; + pub fn BIO_meth_new(type_: c_int, name: *const c_char) -> *mut ::BIO_METHOD; + pub fn BIO_meth_free(biom: *mut ::BIO_METHOD); + pub fn BIO_meth_set_write(biom: *mut ::BIO_METHOD, + write: unsafe extern fn(*mut ::BIO, + *const c_char, + c_int) -> c_int) -> c_int; + pub fn BIO_meth_set_read(biom: *mut ::BIO_METHOD, + read: unsafe extern fn(*mut ::BIO, + *mut c_char, + c_int) -> c_int) -> c_int; + pub fn BIO_meth_set_puts(biom: *mut ::BIO_METHOD, + read: unsafe extern fn(*mut ::BIO, + *const c_char) -> c_int) -> c_int; + pub fn BIO_meth_set_ctrl(biom: *mut ::BIO_METHOD, + read: unsafe extern fn(*mut ::BIO, + c_int, + c_long, + *mut c_void) -> c_long) -> c_int; + pub fn BIO_meth_set_create(biom: *mut ::BIO_METHOD, + create: unsafe extern fn(*mut ::BIO) -> c_int) -> c_int; + pub fn BIO_meth_set_destroy(biom: *mut ::BIO_METHOD, + destroy: unsafe extern fn(*mut ::BIO) -> c_int) -> c_int; + pub fn CRYPTO_get_ex_new_index(class_index: c_int, + argl: c_long, + argp: *mut c_void, + new_func: Option<::CRYPTO_EX_new>, + dup_func: Option<::CRYPTO_EX_dup>, + free_func: Option<::CRYPTO_EX_free>) + -> c_int; + pub fn X509_up_ref(x: *mut X509) -> c_int; + pub fn SSL_CTX_up_ref(x: *mut SSL_CTX) -> c_int; + pub fn X509_get0_extensions(req: *const ::X509) -> *const stack_st_X509_EXTENSION; + + pub fn OpenSSL_version_num() -> c_ulong; + pub fn OpenSSL_version(key: c_int) -> *const c_char; + pub fn OPENSSL_sk_free(st: *mut _STACK); + pub fn OPENSSL_sk_pop_free(st: *mut _STACK, free: Option); + pub fn OPENSSL_sk_pop(st: *mut _STACK) -> *mut c_void; +} diff --git a/openssl-sys/src/probe.rs b/openssl-sys/src/probe.rs deleted file mode 100644 index e3711b54..00000000 --- a/openssl-sys/src/probe.rs +++ /dev/null @@ -1,77 +0,0 @@ -use std::env; -use std::fs; -use std::path::PathBuf; - -pub struct ProbeResult { - pub cert_file: Option, - pub cert_dir: Option, -} - -/// Probe the system for the directory in which CA certificates should likely be -/// found. -/// -/// This will only search known system locations. -pub fn find_certs_dirs() -> Vec { - // see http://gagravarr.org/writing/openssl-certs/others.shtml - [ - "/var/ssl", - "/usr/share/ssl", - "/usr/local/ssl", - "/usr/local/openssl", - "/usr/local/share", - "/usr/lib/ssl", - "/usr/ssl", - "/etc/openssl", - "/etc/pki/tls", - "/etc/ssl", - ].iter().map(|s| PathBuf::from(*s)).filter(|p| { - fs::metadata(p).is_ok() - }).collect() -} - -pub fn init_ssl_cert_env_vars() { - let ProbeResult { cert_file, cert_dir } = probe(); - match cert_file { - Some(path) => put("SSL_CERT_FILE", path), - None => {} - } - match cert_dir { - Some(path) => put("SSL_CERT_DIR", path), - None => {} - } - - fn put(var: &str, path: PathBuf) { - // Don't stomp over what anyone else has set - match env::var(var) { - Ok(..) => {} - Err(..) => env::set_var(var, &path), - } - } -} - -pub fn probe() -> ProbeResult { - let mut result = ProbeResult { - cert_file: env::var_os("SSL_CERT_FILE").map(PathBuf::from), - cert_dir: env::var_os("SSL_CERT_DIR").map(PathBuf::from), - }; - for certs_dir in find_certs_dirs().iter() { - // cert.pem looks to be an openssl 1.0.1 thing, while - // certs/ca-certificates.crt appears to be a 0.9.8 thing - for cert in [ - "cert.pem", - "certs.pem", - "certs/ca-certificates.crt", - "certs/ca-root-nss.crt" - ].iter() { - try(&mut result.cert_file, certs_dir.join(cert)); - } - try(&mut result.cert_dir, certs_dir.join("certs")); - } - result -} - -fn try(dst: &mut Option, val: PathBuf) { - if dst.is_none() && fs::metadata(&val).is_ok() { - *dst = Some(val); - } -} diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 3fd46c4b..d9691403 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -12,28 +12,23 @@ build = "build.rs" exclude = ["test/*"] [features] -tlsv1_2 = ["openssl-sys/tlsv1_2"] -tlsv1_1 = ["openssl-sys/tlsv1_1"] -dtlsv1 = ["openssl-sys/dtlsv1"] -dtlsv1_2 = ["openssl-sys/dtlsv1_2"] -sslv2 = ["openssl-sys/sslv2"] -sslv3 = ["openssl-sys/sslv3"] -aes_xts = ["openssl-sys/aes_xts"] -aes_ctr = ["openssl-sys/aes_ctr"] -npn = ["openssl-sys/npn"] -alpn = ["openssl-sys/alpn"] -rfc5114 = ["openssl-sys/rfc5114"] -ecdh_auto = ["openssl-sys/ecdh_auto"] -pkcs5_pbkdf2_hmac = ["openssl-sys/pkcs5_pbkdf2_hmac"] -hmac_clone = ["openssl-sys/hmac_clone"] +aes_xts = [] +aes_ctr = [] -c_helpers = ["gcc"] -x509_clone = ["c_helpers"] -x509_generator_request = ["c_helpers"] -x509_expiry = ["c_helpers"] -ssl_context_clone = ["c_helpers"] -hmac = ["c_helpers"] -dh_from_params = ["c_helpers"] +# Added in OpenSSL 1.0.2 +rfc5114 = [] + +# TODO: what to do about these features? +# tlsv1_2 = [] +# tlsv1_1 = [] +# dtlsv1 = [] +# dtlsv1_2 = [] +# sslv2 = [] +# sslv3 = [] + +npn = [] +alpn = [] +ecdh_auto = [] [dependencies] bitflags = "0.7" @@ -41,11 +36,9 @@ lazy_static = "0.2" libc = "0.2" openssl-sys = { version = "0.7.17", path = "../openssl-sys" } -[build-dependencies] -gcc = { version = "0.3", optional = true } - [dev-dependencies] -rustc-serialize = "0.3" net2 = "0.2.16" +rustc-serialize = "0.3" +tempdir = "0.3" winapi = "0.2" ws2_32-sys = "0.2" diff --git a/openssl/build.rs b/openssl/build.rs index b07c1b3e..15d4b4db 100644 --- a/openssl/build.rs +++ b/openssl/build.rs @@ -1,28 +1,15 @@ -#[cfg(feature = "c_helpers")] -mod imp { - extern crate gcc; - - use std::env; - use std::path::PathBuf; - - pub fn main() { - let mut config = gcc::Config::new(); - - if let Some(paths) = env::var_os("DEP_OPENSSL_INCLUDE") { - for path in env::split_paths(&paths) { - config.include(PathBuf::from(path)); - } - } - - config.file("src/c_helpers.c").compile("libc_helpers.a"); - } -} - -#[cfg(not(feature = "c_helpers"))] -mod imp { - pub fn main() {} -} +use std::env; fn main() { - imp::main() + if env::var("DEP_OPENSSL_IS_101").is_ok() { + println!("cargo:rustc-cfg=ossl101"); + println!("cargo:rustc-cfg=ossl10x"); + } + if env::var("DEP_OPENSSL_IS_102").is_ok() { + println!("cargo:rustc-cfg=ossl102"); + println!("cargo:rustc-cfg=ossl10x"); + } + if env::var("DEP_OPENSSL_IS_110").is_ok() { + println!("cargo:rustc-cfg=ossl110"); + } } diff --git a/openssl/src/bn/mod.rs b/openssl/src/bn/mod.rs index de9d0d2a..7d1f5458 100644 --- a/openssl/src/bn/mod.rs +++ b/openssl/src/bn/mod.rs @@ -1,4 +1,4 @@ -use libc::{c_int, c_ulong, c_void}; +use libc::{c_int, c_void}; use std::ffi::{CStr, CString}; use std::cmp::Ordering; use std::{fmt, ptr}; @@ -185,10 +185,11 @@ impl<'a> BigNumRef<'a> { } } - /// Add an `unsigned long` to `self`. This is more efficient than adding a `BigNum`. - pub fn add_word(&mut self, w: c_ulong) -> Result<(), ErrorStack> { + /// Add a `u32` to `self`. This is more efficient than adding a + /// `BigNum`. + pub fn add_word(&mut self, w: u32) -> Result<(), ErrorStack> { unsafe { - if ffi::BN_add_word(self.as_ptr(), w) == 1 { + if ffi::BN_add_word(self.as_ptr(), w as ffi::BN_ULONG) == 1 { Ok(()) } else { Err(ErrorStack::get()) @@ -196,9 +197,9 @@ impl<'a> BigNumRef<'a> { } } - pub fn sub_word(&mut self, w: c_ulong) -> Result<(), ErrorStack> { + pub fn sub_word(&mut self, w: u32) -> Result<(), ErrorStack> { unsafe { - if ffi::BN_sub_word(self.as_ptr(), w) == 1 { + if ffi::BN_sub_word(self.as_ptr(), w as ffi::BN_ULONG) == 1 { Ok(()) } else { Err(ErrorStack::get()) @@ -206,9 +207,9 @@ impl<'a> BigNumRef<'a> { } } - pub fn mul_word(&mut self, w: c_ulong) -> Result<(), ErrorStack> { + pub fn mul_word(&mut self, w: u32) -> Result<(), ErrorStack> { unsafe { - if ffi::BN_mul_word(self.as_ptr(), w) == 1 { + if ffi::BN_mul_word(self.as_ptr(), w as ffi::BN_ULONG) == 1 { Ok(()) } else { Err(ErrorStack::get()) @@ -216,22 +217,22 @@ impl<'a> BigNumRef<'a> { } } - pub fn div_word(&mut self, w: c_ulong) -> Result { + pub fn div_word(&mut self, w: u32) -> Result { unsafe { - let result = ffi::BN_div_word(self.as_ptr(), w); - if result != !0 as c_ulong { - Ok(result) + let result = ffi::BN_div_word(self.as_ptr(), w as ffi::BN_ULONG); + if result != !0 { + Ok(result.into()) } else { Err(ErrorStack::get()) } } } - pub fn mod_word(&self, w: c_ulong) -> Result { + pub fn mod_word(&self, w: u32) -> Result { unsafe { - let result = ffi::BN_mod_word(self.as_ptr(), w); - if result != !0 as c_ulong { - Ok(result) + let result = ffi::BN_mod_word(self.as_ptr(), w as ffi::BN_ULONG); + if result != !0 { + Ok(result as u64) } else { Err(ErrorStack::get()) } @@ -257,7 +258,10 @@ impl<'a> BigNumRef<'a> { pub fn is_prime(&self, checks: i32) -> Result { unsafe { with_ctx!(ctx, { - Ok(ffi::BN_is_prime_ex(self.as_ptr(), checks as c_int, ctx, ptr::null()) == 1) + Ok(ffi::BN_is_prime_ex(self.as_ptr(), + checks as c_int, + ctx, + ptr::null_mut()) == 1) }) } } @@ -278,7 +282,7 @@ impl<'a> BigNumRef<'a> { checks as c_int, ctx, do_trial_division as c_int, - ptr::null()) == 1) + ptr::null_mut()) == 1) }) } } @@ -483,9 +487,19 @@ impl<'a> BigNumRef<'a> { } 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 } + } + /// Returns the number of significant bits in `self`. pub fn num_bits(&self) -> i32 { unsafe { ffi::BN_num_bits(self.as_ptr()) as i32 } @@ -536,7 +550,7 @@ impl<'a> BigNumRef<'a> { assert!(!buf.is_null()); let str = String::from_utf8(CStr::from_ptr(buf as *const _).to_bytes().to_vec()) .unwrap(); - ffi::CRYPTO_free(buf as *mut c_void); + CRYPTO_free!(buf as *mut c_void); str } } @@ -555,7 +569,7 @@ impl<'a> BigNumRef<'a> { assert!(!buf.is_null()); let str = String::from_utf8(CStr::from_ptr(buf as *const _).to_bytes().to_vec()) .unwrap(); - ffi::CRYPTO_free(buf as *mut c_void); + CRYPTO_free!(buf as *mut c_void); str } } @@ -580,27 +594,27 @@ impl BigNum { } /// Creates a new `BigNum` with the given value. - pub fn new_from(n: c_ulong) -> Result { + pub fn new_from(n: u32) -> Result { BigNum::new().and_then(|v| unsafe { - try_ssl!(ffi::BN_set_word(v.as_ptr(), n)); + try_ssl!(ffi::BN_set_word(v.as_ptr(), n as ffi::BN_ULONG)); Ok(v) }) } /// Creates a `BigNum` from a decimal string. pub fn from_dec_str(s: &str) -> Result { - BigNum::new().and_then(|v| unsafe { + BigNum::new().and_then(|mut v| unsafe { let c_str = CString::new(s.as_bytes()).unwrap(); - try_ssl!(ffi::BN_dec2bn(&(v.0).0, c_str.as_ptr() as *const _)); + try_ssl!(ffi::BN_dec2bn(&mut (v.0).0, c_str.as_ptr() as *const _)); Ok(v) }) } /// Creates a `BigNum` from a hexadecimal string. pub fn from_hex_str(s: &str) -> Result { - BigNum::new().and_then(|v| unsafe { + BigNum::new().and_then(|mut v| unsafe { let c_str = CString::new(s.as_bytes()).unwrap(); - try_ssl!(ffi::BN_hex2bn(&(v.0).0, c_str.as_ptr() as *const _)); + try_ssl!(ffi::BN_hex2bn(&mut (v.0).0, c_str.as_ptr() as *const _)); Ok(v) }) } @@ -646,7 +660,7 @@ impl BigNum { safe as c_int, add_arg, rem_arg, - ptr::null()) == 1 + ptr::null_mut()) == 1 }) } } diff --git a/openssl/src/c_helpers.c b/openssl/src/c_helpers.c deleted file mode 100644 index 6e6a5021..00000000 --- a/openssl/src/c_helpers.c +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include -#include -#include - -void rust_0_8_SSL_CTX_clone(SSL_CTX *ctx) { - CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX); -} - -void rust_0_8_X509_clone(X509 *x509) { - CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); -} - -STACK_OF(X509_EXTENSION) *rust_0_8_X509_get_extensions(X509 *x) { - return x->cert_info ? x->cert_info->extensions : NULL; -} - -ASN1_TIME* rust_0_8_X509_get_notAfter(X509 *x) { - return X509_get_notAfter(x); -} - -ASN1_TIME* rust_0_8_X509_get_notBefore(X509 *x) { - return X509_get_notBefore(x); -} - -DH *rust_0_8_DH_new_from_params(BIGNUM *p, BIGNUM *g, BIGNUM *q) { - DH *dh; - - if ((dh = DH_new()) == NULL) { - return NULL; - } - dh->p = p; - dh->g = g; - dh->q = q; - return dh; -} - -#if OPENSSL_VERSION_NUMBER < 0x10000000L -int rust_0_8_HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md, ENGINE *impl) { - HMAC_Init_ex(ctx, key, key_len, md, impl); - return 1; -} - -int rust_0_8_HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, int len) { - HMAC_Update(ctx, data, len); - return 1; -} - -int rust_0_8_HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len) { - HMAC_Final(ctx, md, len); - return 1; -} - -#else - -int rust_0_8_HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md, ENGINE *impl) { - return HMAC_Init_ex(ctx, key, key_len, md, impl); -} - -int rust_0_8_HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, int len) { - return HMAC_Update(ctx, data, len); -} - -int rust_0_8_HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len) { - return HMAC_Final(ctx, md, len); -} -#endif diff --git a/openssl/src/c_helpers.rs b/openssl/src/c_helpers.rs deleted file mode 100644 index d16c3125..00000000 --- a/openssl/src/c_helpers.rs +++ /dev/null @@ -1,15 +0,0 @@ -use ffi; -use libc::{c_int, c_void, c_uint, c_uchar}; - -#[allow(dead_code)] -extern "C" { - pub fn rust_0_8_SSL_CTX_clone(cxt: *mut ffi::SSL_CTX); - pub fn rust_0_8_X509_clone(x509: *mut ffi::X509); - pub fn rust_0_8_X509_get_extensions(x: *mut ffi::X509) -> *mut ffi::stack_st_X509_EXTENSION; - pub fn rust_0_8_X509_get_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME; - pub fn rust_0_8_X509_get_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME; - pub fn rust_0_8_HMAC_Init_ex(ctx: *mut ffi::HMAC_CTX, key: *const c_void, keylen: c_int, md: *const ffi::EVP_MD, impl_: *mut ffi::ENGINE) -> c_int; - pub fn rust_0_8_HMAC_Final(ctx: *mut ffi::HMAC_CTX, output: *mut c_uchar, len: *mut c_uint) -> c_int; - pub fn rust_0_8_HMAC_Update(ctx: *mut ffi::HMAC_CTX, input: *const c_uchar, len: c_uint) -> c_int; - pub fn rust_0_8_DH_new_from_params(p: *mut ffi::BIGNUM, g: *mut ffi::BIGNUM, q: *mut ffi::BIGNUM) -> *mut ffi::DH; -} diff --git a/openssl/src/crypto/dsa.rs b/openssl/src/crypto/dsa.rs index 97ba7a97..bb4fe474 100644 --- a/openssl/src/crypto/dsa.rs +++ b/openssl/src/crypto/dsa.rs @@ -19,8 +19,13 @@ impl DSAParams { unsafe { // Wrap it so that if we panic we'll call the dtor let dsa = DSAParams(try_ssl_null!(ffi::DSA_new())); - try_ssl!(ffi::DSA_generate_parameters_ex(dsa.0, size as c_int, ptr::null(), 0, - ptr::null_mut(), ptr::null_mut(), ptr::null())); + try_ssl!(ffi::DSA_generate_parameters_ex(dsa.0, + size as c_int, + ptr::null(), + 0, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut())); Ok(dsa) } } @@ -190,43 +195,74 @@ impl DSA { pub fn p<'a>(&'a self) -> Option> { unsafe { - let p = (*self.0).p; + let p = compat::pqg(self.0)[0]; if p.is_null() { None } else { - Some(BigNumRef::from_ptr((*self.0).p)) + Some(BigNumRef::from_ptr(p as *mut _)) } } } pub fn q<'a>(&'a self) -> Option> { unsafe { - let q = (*self.0).q; + let q = compat::pqg(self.0)[1]; if q.is_null() { None } else { - Some(BigNumRef::from_ptr((*self.0).q)) + Some(BigNumRef::from_ptr(q as *mut _)) } } } pub fn g<'a>(&'a self) -> Option> { unsafe { - let g = (*self.0).g; + let g = compat::pqg(self.0)[2]; if g.is_null() { None } else { - Some(BigNumRef::from_ptr((*self.0).g)) + Some(BigNumRef::from_ptr(g as *mut _)) } } } pub fn has_public_key(&self) -> bool { - unsafe { !(*self.0).pub_key.is_null() } + unsafe { !compat::keys(self.0)[0].is_null() } } pub fn has_private_key(&self) -> bool { - unsafe { !(*self.0).priv_key.is_null() } + unsafe { !compat::keys(self.0)[1].is_null() } + } +} + +#[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] + } + + pub unsafe fn keys(d: *const DSA) -> [*const BIGNUM; 2] { + let (mut pub_key, mut priv_key) = (ptr::null(), ptr::null()); + ffi::DSA_get0_key(d, &mut pub_key, &mut priv_key); + [pub_key, priv_key] + } +} + +#[cfg(ossl10x)] +mod compat { + use ffi::{BIGNUM, DSA}; + + pub unsafe fn pqg(d: *const DSA) -> [*const BIGNUM; 3] { + [(*d).p, (*d).q, (*d).g] + } + + pub unsafe fn keys(d: *const DSA) -> [*const BIGNUM; 2] { + [(*d).pub_key, (*d).priv_key] } } diff --git a/openssl/src/crypto/hash.rs b/openssl/src/crypto/hash.rs index 207a55f5..d87c43c5 100644 --- a/openssl/src/crypto/hash.rs +++ b/openssl/src/crypto/hash.rs @@ -1,8 +1,6 @@ -use libc::c_uint; use std::io::prelude::*; use std::io; use std::ptr; -use std::cmp; use ffi; use HashTypeInternals; @@ -102,7 +100,7 @@ impl Hasher { pub fn new(ty: Type) -> Result { ffi::init(); - let ctx = unsafe { try_ssl_null!(ffi::EVP_MD_CTX_create()) }; + let ctx = unsafe { try_ssl_null!(ffi::EVP_MD_CTX_new()) }; let md = ty.evp_md(); let mut h = Hasher { @@ -123,22 +121,20 @@ impl Hasher { } Finalized => (), } - unsafe { try_ssl!(ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *const _)); } + unsafe { try_ssl!(ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *mut _)); } self.state = Reset; Ok(()) } /// Feeds data into the hasher. - pub fn update(&mut self, mut data: &[u8]) -> Result<(), ErrorStack> { + pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> { if self.state == Finalized { try!(self.init()); } - while !data.is_empty() { - let len = cmp::min(data.len(), c_uint::max_value() as usize); - unsafe { - try_ssl!(ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), len as c_uint)); - } - data = &data[len..]; + unsafe { + try_ssl!(ffi::EVP_DigestUpdate(self.ctx, + data.as_ptr() as *mut _, + data.len())); } self.state = Updated; Ok(()) @@ -176,7 +172,7 @@ impl Write for Hasher { impl Clone for Hasher { fn clone(&self) -> Hasher { let ctx = unsafe { - let ctx = ffi::EVP_MD_CTX_create(); + let ctx = ffi::EVP_MD_CTX_new(); assert!(!ctx.is_null()); let r = ffi::EVP_MD_CTX_copy_ex(ctx, self.ctx); assert_eq!(r, 1); @@ -197,7 +193,7 @@ impl Drop for Hasher { if self.state != Finalized { drop(self.finish()); } - ffi::EVP_MD_CTX_destroy(self.ctx); + ffi::EVP_MD_CTX_free(self.ctx); } } } diff --git a/openssl/src/crypto/hmac.rs b/openssl/src/crypto/hmac.rs index 1847d6b1..8f44ed7f 100644 --- a/openssl/src/crypto/hmac.rs +++ b/openssl/src/crypto/hmac.rs @@ -13,16 +13,14 @@ // limitations under the License. // -use libc::{c_int, c_uint}; +use libc::{c_int}; use std::io; use std::io::prelude::*; -use std::cmp; use ffi; use HashTypeInternals; use crypto::hash::Type; use error::ErrorStack; -use c_helpers; #[derive(PartialEq, Copy, Clone)] enum State { @@ -66,7 +64,7 @@ use self::State::*; /// assert_eq!(res, spec); /// ``` pub struct HMAC { - ctx: ffi::HMAC_CTX, + ctx: compat::HMAC_CTX, state: State, } @@ -75,11 +73,7 @@ impl HMAC { pub fn new(ty: Type, key: &[u8]) -> Result { ffi::init(); - let ctx = unsafe { - let mut ctx = ::std::mem::uninitialized(); - ffi::HMAC_CTX_init(&mut ctx); - ctx - }; + let ctx = compat::HMAC_CTX::new(); let md = ty.evp_md(); let mut h = HMAC { @@ -92,11 +86,11 @@ impl HMAC { fn init_once(&mut self, md: *const ffi::EVP_MD, key: &[u8]) -> Result<(), ErrorStack> { unsafe { - try_ssl!(c_helpers::rust_0_8_HMAC_Init_ex(&mut self.ctx, - key.as_ptr() as *const _, - key.len() as c_int, - md, - 0 as *mut _)); + try_ssl!(ffi::HMAC_Init_ex(self.ctx.get(), + key.as_ptr() as *const _, + key.len() as c_int, + md, + 0 as *mut _)); } self.state = Reset; Ok(()) @@ -113,26 +107,24 @@ impl HMAC { // If the key and/or md is not supplied it's reused from the last time // avoiding redundant initializations unsafe { - try_ssl!(c_helpers::rust_0_8_HMAC_Init_ex(&mut self.ctx, - 0 as *const _, - 0, - 0 as *const _, - 0 as *mut _)); + try_ssl!(ffi::HMAC_Init_ex(self.ctx.get(), + 0 as *const _, + 0, + 0 as *const _, + 0 as *mut _)); } self.state = Reset; Ok(()) } - pub fn update(&mut self, mut data: &[u8]) -> Result<(), ErrorStack> { + pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> { if self.state == Finalized { try!(self.init()); } - while !data.is_empty() { - let len = cmp::min(data.len(), c_uint::max_value() as usize); - unsafe { - try_ssl!(c_helpers::rust_0_8_HMAC_Update(&mut self.ctx, data.as_ptr(), len as c_uint)); - } - data = &data[len..]; + unsafe { + try_ssl!(ffi::HMAC_Update(self.ctx.get(), + data.as_ptr(), + data.len())); } self.state = Updated; Ok(()) @@ -147,7 +139,9 @@ impl HMAC { unsafe { let mut len = ffi::EVP_MAX_MD_SIZE; let mut res = vec![0; len as usize]; - try_ssl!(c_helpers::rust_0_8_HMAC_Final(&mut self.ctx, res.as_mut_ptr(), &mut len)); + try_ssl!(ffi::HMAC_Final(self.ctx.get(), + res.as_mut_ptr(), + &mut len)); res.truncate(len as usize); self.state = Finalized; Ok(res) @@ -167,14 +161,11 @@ impl Write for HMAC { } } -#[cfg(feature = "hmac_clone")] impl Clone for HMAC { - /// Requires the `hmac_clone` feature. fn clone(&self) -> HMAC { - let mut ctx: ffi::HMAC_CTX; + let ctx = compat::HMAC_CTX::new(); unsafe { - ctx = ::std::mem::uninitialized(); - let r = ffi::HMAC_CTX_copy(&mut ctx, &self.ctx); + let r = ffi::HMAC_CTX_copy(ctx.get(), self.ctx.get()); assert_eq!(r, 1); } HMAC { @@ -186,11 +177,8 @@ impl Clone for HMAC { impl Drop for HMAC { fn drop(&mut self) { - unsafe { - if self.state != Finalized { - drop(self.finish()); - } - ffi::HMAC_CTX_cleanup(&mut self.ctx); + if self.state != Finalized { + drop(self.finish()); } } } @@ -202,6 +190,73 @@ pub fn hmac(t: Type, key: &[u8], data: &[u8]) -> Result, ErrorStack> { h.finish() } +#[cfg(ossl110)] +#[allow(bad_style)] +mod compat { + use ffi; + + pub struct HMAC_CTX { + ctx: *mut ffi::HMAC_CTX, + } + + impl HMAC_CTX { + pub fn new() -> HMAC_CTX { + unsafe { + let ctx = ffi::HMAC_CTX_new(); + assert!(!ctx.is_null()); + HMAC_CTX { ctx: ctx } + } + } + + pub fn get(&self) -> *mut ffi::HMAC_CTX { + self.ctx + } + } + + impl Drop for HMAC_CTX { + fn drop(&mut self) { + unsafe { + ffi::HMAC_CTX_free(self.ctx); + } + } + } +} + +#[cfg(ossl10x)] +#[allow(bad_style)] +mod compat { + use std::mem; + use std::cell::UnsafeCell; + + use ffi; + + pub struct HMAC_CTX { + ctx: UnsafeCell, + } + + impl HMAC_CTX { + pub fn new() -> HMAC_CTX { + unsafe { + let mut ctx = mem::zeroed(); + ffi::HMAC_CTX_init(&mut ctx); + HMAC_CTX { ctx: UnsafeCell::new(ctx) } + } + } + + pub fn get(&self) -> *mut ffi::HMAC_CTX { + self.ctx.get() + } + } + + impl Drop for HMAC_CTX { + fn drop(&mut self) { + unsafe { + ffi::HMAC_CTX_cleanup(self.get()); + } + } + } +} + #[cfg(test)] mod tests { use std::iter::repeat; @@ -289,7 +344,6 @@ mod tests { } #[test] - #[cfg(feature = "hmac_clone")] fn test_clone() { let tests: [(Vec, Vec, Vec); 2] = [(repeat(0xaa_u8).take(80).collect(), diff --git a/openssl/src/crypto/mod.rs b/openssl/src/crypto/mod.rs index b8b109a2..389b7cc9 100644 --- a/openssl/src/crypto/mod.rs +++ b/openssl/src/crypto/mod.rs @@ -15,7 +15,6 @@ // pub mod hash; -#[cfg(feature = "hmac")] pub mod hmac; pub mod pkcs5; pub mod pkcs12; diff --git a/openssl/src/crypto/pkcs12.rs b/openssl/src/crypto/pkcs12.rs index 89bcbd5c..5f03a3d5 100644 --- a/openssl/src/crypto/pkcs12.rs +++ b/openssl/src/crypto/pkcs12.rs @@ -44,13 +44,14 @@ impl Pkcs12 { let pkey = PKey::from_ptr(pkey); let cert = X509::from_ptr(cert); + let chain = chain as *mut _; let mut chain_out = vec![]; - for i in 0..(*chain).stack.num { - let x509 = *(*chain).stack.data.offset(i as isize) as *mut _; - chain_out.push(X509::from_ptr(x509)); + for i in 0..compat::OPENSSL_sk_num(chain) { + let x509 = compat::OPENSSL_sk_value(chain, i); + chain_out.push(X509::from_ptr(x509 as *mut _)); } - ffi::sk_free(&mut (*chain).stack); + compat::OPENSSL_sk_free(chain as *mut _); Ok(ParsedPkcs12 { pkey: pkey, @@ -69,6 +70,31 @@ pub struct ParsedPkcs12 { _p: (), } +#[cfg(ossl110)] +mod compat { + pub use ffi::OPENSSL_sk_free; + pub use ffi::OPENSSL_sk_num; + pub use ffi::OPENSSL_sk_value; +} + +#[cfg(ossl10x)] +#[allow(bad_style)] +mod compat { + use libc::{c_int, c_void}; + use ffi; + + pub use ffi::sk_free as OPENSSL_sk_free; + + pub unsafe fn OPENSSL_sk_num(stack: *mut ffi::_STACK) -> c_int { + (*stack).num + } + + pub unsafe fn OPENSSL_sk_value(stack: *const ffi::_STACK, idx: c_int) + -> *mut c_void { + *(*stack).data.offset(idx as isize) as *mut c_void + } +} + #[cfg(test)] mod test { use crypto::hash::Type::SHA1; diff --git a/openssl/src/crypto/pkcs5.rs b/openssl/src/crypto/pkcs5.rs index ef84fbe1..adcbc9db 100644 --- a/openssl/src/crypto/pkcs5.rs +++ b/openssl/src/crypto/pkcs5.rs @@ -82,7 +82,7 @@ pub fn pbkdf2_hmac_sha1(pass: &[u8], ffi::init(); - try_ssl!(ffi::PKCS5_PBKDF2_HMAC_SHA1(pass.as_ptr(), + try_ssl!(ffi::PKCS5_PBKDF2_HMAC_SHA1(pass.as_ptr() as *const _, pass.len() as c_int, salt.as_ptr(), salt.len() as c_int, @@ -94,7 +94,6 @@ pub fn pbkdf2_hmac_sha1(pass: &[u8], } /// Derives a key from a password and salt using the PBKDF2-HMAC algorithm with a digest function. -#[cfg(feature = "pkcs5_pbkdf2_hmac")] pub fn pbkdf2_hmac(pass: &[u8], salt: &[u8], iter: usize, @@ -104,7 +103,7 @@ pub fn pbkdf2_hmac(pass: &[u8], unsafe { let mut out = vec![0; keylen]; ffi::init(); - try_ssl!(ffi::PKCS5_PBKDF2_HMAC(pass.as_ptr(), + try_ssl!(ffi::PKCS5_PBKDF2_HMAC(pass.as_ptr() as *const _, pass.len() as c_int, salt.as_ptr(), salt.len() as c_int, @@ -162,7 +161,6 @@ mod tests { // Test vectors from // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c #[test] - #[cfg(feature = "pkcs5_pbkdf2_hmac")] fn test_pbkdf2_hmac_sha256() { assert_eq!(super::pbkdf2_hmac(b"passwd", b"salt", 1, hash::Type::SHA256, 16).unwrap(), vec![0x55_u8, 0xac_u8, 0x04_u8, 0x6e_u8, 0x56_u8, 0xe3_u8, 0x08_u8, 0x9f_u8, @@ -176,7 +174,6 @@ mod tests { // Test vectors from // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c #[test] - #[cfg(feature = "pkcs5_pbkdf2_hmac")] fn test_pbkdf2_hmac_sha512() { assert_eq!(super::pbkdf2_hmac(b"password", b"NaCL", 1, hash::Type::SHA512, 64).unwrap(), vec![0x73_u8, 0xde_u8, 0xcf_u8, 0xa5_u8, 0x8a_u8, 0xa2_u8, 0xe8_u8, 0x4f_u8, diff --git a/openssl/src/crypto/rsa.rs b/openssl/src/crypto/rsa.rs index 8a3f9188..f91f39fb 100644 --- a/openssl/src/crypto/rsa.rs +++ b/openssl/src/crypto/rsa.rs @@ -2,7 +2,7 @@ use ffi; use std::fmt; use std::ptr; use std::mem; -use libc::{c_int, c_void, c_char, c_ulong}; +use libc::{c_int, c_void, c_char}; use bn::{BigNum, BigNumRef}; use bio::{MemBio, MemBioSlice}; @@ -44,12 +44,13 @@ impl RSA { /// the supplied load and save methods for DER formatted keys. pub fn from_public_components(n: BigNum, e: BigNum) -> Result { unsafe { - let rsa = try_ssl_null!(ffi::RSA_new()); - (*rsa).n = n.as_ptr(); - (*rsa).e = e.as_ptr(); - mem::forget(n); - mem::forget(e); - Ok(RSA(rsa)) + let rsa = RSA(try_ssl_null!(ffi::RSA_new())); + try_ssl!(compat::set_key(rsa.0, + n.as_ptr(), + e.as_ptr(), + ptr::null_mut())); + mem::forget((n, e)); + Ok(rsa) } } @@ -63,24 +64,15 @@ impl RSA { qi: BigNum) -> Result { unsafe { - let rsa = try_ssl_null!(ffi::RSA_new()); - (*rsa).n = n.as_ptr(); - (*rsa).e = e.as_ptr(); - (*rsa).d = d.as_ptr(); - (*rsa).p = p.as_ptr(); - (*rsa).q = q.as_ptr(); - (*rsa).dmp1 = dp.as_ptr(); - (*rsa).dmq1 = dq.as_ptr(); - (*rsa).iqmp = qi.as_ptr(); - mem::forget(n); - mem::forget(e); - mem::forget(d); - mem::forget(p); - mem::forget(q); - mem::forget(dp); - mem::forget(dq); - mem::forget(qi); - Ok(RSA(rsa)) + let rsa = RSA(try_ssl_null!(ffi::RSA_new())); + try_ssl!(compat::set_key(rsa.0, n.as_ptr(), e.as_ptr(), d.as_ptr())); + mem::forget((n, e, d)); + try_ssl!(compat::set_factors(rsa.0, p.as_ptr(), q.as_ptr())); + mem::forget((p, q)); + try_ssl!(compat::set_crt_params(rsa.0, dp.as_ptr(), dq.as_ptr(), + qi.as_ptr())); + mem::forget((dp, dq, qi)); + Ok(rsa) } } @@ -95,7 +87,7 @@ impl RSA { unsafe { let rsa = try_ssl_null!(ffi::RSA_new()); let rsa = RSA(rsa); - let e = try!(BigNum::new_from(ffi::RSA_F4 as c_ulong)); + let e = try!(BigNum::new_from(ffi::RSA_F4 as u32)); try_ssl!(ffi::RSA_generate_key_ex(rsa.0, bits as c_int, e.as_ptr(), ptr::null_mut())); @@ -292,55 +284,55 @@ impl RSA { pub fn n<'a>(&'a self) -> Option> { unsafe { - let n = (*self.0).n; + let n = compat::key(self.0)[0]; if n.is_null() { None } else { - Some(BigNumRef::from_ptr(n)) + Some(BigNumRef::from_ptr(n as *mut _)) } } } pub fn d<'a>(&self) -> Option> { unsafe { - let d = (*self.0).d; + let d = compat::key(self.0)[2]; if d.is_null() { None } else { - Some(BigNumRef::from_ptr(d)) + Some(BigNumRef::from_ptr(d as *mut _)) } } } pub fn e<'a>(&'a self) -> Option> { unsafe { - let e = (*self.0).e; + let e = compat::key(self.0)[1]; if e.is_null() { None } else { - Some(BigNumRef::from_ptr(e)) + Some(BigNumRef::from_ptr(e as *mut _)) } } } pub fn p<'a>(&'a self) -> Option> { unsafe { - let p = (*self.0).p; + let p = compat::factors(self.0)[0]; if p.is_null() { None } else { - Some(BigNumRef::from_ptr(p)) + Some(BigNumRef::from_ptr(p as *mut _)) } } } pub fn q<'a>(&'a self) -> Option> { unsafe { - let q = (*self.0).q; + let q = compat::factors(self.0)[1]; if q.is_null() { None } else { - Some(BigNumRef::from_ptr(q)) + Some(BigNumRef::from_ptr(q as *mut _)) } } } @@ -352,6 +344,89 @@ impl fmt::Debug for RSA { } } +#[cfg(ossl110)] +mod compat { + use std::ptr; + + use ffi::{self, BIGNUM, RSA}; + use libc::c_int; + + 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] + } + + 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] + } + + 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 libc::c_int; + use ffi::{BIGNUM, RSA}; + + 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 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? + } +} + + #[cfg(test)] mod test { use std::io::Write; @@ -449,9 +524,9 @@ mod test { #[test] fn test_private_encrypt() { - let mut k0 = super::RSA::generate(512).unwrap(); + let k0 = super::RSA::generate(512).unwrap(); let k0pkey = k0.public_key_to_pem().unwrap(); - let mut k1 = super::RSA::public_key_from_pem(&k0pkey).unwrap(); + let k1 = super::RSA::public_key_from_pem(&k0pkey).unwrap(); let msg = vec!(0xdeu8, 0xadu8, 0xd0u8, 0x0du8); @@ -462,9 +537,9 @@ mod test { #[test] fn test_public_encrypt() { - let mut k0 = super::RSA::generate(512).unwrap(); + let k0 = super::RSA::generate(512).unwrap(); let k0pkey = k0.public_key_to_pem().unwrap(); - let mut k1 = super::RSA::public_key_from_pem(&k0pkey).unwrap(); + let k1 = super::RSA::public_key_from_pem(&k0pkey).unwrap(); let msg = vec!(0xdeu8, 0xadu8, 0xd0u8, 0x0du8); @@ -475,9 +550,9 @@ mod test { #[test] fn test_public_encrypt_pkcs() { - let mut k0 = super::RSA::generate(512).unwrap(); + let k0 = super::RSA::generate(512).unwrap(); let k0pkey = k0.public_key_to_pem().unwrap(); - let mut k1 = super::RSA::public_key_from_pem(&k0pkey).unwrap(); + let k1 = super::RSA::public_key_from_pem(&k0pkey).unwrap(); let msg = vec!(0xdeu8, 0xadu8, 0xd0u8, 0x0du8); diff --git a/openssl/src/crypto/symm.rs b/openssl/src/crypto/symm.rs index 93764e4d..c4021338 100644 --- a/openssl/src/crypto/symm.rs +++ b/openssl/src/crypto/symm.rs @@ -81,7 +81,7 @@ impl Type { /// Returns the length of keys used with this cipher. pub fn key_len(&self) -> usize { unsafe { - ffi::EVP_CIPHER_key_length(self.as_ptr()) as usize + EVP_CIPHER_key_length(self.as_ptr()) as usize } } @@ -89,7 +89,7 @@ impl Type { /// cipher does not use an IV. pub fn iv_len(&self) -> Option { unsafe { - let len = ffi::EVP_CIPHER_iv_length(self.as_ptr()) as usize; + let len = EVP_CIPHER_iv_length(self.as_ptr()) as usize; if len == 0 { None } else { @@ -105,7 +105,7 @@ impl Type { /// Stream ciphers such as RC4 have a block size of 1. pub fn block_size(&self) -> usize { unsafe { - ffi::EVP_CIPHER_block_size(self.as_ptr()) as usize + EVP_CIPHER_block_size(self.as_ptr()) as usize } } } @@ -272,6 +272,30 @@ fn cipher(t: Type, Ok(out) } +#[cfg(ossl110)] +use ffi::{EVP_CIPHER_iv_length, EVP_CIPHER_block_size, EVP_CIPHER_key_length}; + +#[cfg(ossl10x)] +#[allow(bad_style)] +mod compat { + use libc::c_int; + use ffi::EVP_CIPHER; + + 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 + } +} +#[cfg(ossl10x)] +use self::compat::*; + #[cfg(test)] mod tests { use serialize::hex::{FromHex, ToHex}; diff --git a/openssl/src/dh/mod.rs b/openssl/src/dh/mod.rs index e0cf885a..4ee2d890 100644 --- a/openssl/src/dh/mod.rs +++ b/openssl/src/dh/mod.rs @@ -3,24 +3,22 @@ use error::ErrorStack; use bio::MemBioSlice; use std::ptr; -#[cfg(feature = "dh_from_params")] use bn::BigNum; -#[cfg(feature = "dh_from_params")] use std::mem; pub struct DH(*mut ffi::DH); impl DH { - /// Requires the `dh_from_params` feature. - #[cfg(feature = "dh_from_params")] pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result { - let dh = unsafe { - try_ssl_null!(::c_helpers::rust_0_8_DH_new_from_params(p.as_ptr(), g.as_ptr(), q.as_ptr())) - }; - mem::forget(p); - mem::forget(g); - mem::forget(q); - Ok(DH(dh)) + unsafe { + let dh = DH(try_ssl_null!(ffi::DH_new())); + try_ssl!(compat::DH_set0_pqg(dh.0, + p.as_ptr(), + q.as_ptr(), + g.as_ptr())); + mem::forget((p, g, q)); + Ok(dh) + } } pub fn from_pem(buf: &[u8]) -> Result { @@ -32,19 +30,19 @@ impl DH { Ok(DH(dh)) } - #[cfg(feature = "rfc5114")] + #[cfg(all(feature = "rfc5114", not(ossl101)))] pub fn get_1024_160() -> Result { let dh = try_ssl_null!(unsafe { ffi::DH_get_1024_160() }); Ok(DH(dh)) } - #[cfg(feature = "rfc5114")] + #[cfg(all(feature = "rfc5114", not(ossl101)))] pub fn get_2048_224() -> Result { let dh = try_ssl_null!(unsafe { ffi::DH_get_2048_224() }); Ok(DH(dh)) } - #[cfg(feature = "rfc5114")] + #[cfg(all(feature = "rfc5114", not(ossl101)))] pub fn get_2048_256() -> Result { let dh = try_ssl_null!(unsafe { ffi::DH_get_2048_256() }); Ok(DH(dh)) @@ -64,17 +62,39 @@ impl Drop for 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(test)] mod tests { use super::DH; use bn::BigNum; use ssl::SslContext; - use ssl::SslMethod::Sslv23; + use ssl::SslMethod::Tls; #[test] - #[cfg(feature = "rfc5114")] + #[cfg(all(feature = "rfc5114", not(ossl101)))] fn test_dh_rfc5114() { - let mut ctx = SslContext::new(Sslv23).unwrap(); + let mut ctx = SslContext::new(Tls).unwrap(); let dh1 = DH::get_1024_160().unwrap(); ctx.set_tmp_dh(&dh1).unwrap(); let dh2 = DH::get_2048_224().unwrap(); @@ -84,9 +104,8 @@ mod tests { } #[test] - #[cfg(feature = "dh_from_params")] fn test_dh() { - let mut ctx = SslContext::new(Sslv23).unwrap(); + let mut ctx = SslContext::new(Tls).unwrap(); let p = BigNum::from_hex_str("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435\ E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF429\ 6D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C02\ @@ -116,7 +135,7 @@ mod tests { #[test] fn test_dh_from_pem() { - let mut ctx = SslContext::new(Sslv23).unwrap(); + let mut ctx = SslContext::new(Tls).unwrap(); let params = include_bytes!("../../test/dhparams.pem"); let dh = DH::from_pem(params).ok().expect("Failed to load PEM"); ctx.set_tmp_dh(&dh).unwrap(); diff --git a/openssl/src/error.rs b/openssl/src/error.rs index d76e7cbd..f54d7bda 100644 --- a/openssl/src/error.rs +++ b/openssl/src/error.rs @@ -71,7 +71,7 @@ impl Error { match unsafe { ffi::ERR_get_error() } { 0 => None, - err => Some((Error(err))), + err => Some(Error(err)), } } @@ -121,6 +121,7 @@ impl error::Error for Error { fn get_lib(err: c_ulong) -> &'static str { unsafe { let cstr = ffi::ERR_lib_error_string(err); + assert!(!cstr.is_null(), "bad lib: {}", err); let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); str::from_utf8(bytes).unwrap() } @@ -129,6 +130,7 @@ fn get_lib(err: c_ulong) -> &'static str { fn get_func(err: c_ulong) -> &'static str { unsafe { let cstr = ffi::ERR_func_error_string(err); + assert!(!cstr.is_null(), "bad func: {}", err); let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); str::from_utf8(bytes).unwrap() } @@ -137,6 +139,7 @@ fn get_func(err: c_ulong) -> &'static str { fn get_reason(err: c_ulong) -> &'static str { unsafe { let cstr = ffi::ERR_reason_error_string(err); + assert!(!cstr.is_null(), "bad reason: {}", err); let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); str::from_utf8(bytes).unwrap() } diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index 879681f4..66c767dc 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -13,6 +13,9 @@ extern crate rustc_serialize as serialize; #[cfg(test)] extern crate net2; +#[cfg(test)] +extern crate tempdir; + #[doc(inline)] pub use ffi::init; @@ -23,8 +26,6 @@ mod macros; pub mod asn1; mod bio; pub mod bn; -#[cfg(feature = "c_helpers")] -mod c_helpers; pub mod crypto; pub mod dh; pub mod error; diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs index e2d9cae5..31c298fa 100644 --- a/openssl/src/macros.rs +++ b/openssl/src/macros.rs @@ -80,3 +80,17 @@ macro_rules! lift_ssl_returns_size { } }) } + +#[cfg(ossl10x)] +macro_rules! CRYPTO_free { + ($e:expr) => (::ffi::CRYPTO_free($e)) +} + +#[cfg(ossl110)] +macro_rules! CRYPTO_free { + ($e:expr) => ( + ::ffi::CRYPTO_free($e, + concat!(file!(), "\0").as_ptr() as *const _, + line!() as i32) + ) +} diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs index c5663eb1..ccf3a472 100644 --- a/openssl/src/ssl/bio.rs +++ b/openssl/src/ssl/bio.rs @@ -1,5 +1,5 @@ use libc::{c_char, c_int, c_long, c_void, strlen}; -use ffi::{self, BIO, BIO_CTRL_FLUSH, BIO_TYPE_NONE, BIO_new, BIO_clear_retry_flags, +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; @@ -18,22 +18,11 @@ pub struct StreamState { } /// Safe wrapper for BIO_METHOD -pub struct BioMethod(ffi::BIO_METHOD); +pub struct BioMethod(compat::BIO_METHOD); impl BioMethod { pub fn new() -> BioMethod { - BioMethod(ffi::BIO_METHOD { - type_: 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, - }) + BioMethod(compat::BIO_METHOD::new::()) } } @@ -49,9 +38,9 @@ pub fn new(stream: S) -> Result<(*mut BIO, Arc), Err }); unsafe { - let bio = try_ssl_null!(BIO_new(&method.0)); - (*bio).ptr = Box::into_raw(state) as *mut _; - (*bio).init = 1; + let bio = try_ssl_null!(BIO_new(method.0.get())); + compat::BIO_set_data(bio, Box::into_raw(state) as *mut _); + compat::BIO_set_init(bio, 1); return Ok((bio, method)); } @@ -62,14 +51,13 @@ pub unsafe fn take_error(bio: *mut BIO) -> Option { state.error.take() } -#[cfg_attr(not(feature = "nightly"), allow(dead_code))] pub unsafe fn take_panic(bio: *mut BIO) -> Option> { let state = state::(bio); state.panic.take() } pub unsafe fn get_ref<'a, S: 'a>(bio: *mut BIO) -> &'a S { - let state: &'a StreamState = mem::transmute((*bio).ptr); + let state: &'a StreamState = mem::transmute(compat::BIO_get_data(bio)); &state.stream } @@ -78,24 +66,16 @@ pub unsafe fn get_mut<'a, S: 'a>(bio: *mut BIO) -> &'a mut S { } unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState { - mem::transmute((*bio).ptr) + mem::transmute(compat::BIO_get_data(bio)) } -#[cfg(feature = "nightly")] fn catch_unwind(f: F) -> Result> where F: FnOnce() -> T { ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(f)) } -#[cfg(not(feature = "nightly"))] -fn catch_unwind(f: F) -> Result> - where F: FnOnce() -> T -{ - Ok(f()) -} - -unsafe extern "C" fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int { +unsafe extern fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int { BIO_clear_retry_flags(bio); let state = state::(bio); @@ -117,7 +97,7 @@ unsafe extern "C" fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_ } } -unsafe extern "C" fn bread(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int { +unsafe extern fn bread(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int { BIO_clear_retry_flags(bio); let state = state::(bio); @@ -147,15 +127,15 @@ fn retriable_error(err: &io::Error) -> bool { } } -unsafe extern "C" fn bputs(bio: *mut BIO, s: *const c_char) -> c_int { +unsafe extern fn bputs(bio: *mut BIO, s: *const c_char) -> c_int { bwrite::(bio, s, strlen(s) as c_int) } -unsafe extern "C" fn ctrl(bio: *mut BIO, - cmd: c_int, - _num: c_long, - _ptr: *mut c_void) - -> c_long { +unsafe extern fn ctrl(bio: *mut BIO, + cmd: c_int, + _num: c_long, + _ptr: *mut c_void) + -> c_long { if cmd == BIO_CTRL_FLUSH { let state = state::(bio); @@ -175,22 +155,126 @@ unsafe extern "C" fn ctrl(bio: *mut BIO, } } -unsafe extern "C" fn create(bio: *mut BIO) -> c_int { - (*bio).init = 0; - (*bio).num = 0; - (*bio).ptr = ptr::null_mut(); - (*bio).flags = 0; +unsafe extern fn create(bio: *mut BIO) -> c_int { + compat::BIO_set_init(bio, 0); + compat::BIO_set_num(bio, 0); + compat::BIO_set_data(bio, ptr::null_mut()); + compat::BIO_set_flags(bio, 0); 1 } -unsafe extern "C" fn destroy(bio: *mut BIO) -> c_int { +unsafe extern fn destroy(bio: *mut BIO) -> c_int { if bio.is_null() { return 0; } - assert!(!(*bio).ptr.is_null()); - Box::>::from_raw((*bio).ptr as *mut _); - (*bio).ptr = ptr::null_mut(); - (*bio).init = 0; + let data = compat::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); 1 } + +#[cfg(ossl110)] +#[allow(bad_style)] +mod compat { + use std::io::{Read, Write}; + + use libc::c_int; + use ffi; + pub use ffi::{BIO_set_init, BIO_set_flags, BIO_set_data, BIO_get_data}; + + pub unsafe fn BIO_set_num(_bio: *mut ffi::BIO, _num: c_int) {} + + pub struct BIO_METHOD { + inner: *mut ffi::BIO_METHOD, + } + + 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 { inner: 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 + } + } + + pub fn get(&self) -> *mut ffi::BIO_METHOD { + self.inner + } + } + + impl Drop for BIO_METHOD { + fn drop(&mut self) { + unsafe { + ffi::BIO_meth_free(self.inner); + } + } + } +} + +#[cfg(ossl10x)] +#[allow(bad_style)] +mod compat { + use std::io::{Read, Write}; + use std::cell::UnsafeCell; + + use ffi; + use libc::{c_int, c_void}; + + pub struct BIO_METHOD { + inner: UnsafeCell, + } + + impl BIO_METHOD { + pub fn new() -> BIO_METHOD { + BIO_METHOD { + inner: UnsafeCell::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, + }), + } + } + + pub fn get(&self) -> *mut ffi::BIO_METHOD { + self.inner.get() + } + } + + 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/mod.rs b/openssl/src/ssl/mod.rs index 6e365af6..51bfc790 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1,4 +1,4 @@ -use libc::{c_int, c_void, c_long}; +use libc::{c_int, c_void, c_long, c_ulong}; use std::any::Any; use std::any::TypeId; use std::cmp; @@ -38,12 +38,11 @@ use self::bio::BioMethod; pub use ssl::error::Error; bitflags! { - pub flags SslContextOptions: c_long { + pub flags SslContextOptions: c_ulong { const SSL_OP_MICROSOFT_SESS_ID_BUG = ffi::SSL_OP_MICROSOFT_SESS_ID_BUG, const SSL_OP_NETSCAPE_CHALLENGE_BUG = ffi::SSL_OP_NETSCAPE_CHALLENGE_BUG, const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = ffi::SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG, - const SSL_OP_TLSEXT_PADDING = ffi::SSL_OP_TLSEXT_PADDING, const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = ffi::SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER, const SSL_OP_SSLEAY_080_CLIENT_DH_BUG = ffi::SSL_OP_SSLEAY_080_CLIENT_DH_BUG, const SSL_OP_TLS_D5_BUG = ffi::SSL_OP_TLS_D5_BUG, @@ -73,74 +72,11 @@ bitflags! { #[allow(non_camel_case_types)] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum SslMethod { - #[cfg(feature = "sslv2")] - /// Only support the SSLv2 protocol, requires the `sslv2` feature. - Sslv2, - /// Support the SSLv2, SSLv3, TLSv1, TLSv1.1, and TLSv1.2 protocols depending on what the - /// linked OpenSSL library supports. - Sslv23, - #[cfg(feature = "sslv3")] - /// Only support the SSLv3 protocol. - Sslv3, - /// Only support the TLSv1 protocol. - Tlsv1, - #[cfg(feature = "tlsv1_1")] - /// Support TLSv1.1 protocol, requires the `tlsv1_1` feature. - Tlsv1_1, - #[cfg(feature = "tlsv1_2")] - /// Support TLSv1.2 protocol, requires the `tlsv1_2` feature. - Tlsv1_2, - #[cfg(feature = "dtlsv1")] - /// Support DTLSv1 protocol, requires the `dtlsv1` feature. - Dtlsv1, - #[cfg(feature = "dtlsv1_2")] - /// Support DTLSv1.2 protocol, requires the `dtlsv1_2` feature. - Dtlsv1_2, -} - -impl SslMethod { - fn to_raw(&self) -> *const ffi::SSL_METHOD { - unsafe { - match *self { - #[cfg(feature = "sslv2")] - SslMethod::Sslv2 => ffi::SSLv2_method(), - #[cfg(feature = "sslv3")] - SslMethod::Sslv3 => ffi::SSLv3_method(), - SslMethod::Tlsv1 => ffi::TLSv1_method(), - SslMethod::Sslv23 => ffi::SSLv23_method(), - #[cfg(feature = "tlsv1_1")] - SslMethod::Tlsv1_1 => ffi::TLSv1_1_method(), - #[cfg(feature = "tlsv1_2")] - SslMethod::Tlsv1_2 => ffi::TLSv1_2_method(), - #[cfg(feature = "dtlsv1")] - SslMethod::Dtlsv1 => ffi::DTLSv1_method(), - #[cfg(feature = "dtlsv1_2")] - SslMethod::Dtlsv1_2 => ffi::DTLSv1_2_method(), - } - } - } - - fn from_raw(method: *const ffi::SSL_METHOD) -> Option { - unsafe { - match method { - #[cfg(feature = "sslv2")] - x if x == ffi::SSLv2_method() => Some(SslMethod::Sslv2), - #[cfg(feature = "sslv3")] - x if x == ffi::SSLv3_method() => Some(SslMethod::Sslv3), - x if x == ffi::TLSv1_method() => Some(SslMethod::Tlsv1), - x if x == ffi::SSLv23_method() => Some(SslMethod::Sslv23), - #[cfg(feature = "tlsv1_1")] - x if x == ffi::TLSv1_1_method() => Some(SslMethod::Tlsv1_1), - #[cfg(feature = "tlsv1_2")] - x if x == ffi::TLSv1_2_method() => Some(SslMethod::Tlsv1_2), - #[cfg(feature = "dtlsv1")] - x if x == ffi::DTLSv1_method() => Some(SslMethod::Dtlsv1), - #[cfg(feature = "dtlsv1_2")] - x if x == ffi::DTLSv1_2_method() => Some(SslMethod::Dtlsv1_2), - _ => None, - } - } - } + // TODO: support more methods + /// Support the TLS protocol + Tls, + /// Support DTLS protocol + Dtls, } /// Determines the type of certificate verification used @@ -172,11 +108,11 @@ fn get_ssl_verify_data_idx() -> c_int { *SSL_INDEXES.lock().unwrap().entry(TypeId::of::()).or_insert_with(|| get_new_ssl_idx::()) } -#[cfg(feature = "npn")] +#[cfg(all(feature = "npn", not(ossl101)))] lazy_static! { static ref NPN_PROTOS_IDX: c_int = get_new_idx::>(); } -#[cfg(feature = "alpn")] +#[cfg(all(feature = "alpn", not(ossl101)))] lazy_static! { static ref ALPN_PROTOS_IDX: c_int = get_new_idx::>(); } @@ -184,52 +120,50 @@ lazy_static! { /// Determine a new index to use for SSL CTX ex data. /// Registers a destruct for the data which will be called by openssl when the context is freed. fn get_new_idx() -> c_int { - extern "C" fn free_data_box(_parent: *mut c_void, - ptr: *mut c_void, - _ad: *mut ffi::CRYPTO_EX_DATA, - _idx: c_int, - _argl: c_long, - _argp: *mut c_void) { + extern fn free_data_box(_parent: *mut c_void, + ptr: *mut c_void, + _ad: *mut ffi::CRYPTO_EX_DATA, + _idx: c_int, + _argl: c_long, + _argp: *mut c_void) { if !ptr.is_null() { let _: Box = unsafe { mem::transmute(ptr) }; } } unsafe { - let f: ffi::CRYPTO_EX_free = free_data_box::; - let idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, Some(f)); + let idx = compat::get_new_idx(free_data_box::); assert!(idx >= 0); idx } } fn get_new_ssl_idx() -> c_int { - extern "C" fn free_data_box(_parent: *mut c_void, - ptr: *mut c_void, - _ad: *mut ffi::CRYPTO_EX_DATA, - _idx: c_int, - _argl: c_long, - _argp: *mut c_void) { + extern fn free_data_box(_parent: *mut c_void, + ptr: *mut c_void, + _ad: *mut ffi::CRYPTO_EX_DATA, + _idx: c_int, + _argl: c_long, + _argp: *mut c_void) { if !ptr.is_null() { let _: Box = unsafe { mem::transmute(ptr) }; } } unsafe { - let f: ffi::CRYPTO_EX_free = free_data_box::; - let idx = ffi::SSL_get_ex_new_index(0, ptr::null(), None, None, Some(f)); + let idx = compat::get_new_ssl_idx(free_data_box::); assert!(idx >= 0); idx } } -extern "C" fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int +extern fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int where F: Fn(bool, &X509StoreContext) -> bool + Any + 'static + Sync + Send { unsafe { let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx(); let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx); - let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); + let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl as *const _); let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::()); let verify: &F = mem::transmute(verify); @@ -239,13 +173,14 @@ extern "C" fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_ } } -extern "C" fn ssl_raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int +extern fn ssl_raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int where F: Fn(bool, &X509StoreContext) -> bool + Any + 'static + Sync + Send { unsafe { let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx(); let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx); - let verify = ffi::SSL_get_ex_data(ssl, get_ssl_verify_data_idx::()); + let verify = ffi::SSL_get_ex_data(ssl as *const _, + get_ssl_verify_data_idx::()); let verify: &F = mem::transmute(verify); let ctx = X509StoreContext::new(x509_ctx); @@ -254,7 +189,7 @@ extern "C" fn ssl_raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_ST } } -extern "C" fn raw_sni(ssl: *mut ffi::SSL, al: *mut c_int, _arg: *mut c_void) -> c_int +extern fn raw_sni(ssl: *mut ffi::SSL, al: *mut c_int, _arg: *mut c_void) -> c_int where F: Fn(&mut SslRef) -> Result<(), SniError> + Any + 'static + Sync + Send { unsafe { @@ -278,7 +213,7 @@ extern "C" fn raw_sni(ssl: *mut ffi::SSL, al: *mut c_int, _arg: *mut c_void) } } -#[cfg(any(feature = "npn", feature = "alpn"))] +#[cfg(all(any(feature = "npn", feature = "alpn"), not(ossl101)))] unsafe fn select_proto_using(ssl: *mut ffi::SSL, out: *mut *mut c_uchar, outlen: *mut c_uchar, @@ -311,26 +246,26 @@ unsafe fn select_proto_using(ssl: *mut ffi::SSL, /// supported by the server. It achieves this by delegating to the `SSL_select_next_proto` /// function. The list of protocols supported by the client is found in the extra data of the /// OpenSSL context. -#[cfg(feature = "npn")] -extern "C" fn raw_next_proto_select_cb(ssl: *mut ffi::SSL, - out: *mut *mut c_uchar, - outlen: *mut c_uchar, - inbuf: *const c_uchar, - inlen: c_uint, - _arg: *mut c_void) - -> c_int { +#[cfg(all(feature = "npn", not(ossl101)))] +extern fn raw_next_proto_select_cb(ssl: *mut ffi::SSL, + out: *mut *mut c_uchar, + outlen: *mut c_uchar, + inbuf: *const c_uchar, + inlen: c_uint, + _arg: *mut c_void) + -> c_int { unsafe { select_proto_using(ssl, out, outlen, inbuf, inlen, *NPN_PROTOS_IDX) } } -#[cfg(feature = "alpn")] -extern "C" fn raw_alpn_select_cb(ssl: *mut ffi::SSL, - out: *mut *mut c_uchar, - outlen: *mut c_uchar, - inbuf: *const c_uchar, - inlen: c_uint, - _arg: *mut c_void) - -> c_int { - unsafe { select_proto_using(ssl, out, outlen, inbuf, inlen, *ALPN_PROTOS_IDX) } +#[cfg(all(feature = "alpn", not(ossl101)))] +extern fn raw_alpn_select_cb(ssl: *mut ffi::SSL, + out: *mut *const c_uchar, + outlen: *mut c_uchar, + inbuf: *const c_uchar, + inlen: c_uint, + _arg: *mut c_void) + -> c_int { + unsafe { select_proto_using(ssl, out as *mut _, outlen, inbuf, inlen, *ALPN_PROTOS_IDX) } } /// The function is given as the callback to `SSL_CTX_set_next_protos_advertised_cb`. @@ -340,12 +275,12 @@ extern "C" fn raw_alpn_select_cb(ssl: *mut ffi::SSL, /// that it supports. /// The list of supported protocols is found in the extra data of the OpenSSL /// context. -#[cfg(feature = "npn")] -extern "C" fn raw_next_protos_advertise_cb(ssl: *mut ffi::SSL, - out: *mut *const c_uchar, - outlen: *mut c_uint, - _arg: *mut c_void) - -> c_int { +#[cfg(all(feature = "npn", not(ossl101)))] +extern fn raw_next_protos_advertise_cb(ssl: *mut ffi::SSL, + out: *mut *const c_uchar, + outlen: *mut c_uint, + _arg: *mut c_void) + -> c_int { unsafe { // First, get the list of (supported) protocols saved in the context extra data. let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); @@ -367,7 +302,7 @@ extern "C" fn raw_next_protos_advertise_cb(ssl: *mut ffi::SSL, /// Convert a set of byte slices into a series of byte strings encoded for SSL. Encoding is a byte /// containing the length followed by the string. -#[cfg(any(feature = "npn", feature = "alpn"))] +#[cfg(all(any(feature = "alpn", feature = "npn"), not(ossl101)))] fn ssl_encode_byte_strings(strings: &[&[u8]]) -> Vec { let mut enc = Vec::new(); for string in strings { @@ -442,8 +377,8 @@ impl<'a> SslContextRef<'a> { ffi::SSL_CTX_set_ex_data(self.as_ptr(), get_verify_data_idx::(), mem::transmute(callback)); - let f: extern "C" fn(_, _, _) -> _ = raw_sni::; - let f: extern "C" fn() = mem::transmute(f); + let f: extern fn(_, _, _) -> _ = raw_sni::; + let f: extern fn() = mem::transmute(f); ffi::SSL_CTX_set_tlsext_servername_callback(self.as_ptr(), Some(f)); } } @@ -515,15 +450,12 @@ impl<'a> SslContextRef<'a> { } /// Specifies the file that contains certificate chain - pub fn set_certificate_chain_file>(&mut self, - file: P, - file_type: X509FileType) + pub fn set_certificate_chain_file>(&mut self, file: P) -> Result<(), ErrorStack> { let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap(); wrap_ssl_result(unsafe { ffi::SSL_CTX_use_certificate_chain_file(self.as_ptr(), - file.as_ptr() as *const _, - file_type as c_int) + file.as_ptr() as *const _) }) } @@ -575,27 +507,44 @@ impl<'a> SslContextRef<'a> { }) } - /// If `onoff` is set to `true`, enable ECDHE for key exchange with compatible - /// clients, and automatically select an appropriate elliptic curve. + /// If `onoff` is set to `true`, enable ECDHE for key exchange with + /// compatible clients, and automatically select an appropriate elliptic + /// curve. /// - /// This method requires OpenSSL >= 1.0.2 or LibreSSL and the `ecdh_auto` feature. - #[cfg(feature = "ecdh_auto")] + /// This method requires OpenSSL >= 1.0.2 or LibreSSL and the `ecdh_auto` + /// feature. + #[cfg(all(feature = "ecdh_auto", not(ossl101)))] pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { - wrap_ssl_result(unsafe { ffi::SSL_CTX_set_ecdh_auto(self.as_ptr(), onoff as c_long) as c_int }) + self._set_ecdh_auto(onoff) + } + + #[cfg(all(feature = "ecdh_auto", ossl102))] + fn _set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { + wrap_ssl_result(unsafe { + ffi::SSL_CTX_ctrl(self.as_ptr(), + ffi::SSL_CTRL_SET_ECDH_AUTO, + onoff as c_long, + ptr::null_mut()) as c_int + }) + } + + #[cfg(all(feature = "ecdh_auto", ossl110))] + fn _set_ecdh_auto(&mut self, _onoff: bool) -> Result<(), ErrorStack> { + Ok(()) } pub fn set_options(&mut self, option: SslContextOptions) -> SslContextOptions { - let ret = unsafe { ffi::SSL_CTX_set_options(self.as_ptr(), option.bits()) }; + let ret = unsafe { compat::SSL_CTX_set_options(self.as_ptr(), option.bits()) }; SslContextOptions::from_bits(ret).unwrap() } pub fn options(&self) -> SslContextOptions { - let ret = unsafe { ffi::SSL_CTX_get_options(self.as_ptr()) }; + let ret = unsafe { compat::SSL_CTX_get_options(self.as_ptr()) }; SslContextOptions::from_bits(ret).unwrap() } pub fn clear_options(&mut self, option: SslContextOptions) -> SslContextOptions { - let ret = unsafe { ffi::SSL_CTX_clear_options(self.as_ptr(), option.bits()) }; + let ret = unsafe { compat::SSL_CTX_clear_options(self.as_ptr(), option.bits()) }; SslContextOptions::from_bits(ret).unwrap() } @@ -603,7 +552,7 @@ impl<'a> SslContextRef<'a> { /// supported by the application). /// /// This method needs the `npn` feature. - #[cfg(feature = "npn")] + #[cfg(all(feature = "npn", not(ossl101)))] pub fn set_npn_protocols(&mut self, protocols: &[&[u8]]) { // Firstly, convert the list of protocols to a byte-array that can be passed to OpenSSL // APIs -- a list of length-prefixed strings. @@ -635,7 +584,7 @@ impl<'a> SslContextRef<'a> { /// Note that ordering of the protocols controls the priority with which they are chosen. /// /// This method needs the `alpn` feature. - #[cfg(feature = "alpn")] + #[cfg(all(feature = "alpn", not(ossl101)))] pub fn set_alpn_protocols(&mut self, protocols: &[&[u8]]) { let protocols: Box> = Box::new(ssl_encode_byte_strings(protocols)); unsafe { @@ -662,12 +611,10 @@ pub struct SslContext(SslContextRef<'static>); unsafe impl Send for SslContext {} unsafe impl Sync for SslContext {} -#[cfg(feature = "ssl_context_clone")] impl Clone for SslContext { - /// Requires the `ssl_context_clone` feature. fn clone(&self) -> Self { unsafe { - ::c_helpers::rust_0_8_SSL_CTX_clone(self.as_ptr()); + compat::SSL_CTX_up_ref(self.as_ptr()); SslContext::from_ptr(self.as_ptr()) } } @@ -706,15 +653,13 @@ impl SslContext { init(); let mut ctx = unsafe { - let ctx = try_ssl_null!(ffi::SSL_CTX_new(method.to_raw())); + let method = compat::get_method(method); + let ctx = try_ssl_null!(ffi::SSL_CTX_new(method)); SslContext::from_ptr(ctx) }; match method { - #[cfg(feature = "dtlsv1")] - SslMethod::Dtlsv1 => ctx.set_read_ahead(1), - #[cfg(feature = "dtlsv1_2")] - SslMethod::Dtlsv1_2 => ctx.set_read_ahead(1), + SslMethod::Dtls => ctx.set_read_ahead(1), _ => {} } // this is a bit dubious (?) @@ -982,7 +927,7 @@ impl<'a> SslRef<'a> { /// to interpret it. /// /// This method needs the `alpn` feature. - #[cfg(feature = "alpn")] + #[cfg(all(feature = "alpn", not(ossl101)))] pub fn selected_alpn_protocol(&self) -> Option<&[u8]> { unsafe { let mut data: *const c_uchar = ptr::null(); @@ -1023,13 +968,6 @@ impl<'a> SslRef<'a> { Some(s) } - pub fn ssl_method(&self) -> SslMethod { - unsafe { - let method = ffi::SSL_get_ssl_method(self.as_ptr()); - SslMethod::from_raw(method).unwrap() - } - } - /// Returns the server's name for the current connection pub fn servername(&self) -> Option { let name = unsafe { ffi::SSL_get_servername(self.as_ptr(), ffi::TLSEXT_NAMETYPE_host_name) }; @@ -1319,16 +1257,12 @@ impl SslStream { } } - #[cfg(feature = "nightly")] fn check_panic(&mut self) { if let Some(err) = unsafe { bio::take_panic::(self.ssl.get_raw_rbio()) } { ::std::panic::resume_unwind(err) } } - #[cfg(not(feature = "nightly"))] - fn check_panic(&mut self) {} - fn get_bio_error(&mut self) -> io::Error { let error = unsafe { bio::take_error::(self.ssl.get_raw_rbio()) }; match error { @@ -1412,3 +1346,107 @@ impl<'a> IntoSsl for &'a SslContext { Ssl::new(self) } } + +#[cfg(ossl110)] +mod compat { + use std::ptr; + + use ffi; + use libc::c_int; + + pub use ffi::{SSL_CTX_get_options, SSL_CTX_set_options}; + pub use ffi::{SSL_CTX_clear_options, SSL_CTX_up_ref}; + + use super::SslMethod; + + 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_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_method(method: SslMethod) -> *const ffi::SSL_METHOD { + match method { + SslMethod::Tls => ffi::TLS_method(), + SslMethod::Dtls => ffi::DTLS_method(), + } + } +} + +#[cfg(ossl10x)] +#[allow(bad_style)] +mod compat { + use std::ptr; + + use ffi; + use libc::{self, c_long, c_ulong, c_int}; + + use super::SslMethod; + + 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 get_method(method: SslMethod) -> *const ffi::SSL_METHOD { + match method { + SslMethod::Tls => ffi::SSLv23_method(), + SslMethod::Dtls => ffi::DTLSv1_method(), + } + } + + 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 + } +} diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 3bbbed03..e5bdc8da 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1,5 +1,6 @@ #![allow(unused_imports)] +use std::env; use std::fs::File; use std::io::prelude::*; use std::io::{self, BufReader}; @@ -12,11 +13,12 @@ use std::thread; use std::time::Duration; use net2::TcpStreamExt; +use tempdir::TempDir; use crypto::hash::Type::SHA256; use ssl; use ssl::SSL_VERIFY_PEER; -use ssl::SslMethod::Sslv23; +use ssl::SslMethod::Tls; use ssl::{SslMethod, HandshakeError}; use ssl::error::Error; use ssl::{SslContext, SslStream}; @@ -46,10 +48,21 @@ fn next_addr() -> SocketAddr { struct Server { p: Child, + _temp: TempDir, } impl Server { fn spawn(args: &[&str], input: Option>) -> (Server, SocketAddr) { + static CERT: &'static [u8] = include_bytes!("../../../test/cert.pem"); + static KEY: &'static [u8] = include_bytes!("../../../test/key.pem"); + + + let td = TempDir::new("openssl").unwrap(); + let cert = td.path().join("cert.pem"); + let key = td.path().join("key.pem"); + File::create(&cert).unwrap().write_all(CERT).unwrap(); + File::create(&key).unwrap().write_all(KEY).unwrap(); + let addr = next_addr(); let mut child = Command::new("openssl") .arg("s_server") @@ -57,11 +70,10 @@ impl Server { .arg(addr.port().to_string()) .args(args) .arg("-cert") - .arg("cert.pem") + .arg(&cert) .arg("-key") - .arg("key.pem") + .arg(&key) .arg("-no_dhe") - .current_dir("test") .stdout(Stdio::null()) .stderr(Stdio::null()) .stdin(Stdio::piped()) @@ -71,7 +83,7 @@ impl Server { if let Some(mut input) = input { thread::spawn(move || input(stdin)); } - (Server { p: child }, addr) + (Server { p: child, _temp: td }, addr) } fn new_tcp(args: &[&str]) -> (Server, TcpStream) { @@ -92,7 +104,7 @@ impl Server { Server::new_tcp(&["-www"]) } - #[cfg(any(feature = "alpn", feature = "npn"))] + #[cfg(all(any(feature = "alpn", feature = "npn"), not(ossl101)))] fn new_alpn() -> (Server, TcpStream) { Server::new_tcp(&["-www", "-nextprotoneg", @@ -119,7 +131,7 @@ impl Server { // but don't currently have a great way to do that so just wait for a // bit. thread::sleep(Duration::from_millis(100)); - let socket = UdpSocket::bind(next_addr()).unwrap(); + let socket = UdpSocket::bind("127.0.0.1:0").unwrap(); socket.connect(&addr).unwrap(); (s, UdpConnected(socket)) } @@ -205,7 +217,7 @@ macro_rules! run_test( #[test] fn sslv23() { let (_s, stream) = Server::new(); - $blk(SslMethod::Sslv23, stream); + $blk(SslMethod::Tls, stream); } #[test] @@ -226,11 +238,6 @@ run_test!(new_sslstream, |method, stream| { SslStream::connect(&SslContext::new(method).unwrap(), stream).unwrap(); }); -run_test!(get_ssl_method, |method, _| { - let ssl = Ssl::new(&SslContext::new(method).unwrap()).unwrap(); - assert_eq!(ssl.ssl_method(), method); -}); - run_test!(verify_untrusted, |method, stream| { let mut ctx = SslContext::new(method).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); @@ -391,11 +398,11 @@ run_test!(ssl_verify_callback, |method, stream| { // Make sure every write call translates to a write call to the underlying socket. #[test] fn test_write_hits_stream() { - let listener = TcpListener::bind(next_addr()).unwrap(); + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = listener.local_addr().unwrap(); let guard = thread::spawn(move || { - let ctx = SslContext::new(Sslv23).unwrap(); + let ctx = SslContext::new(Tls).unwrap(); let stream = TcpStream::connect(addr).unwrap(); let mut stream = SslStream::connect(&ctx, stream).unwrap(); @@ -403,7 +410,7 @@ fn test_write_hits_stream() { stream }); - let mut ctx = SslContext::new(Sslv23).unwrap(); + let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM).unwrap(); ctx.set_private_key_file(&Path::new("test/key.pem"), X509FileType::PEM).unwrap(); @@ -423,7 +430,7 @@ fn test_set_certificate_and_private_key() { let cert = include_bytes!("../../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); - let mut ctx = SslContext::new(Sslv23).unwrap(); + let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_private_key(&key).unwrap(); ctx.set_certificate(&cert).unwrap(); @@ -451,7 +458,7 @@ run_test!(clear_ctx_options, |method, _| { #[test] fn test_write() { let (_s, stream) = Server::new(); - let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); + let mut stream = SslStream::connect(&SslContext::new(Tls).unwrap(), stream).unwrap(); stream.write_all("hello".as_bytes()).unwrap(); stream.flush().unwrap(); stream.write_all(" there".as_bytes()).unwrap(); @@ -461,7 +468,7 @@ fn test_write() { #[test] fn test_write_direct() { let (_s, stream) = Server::new(); - let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); + let mut stream = SslStream::connect(&SslContext::new(Tls).unwrap(), stream).unwrap(); stream.write_all("hello".as_bytes()).unwrap(); stream.flush().unwrap(); stream.write_all(" there".as_bytes()).unwrap(); @@ -492,7 +499,7 @@ fn test_write_dtlsv1() { #[test] fn test_read() { let (_s, tcp) = Server::new(); - let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); + let mut stream = SslStream::connect(&SslContext::new(Tls).unwrap(), tcp).unwrap(); stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); stream.flush().unwrap(); io::copy(&mut stream, &mut io::sink()).ok().expect("read error"); @@ -501,7 +508,7 @@ fn test_read() { #[test] fn test_read_direct() { let (_s, tcp) = Server::new(); - let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); + let mut stream = SslStream::connect(&SslContext::new(Tls).unwrap(), tcp).unwrap(); stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); stream.flush().unwrap(); io::copy(&mut stream, &mut io::sink()).ok().expect("read error"); @@ -510,7 +517,7 @@ fn test_read_direct() { #[test] fn test_pending() { let (_s, tcp) = Server::new(); - let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); + let mut stream = SslStream::connect(&SslContext::new(Tls).unwrap(), tcp).unwrap(); stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); stream.flush().unwrap(); @@ -533,7 +540,7 @@ fn test_pending() { #[test] fn test_state() { let (_s, tcp) = Server::new(); - let stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); + let stream = SslStream::connect(&SslContext::new(Tls).unwrap(), tcp).unwrap(); assert_eq!(stream.ssl().state_string(), "SSLOK "); assert_eq!(stream.ssl().state_string_long(), "SSL negotiation finished successfully"); @@ -542,10 +549,10 @@ fn test_state() { /// Tests that connecting with the client using ALPN, but the server not does not /// break the existing connection behavior. #[test] -#[cfg(feature = "alpn")] +#[cfg(all(feature = "alpn", not(ossl101)))] fn test_connect_with_unilateral_alpn() { let (_s, stream) = Server::new(); - let mut ctx = SslContext::new(Sslv23).unwrap(); + let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]); match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { @@ -564,10 +571,10 @@ fn test_connect_with_unilateral_alpn() { /// Tests that connecting with the client using NPN, but the server not does not /// break the existing connection behavior. #[test] -#[cfg(feature = "npn")] +#[cfg(all(feature = "npn", not(ossl101)))] fn test_connect_with_unilateral_npn() { let (_s, stream) = Server::new(); - let mut ctx = SslContext::new(Sslv23).unwrap(); + let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); ctx.set_npn_protocols(&[b"http/1.1", b"spdy/3.1"]); match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { @@ -586,10 +593,10 @@ fn test_connect_with_unilateral_npn() { /// 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(feature = "alpn")] +#[cfg(all(feature = "alpn", not(ossl101)))] fn test_connect_with_alpn_successful_multiple_matching() { let (_s, stream) = Server::new_alpn(); - let mut ctx = SslContext::new(Sslv23).unwrap(); + let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); ctx.set_alpn_protocols(&[b"spdy/3.1", b"http/1.1"]); match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { @@ -608,10 +615,10 @@ fn test_connect_with_alpn_successful_multiple_matching() { /// Tests that when both the client as well as the server use NPN and their /// lists of supported protocols have an overlap, the correct protocol is chosen. #[test] -#[cfg(feature = "npn")] +#[cfg(all(feature = "npn", not(ossl101)))] fn test_connect_with_npn_successful_multiple_matching() { let (_s, stream) = Server::new_alpn(); - let mut ctx = SslContext::new(Sslv23).unwrap(); + let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); ctx.set_npn_protocols(&[b"spdy/3.1", b"http/1.1"]); match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { @@ -631,10 +638,10 @@ fn test_connect_with_npn_successful_multiple_matching() { /// lists of supported protocols have an overlap -- with only ONE protocol /// being valid for both. #[test] -#[cfg(feature = "alpn")] +#[cfg(all(feature = "alpn", not(ossl101)))] fn test_connect_with_alpn_successful_single_match() { let (_s, stream) = Server::new_alpn(); - let mut ctx = SslContext::new(Sslv23).unwrap(); + let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); ctx.set_alpn_protocols(&[b"spdy/3.1"]); match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { @@ -655,10 +662,10 @@ fn test_connect_with_alpn_successful_single_match() { /// lists of supported protocols have an overlap -- with only ONE protocol /// being valid for both. #[test] -#[cfg(feature = "npn")] +#[cfg(all(feature = "npn", not(ossl101)))] fn test_connect_with_npn_successful_single_match() { let (_s, stream) = Server::new_alpn(); - let mut ctx = SslContext::new(Sslv23).unwrap(); + let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); ctx.set_npn_protocols(&[b"spdy/3.1"]); match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { @@ -677,13 +684,13 @@ fn test_connect_with_npn_successful_single_match() { /// Tests that when the `SslStream` is created as a server stream, the protocols /// are correctly advertised to the client. #[test] -#[cfg(feature = "npn")] +#[cfg(all(feature = "npn", not(ossl101)))] fn test_npn_server_advertise_multiple() { - let listener = TcpListener::bind(next_addr()).unwrap(); + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let localhost = listener.local_addr().unwrap(); // We create a different context instance for the server... let listener_ctx = { - let mut ctx = SslContext::new(Sslv23).unwrap(); + let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); ctx.set_npn_protocols(&[b"http/1.1", b"spdy/3.1"]); assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM) @@ -698,7 +705,7 @@ fn test_npn_server_advertise_multiple() { let _ = SslStream::accept(&listener_ctx, stream).unwrap(); }); - let mut ctx = SslContext::new(Sslv23).unwrap(); + let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); ctx.set_npn_protocols(&[b"spdy/3.1"]); match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { @@ -718,13 +725,13 @@ fn test_npn_server_advertise_multiple() { /// Tests that when the `SslStream` is created as a server stream, the protocols /// are correctly advertised to the client. #[test] -#[cfg(feature = "alpn")] +#[cfg(all(feature = "alpn", not(ossl101)))] fn test_alpn_server_advertise_multiple() { - let listener = TcpListener::bind(next_addr()).unwrap(); + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let localhost = listener.local_addr().unwrap(); // We create a different context instance for the server... let listener_ctx = { - let mut ctx = SslContext::new(Sslv23).unwrap(); + let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]); assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM) @@ -739,7 +746,7 @@ fn test_alpn_server_advertise_multiple() { let _ = SslStream::accept(&listener_ctx, stream).unwrap(); }); - let mut ctx = SslContext::new(Sslv23).unwrap(); + let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); ctx.set_alpn_protocols(&[b"spdy/3.1"]); match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { @@ -759,13 +766,13 @@ fn test_alpn_server_advertise_multiple() { /// Test that Servers supporting ALPN don't report a protocol when none of their protocols match /// the client's reported protocol. #[test] -#[cfg(feature = "alpn")] +#[cfg(all(feature = "alpn", not(ossl101)))] fn test_alpn_server_select_none() { - let listener = TcpListener::bind(next_addr()).unwrap(); + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let localhost = listener.local_addr().unwrap(); // We create a different context instance for the server... let listener_ctx = { - let mut ctx = SslContext::new(Sslv23).unwrap(); + let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]); assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM) @@ -780,7 +787,7 @@ fn test_alpn_server_select_none() { let _ = SslStream::accept(&listener_ctx, stream).unwrap(); }); - let mut ctx = SslContext::new(Sslv23).unwrap(); + let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); ctx.set_alpn_protocols(&[b"http/2"]); match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { @@ -875,7 +882,7 @@ fn handshake(res: Result, HandshakeError>) fn test_write_nonblocking() { let (_s, stream) = Server::new(); stream.set_nonblocking(true).unwrap(); - let cx = SslContext::new(Sslv23).unwrap(); + let cx = SslContext::new(Tls).unwrap(); let mut stream = handshake(SslStream::connect(&cx, stream)); let mut iterations = 0; @@ -913,7 +920,7 @@ fn test_write_nonblocking() { fn test_read_nonblocking() { let (_s, stream) = Server::new(); stream.set_nonblocking(true).unwrap(); - let cx = SslContext::new(Sslv23).unwrap(); + let cx = SslContext::new(Tls).unwrap(); let mut stream = handshake(SslStream::connect(&cx, stream)); let mut iterations = 0; @@ -965,7 +972,6 @@ fn test_read_nonblocking() { #[test] #[should_panic(expected = "blammo")] -#[cfg(feature = "nightly")] fn write_panic() { struct ExplodingStream(TcpStream); @@ -988,13 +994,12 @@ fn write_panic() { let (_s, stream) = Server::new(); let stream = ExplodingStream(stream); - let ctx = SslContext::new(SslMethod::Sslv23).unwrap(); + let ctx = SslContext::new(SslMethod::Tls).unwrap(); let _ = SslStream::connect(&ctx, stream); } #[test] #[should_panic(expected = "blammo")] -#[cfg(feature = "nightly")] fn read_panic() { struct ExplodingStream(TcpStream); @@ -1017,13 +1022,12 @@ fn read_panic() { let (_s, stream) = Server::new(); let stream = ExplodingStream(stream); - let ctx = SslContext::new(SslMethod::Sslv23).unwrap(); + let ctx = SslContext::new(SslMethod::Tls).unwrap(); let _ = SslStream::connect(&ctx, stream); } #[test] #[should_panic(expected = "blammo")] -#[cfg(feature = "nightly")] fn flush_panic() { struct ExplodingStream(TcpStream); @@ -1046,20 +1050,20 @@ fn flush_panic() { let (_s, stream) = Server::new(); let stream = ExplodingStream(stream); - let ctx = SslContext::new(SslMethod::Sslv23).unwrap(); - let mut stream = SslStream::connect(&ctx, stream).unwrap(); + let ctx = SslContext::new(SslMethod::Tls).unwrap(); + let mut stream = SslStream::connect(&ctx, stream).ok().unwrap(); let _ = stream.flush(); } #[test] fn refcount_ssl_context() { let mut ssl = { - let ctx = SslContext::new(SslMethod::Sslv23).unwrap(); + let ctx = SslContext::new(SslMethod::Tls).unwrap(); ssl::Ssl::new(&ctx).unwrap() }; { - let new_ctx_a = SslContext::new(SslMethod::Sslv23).unwrap(); + let new_ctx_a = SslContext::new(SslMethod::Tls).unwrap(); let _new_ctx_b = ssl.set_ssl_context(&new_ctx_a); } } @@ -1067,7 +1071,7 @@ fn refcount_ssl_context() { #[test] #[cfg_attr(windows, ignore)] // don't have a trusted CA list easily available :( fn default_verify_paths() { - let mut ctx = SslContext::new(SslMethod::Sslv23).unwrap(); + let mut ctx = SslContext::new(SslMethod::Tls).unwrap(); ctx.set_default_verify_paths().unwrap(); ctx.set_verify(SSL_VERIFY_PEER); let s = TcpStream::connect("google.com:443").unwrap(); @@ -1086,6 +1090,6 @@ fn default_verify_paths() { fn add_extra_chain_cert() { let cert = include_bytes!("../../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); - let mut ctx = SslContext::new(SslMethod::Sslv23).unwrap(); + let mut ctx = SslContext::new(SslMethod::Tls).unwrap(); ctx.add_extra_chain_cert(&cert).unwrap(); } diff --git a/openssl/src/version.rs b/openssl/src/version.rs index 0e9f61d8..245305e8 100644 --- a/openssl/src/version.rs +++ b/openssl/src/version.rs @@ -11,9 +11,26 @@ // limitations under the License. // -use ffi; 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}; +#[cfg(ossl110)] +use ffi::{OPENSSL_BUILT_ON, OPENSSL_PLATFORM, OPENSSL_DIR}; +#[cfg(ossl110)] +use ffi::{OpenSSL_version_num, OpenSSL_version}; + /// OPENSSL_VERSION_NUMBER is a numeric release version identifier: /// /// `MNNFFPPS: major minor fix patch status` @@ -39,34 +56,34 @@ use std::ffi::CStr; /// /// The return value of this function can be compared to the macro to make sure that the correct version of the library has been loaded, especially when using DLLs on Windows systems. pub fn number() -> i64 { - unsafe { ffi::SSLeay() as i64 } + 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 { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_VERSION)).to_str().unwrap() } + unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_VERSION)).to_str().unwrap() } } /// The compiler flags set for the compilation process in the form "compiler: ..." if available or /// "compiler: information not available" otherwise. pub fn c_flags() -> &'static str { - unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_CFLAGS)).to_str().unwrap() } + unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_CFLAGS)).to_str().unwrap() } } /// The date of the build process in the form "built on: ..." if available or "built on: date not available" otherwise. pub fn built_on() -> &'static str { - unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_BUILT_ON)).to_str().unwrap() } + unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_BUILT_ON)).to_str().unwrap() } } /// The "Configure" target of the library build in the form "platform: ..." if available or "platform: information not available" otherwise. pub fn platform() -> &'static str { - unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_PLATFORM)).to_str().unwrap() } + unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_PLATFORM)).to_str().unwrap() } } /// The "OPENSSLDIR" setting of the library build in the form "OPENSSLDIR: "..."" if available or "OPENSSLDIR: N/A" otherwise. pub fn dir() -> &'static str { - unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_DIR)).to_str().unwrap() } + unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_DIR)).to_str().unwrap() } } /// This test ensures that we do not segfault when calling the functions of this module diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index f5369447..086342dd 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -12,7 +12,6 @@ use std::marker::PhantomData; use HashTypeInternals; use asn1::Asn1Time; -#[cfg(feature = "x509_expiry")] use asn1::Asn1TimeRef; use bio::{MemBio, MemBioSlice}; @@ -24,6 +23,19 @@ use ffi; use nid::Nid; use error::ErrorStack; +#[cfg(ossl10x)] +use ffi::{ + X509_set_notBefore, + X509_set_notAfter, + ASN1_STRING_data, +}; +#[cfg(ossl110)] +use ffi::{ + X509_set1_notBefore as X509_set_notBefore, + X509_set1_notAfter as X509_set_notAfter, + ASN1_STRING_get0_data as ASN1_STRING_data, +}; + pub mod extension; use self::extension::{ExtensionType, Extension}; @@ -36,7 +48,7 @@ pub struct SslString(&'static str); impl<'s> Drop for SslString { fn drop(&mut self) { unsafe { - ffi::CRYPTO_free(self.0.as_ptr() as *mut c_void); + CRYPTO_free!(self.0.as_ptr() as *mut c_void); } } } @@ -50,8 +62,8 @@ impl Deref for SslString { } impl SslString { - unsafe fn new(buf: *const c_char, len: c_int) -> SslString { - let slice = slice::from_raw_parts(buf as *const _, len as usize); + unsafe fn new(buf: *const u8, len: c_int) -> SslString { + let slice = slice::from_raw_parts(buf, len as usize); SslString(str::from_utf8_unchecked(slice)) } } @@ -311,11 +323,11 @@ impl X509Generator { let not_before = try!(Asn1Time::days_from_now(0)); let not_after = try!(Asn1Time::days_from_now(self.days)); - try_ssl!(ffi::X509_set_notBefore(x509.as_ptr(), not_before.as_ptr() as *const _)); + try_ssl!(X509_set_notBefore(x509.as_ptr(), not_before.as_ptr() as *const _)); // If prev line succeded - ownership should go to cert mem::forget(not_before); - try_ssl!(ffi::X509_set_notAfter(x509.as_ptr(), not_after.as_ptr() as *const _)); + try_ssl!(X509_set_notAfter(x509.as_ptr(), not_after.as_ptr() as *const _)); // If prev line succeded - ownership should go to cert mem::forget(not_after); @@ -350,9 +362,6 @@ impl X509Generator { } /// Obtain a certificate signing request (CSR) - /// - /// Requries the `x509_generator_request` feature. - #[cfg(feature = "x509_generator_request")] pub fn request(&self, p_key: &PKey) -> Result { let cert = match self.sign(p_key) { Ok(c) => c, @@ -363,9 +372,9 @@ impl X509Generator { let req = ffi::X509_to_X509_REQ(cert.as_ptr(), ptr::null_mut(), ptr::null()); try_ssl_null!(req); - let exts = ::c_helpers::rust_0_8_X509_get_extensions(cert.as_ptr()); + let exts = compat::X509_get0_extensions(cert.as_ptr()); if exts != ptr::null_mut() { - try_ssl!(ffi::X509_REQ_add_extensions(req, exts)); + try_ssl!(ffi::X509_REQ_add_extensions(req, exts as *mut _)); } let hash_fn = self.hash_type.evp_md(); @@ -438,22 +447,18 @@ impl<'a> X509Ref<'a> { } /// Returns certificate Not After validity period. - /// Requires the `x509_expiry` feature. - #[cfg(feature = "x509_expiry")] pub fn not_after<'b>(&'b self) -> Asn1TimeRef<'b> { unsafe { - let date = ::c_helpers::rust_0_8_X509_get_notAfter(self.0); + let date = compat::X509_get_notAfter(self.0); assert!(!date.is_null()); Asn1TimeRef::from_ptr(date) } } /// Returns certificate Not Before validity period. - /// Requires the `x509_expiry` feature. - #[cfg(feature = "x509_expiry")] pub fn not_before<'b>(&'b self) -> Asn1TimeRef<'b> { unsafe { - let date = ::c_helpers::rust_0_8_X509_get_notBefore(self.0); + let date = compat::X509_get_notBefore(self.0); assert!(!date.is_null()); Asn1TimeRef::from_ptr(date) } @@ -496,7 +501,7 @@ impl X509 { /// Reads a certificate from DER. pub fn from_der(buf: &[u8]) -> Result { unsafe { - let mut ptr = buf.as_ptr() as *mut _; + let mut ptr = buf.as_ptr(); let len = cmp::min(buf.len(), c_long::max_value() as usize) as c_long; let x509 = try_ssl_null!(ffi::d2i_X509(ptr::null_mut(), &mut ptr, len)); Ok(X509::from_ptr(x509)) @@ -524,13 +529,11 @@ impl Deref for X509 { } } -#[cfg(feature = "x509_clone")] impl Clone for X509 { - /// Requires the `x509_clone` feature. fn clone(&self) -> X509 { unsafe { - ::c_helpers::rust_0_8_X509_clone(self.as_ptr()); - X509::new(self.as_ptr()) + compat::X509_up_ref(self.as_ptr()); + X509::from_ptr(self.as_ptr()) } } } @@ -561,7 +564,7 @@ impl<'x> X509Name<'x> { return None; } - let mut str_from_asn1: *mut c_char = ptr::null_mut(); + let mut str_from_asn1: *mut u8 = ptr::null_mut(); let len = ffi::ASN1_STRING_to_UTF8(&mut str_from_asn1, asn1_str); if len < 0 { @@ -779,22 +782,43 @@ pub struct GeneralNames<'a> { } impl<'a> Drop for GeneralNames<'a> { + #[cfg(ossl10x)] fn drop(&mut self) { unsafe { // This transmute is dubious but it's what openssl itself does... - let free: unsafe extern "C" fn(*mut ffi::GENERAL_NAME) = ffi::GENERAL_NAME_free; - let free: unsafe extern "C" fn(*mut c_void) = mem::transmute(free); + let free: unsafe extern fn(*mut ffi::GENERAL_NAME) = ffi::GENERAL_NAME_free; + let free: unsafe extern fn(*mut c_void) = mem::transmute(free); ffi::sk_pop_free(&mut (*self.stack).stack, Some(free)); } } + + #[cfg(ossl110)] + fn drop(&mut self) { + unsafe { + // This transmute is dubious but it's what openssl itself does... + let free: unsafe extern fn(*mut ffi::GENERAL_NAME) = ffi::GENERAL_NAME_free; + let free: unsafe extern fn(*mut c_void) = mem::transmute(free); + ffi::OPENSSL_sk_pop_free(self.stack as *mut _, Some(free)); + } + } } impl<'a> GeneralNames<'a> { /// Returns the number of `GeneralName`s in this structure. pub fn len(&self) -> usize { + self._len() + } + + #[cfg(ossl10x)] + fn _len(&self) -> usize { unsafe { (*self.stack).stack.num as usize } } + #[cfg(ossl110)] + fn _len(&self) -> usize { + unsafe { ffi::OPENSSL_sk_num(self.stack as *const _) as usize } + } + /// Returns the specified `GeneralName`. /// /// # Panics @@ -803,14 +827,23 @@ impl<'a> GeneralNames<'a> { pub fn get(&self, idx: usize) -> GeneralName<'a> { unsafe { assert!(idx < self.len()); - GeneralName { - name: *(*self.stack).stack.data.offset(idx as isize) as *const ffi::GENERAL_NAME, + name: self._get(idx), m: PhantomData, } } } + #[cfg(ossl10x)] + unsafe fn _get(&self, idx: usize) -> *const ffi::GENERAL_NAME { + *(*self.stack).stack.data.offset(idx as isize) as *const ffi::GENERAL_NAME + } + + #[cfg(ossl110)] + unsafe fn _get(&self, idx: usize) -> *const ffi::GENERAL_NAME { + ffi::OPENSSL_sk_value(self.stack as *const _, idx as c_int) as *mut _ + } + /// Returns an iterator over the `GeneralName`s in this structure. pub fn iter(&self) -> GeneralNamesIter { GeneralNamesIter { @@ -870,7 +903,7 @@ impl<'a> GeneralName<'a> { return None; } - let ptr = ffi::ASN1_STRING_data((*self.name).d as *mut _); + let ptr = ASN1_STRING_data((*self.name).d as *mut _); let len = ffi::ASN1_STRING_length((*self.name).d as *mut _); let slice = slice::from_raw_parts(ptr as *const u8, len as usize); @@ -888,7 +921,7 @@ impl<'a> GeneralName<'a> { return None; } - let ptr = ffi::ASN1_STRING_data((*self.name).d as *mut _); + let ptr = ASN1_STRING_data((*self.name).d as *mut _); let len = ffi::ASN1_STRING_length((*self.name).d as *mut _); Some(slice::from_raw_parts(ptr as *const u8, len as usize)) @@ -904,3 +937,44 @@ fn test_negative_serial() { "All serials should be positive"); } } + +#[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_get0_extensions; +} + +#[cfg(ossl10x)] +#[allow(bad_style)] +mod compat { + use libc::c_int; + 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_get0_extensions(cert: *const ffi::X509) + -> *const ffi::stack_st_X509_EXTENSION { + let info = (*cert).cert_info; + if info.is_null() { + 0 as *mut _ + } else { + (*info).extensions + } + } +} diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index eac08941..07d9e1d4 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -69,7 +69,6 @@ fn test_cert_gen_extension_bad_ordering() { } #[test] -#[cfg(feature = "x509_generator_request")] fn test_req_gen() { let pkey = pkey(); @@ -93,7 +92,6 @@ fn test_cert_loading() { } #[test] -#[cfg(feature = "x509_expiry")] fn test_cert_issue_validity() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); diff --git a/openssl/test/build.sh b/openssl/test/build.sh index 2c38f3a3..106a38d3 100755 --- a/openssl/test/build.sh +++ b/openssl/test/build.sh @@ -1,33 +1,48 @@ #!/bin/bash -set -e + +set -ex MAX_REDIRECTS=5 -OPENSSL=openssl-1.0.2h.tar.gz +OPENSSL=openssl-$BUILD_OPENSSL_VERSION.tar.gz OUT=/tmp/$OPENSSL -SHA1="577585f5f5d299c44dd3c993d3c0ac7a219e4949" + +me=$0 +myname=`basename $me` + +cmp --silent $me $HOME/openssl/$myname && exit 0 || echo "cache is busted" + +rm -rf $HOME/openssl if [ "$TRAVIS_OS_NAME" == "osx" ]; then exit 0 fi -if [ "$TARGET" == "arm-unknown-linux-gnueabihf" ]; then - export C_INCLUDE_PATH=/usr/arm-linux-gnueabihf/include - CROSS=arm-linux-gnueabihf- +if [ "$BUILD_OPENSSL_VERSION" == "" ]; then + exit 0 +fi + +if [ "$TARGET" == "i686-unknown-linux-gnu" ]; then + OS_COMPILER=linux-elf + OS_FLAGS=-m32 +elif [ "$TARGET" == "arm-unknown-linux-gnueabihf" ]; then OS_COMPILER=linux-armv4 + export AR=arm-linux-gnueabihf-ar + export CC=arm-linux-gnueabihf-gcc else OS_COMPILER=linux-x86_64 fi mkdir -p /tmp/openssl +cp $me /tmp/openssl/$myname cd /tmp/openssl curl -o $OUT -L --max-redirs $MAX_REDIRECTS https://openssl.org/source/$OPENSSL \ || curl -o $OUT -L --max-redirs ${MAX_REDIRECTS} http://mirrors.ibiblio.org/openssl/source/$OPENSSL -echo "$SHA1 $OUT" | sha1sum -c - - tar --strip-components=1 -xzf $OUT -./Configure --prefix=$HOME/openssl shared --cross-compile-prefix=$CROSS $OS_COMPILER -make +./Configure --prefix=$HOME/openssl $OS_COMPILER -fPIC $OS_FLAGS + +make -j$(nproc) make install +cp $myname $HOME/openssl/$myname diff --git a/openssl/test/run.sh b/openssl/test/run.sh index 2c2473b1..eed7ebac 100755 --- a/openssl/test/run.sh +++ b/openssl/test/run.sh @@ -1,32 +1,15 @@ #!/bin/bash set -e -MAIN_TARGETS=https://static.rust-lang.org/dist - -if [ "$TEST_FEATURES" == "true" ]; then - FEATURES="tlsv1_2 tlsv1_1 dtlsv1 dtlsv1_2 sslv3 aes_xts aes_ctr npn alpn rfc5114 ecdh_auto pkcs5_pbkdf2_hmac x509_clone ssl_context_clone x509_generator_request hmac hmac_clone dh_from_params x509_expiry" +if [ "$BUILD_OPENSSL_VERSION" != "" ]; then + FEATURES="aes_xts aes_ctr npn alpn rfc5114 ecdh_auto" fi -if [ "$TRAVIS_OS_NAME" != "osx" ]; then - export OPENSSL_LIB_DIR=$HOME/openssl/lib - export OPENSSL_INCLUDE_DIR=$HOME/openssl/include - export LD_LIBRARY_PATH=$HOME/openssl/lib:$LD_LIBRARY_PATH +if [ -d "$HOME/openssl/lib" ]; then + export OPENSSL_DIR=$HOME/openssl + export PATH=$HOME/openssl/bin:$PATH fi -if [ -n "$TARGET" ]; then - FLAGS="--target=$TARGET" - COMMAND="build" - - # Download the rustlib folder from the relevant portion of main distribution's - # tarballs. - dir=rust-std-$TARGET - pkg=rust-std - curl -s $MAIN_TARGETS/$pkg-$TRAVIS_RUST_VERSION-$TARGET.tar.gz | \ - tar xzf - -C $HOME/rust/lib/rustlib --strip-components=4 \ - $pkg-$TRAVIS_RUST_VERSION-$TARGET/$dir/lib/rustlib/$TARGET -else - COMMAND="test" -fi - -export PATH=$HOME/openssl/bin:$PATH -(cd openssl && RUST_BACKTRACE=1 cargo $COMMAND $FLAGS --features "$FEATURES") +cargo run --manifest-path systest/Cargo.toml --target $TARGET +exec cargo test --manifest-path openssl/Cargo.toml --target $TARGET \ + --features "$FEATURES" diff --git a/systest/Cargo.toml b/systest/Cargo.toml new file mode 100644 index 00000000..3997bf35 --- /dev/null +++ b/systest/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "systest" +version = "0.1.0" +authors = ["Alex Crichton "] +build = "build.rs" + +[dependencies] +libc = "0.2" +openssl-sys = { path = "../openssl-sys" } + +[build-dependencies] +ctest = "0.1" diff --git a/systest/build.rs b/systest/build.rs new file mode 100644 index 00000000..b2820e5b --- /dev/null +++ b/systest/build.rs @@ -0,0 +1,110 @@ +extern crate ctest; + +use std::env; + +fn main() { + let mut cfg = ctest::TestGenerator::new(); + let target = env::var("TARGET").unwrap(); + + if let Ok(out) = env::var("DEP_OPENSSL_INCLUDE") { + cfg.include(&out); + } + + // Needed to get OpenSSL to correctly undef symbols that are already on + // Windows like X509_NAME + if target.contains("windows") { + cfg.header("windows.h"); + + // weird "different 'const' qualifiers" error on Windows, maybe a cl.exe + // thing? + if target.contains("msvc") { + cfg.flag("/wd4090"); + } + } + + if env::var("DEP_OPENSSL_IS_101").is_ok() { + cfg.cfg("ossl101", None); + } + if env::var("DEP_OPENSSL_IS_102").is_ok() { + cfg.cfg("ossl102", None); + } + if env::var("DEP_OPENSSL_IS_110").is_ok() { + cfg.cfg("ossl110", None); + } + + cfg.header("openssl/comp.h") + .header("openssl/dh.h") + .header("openssl/ossl_typ.h") + .header("openssl/stack.h") + .header("openssl/x509.h") + .header("openssl/bio.h") + .header("openssl/x509v3.h") + .header("openssl/safestack.h") + .header("openssl/hmac.h") + .header("openssl/ssl.h") + .header("openssl/err.h") + .header("openssl/rand.h") + .header("openssl/pkcs12.h") + .header("openssl/bn.h"); + cfg.type_name(|s, is_struct| { + // Add some `*` on some callback parameters to get function pointer to + // typecheck in C, especially on MSVC. + if s == "PasswordCallback" { + format!("pem_password_cb*") + } else if s == "bio_info_cb" { + format!("bio_info_cb*") + } else if s == "_STACK" { + format!("struct stack_st") + } else if is_struct && s.chars().next().unwrap().is_lowercase() { + format!("struct {}", s) + } else { + format!("{}", s) + } + }); + cfg.skip_type(|s| { + // function pointers are declared without a `*` in openssl so their + // sizeof is 1 which isn't what we want. + s == "PasswordCallback" || + s == "bio_info_cb" || + s.starts_with("CRYPTO_EX_") + }); + cfg.skip_struct(|s| { + s == "ProbeResult" + }); + cfg.skip_fn(move |s| { + s == "CRYPTO_memcmp" || // uses volatile + s == "X509V3_EXT_conf_nid" || // weird lhash first param + s == "X509V3_EXT_conf" || // weird lhash first param + + // one parameter is `const` in OpenSSL 1.0.1, no need for a new + // definition or a new file here. + (s == "BIO_new_mem_buf" && env::var("DEP_OPENSSL_IS_101").is_ok()) || + + // Skip some functions with function pointers on windows, not entirely + // sure how to get them to work out... + (target.contains("windows") && { + s == "SSL_get_ex_new_index" || + s == "SSL_CTX_get_ex_new_index" || + s == "CRYPTO_get_ex_new_index" + }) + }); + cfg.skip_field_type(|s, field| { + (s == "EVP_PKEY" && field == "pkey") || // union + (s == "GENERAL_NAME" && field == "d") // union + }); + cfg.skip_signededness(|s| { + s.ends_with("_cb") || + s.starts_with("CRYPTO_") || + s == "PasswordCallback" + }); + cfg.field_name(|_s, field| { + if field == "type_" { + format!("type") + } else { + format!("{}", field) + } + }); + cfg.fn_cname(|rust, link_name| link_name.unwrap_or(rust).to_string()); + cfg.generate("../openssl-sys/src/lib.rs", "all.rs"); +} + diff --git a/systest/src/main.rs b/systest/src/main.rs new file mode 100644 index 00000000..39d31b2f --- /dev/null +++ b/systest/src/main.rs @@ -0,0 +1,9 @@ +#![allow(bad_style)] + +extern crate openssl_sys; +extern crate libc; + +use libc::*; +use openssl_sys::*; + +include!(concat!(env!("OUT_DIR"), "/all.rs"));