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
This commit is contained in:
Alex Crichton 2016-09-30 00:43:05 -07:00
parent c1e41349fb
commit 43c951f743
38 changed files with 2513 additions and 1443 deletions

View File

@ -1,28 +1,86 @@
language: rust language: rust
sudo: false sudo: required
addons: rust: stable
apt: dist: trusty
packages:
- gcc-arm-linux-gnueabihf
rust:
- nightly
- 1.9.0
os:
- osx
- linux
env: env:
matrix: global:
- TEST_FEATURES=false - TARGET=x86_64-unknown-linux-gnu
- TEST_FEATURES=true
matrix: matrix:
# include: include:
# - os: linux # ARM-bit version compat
# env: TARGET=arm-unknown-linux-gnueabihf TEST_FEATURES=true - env: >
# rust: 1.7.0 TARGET=arm-unknown-linux-gnueabihf
exclude: BUILD_OPENSSL_VERSION=1.0.2h
- os: osx CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc
env: TEST_FEATURES=true 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: 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: script:
- ./openssl/test/run.sh - ./openssl/test/run.sh
cache:
cargo: true
directories:
- $HOME/openssl

View File

@ -1,2 +1,2 @@
[workspace] [workspace]
members = ["openssl", "openssl-sys"] members = ["openssl", "openssl-sys", "systest"]

114
README.md
View File

@ -6,13 +6,16 @@
## Building ## 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 ### Linux
On Linux, you can install OpenSSL via your package manager. The headers are On Linux, you can typically install OpenSSL via your package manager. The
sometimes provided in a separate package than the runtime libraries - look for headers are sometimes provided in a separate package than the runtime libraries
something like `openssl-devel` or `libssl-dev`. - look for something like `openssl-devel` or `libssl-dev`.
```bash ```bash
# On Ubuntu # On Ubuntu
@ -23,79 +26,78 @@ sudo pacman -S openssl
sudo dnf install openssl-devel 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 ### OSX
OpenSSL 0.9.8 is preinstalled on OSX. Some features are only available when Although OpenSSL 0.9.8 is preinstalled on OSX this library is being phased out
linking against OpenSSL 1.0.0 or greater; see below on how to point of OSX and this crate also does not support this version of OpenSSL. To use this
rust-openssl to a separate installation. OSX releases starting at 10.11, "El crate on OSX you'll need to install OpenSSL via some alternate means, typically
Capitan", no longer include OpenSSL headers which will prevent the `openssl` homebrew:
crate from compiling.
For OSX 10.11 you can use brew to install OpenSSL and then set the environment variables
as described below.
```bash ```bash
brew install openssl 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/). [precompiled binaries]: http://slproweb.com/products/Win32OpenSSL.html
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.
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 set OPENSSL_DIR=C:\OpenSSL-Win64
pacman -S mingw-w64-i686-gcc
``` ```
64-bit After that, you're just a `cargo build` away!
```bash
pacman -S mingw-w64-x86_64-gcc ### 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
``` ```
and then install the mingw-w64 toolchain. And after that, a `cargo build` should be all you need!
32-bit:
```bash
pacman -S mingw-w64-i686-toolchain
```
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
```
### Manual configuration ### Manual configuration
rust-openssl's build script will by default attempt to locate OpenSSL via 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 pkg-config or other system-specific mechanisms. This will not work in some
don't have pkg-config, when cross compiling, or when using a copy of OpenSSL situations however, for example cross compiling or when using a copy of OpenSSL
other than the normal system install. other than the normal system install.
The build script can be configured via environment variables: 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_DIR` - If specified, a directory that will be used to find
* `OPENSSL_INCLUDE_DIR` - If specified, a directory that will be used to find OpenSSL installation. It's expected that under this directory the `include`
OpenSSL headers. folder has header files and a `lib` folder has the runtime libraries.
* `OPENSSL_STATIC` - If specified, OpenSSL libraries will be statically rather * `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 If `OPENSSL_DIR` is specified, then the build script will skip the pkg-config
build script will skip the pkg-config step. step.
[1]: http://slproweb.com/products/Win32OpenSSL.html

View File

@ -1,25 +1,43 @@
environment: environment:
OPENSSL_INCLUDE_DIR: C:\OpenSSL\include
OPENSSL_LIB_DIR: C:\OpenSSL\lib
OPENSSL_LIBS: ssleay32:libeay32
matrix: matrix:
- TARGET: i686-pc-windows-gnu # 1.1.0, 64/32 bit
BITS: 32 - TARGET: i686-pc-windows-gnu
- TARGET: x86_64-pc-windows-msvc BITS: 32
BITS: 64 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: install:
- ps: Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-1_0_2h.exe" # install OpenSSL
- Win%BITS%OpenSSL-1_0_2h.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL" - ps: Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-${env:OPENSSL_VERSION}.exe"
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.9.0-${env:TARGET}.exe" - Win%BITS%OpenSSL-%OPENSSL_VERSION%.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL"
- rust-1.9.0-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin # Install Rust
- SET PATH=%PATH%;C:\MinGW\bin - 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 - rustc -V
- cargo -V - cargo -V
build: false build: false
# Don't run doctests due to rust-lang/cargo#1592
test_script: 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

View File

@ -10,38 +10,12 @@ documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.17/openssl_sys
links = "openssl" links = "openssl"
build = "build.rs" 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] [dependencies]
libc = "0.2" libc = "0.2"
[build-dependencies] [build-dependencies]
pkg-config = "0.3" 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] [target.'cfg(windows)'.dependencies]
user32-sys = "0.2" user32-sys = "0.2"
gdi32-sys = "0.2" gdi32-sys = "0.2"

View File

@ -1,86 +1,344 @@
extern crate pkg_config; extern crate pkg_config;
use std::collections::HashSet;
use std::env; use std::env;
use std::ffi::OsString;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
fn main() { fn main() {
let target = env::var("TARGET").unwrap(); let target = env::var("TARGET").unwrap();
// libressl_pnacl_sys links the libs needed. let openssl_dir = env::var_os("OPENSSL_DIR").unwrap_or_else(|| {
if target.ends_with("nacl") { return; } find_openssl_dir(&target)
});
let lib_dir = env::var("OPENSSL_LIB_DIR").ok(); let lib_dir = Path::new(&openssl_dir).join("lib");
let include_dir = env::var("OPENSSL_INCLUDE_DIR").ok(); let include_dir = Path::new(&openssl_dir).join("include");
if !Path::new(&lib_dir).exists() {
if lib_dir.is_none() && include_dir.is_none() { panic!("OpenSSL library directory does not exist: {}",
// rustc doesn't seem to work with pkg-config's output in mingw64 lib_dir.to_string_lossy());
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 libs_env = env::var("OPENSSL_LIBS").ok(); if !Path::new(&include_dir).exists() {
let libs = match libs_env { panic!("OpenSSL include directory does not exist: {}",
Some(ref v) => v.split(":").collect(), include_dir.to_string_lossy());
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"]
}
};
let mode = if env::var_os("OPENSSL_STATIC").is_some() { println!("cargo:rustc-link-search=native={}", lib_dir.to_string_lossy());
"static" 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 { } else {
"dylib" ["ssl", "crypto"]
}; };
if let Some(lib_dir) = lib_dir { let kind = determine_mode(Path::new(&lib_dir), &libs);
println!("cargo:rustc-link-search=native={}", lib_dir); for lib in libs.iter() {
} println!("cargo:rustc-link-lib={}={}", kind, lib);
for lib in libs {
println!("cargo:rustc-link-lib={}={}", mode, lib);
}
if let Some(include_dir) = include_dir {
println!("cargo:include={}", include_dir);
} }
} }
fn get_mingw_in_path() -> Option<Vec<String>> { fn find_openssl_dir(target: &str) -> OsString {
match env::var_os("PATH") { let host = env::var("HOST").unwrap();
Some(env_path) => {
let paths: Vec<String> = env::split_paths(&env_path).filter_map(|path| {
use std::ascii::AsciiExt;
match path.to_str() { if host.contains("apple-darwin") && target.contains("apple-darwin") {
Some(path_str) => { let homebrew = Path::new("/usr/local/opt/openssl");
if path_str.to_ascii_lowercase().contains("mingw") { if homebrew.exists() {
Some(path_str.to_string()) return homebrew.to_path_buf().into()
} else { None } }
}, let homebrew = Path::new("/usr/local/opt/openssl@1.1");
None => None 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::<PathBuf>()
}).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 } // Look for `#define OPENSSL_FOO`, print out everything as our own
}, // #[cfg] flag.
None => None 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::<HashSet<_>>();
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"
} }

File diff suppressed because it is too large Load Diff

569
openssl-sys/src/ossl10x.rs Normal file
View File

@ -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<unsafe extern fn(*const c_void, *const c_void) -> c_int>,
}
#[repr(C)]
pub struct BIO_METHOD {
pub type_: c_int,
pub name: *const c_char,
pub bwrite: Option<unsafe extern fn(*mut ::BIO, *const c_char, c_int) -> c_int>,
pub bread: Option<unsafe extern fn(*mut ::BIO, *mut c_char, c_int) -> c_int>,
pub bputs: Option<unsafe extern fn(*mut ::BIO, *const c_char) -> c_int>,
pub bgets: Option<unsafe extern fn(*mut ::BIO, *mut c_char, c_int) -> c_int>,
pub ctrl: Option<unsafe extern fn(*mut ::BIO, c_int, c_long, *mut c_void) -> c_long>,
pub create: Option<unsafe extern fn(*mut ::BIO) -> c_int>,
pub destroy: Option<unsafe extern fn(*mut ::BIO) -> c_int>,
pub callback_ctrl: Option<unsafe extern fn(*mut ::BIO, c_int, ::bio_info_cb) -> 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<unsafe extern fn(*mut ::BIO,
c_int,
*const c_char,
c_int,
c_long,
c_long)
-> 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<unsafe extern fn(*mut ::EVP_CIPHER_CTX,
*const c_uchar,
*const c_uchar,
c_int) -> c_int>,
pub do_cipher: Option<unsafe extern fn(*mut ::EVP_CIPHER_CTX,
*mut c_uchar,
*const c_uchar,
size_t) -> c_int>,
pub cleanup: Option<unsafe extern fn(*mut ::EVP_CIPHER_CTX) -> c_int>,
pub ctx_size: c_int,
pub set_asn1_parameters: Option<unsafe extern fn(*mut ::EVP_CIPHER_CTX,
*mut ::ASN1_TYPE) -> c_int>,
pub get_asn1_parameters: Option<unsafe extern fn(*mut ::EVP_CIPHER_CTX,
*mut ::ASN1_TYPE) -> c_int>,
pub ctrl: Option<unsafe extern fn(*mut ::EVP_CIPHER_CTX,
c_int,
c_int,
*mut c_void) -> 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<Mutex<()>> = 0 as *mut Vec<Mutex<()>>;
static mut GUARDS: *mut Vec<Option<MutexGuard<'static, ()>>> = 0 as *mut Vec<Option<MutexGuard<'static, ()>>>;
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<Vec<Option<MutexGuard<()>>>> =
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<extern fn(c_int, c_int, *mut c_void)>,
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<unsafe extern "C" fn (*mut c_void)>);
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;
}

146
openssl-sys/src/ossl110.rs Normal file
View File

@ -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<unsafe extern "C" fn (*mut c_void)>);
pub fn OPENSSL_sk_pop(st: *mut _STACK) -> *mut c_void;
}

View File

@ -1,77 +0,0 @@
use std::env;
use std::fs;
use std::path::PathBuf;
pub struct ProbeResult {
pub cert_file: Option<PathBuf>,
pub cert_dir: Option<PathBuf>,
}
/// 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<PathBuf> {
// 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<PathBuf>, val: PathBuf) {
if dst.is_none() && fs::metadata(&val).is_ok() {
*dst = Some(val);
}
}

View File

@ -12,28 +12,23 @@ build = "build.rs"
exclude = ["test/*"] exclude = ["test/*"]
[features] [features]
tlsv1_2 = ["openssl-sys/tlsv1_2"] aes_xts = []
tlsv1_1 = ["openssl-sys/tlsv1_1"] aes_ctr = []
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"]
c_helpers = ["gcc"] # Added in OpenSSL 1.0.2
x509_clone = ["c_helpers"] rfc5114 = []
x509_generator_request = ["c_helpers"]
x509_expiry = ["c_helpers"] # TODO: what to do about these features?
ssl_context_clone = ["c_helpers"] # tlsv1_2 = []
hmac = ["c_helpers"] # tlsv1_1 = []
dh_from_params = ["c_helpers"] # dtlsv1 = []
# dtlsv1_2 = []
# sslv2 = []
# sslv3 = []
npn = []
alpn = []
ecdh_auto = []
[dependencies] [dependencies]
bitflags = "0.7" bitflags = "0.7"
@ -41,11 +36,9 @@ lazy_static = "0.2"
libc = "0.2" libc = "0.2"
openssl-sys = { version = "0.7.17", path = "../openssl-sys" } openssl-sys = { version = "0.7.17", path = "../openssl-sys" }
[build-dependencies]
gcc = { version = "0.3", optional = true }
[dev-dependencies] [dev-dependencies]
rustc-serialize = "0.3"
net2 = "0.2.16" net2 = "0.2.16"
rustc-serialize = "0.3"
tempdir = "0.3"
winapi = "0.2" winapi = "0.2"
ws2_32-sys = "0.2" ws2_32-sys = "0.2"

View File

@ -1,28 +1,15 @@
#[cfg(feature = "c_helpers")] use std::env;
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() {}
}
fn main() { 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");
}
} }

View File

@ -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::ffi::{CStr, CString};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::{fmt, ptr}; 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`. /// Add a `u32` to `self`. This is more efficient than adding a
pub fn add_word(&mut self, w: c_ulong) -> Result<(), ErrorStack> { /// `BigNum`.
pub fn add_word(&mut self, w: u32) -> Result<(), ErrorStack> {
unsafe { 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(()) Ok(())
} else { } else {
Err(ErrorStack::get()) 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 { 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(()) Ok(())
} else { } else {
Err(ErrorStack::get()) 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 { 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(()) Ok(())
} else { } else {
Err(ErrorStack::get()) Err(ErrorStack::get())
@ -216,22 +217,22 @@ impl<'a> BigNumRef<'a> {
} }
} }
pub fn div_word(&mut self, w: c_ulong) -> Result<c_ulong, ErrorStack> { pub fn div_word(&mut self, w: u32) -> Result<u64, ErrorStack> {
unsafe { unsafe {
let result = ffi::BN_div_word(self.as_ptr(), w); let result = ffi::BN_div_word(self.as_ptr(), w as ffi::BN_ULONG);
if result != !0 as c_ulong { if result != !0 {
Ok(result) Ok(result.into())
} else { } else {
Err(ErrorStack::get()) Err(ErrorStack::get())
} }
} }
} }
pub fn mod_word(&self, w: c_ulong) -> Result<c_ulong, ErrorStack> { pub fn mod_word(&self, w: u32) -> Result<u64, ErrorStack> {
unsafe { unsafe {
let result = ffi::BN_mod_word(self.as_ptr(), w); let result = ffi::BN_mod_word(self.as_ptr(), w as ffi::BN_ULONG);
if result != !0 as c_ulong { if result != !0 {
Ok(result) Ok(result as u64)
} else { } else {
Err(ErrorStack::get()) Err(ErrorStack::get())
} }
@ -257,7 +258,10 @@ impl<'a> BigNumRef<'a> {
pub fn is_prime(&self, checks: i32) -> Result<bool, ErrorStack> { pub fn is_prime(&self, checks: i32) -> Result<bool, ErrorStack> {
unsafe { unsafe {
with_ctx!(ctx, { 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, checks as c_int,
ctx, ctx,
do_trial_division as c_int, 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 { pub fn is_negative(&self) -> bool {
self._is_negative()
}
#[cfg(ossl10x)]
fn _is_negative(&self) -> bool {
unsafe { (*self.as_ptr()).neg == 1 } 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`. /// Returns the number of significant bits in `self`.
pub fn num_bits(&self) -> i32 { pub fn num_bits(&self) -> i32 {
unsafe { ffi::BN_num_bits(self.as_ptr()) as i32 } unsafe { ffi::BN_num_bits(self.as_ptr()) as i32 }
@ -536,7 +550,7 @@ impl<'a> BigNumRef<'a> {
assert!(!buf.is_null()); assert!(!buf.is_null());
let str = String::from_utf8(CStr::from_ptr(buf as *const _).to_bytes().to_vec()) let str = String::from_utf8(CStr::from_ptr(buf as *const _).to_bytes().to_vec())
.unwrap(); .unwrap();
ffi::CRYPTO_free(buf as *mut c_void); CRYPTO_free!(buf as *mut c_void);
str str
} }
} }
@ -555,7 +569,7 @@ impl<'a> BigNumRef<'a> {
assert!(!buf.is_null()); assert!(!buf.is_null());
let str = String::from_utf8(CStr::from_ptr(buf as *const _).to_bytes().to_vec()) let str = String::from_utf8(CStr::from_ptr(buf as *const _).to_bytes().to_vec())
.unwrap(); .unwrap();
ffi::CRYPTO_free(buf as *mut c_void); CRYPTO_free!(buf as *mut c_void);
str str
} }
} }
@ -580,27 +594,27 @@ impl BigNum {
} }
/// Creates a new `BigNum` with the given value. /// Creates a new `BigNum` with the given value.
pub fn new_from(n: c_ulong) -> Result<BigNum, ErrorStack> { pub fn new_from(n: u32) -> Result<BigNum, ErrorStack> {
BigNum::new().and_then(|v| unsafe { 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) Ok(v)
}) })
} }
/// Creates a `BigNum` from a decimal string. /// Creates a `BigNum` from a decimal string.
pub fn from_dec_str(s: &str) -> Result<BigNum, ErrorStack> { pub fn from_dec_str(s: &str) -> Result<BigNum, ErrorStack> {
BigNum::new().and_then(|v| unsafe { BigNum::new().and_then(|mut v| unsafe {
let c_str = CString::new(s.as_bytes()).unwrap(); 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) Ok(v)
}) })
} }
/// Creates a `BigNum` from a hexadecimal string. /// Creates a `BigNum` from a hexadecimal string.
pub fn from_hex_str(s: &str) -> Result<BigNum, ErrorStack> { pub fn from_hex_str(s: &str) -> Result<BigNum, ErrorStack> {
BigNum::new().and_then(|v| unsafe { BigNum::new().and_then(|mut v| unsafe {
let c_str = CString::new(s.as_bytes()).unwrap(); 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) Ok(v)
}) })
} }
@ -646,7 +660,7 @@ impl BigNum {
safe as c_int, safe as c_int,
add_arg, add_arg,
rem_arg, rem_arg,
ptr::null()) == 1 ptr::null_mut()) == 1
}) })
} }
} }

View File

@ -1,67 +0,0 @@
#include <openssl/hmac.h>
#include <openssl/ssl.h>
#include <openssl/dh.h>
#include <openssl/bn.h>
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

View File

@ -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;
}

View File

@ -19,8 +19,13 @@ impl DSAParams {
unsafe { unsafe {
// Wrap it so that if we panic we'll call the dtor // Wrap it so that if we panic we'll call the dtor
let dsa = DSAParams(try_ssl_null!(ffi::DSA_new())); 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, try_ssl!(ffi::DSA_generate_parameters_ex(dsa.0,
ptr::null_mut(), ptr::null_mut(), ptr::null())); size as c_int,
ptr::null(),
0,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut()));
Ok(dsa) Ok(dsa)
} }
} }
@ -190,43 +195,74 @@ impl DSA {
pub fn p<'a>(&'a self) -> Option<BigNumRef<'a>> { pub fn p<'a>(&'a self) -> Option<BigNumRef<'a>> {
unsafe { unsafe {
let p = (*self.0).p; let p = compat::pqg(self.0)[0];
if p.is_null() { if p.is_null() {
None None
} else { } else {
Some(BigNumRef::from_ptr((*self.0).p)) Some(BigNumRef::from_ptr(p as *mut _))
} }
} }
} }
pub fn q<'a>(&'a self) -> Option<BigNumRef<'a>> { pub fn q<'a>(&'a self) -> Option<BigNumRef<'a>> {
unsafe { unsafe {
let q = (*self.0).q; let q = compat::pqg(self.0)[1];
if q.is_null() { if q.is_null() {
None None
} else { } else {
Some(BigNumRef::from_ptr((*self.0).q)) Some(BigNumRef::from_ptr(q as *mut _))
} }
} }
} }
pub fn g<'a>(&'a self) -> Option<BigNumRef<'a>> { pub fn g<'a>(&'a self) -> Option<BigNumRef<'a>> {
unsafe { unsafe {
let g = (*self.0).g; let g = compat::pqg(self.0)[2];
if g.is_null() { if g.is_null() {
None None
} else { } else {
Some(BigNumRef::from_ptr((*self.0).g)) Some(BigNumRef::from_ptr(g as *mut _))
} }
} }
} }
pub fn has_public_key(&self) -> bool { 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 { 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]
} }
} }

View File

@ -1,8 +1,6 @@
use libc::c_uint;
use std::io::prelude::*; use std::io::prelude::*;
use std::io; use std::io;
use std::ptr; use std::ptr;
use std::cmp;
use ffi; use ffi;
use HashTypeInternals; use HashTypeInternals;
@ -102,7 +100,7 @@ impl Hasher {
pub fn new(ty: Type) -> Result<Hasher, ErrorStack> { pub fn new(ty: Type) -> Result<Hasher, ErrorStack> {
ffi::init(); 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 md = ty.evp_md();
let mut h = Hasher { let mut h = Hasher {
@ -123,22 +121,20 @@ impl Hasher {
} }
Finalized => (), 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; self.state = Reset;
Ok(()) Ok(())
} }
/// Feeds data into the hasher. /// 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 { if self.state == Finalized {
try!(self.init()); try!(self.init());
} }
while !data.is_empty() { unsafe {
let len = cmp::min(data.len(), c_uint::max_value() as usize); try_ssl!(ffi::EVP_DigestUpdate(self.ctx,
unsafe { data.as_ptr() as *mut _,
try_ssl!(ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), len as c_uint)); data.len()));
}
data = &data[len..];
} }
self.state = Updated; self.state = Updated;
Ok(()) Ok(())
@ -176,7 +172,7 @@ impl Write for Hasher {
impl Clone for Hasher { impl Clone for Hasher {
fn clone(&self) -> Hasher { fn clone(&self) -> Hasher {
let ctx = unsafe { let ctx = unsafe {
let ctx = ffi::EVP_MD_CTX_create(); let ctx = ffi::EVP_MD_CTX_new();
assert!(!ctx.is_null()); assert!(!ctx.is_null());
let r = ffi::EVP_MD_CTX_copy_ex(ctx, self.ctx); let r = ffi::EVP_MD_CTX_copy_ex(ctx, self.ctx);
assert_eq!(r, 1); assert_eq!(r, 1);
@ -197,7 +193,7 @@ impl Drop for Hasher {
if self.state != Finalized { if self.state != Finalized {
drop(self.finish()); drop(self.finish());
} }
ffi::EVP_MD_CTX_destroy(self.ctx); ffi::EVP_MD_CTX_free(self.ctx);
} }
} }
} }

View File

@ -13,16 +13,14 @@
// limitations under the License. // limitations under the License.
// //
use libc::{c_int, c_uint}; use libc::{c_int};
use std::io; use std::io;
use std::io::prelude::*; use std::io::prelude::*;
use std::cmp;
use ffi; use ffi;
use HashTypeInternals; use HashTypeInternals;
use crypto::hash::Type; use crypto::hash::Type;
use error::ErrorStack; use error::ErrorStack;
use c_helpers;
#[derive(PartialEq, Copy, Clone)] #[derive(PartialEq, Copy, Clone)]
enum State { enum State {
@ -66,7 +64,7 @@ use self::State::*;
/// assert_eq!(res, spec); /// assert_eq!(res, spec);
/// ``` /// ```
pub struct HMAC { pub struct HMAC {
ctx: ffi::HMAC_CTX, ctx: compat::HMAC_CTX,
state: State, state: State,
} }
@ -75,11 +73,7 @@ impl HMAC {
pub fn new(ty: Type, key: &[u8]) -> Result<HMAC, ErrorStack> { pub fn new(ty: Type, key: &[u8]) -> Result<HMAC, ErrorStack> {
ffi::init(); ffi::init();
let ctx = unsafe { let ctx = compat::HMAC_CTX::new();
let mut ctx = ::std::mem::uninitialized();
ffi::HMAC_CTX_init(&mut ctx);
ctx
};
let md = ty.evp_md(); let md = ty.evp_md();
let mut h = HMAC { let mut h = HMAC {
@ -92,11 +86,11 @@ impl HMAC {
fn init_once(&mut self, md: *const ffi::EVP_MD, key: &[u8]) -> Result<(), ErrorStack> { fn init_once(&mut self, md: *const ffi::EVP_MD, key: &[u8]) -> Result<(), ErrorStack> {
unsafe { unsafe {
try_ssl!(c_helpers::rust_0_8_HMAC_Init_ex(&mut self.ctx, try_ssl!(ffi::HMAC_Init_ex(self.ctx.get(),
key.as_ptr() as *const _, key.as_ptr() as *const _,
key.len() as c_int, key.len() as c_int,
md, md,
0 as *mut _)); 0 as *mut _));
} }
self.state = Reset; self.state = Reset;
Ok(()) Ok(())
@ -113,26 +107,24 @@ impl HMAC {
// If the key and/or md is not supplied it's reused from the last time // If the key and/or md is not supplied it's reused from the last time
// avoiding redundant initializations // avoiding redundant initializations
unsafe { unsafe {
try_ssl!(c_helpers::rust_0_8_HMAC_Init_ex(&mut self.ctx, try_ssl!(ffi::HMAC_Init_ex(self.ctx.get(),
0 as *const _, 0 as *const _,
0, 0,
0 as *const _, 0 as *const _,
0 as *mut _)); 0 as *mut _));
} }
self.state = Reset; self.state = Reset;
Ok(()) Ok(())
} }
pub fn update(&mut self, mut data: &[u8]) -> Result<(), ErrorStack> { pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
if self.state == Finalized { if self.state == Finalized {
try!(self.init()); try!(self.init());
} }
while !data.is_empty() { unsafe {
let len = cmp::min(data.len(), c_uint::max_value() as usize); try_ssl!(ffi::HMAC_Update(self.ctx.get(),
unsafe { data.as_ptr(),
try_ssl!(c_helpers::rust_0_8_HMAC_Update(&mut self.ctx, data.as_ptr(), len as c_uint)); data.len()));
}
data = &data[len..];
} }
self.state = Updated; self.state = Updated;
Ok(()) Ok(())
@ -147,7 +139,9 @@ impl HMAC {
unsafe { unsafe {
let mut len = ffi::EVP_MAX_MD_SIZE; let mut len = ffi::EVP_MAX_MD_SIZE;
let mut res = vec![0; len as usize]; 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); res.truncate(len as usize);
self.state = Finalized; self.state = Finalized;
Ok(res) Ok(res)
@ -167,14 +161,11 @@ impl Write for HMAC {
} }
} }
#[cfg(feature = "hmac_clone")]
impl Clone for HMAC { impl Clone for HMAC {
/// Requires the `hmac_clone` feature.
fn clone(&self) -> HMAC { fn clone(&self) -> HMAC {
let mut ctx: ffi::HMAC_CTX; let ctx = compat::HMAC_CTX::new();
unsafe { unsafe {
ctx = ::std::mem::uninitialized(); let r = ffi::HMAC_CTX_copy(ctx.get(), self.ctx.get());
let r = ffi::HMAC_CTX_copy(&mut ctx, &self.ctx);
assert_eq!(r, 1); assert_eq!(r, 1);
} }
HMAC { HMAC {
@ -186,11 +177,8 @@ impl Clone for HMAC {
impl Drop for HMAC { impl Drop for HMAC {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { if self.state != Finalized {
if self.state != Finalized { drop(self.finish());
drop(self.finish());
}
ffi::HMAC_CTX_cleanup(&mut self.ctx);
} }
} }
} }
@ -202,6 +190,73 @@ pub fn hmac(t: Type, key: &[u8], data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
h.finish() 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<ffi::HMAC_CTX>,
}
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)] #[cfg(test)]
mod tests { mod tests {
use std::iter::repeat; use std::iter::repeat;
@ -289,7 +344,6 @@ mod tests {
} }
#[test] #[test]
#[cfg(feature = "hmac_clone")]
fn test_clone() { fn test_clone() {
let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 2] = let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 2] =
[(repeat(0xaa_u8).take(80).collect(), [(repeat(0xaa_u8).take(80).collect(),

View File

@ -15,7 +15,6 @@
// //
pub mod hash; pub mod hash;
#[cfg(feature = "hmac")]
pub mod hmac; pub mod hmac;
pub mod pkcs5; pub mod pkcs5;
pub mod pkcs12; pub mod pkcs12;

View File

@ -44,13 +44,14 @@ impl Pkcs12 {
let pkey = PKey::from_ptr(pkey); let pkey = PKey::from_ptr(pkey);
let cert = X509::from_ptr(cert); let cert = X509::from_ptr(cert);
let chain = chain as *mut _;
let mut chain_out = vec![]; let mut chain_out = vec![];
for i in 0..(*chain).stack.num { for i in 0..compat::OPENSSL_sk_num(chain) {
let x509 = *(*chain).stack.data.offset(i as isize) as *mut _; let x509 = compat::OPENSSL_sk_value(chain, i);
chain_out.push(X509::from_ptr(x509)); chain_out.push(X509::from_ptr(x509 as *mut _));
} }
ffi::sk_free(&mut (*chain).stack); compat::OPENSSL_sk_free(chain as *mut _);
Ok(ParsedPkcs12 { Ok(ParsedPkcs12 {
pkey: pkey, pkey: pkey,
@ -69,6 +70,31 @@ pub struct ParsedPkcs12 {
_p: (), _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)] #[cfg(test)]
mod test { mod test {
use crypto::hash::Type::SHA1; use crypto::hash::Type::SHA1;

View File

@ -82,7 +82,7 @@ pub fn pbkdf2_hmac_sha1(pass: &[u8],
ffi::init(); 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, pass.len() as c_int,
salt.as_ptr(), salt.as_ptr(),
salt.len() as c_int, 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. /// 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], pub fn pbkdf2_hmac(pass: &[u8],
salt: &[u8], salt: &[u8],
iter: usize, iter: usize,
@ -104,7 +103,7 @@ pub fn pbkdf2_hmac(pass: &[u8],
unsafe { unsafe {
let mut out = vec![0; keylen]; let mut out = vec![0; keylen];
ffi::init(); 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, pass.len() as c_int,
salt.as_ptr(), salt.as_ptr(),
salt.len() as c_int, salt.len() as c_int,
@ -162,7 +161,6 @@ mod tests {
// Test vectors from // Test vectors from
// https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c
#[test] #[test]
#[cfg(feature = "pkcs5_pbkdf2_hmac")]
fn test_pbkdf2_hmac_sha256() { fn test_pbkdf2_hmac_sha256() {
assert_eq!(super::pbkdf2_hmac(b"passwd", b"salt", 1, hash::Type::SHA256, 16).unwrap(), 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, 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 // Test vectors from
// https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c
#[test] #[test]
#[cfg(feature = "pkcs5_pbkdf2_hmac")]
fn test_pbkdf2_hmac_sha512() { fn test_pbkdf2_hmac_sha512() {
assert_eq!(super::pbkdf2_hmac(b"password", b"NaCL", 1, hash::Type::SHA512, 64).unwrap(), 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, vec![0x73_u8, 0xde_u8, 0xcf_u8, 0xa5_u8, 0x8a_u8, 0xa2_u8, 0xe8_u8, 0x4f_u8,

View File

@ -2,7 +2,7 @@ use ffi;
use std::fmt; use std::fmt;
use std::ptr; use std::ptr;
use std::mem; 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 bn::{BigNum, BigNumRef};
use bio::{MemBio, MemBioSlice}; use bio::{MemBio, MemBioSlice};
@ -44,12 +44,13 @@ impl RSA {
/// the supplied load and save methods for DER formatted keys. /// the supplied load and save methods for DER formatted keys.
pub fn from_public_components(n: BigNum, e: BigNum) -> Result<RSA, ErrorStack> { pub fn from_public_components(n: BigNum, e: BigNum) -> Result<RSA, ErrorStack> {
unsafe { unsafe {
let rsa = try_ssl_null!(ffi::RSA_new()); let rsa = RSA(try_ssl_null!(ffi::RSA_new()));
(*rsa).n = n.as_ptr(); try_ssl!(compat::set_key(rsa.0,
(*rsa).e = e.as_ptr(); n.as_ptr(),
mem::forget(n); e.as_ptr(),
mem::forget(e); ptr::null_mut()));
Ok(RSA(rsa)) mem::forget((n, e));
Ok(rsa)
} }
} }
@ -63,24 +64,15 @@ impl RSA {
qi: BigNum) qi: BigNum)
-> Result<RSA, ErrorStack> { -> Result<RSA, ErrorStack> {
unsafe { unsafe {
let rsa = try_ssl_null!(ffi::RSA_new()); let rsa = RSA(try_ssl_null!(ffi::RSA_new()));
(*rsa).n = n.as_ptr(); try_ssl!(compat::set_key(rsa.0, n.as_ptr(), e.as_ptr(), d.as_ptr()));
(*rsa).e = e.as_ptr(); mem::forget((n, e, d));
(*rsa).d = d.as_ptr(); try_ssl!(compat::set_factors(rsa.0, p.as_ptr(), q.as_ptr()));
(*rsa).p = p.as_ptr(); mem::forget((p, q));
(*rsa).q = q.as_ptr(); try_ssl!(compat::set_crt_params(rsa.0, dp.as_ptr(), dq.as_ptr(),
(*rsa).dmp1 = dp.as_ptr(); qi.as_ptr()));
(*rsa).dmq1 = dq.as_ptr(); mem::forget((dp, dq, qi));
(*rsa).iqmp = qi.as_ptr(); Ok(rsa)
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))
} }
} }
@ -95,7 +87,7 @@ impl RSA {
unsafe { unsafe {
let rsa = try_ssl_null!(ffi::RSA_new()); let rsa = try_ssl_null!(ffi::RSA_new());
let rsa = RSA(rsa); 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())); 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<BigNumRef<'a>> { pub fn n<'a>(&'a self) -> Option<BigNumRef<'a>> {
unsafe { unsafe {
let n = (*self.0).n; let n = compat::key(self.0)[0];
if n.is_null() { if n.is_null() {
None None
} else { } else {
Some(BigNumRef::from_ptr(n)) Some(BigNumRef::from_ptr(n as *mut _))
} }
} }
} }
pub fn d<'a>(&self) -> Option<BigNumRef<'a>> { pub fn d<'a>(&self) -> Option<BigNumRef<'a>> {
unsafe { unsafe {
let d = (*self.0).d; let d = compat::key(self.0)[2];
if d.is_null() { if d.is_null() {
None None
} else { } else {
Some(BigNumRef::from_ptr(d)) Some(BigNumRef::from_ptr(d as *mut _))
} }
} }
} }
pub fn e<'a>(&'a self) -> Option<BigNumRef<'a>> { pub fn e<'a>(&'a self) -> Option<BigNumRef<'a>> {
unsafe { unsafe {
let e = (*self.0).e; let e = compat::key(self.0)[1];
if e.is_null() { if e.is_null() {
None None
} else { } else {
Some(BigNumRef::from_ptr(e)) Some(BigNumRef::from_ptr(e as *mut _))
} }
} }
} }
pub fn p<'a>(&'a self) -> Option<BigNumRef<'a>> { pub fn p<'a>(&'a self) -> Option<BigNumRef<'a>> {
unsafe { unsafe {
let p = (*self.0).p; let p = compat::factors(self.0)[0];
if p.is_null() { if p.is_null() {
None None
} else { } else {
Some(BigNumRef::from_ptr(p)) Some(BigNumRef::from_ptr(p as *mut _))
} }
} }
} }
pub fn q<'a>(&'a self) -> Option<BigNumRef<'a>> { pub fn q<'a>(&'a self) -> Option<BigNumRef<'a>> {
unsafe { unsafe {
let q = (*self.0).q; let q = compat::factors(self.0)[1];
if q.is_null() { if q.is_null() {
None None
} else { } 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)] #[cfg(test)]
mod test { mod test {
use std::io::Write; use std::io::Write;
@ -449,9 +524,9 @@ mod test {
#[test] #[test]
fn test_private_encrypt() { 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 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); let msg = vec!(0xdeu8, 0xadu8, 0xd0u8, 0x0du8);
@ -462,9 +537,9 @@ mod test {
#[test] #[test]
fn test_public_encrypt() { 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 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); let msg = vec!(0xdeu8, 0xadu8, 0xd0u8, 0x0du8);
@ -475,9 +550,9 @@ mod test {
#[test] #[test]
fn test_public_encrypt_pkcs() { 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 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); let msg = vec!(0xdeu8, 0xadu8, 0xd0u8, 0x0du8);

View File

@ -81,7 +81,7 @@ impl Type {
/// Returns the length of keys used with this cipher. /// Returns the length of keys used with this cipher.
pub fn key_len(&self) -> usize { pub fn key_len(&self) -> usize {
unsafe { 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. /// cipher does not use an IV.
pub fn iv_len(&self) -> Option<usize> { pub fn iv_len(&self) -> Option<usize> {
unsafe { 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 { if len == 0 {
None None
} else { } else {
@ -105,7 +105,7 @@ impl Type {
/// Stream ciphers such as RC4 have a block size of 1. /// Stream ciphers such as RC4 have a block size of 1.
pub fn block_size(&self) -> usize { pub fn block_size(&self) -> usize {
unsafe { 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) 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)] #[cfg(test)]
mod tests { mod tests {
use serialize::hex::{FromHex, ToHex}; use serialize::hex::{FromHex, ToHex};

View File

@ -3,24 +3,22 @@ use error::ErrorStack;
use bio::MemBioSlice; use bio::MemBioSlice;
use std::ptr; use std::ptr;
#[cfg(feature = "dh_from_params")]
use bn::BigNum; use bn::BigNum;
#[cfg(feature = "dh_from_params")]
use std::mem; use std::mem;
pub struct DH(*mut ffi::DH); pub struct DH(*mut ffi::DH);
impl 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<DH, ErrorStack> { pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result<DH, ErrorStack> {
let dh = unsafe { unsafe {
try_ssl_null!(::c_helpers::rust_0_8_DH_new_from_params(p.as_ptr(), g.as_ptr(), q.as_ptr())) let dh = DH(try_ssl_null!(ffi::DH_new()));
}; try_ssl!(compat::DH_set0_pqg(dh.0,
mem::forget(p); p.as_ptr(),
mem::forget(g); q.as_ptr(),
mem::forget(q); g.as_ptr()));
Ok(DH(dh)) mem::forget((p, g, q));
Ok(dh)
}
} }
pub fn from_pem(buf: &[u8]) -> Result<DH, ErrorStack> { pub fn from_pem(buf: &[u8]) -> Result<DH, ErrorStack> {
@ -32,19 +30,19 @@ impl DH {
Ok(DH(dh)) Ok(DH(dh))
} }
#[cfg(feature = "rfc5114")] #[cfg(all(feature = "rfc5114", not(ossl101)))]
pub fn get_1024_160() -> Result<DH, ErrorStack> { pub fn get_1024_160() -> Result<DH, ErrorStack> {
let dh = try_ssl_null!(unsafe { ffi::DH_get_1024_160() }); let dh = try_ssl_null!(unsafe { ffi::DH_get_1024_160() });
Ok(DH(dh)) Ok(DH(dh))
} }
#[cfg(feature = "rfc5114")] #[cfg(all(feature = "rfc5114", not(ossl101)))]
pub fn get_2048_224() -> Result<DH, ErrorStack> { pub fn get_2048_224() -> Result<DH, ErrorStack> {
let dh = try_ssl_null!(unsafe { ffi::DH_get_2048_224() }); let dh = try_ssl_null!(unsafe { ffi::DH_get_2048_224() });
Ok(DH(dh)) Ok(DH(dh))
} }
#[cfg(feature = "rfc5114")] #[cfg(all(feature = "rfc5114", not(ossl101)))]
pub fn get_2048_256() -> Result<DH, ErrorStack> { pub fn get_2048_256() -> Result<DH, ErrorStack> {
let dh = try_ssl_null!(unsafe { ffi::DH_get_2048_256() }); let dh = try_ssl_null!(unsafe { ffi::DH_get_2048_256() });
Ok(DH(dh)) 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)] #[cfg(test)]
mod tests { mod tests {
use super::DH; use super::DH;
use bn::BigNum; use bn::BigNum;
use ssl::SslContext; use ssl::SslContext;
use ssl::SslMethod::Sslv23; use ssl::SslMethod::Tls;
#[test] #[test]
#[cfg(feature = "rfc5114")] #[cfg(all(feature = "rfc5114", not(ossl101)))]
fn test_dh_rfc5114() { 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(); let dh1 = DH::get_1024_160().unwrap();
ctx.set_tmp_dh(&dh1).unwrap(); ctx.set_tmp_dh(&dh1).unwrap();
let dh2 = DH::get_2048_224().unwrap(); let dh2 = DH::get_2048_224().unwrap();
@ -84,9 +104,8 @@ mod tests {
} }
#[test] #[test]
#[cfg(feature = "dh_from_params")]
fn test_dh() { fn test_dh() {
let mut ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Tls).unwrap();
let p = BigNum::from_hex_str("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435\ let p = BigNum::from_hex_str("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435\
E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF429\ E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF429\
6D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C02\ 6D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C02\
@ -116,7 +135,7 @@ mod tests {
#[test] #[test]
fn test_dh_from_pem() { 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 params = include_bytes!("../../test/dhparams.pem");
let dh = DH::from_pem(params).ok().expect("Failed to load PEM"); let dh = DH::from_pem(params).ok().expect("Failed to load PEM");
ctx.set_tmp_dh(&dh).unwrap(); ctx.set_tmp_dh(&dh).unwrap();

View File

@ -71,7 +71,7 @@ impl Error {
match unsafe { ffi::ERR_get_error() } { match unsafe { ffi::ERR_get_error() } {
0 => None, 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 { fn get_lib(err: c_ulong) -> &'static str {
unsafe { unsafe {
let cstr = ffi::ERR_lib_error_string(err); 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(); let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
str::from_utf8(bytes).unwrap() 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 { fn get_func(err: c_ulong) -> &'static str {
unsafe { unsafe {
let cstr = ffi::ERR_func_error_string(err); 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(); let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
str::from_utf8(bytes).unwrap() 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 { fn get_reason(err: c_ulong) -> &'static str {
unsafe { unsafe {
let cstr = ffi::ERR_reason_error_string(err); 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(); let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
str::from_utf8(bytes).unwrap() str::from_utf8(bytes).unwrap()
} }

View File

@ -13,6 +13,9 @@ extern crate rustc_serialize as serialize;
#[cfg(test)] #[cfg(test)]
extern crate net2; extern crate net2;
#[cfg(test)]
extern crate tempdir;
#[doc(inline)] #[doc(inline)]
pub use ffi::init; pub use ffi::init;
@ -23,8 +26,6 @@ mod macros;
pub mod asn1; pub mod asn1;
mod bio; mod bio;
pub mod bn; pub mod bn;
#[cfg(feature = "c_helpers")]
mod c_helpers;
pub mod crypto; pub mod crypto;
pub mod dh; pub mod dh;
pub mod error; pub mod error;

View File

@ -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)
)
}

View File

@ -1,5 +1,5 @@
use libc::{c_char, c_int, c_long, c_void, strlen}; 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}; BIO_set_retry_read, BIO_set_retry_write};
use std::any::Any; use std::any::Any;
use std::io; use std::io;
@ -18,22 +18,11 @@ pub struct StreamState<S> {
} }
/// Safe wrapper for BIO_METHOD /// Safe wrapper for BIO_METHOD
pub struct BioMethod(ffi::BIO_METHOD); pub struct BioMethod(compat::BIO_METHOD);
impl BioMethod { impl BioMethod {
pub fn new<S: Read + Write>() -> BioMethod { pub fn new<S: Read + Write>() -> BioMethod {
BioMethod(ffi::BIO_METHOD { BioMethod(compat::BIO_METHOD::new::<S>())
type_: BIO_TYPE_NONE,
name: b"rust\0".as_ptr() as *const _,
bwrite: Some(bwrite::<S>),
bread: Some(bread::<S>),
bputs: Some(bputs::<S>),
bgets: None,
ctrl: Some(ctrl::<S>),
create: Some(create),
destroy: Some(destroy::<S>),
callback_ctrl: None,
})
} }
} }
@ -49,9 +38,9 @@ pub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, Arc<BioMethod>), Err
}); });
unsafe { unsafe {
let bio = try_ssl_null!(BIO_new(&method.0)); let bio = try_ssl_null!(BIO_new(method.0.get()));
(*bio).ptr = Box::into_raw(state) as *mut _; compat::BIO_set_data(bio, Box::into_raw(state) as *mut _);
(*bio).init = 1; compat::BIO_set_init(bio, 1);
return Ok((bio, method)); return Ok((bio, method));
} }
@ -62,14 +51,13 @@ pub unsafe fn take_error<S>(bio: *mut BIO) -> Option<io::Error> {
state.error.take() state.error.take()
} }
#[cfg_attr(not(feature = "nightly"), allow(dead_code))]
pub unsafe fn take_panic<S>(bio: *mut BIO) -> Option<Box<Any + Send>> { pub unsafe fn take_panic<S>(bio: *mut BIO) -> Option<Box<Any + Send>> {
let state = state::<S>(bio); let state = state::<S>(bio);
state.panic.take() state.panic.take()
} }
pub unsafe fn get_ref<'a, S: 'a>(bio: *mut BIO) -> &'a S { pub unsafe fn get_ref<'a, S: 'a>(bio: *mut BIO) -> &'a S {
let state: &'a StreamState<S> = mem::transmute((*bio).ptr); let state: &'a StreamState<S> = mem::transmute(compat::BIO_get_data(bio));
&state.stream &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<S> { unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState<S> {
mem::transmute((*bio).ptr) mem::transmute(compat::BIO_get_data(bio))
} }
#[cfg(feature = "nightly")]
fn catch_unwind<F, T>(f: F) -> Result<T, Box<Any + Send>> fn catch_unwind<F, T>(f: F) -> Result<T, Box<Any + Send>>
where F: FnOnce() -> T where F: FnOnce() -> T
{ {
::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(f)) ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(f))
} }
#[cfg(not(feature = "nightly"))] unsafe extern fn bwrite<S: Write>(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int {
fn catch_unwind<F, T>(f: F) -> Result<T, Box<Any + Send>>
where F: FnOnce() -> T
{
Ok(f())
}
unsafe extern "C" fn bwrite<S: Write>(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int {
BIO_clear_retry_flags(bio); BIO_clear_retry_flags(bio);
let state = state::<S>(bio); let state = state::<S>(bio);
@ -117,7 +97,7 @@ unsafe extern "C" fn bwrite<S: Write>(bio: *mut BIO, buf: *const c_char, len: c_
} }
} }
unsafe extern "C" fn bread<S: Read>(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int { unsafe extern fn bread<S: Read>(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int {
BIO_clear_retry_flags(bio); BIO_clear_retry_flags(bio);
let state = state::<S>(bio); let state = state::<S>(bio);
@ -147,15 +127,15 @@ fn retriable_error(err: &io::Error) -> bool {
} }
} }
unsafe extern "C" fn bputs<S: Write>(bio: *mut BIO, s: *const c_char) -> c_int { unsafe extern fn bputs<S: Write>(bio: *mut BIO, s: *const c_char) -> c_int {
bwrite::<S>(bio, s, strlen(s) as c_int) bwrite::<S>(bio, s, strlen(s) as c_int)
} }
unsafe extern "C" fn ctrl<S: Write>(bio: *mut BIO, unsafe extern fn ctrl<S: Write>(bio: *mut BIO,
cmd: c_int, cmd: c_int,
_num: c_long, _num: c_long,
_ptr: *mut c_void) _ptr: *mut c_void)
-> c_long { -> c_long {
if cmd == BIO_CTRL_FLUSH { if cmd == BIO_CTRL_FLUSH {
let state = state::<S>(bio); let state = state::<S>(bio);
@ -175,22 +155,126 @@ unsafe extern "C" fn ctrl<S: Write>(bio: *mut BIO,
} }
} }
unsafe extern "C" fn create(bio: *mut BIO) -> c_int { unsafe extern fn create(bio: *mut BIO) -> c_int {
(*bio).init = 0; compat::BIO_set_init(bio, 0);
(*bio).num = 0; compat::BIO_set_num(bio, 0);
(*bio).ptr = ptr::null_mut(); compat::BIO_set_data(bio, ptr::null_mut());
(*bio).flags = 0; compat::BIO_set_flags(bio, 0);
1 1
} }
unsafe extern "C" fn destroy<S>(bio: *mut BIO) -> c_int { unsafe extern fn destroy<S>(bio: *mut BIO) -> c_int {
if bio.is_null() { if bio.is_null() {
return 0; return 0;
} }
assert!(!(*bio).ptr.is_null()); let data = compat::BIO_get_data(bio);
Box::<StreamState<S>>::from_raw((*bio).ptr as *mut _); assert!(!data.is_null());
(*bio).ptr = ptr::null_mut(); Box::<StreamState<S>>::from_raw(data as *mut _);
(*bio).init = 0; compat::BIO_set_data(bio, ptr::null_mut());
compat::BIO_set_init(bio, 0);
1 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<S: Read + Write>() -> 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::<S>) != 0);
assert!(ffi::BIO_meth_set_read(ptr, super::bread::<S>) != 0);
assert!(ffi::BIO_meth_set_puts(ptr, super::bputs::<S>) != 0);
assert!(ffi::BIO_meth_set_ctrl(ptr, super::ctrl::<S>) != 0);
assert!(ffi::BIO_meth_set_create(ptr, super::create) != 0);
assert!(ffi::BIO_meth_set_destroy(ptr, super::destroy::<S>) != 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<ffi::BIO_METHOD>,
}
impl BIO_METHOD {
pub fn new<S: Read + Write>() -> 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::<S>),
bread: Some(super::bread::<S>),
bputs: Some(super::bputs::<S>),
bgets: None,
ctrl: Some(super::ctrl::<S>),
create: Some(super::create),
destroy: Some(super::destroy::<S>),
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;
}
}

View File

@ -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::Any;
use std::any::TypeId; use std::any::TypeId;
use std::cmp; use std::cmp;
@ -38,12 +38,11 @@ use self::bio::BioMethod;
pub use ssl::error::Error; pub use ssl::error::Error;
bitflags! { 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_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_CHALLENGE_BUG = ffi::SSL_OP_NETSCAPE_CHALLENGE_BUG,
const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG =
ffi::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_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_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, const SSL_OP_TLS_D5_BUG = ffi::SSL_OP_TLS_D5_BUG,
@ -73,74 +72,11 @@ bitflags! {
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum SslMethod { pub enum SslMethod {
#[cfg(feature = "sslv2")] // TODO: support more methods
/// Only support the SSLv2 protocol, requires the `sslv2` feature. /// Support the TLS protocol
Sslv2, Tls,
/// Support the SSLv2, SSLv3, TLSv1, TLSv1.1, and TLSv1.2 protocols depending on what the /// Support DTLS protocol
/// linked OpenSSL library supports. Dtls,
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<SslMethod> {
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,
}
}
}
} }
/// Determines the type of certificate verification used /// Determines the type of certificate verification used
@ -172,11 +108,11 @@ fn get_ssl_verify_data_idx<T: Any + 'static>() -> c_int {
*SSL_INDEXES.lock().unwrap().entry(TypeId::of::<T>()).or_insert_with(|| get_new_ssl_idx::<T>()) *SSL_INDEXES.lock().unwrap().entry(TypeId::of::<T>()).or_insert_with(|| get_new_ssl_idx::<T>())
} }
#[cfg(feature = "npn")] #[cfg(all(feature = "npn", not(ossl101)))]
lazy_static! { lazy_static! {
static ref NPN_PROTOS_IDX: c_int = get_new_idx::<Vec<u8>>(); static ref NPN_PROTOS_IDX: c_int = get_new_idx::<Vec<u8>>();
} }
#[cfg(feature = "alpn")] #[cfg(all(feature = "alpn", not(ossl101)))]
lazy_static! { lazy_static! {
static ref ALPN_PROTOS_IDX: c_int = get_new_idx::<Vec<u8>>(); static ref ALPN_PROTOS_IDX: c_int = get_new_idx::<Vec<u8>>();
} }
@ -184,52 +120,50 @@ lazy_static! {
/// Determine a new index to use for SSL CTX ex data. /// 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. /// Registers a destruct for the data which will be called by openssl when the context is freed.
fn get_new_idx<T>() -> c_int { fn get_new_idx<T>() -> c_int {
extern "C" fn free_data_box<T>(_parent: *mut c_void, extern fn free_data_box<T>(_parent: *mut c_void,
ptr: *mut c_void, ptr: *mut c_void,
_ad: *mut ffi::CRYPTO_EX_DATA, _ad: *mut ffi::CRYPTO_EX_DATA,
_idx: c_int, _idx: c_int,
_argl: c_long, _argl: c_long,
_argp: *mut c_void) { _argp: *mut c_void) {
if !ptr.is_null() { if !ptr.is_null() {
let _: Box<T> = unsafe { mem::transmute(ptr) }; let _: Box<T> = unsafe { mem::transmute(ptr) };
} }
} }
unsafe { unsafe {
let f: ffi::CRYPTO_EX_free = free_data_box::<T>; let idx = compat::get_new_idx(free_data_box::<T>);
let idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, Some(f));
assert!(idx >= 0); assert!(idx >= 0);
idx idx
} }
} }
fn get_new_ssl_idx<T>() -> c_int { fn get_new_ssl_idx<T>() -> c_int {
extern "C" fn free_data_box<T>(_parent: *mut c_void, extern fn free_data_box<T>(_parent: *mut c_void,
ptr: *mut c_void, ptr: *mut c_void,
_ad: *mut ffi::CRYPTO_EX_DATA, _ad: *mut ffi::CRYPTO_EX_DATA,
_idx: c_int, _idx: c_int,
_argl: c_long, _argl: c_long,
_argp: *mut c_void) { _argp: *mut c_void) {
if !ptr.is_null() { if !ptr.is_null() {
let _: Box<T> = unsafe { mem::transmute(ptr) }; let _: Box<T> = unsafe { mem::transmute(ptr) };
} }
} }
unsafe { unsafe {
let f: ffi::CRYPTO_EX_free = free_data_box::<T>; let idx = compat::get_new_ssl_idx(free_data_box::<T>);
let idx = ffi::SSL_get_ex_new_index(0, ptr::null(), None, None, Some(f));
assert!(idx >= 0); assert!(idx >= 0);
idx idx
} }
} }
extern "C" fn raw_verify<F>(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int extern fn raw_verify<F>(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int
where F: Fn(bool, &X509StoreContext) -> bool + Any + 'static + Sync + Send where F: Fn(bool, &X509StoreContext) -> bool + Any + 'static + Sync + Send
{ {
unsafe { unsafe {
let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx(); 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 = 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::<F>()); let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::<F>());
let verify: &F = mem::transmute(verify); let verify: &F = mem::transmute(verify);
@ -239,13 +173,14 @@ extern "C" fn raw_verify<F>(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_
} }
} }
extern "C" fn ssl_raw_verify<F>(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int extern fn ssl_raw_verify<F>(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int
where F: Fn(bool, &X509StoreContext) -> bool + Any + 'static + Sync + Send where F: Fn(bool, &X509StoreContext) -> bool + Any + 'static + Sync + Send
{ {
unsafe { unsafe {
let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx(); 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 = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx);
let verify = ffi::SSL_get_ex_data(ssl, get_ssl_verify_data_idx::<F>()); let verify = ffi::SSL_get_ex_data(ssl as *const _,
get_ssl_verify_data_idx::<F>());
let verify: &F = mem::transmute(verify); let verify: &F = mem::transmute(verify);
let ctx = X509StoreContext::new(x509_ctx); let ctx = X509StoreContext::new(x509_ctx);
@ -254,7 +189,7 @@ extern "C" fn ssl_raw_verify<F>(preverify_ok: c_int, x509_ctx: *mut ffi::X509_ST
} }
} }
extern "C" fn raw_sni<F>(ssl: *mut ffi::SSL, al: *mut c_int, _arg: *mut c_void) -> c_int extern fn raw_sni<F>(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 where F: Fn(&mut SslRef) -> Result<(), SniError> + Any + 'static + Sync + Send
{ {
unsafe { unsafe {
@ -278,7 +213,7 @@ extern "C" fn raw_sni<F>(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, unsafe fn select_proto_using(ssl: *mut ffi::SSL,
out: *mut *mut c_uchar, out: *mut *mut c_uchar,
outlen: *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` /// 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 /// function. The list of protocols supported by the client is found in the extra data of the
/// OpenSSL context. /// OpenSSL context.
#[cfg(feature = "npn")] #[cfg(all(feature = "npn", not(ossl101)))]
extern "C" fn raw_next_proto_select_cb(ssl: *mut ffi::SSL, extern fn raw_next_proto_select_cb(ssl: *mut ffi::SSL,
out: *mut *mut c_uchar, out: *mut *mut c_uchar,
outlen: *mut c_uchar, outlen: *mut c_uchar,
inbuf: *const c_uchar, inbuf: *const c_uchar,
inlen: c_uint, inlen: c_uint,
_arg: *mut c_void) _arg: *mut c_void)
-> c_int { -> c_int {
unsafe { select_proto_using(ssl, out, outlen, inbuf, inlen, *NPN_PROTOS_IDX) } unsafe { select_proto_using(ssl, out, outlen, inbuf, inlen, *NPN_PROTOS_IDX) }
} }
#[cfg(feature = "alpn")] #[cfg(all(feature = "alpn", not(ossl101)))]
extern "C" fn raw_alpn_select_cb(ssl: *mut ffi::SSL, extern fn raw_alpn_select_cb(ssl: *mut ffi::SSL,
out: *mut *mut c_uchar, out: *mut *const c_uchar,
outlen: *mut c_uchar, outlen: *mut c_uchar,
inbuf: *const c_uchar, inbuf: *const c_uchar,
inlen: c_uint, inlen: c_uint,
_arg: *mut c_void) _arg: *mut c_void)
-> c_int { -> c_int {
unsafe { select_proto_using(ssl, out, outlen, inbuf, inlen, *ALPN_PROTOS_IDX) } 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`. /// 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. /// that it supports.
/// The list of supported protocols is found in the extra data of the OpenSSL /// The list of supported protocols is found in the extra data of the OpenSSL
/// context. /// context.
#[cfg(feature = "npn")] #[cfg(all(feature = "npn", not(ossl101)))]
extern "C" fn raw_next_protos_advertise_cb(ssl: *mut ffi::SSL, extern fn raw_next_protos_advertise_cb(ssl: *mut ffi::SSL,
out: *mut *const c_uchar, out: *mut *const c_uchar,
outlen: *mut c_uint, outlen: *mut c_uint,
_arg: *mut c_void) _arg: *mut c_void)
-> c_int { -> c_int {
unsafe { unsafe {
// First, get the list of (supported) protocols saved in the context extra data. // First, get the list of (supported) protocols saved in the context extra data.
let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); 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 /// 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. /// 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<u8> { fn ssl_encode_byte_strings(strings: &[&[u8]]) -> Vec<u8> {
let mut enc = Vec::new(); let mut enc = Vec::new();
for string in strings { for string in strings {
@ -442,8 +377,8 @@ impl<'a> SslContextRef<'a> {
ffi::SSL_CTX_set_ex_data(self.as_ptr(), ffi::SSL_CTX_set_ex_data(self.as_ptr(),
get_verify_data_idx::<F>(), get_verify_data_idx::<F>(),
mem::transmute(callback)); mem::transmute(callback));
let f: extern "C" fn(_, _, _) -> _ = raw_sni::<F>; let f: extern fn(_, _, _) -> _ = raw_sni::<F>;
let f: extern "C" fn() = mem::transmute(f); let f: extern fn() = mem::transmute(f);
ffi::SSL_CTX_set_tlsext_servername_callback(self.as_ptr(), Some(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 /// Specifies the file that contains certificate chain
pub fn set_certificate_chain_file<P: AsRef<Path>>(&mut self, pub fn set_certificate_chain_file<P: AsRef<Path>>(&mut self, file: P)
file: P,
file_type: X509FileType)
-> Result<(), ErrorStack> { -> Result<(), ErrorStack> {
let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap(); let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
wrap_ssl_result(unsafe { wrap_ssl_result(unsafe {
ffi::SSL_CTX_use_certificate_chain_file(self.as_ptr(), ffi::SSL_CTX_use_certificate_chain_file(self.as_ptr(),
file.as_ptr() as *const _, file.as_ptr() as *const _)
file_type as c_int)
}) })
} }
@ -575,27 +507,44 @@ impl<'a> SslContextRef<'a> {
}) })
} }
/// If `onoff` is set to `true`, enable ECDHE for key exchange with compatible /// If `onoff` is set to `true`, enable ECDHE for key exchange with
/// clients, and automatically select an appropriate elliptic curve. /// compatible clients, and automatically select an appropriate elliptic
/// curve.
/// ///
/// This method requires OpenSSL >= 1.0.2 or LibreSSL and the `ecdh_auto` feature. /// This method requires OpenSSL >= 1.0.2 or LibreSSL and the `ecdh_auto`
#[cfg(feature = "ecdh_auto")] /// feature.
#[cfg(all(feature = "ecdh_auto", not(ossl101)))]
pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { 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 { 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() SslContextOptions::from_bits(ret).unwrap()
} }
pub fn options(&self) -> SslContextOptions { 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() SslContextOptions::from_bits(ret).unwrap()
} }
pub fn clear_options(&mut self, option: SslContextOptions) -> SslContextOptions { 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() SslContextOptions::from_bits(ret).unwrap()
} }
@ -603,7 +552,7 @@ impl<'a> SslContextRef<'a> {
/// supported by the application). /// supported by the application).
/// ///
/// This method needs the `npn` feature. /// This method needs the `npn` feature.
#[cfg(feature = "npn")] #[cfg(all(feature = "npn", not(ossl101)))]
pub fn set_npn_protocols(&mut self, protocols: &[&[u8]]) { 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 // Firstly, convert the list of protocols to a byte-array that can be passed to OpenSSL
// APIs -- a list of length-prefixed strings. // 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. /// Note that ordering of the protocols controls the priority with which they are chosen.
/// ///
/// This method needs the `alpn` feature. /// This method needs the `alpn` feature.
#[cfg(feature = "alpn")] #[cfg(all(feature = "alpn", not(ossl101)))]
pub fn set_alpn_protocols(&mut self, protocols: &[&[u8]]) { pub fn set_alpn_protocols(&mut self, protocols: &[&[u8]]) {
let protocols: Box<Vec<u8>> = Box::new(ssl_encode_byte_strings(protocols)); let protocols: Box<Vec<u8>> = Box::new(ssl_encode_byte_strings(protocols));
unsafe { unsafe {
@ -662,12 +611,10 @@ pub struct SslContext(SslContextRef<'static>);
unsafe impl Send for SslContext {} unsafe impl Send for SslContext {}
unsafe impl Sync for SslContext {} unsafe impl Sync for SslContext {}
#[cfg(feature = "ssl_context_clone")]
impl Clone for SslContext { impl Clone for SslContext {
/// Requires the `ssl_context_clone` feature.
fn clone(&self) -> Self { fn clone(&self) -> Self {
unsafe { 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()) SslContext::from_ptr(self.as_ptr())
} }
} }
@ -706,15 +653,13 @@ impl SslContext {
init(); init();
let mut ctx = unsafe { 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) SslContext::from_ptr(ctx)
}; };
match method { match method {
#[cfg(feature = "dtlsv1")] SslMethod::Dtls => ctx.set_read_ahead(1),
SslMethod::Dtlsv1 => ctx.set_read_ahead(1),
#[cfg(feature = "dtlsv1_2")]
SslMethod::Dtlsv1_2 => ctx.set_read_ahead(1),
_ => {} _ => {}
} }
// this is a bit dubious (?) // this is a bit dubious (?)
@ -982,7 +927,7 @@ impl<'a> SslRef<'a> {
/// to interpret it. /// to interpret it.
/// ///
/// This method needs the `alpn` feature. /// This method needs the `alpn` feature.
#[cfg(feature = "alpn")] #[cfg(all(feature = "alpn", not(ossl101)))]
pub fn selected_alpn_protocol(&self) -> Option<&[u8]> { pub fn selected_alpn_protocol(&self) -> Option<&[u8]> {
unsafe { unsafe {
let mut data: *const c_uchar = ptr::null(); let mut data: *const c_uchar = ptr::null();
@ -1023,13 +968,6 @@ impl<'a> SslRef<'a> {
Some(s) 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 /// Returns the server's name for the current connection
pub fn servername(&self) -> Option<String> { pub fn servername(&self) -> Option<String> {
let name = unsafe { ffi::SSL_get_servername(self.as_ptr(), ffi::TLSEXT_NAMETYPE_host_name) }; let name = unsafe { ffi::SSL_get_servername(self.as_ptr(), ffi::TLSEXT_NAMETYPE_host_name) };
@ -1319,16 +1257,12 @@ impl<S> SslStream<S> {
} }
} }
#[cfg(feature = "nightly")]
fn check_panic(&mut self) { fn check_panic(&mut self) {
if let Some(err) = unsafe { bio::take_panic::<S>(self.ssl.get_raw_rbio()) } { if let Some(err) = unsafe { bio::take_panic::<S>(self.ssl.get_raw_rbio()) } {
::std::panic::resume_unwind(err) ::std::panic::resume_unwind(err)
} }
} }
#[cfg(not(feature = "nightly"))]
fn check_panic(&mut self) {}
fn get_bio_error(&mut self) -> io::Error { fn get_bio_error(&mut self) -> io::Error {
let error = unsafe { bio::take_error::<S>(self.ssl.get_raw_rbio()) }; let error = unsafe { bio::take_error::<S>(self.ssl.get_raw_rbio()) };
match error { match error {
@ -1412,3 +1346,107 @@ impl<'a> IntoSsl for &'a SslContext {
Ssl::new(self) 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
}
}

View File

@ -1,5 +1,6 @@
#![allow(unused_imports)] #![allow(unused_imports)]
use std::env;
use std::fs::File; use std::fs::File;
use std::io::prelude::*; use std::io::prelude::*;
use std::io::{self, BufReader}; use std::io::{self, BufReader};
@ -12,11 +13,12 @@ use std::thread;
use std::time::Duration; use std::time::Duration;
use net2::TcpStreamExt; use net2::TcpStreamExt;
use tempdir::TempDir;
use crypto::hash::Type::SHA256; use crypto::hash::Type::SHA256;
use ssl; use ssl;
use ssl::SSL_VERIFY_PEER; use ssl::SSL_VERIFY_PEER;
use ssl::SslMethod::Sslv23; use ssl::SslMethod::Tls;
use ssl::{SslMethod, HandshakeError}; use ssl::{SslMethod, HandshakeError};
use ssl::error::Error; use ssl::error::Error;
use ssl::{SslContext, SslStream}; use ssl::{SslContext, SslStream};
@ -46,10 +48,21 @@ fn next_addr() -> SocketAddr {
struct Server { struct Server {
p: Child, p: Child,
_temp: TempDir,
} }
impl Server { impl Server {
fn spawn(args: &[&str], input: Option<Box<FnMut(ChildStdin) + Send>>) -> (Server, SocketAddr) { fn spawn(args: &[&str], input: Option<Box<FnMut(ChildStdin) + Send>>) -> (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 addr = next_addr();
let mut child = Command::new("openssl") let mut child = Command::new("openssl")
.arg("s_server") .arg("s_server")
@ -57,11 +70,10 @@ impl Server {
.arg(addr.port().to_string()) .arg(addr.port().to_string())
.args(args) .args(args)
.arg("-cert") .arg("-cert")
.arg("cert.pem") .arg(&cert)
.arg("-key") .arg("-key")
.arg("key.pem") .arg(&key)
.arg("-no_dhe") .arg("-no_dhe")
.current_dir("test")
.stdout(Stdio::null()) .stdout(Stdio::null())
.stderr(Stdio::null()) .stderr(Stdio::null())
.stdin(Stdio::piped()) .stdin(Stdio::piped())
@ -71,7 +83,7 @@ impl Server {
if let Some(mut input) = input { if let Some(mut input) = input {
thread::spawn(move || input(stdin)); thread::spawn(move || input(stdin));
} }
(Server { p: child }, addr) (Server { p: child, _temp: td }, addr)
} }
fn new_tcp(args: &[&str]) -> (Server, TcpStream) { fn new_tcp(args: &[&str]) -> (Server, TcpStream) {
@ -92,7 +104,7 @@ impl Server {
Server::new_tcp(&["-www"]) Server::new_tcp(&["-www"])
} }
#[cfg(any(feature = "alpn", feature = "npn"))] #[cfg(all(any(feature = "alpn", feature = "npn"), not(ossl101)))]
fn new_alpn() -> (Server, TcpStream) { fn new_alpn() -> (Server, TcpStream) {
Server::new_tcp(&["-www", Server::new_tcp(&["-www",
"-nextprotoneg", "-nextprotoneg",
@ -119,7 +131,7 @@ impl Server {
// but don't currently have a great way to do that so just wait for a // but don't currently have a great way to do that so just wait for a
// bit. // bit.
thread::sleep(Duration::from_millis(100)); 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(); socket.connect(&addr).unwrap();
(s, UdpConnected(socket)) (s, UdpConnected(socket))
} }
@ -205,7 +217,7 @@ macro_rules! run_test(
#[test] #[test]
fn sslv23() { fn sslv23() {
let (_s, stream) = Server::new(); let (_s, stream) = Server::new();
$blk(SslMethod::Sslv23, stream); $blk(SslMethod::Tls, stream);
} }
#[test] #[test]
@ -226,11 +238,6 @@ run_test!(new_sslstream, |method, stream| {
SslStream::connect(&SslContext::new(method).unwrap(), stream).unwrap(); 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| { run_test!(verify_untrusted, |method, stream| {
let mut ctx = SslContext::new(method).unwrap(); let mut ctx = SslContext::new(method).unwrap();
ctx.set_verify(SSL_VERIFY_PEER); 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. // Make sure every write call translates to a write call to the underlying socket.
#[test] #[test]
fn test_write_hits_stream() { 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 addr = listener.local_addr().unwrap();
let guard = thread::spawn(move || { let guard = thread::spawn(move || {
let ctx = SslContext::new(Sslv23).unwrap(); let ctx = SslContext::new(Tls).unwrap();
let stream = TcpStream::connect(addr).unwrap(); let stream = TcpStream::connect(addr).unwrap();
let mut stream = SslStream::connect(&ctx, stream).unwrap(); let mut stream = SslStream::connect(&ctx, stream).unwrap();
@ -403,7 +410,7 @@ fn test_write_hits_stream() {
stream stream
}); });
let mut ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Tls).unwrap();
ctx.set_verify(SSL_VERIFY_PEER); ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM).unwrap(); 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(); 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 = include_bytes!("../../../test/cert.pem");
let cert = X509::from_pem(cert).unwrap(); 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_private_key(&key).unwrap();
ctx.set_certificate(&cert).unwrap(); ctx.set_certificate(&cert).unwrap();
@ -451,7 +458,7 @@ run_test!(clear_ctx_options, |method, _| {
#[test] #[test]
fn test_write() { fn test_write() {
let (_s, stream) = Server::new(); 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.write_all("hello".as_bytes()).unwrap();
stream.flush().unwrap(); stream.flush().unwrap();
stream.write_all(" there".as_bytes()).unwrap(); stream.write_all(" there".as_bytes()).unwrap();
@ -461,7 +468,7 @@ fn test_write() {
#[test] #[test]
fn test_write_direct() { fn test_write_direct() {
let (_s, stream) = Server::new(); 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.write_all("hello".as_bytes()).unwrap();
stream.flush().unwrap(); stream.flush().unwrap();
stream.write_all(" there".as_bytes()).unwrap(); stream.write_all(" there".as_bytes()).unwrap();
@ -492,7 +499,7 @@ fn test_write_dtlsv1() {
#[test] #[test]
fn test_read() { fn test_read() {
let (_s, tcp) = Server::new(); 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.write_all("GET /\r\n\r\n".as_bytes()).unwrap();
stream.flush().unwrap(); stream.flush().unwrap();
io::copy(&mut stream, &mut io::sink()).ok().expect("read error"); io::copy(&mut stream, &mut io::sink()).ok().expect("read error");
@ -501,7 +508,7 @@ fn test_read() {
#[test] #[test]
fn test_read_direct() { fn test_read_direct() {
let (_s, tcp) = Server::new(); 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.write_all("GET /\r\n\r\n".as_bytes()).unwrap();
stream.flush().unwrap(); stream.flush().unwrap();
io::copy(&mut stream, &mut io::sink()).ok().expect("read error"); io::copy(&mut stream, &mut io::sink()).ok().expect("read error");
@ -510,7 +517,7 @@ fn test_read_direct() {
#[test] #[test]
fn test_pending() { fn test_pending() {
let (_s, tcp) = Server::new(); 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.write_all("GET /\r\n\r\n".as_bytes()).unwrap();
stream.flush().unwrap(); stream.flush().unwrap();
@ -533,7 +540,7 @@ fn test_pending() {
#[test] #[test]
fn test_state() { fn test_state() {
let (_s, tcp) = Server::new(); 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(), "SSLOK ");
assert_eq!(stream.ssl().state_string_long(), assert_eq!(stream.ssl().state_string_long(),
"SSL negotiation finished successfully"); "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 /// Tests that connecting with the client using ALPN, but the server not does not
/// break the existing connection behavior. /// break the existing connection behavior.
#[test] #[test]
#[cfg(feature = "alpn")] #[cfg(all(feature = "alpn", not(ossl101)))]
fn test_connect_with_unilateral_alpn() { fn test_connect_with_unilateral_alpn() {
let (_s, stream) = Server::new(); 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_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]); ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { 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 /// Tests that connecting with the client using NPN, but the server not does not
/// break the existing connection behavior. /// break the existing connection behavior.
#[test] #[test]
#[cfg(feature = "npn")] #[cfg(all(feature = "npn", not(ossl101)))]
fn test_connect_with_unilateral_npn() { fn test_connect_with_unilateral_npn() {
let (_s, stream) = Server::new(); 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_verify(SSL_VERIFY_PEER);
ctx.set_npn_protocols(&[b"http/1.1", b"spdy/3.1"]); ctx.set_npn_protocols(&[b"http/1.1", b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { 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 /// 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. /// lists of supported protocols have an overlap, the correct protocol is chosen.
#[test] #[test]
#[cfg(feature = "alpn")] #[cfg(all(feature = "alpn", not(ossl101)))]
fn test_connect_with_alpn_successful_multiple_matching() { fn test_connect_with_alpn_successful_multiple_matching() {
let (_s, stream) = Server::new_alpn(); 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_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"spdy/3.1", b"http/1.1"]); ctx.set_alpn_protocols(&[b"spdy/3.1", b"http/1.1"]);
match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { 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 /// 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. /// lists of supported protocols have an overlap, the correct protocol is chosen.
#[test] #[test]
#[cfg(feature = "npn")] #[cfg(all(feature = "npn", not(ossl101)))]
fn test_connect_with_npn_successful_multiple_matching() { fn test_connect_with_npn_successful_multiple_matching() {
let (_s, stream) = Server::new_alpn(); 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_verify(SSL_VERIFY_PEER);
ctx.set_npn_protocols(&[b"spdy/3.1", b"http/1.1"]); ctx.set_npn_protocols(&[b"spdy/3.1", b"http/1.1"]);
match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { 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 /// lists of supported protocols have an overlap -- with only ONE protocol
/// being valid for both. /// being valid for both.
#[test] #[test]
#[cfg(feature = "alpn")] #[cfg(all(feature = "alpn", not(ossl101)))]
fn test_connect_with_alpn_successful_single_match() { fn test_connect_with_alpn_successful_single_match() {
let (_s, stream) = Server::new_alpn(); 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_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"spdy/3.1"]); ctx.set_alpn_protocols(&[b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { 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 /// lists of supported protocols have an overlap -- with only ONE protocol
/// being valid for both. /// being valid for both.
#[test] #[test]
#[cfg(feature = "npn")] #[cfg(all(feature = "npn", not(ossl101)))]
fn test_connect_with_npn_successful_single_match() { fn test_connect_with_npn_successful_single_match() {
let (_s, stream) = Server::new_alpn(); 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_verify(SSL_VERIFY_PEER);
ctx.set_npn_protocols(&[b"spdy/3.1"]); ctx.set_npn_protocols(&[b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { 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 /// Tests that when the `SslStream` is created as a server stream, the protocols
/// are correctly advertised to the client. /// are correctly advertised to the client.
#[test] #[test]
#[cfg(feature = "npn")] #[cfg(all(feature = "npn", not(ossl101)))]
fn test_npn_server_advertise_multiple() { 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(); let localhost = listener.local_addr().unwrap();
// We create a different context instance for the server... // We create a different context instance for the server...
let listener_ctx = { 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_verify(SSL_VERIFY_PEER);
ctx.set_npn_protocols(&[b"http/1.1", b"spdy/3.1"]); ctx.set_npn_protocols(&[b"http/1.1", b"spdy/3.1"]);
assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM) 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 _ = 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_verify(SSL_VERIFY_PEER);
ctx.set_npn_protocols(&[b"spdy/3.1"]); ctx.set_npn_protocols(&[b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { 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 /// Tests that when the `SslStream` is created as a server stream, the protocols
/// are correctly advertised to the client. /// are correctly advertised to the client.
#[test] #[test]
#[cfg(feature = "alpn")] #[cfg(all(feature = "alpn", not(ossl101)))]
fn test_alpn_server_advertise_multiple() { 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(); let localhost = listener.local_addr().unwrap();
// We create a different context instance for the server... // We create a different context instance for the server...
let listener_ctx = { 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_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]); ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]);
assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM) 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 _ = 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_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"spdy/3.1"]); ctx.set_alpn_protocols(&[b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { 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 /// Test that Servers supporting ALPN don't report a protocol when none of their protocols match
/// the client's reported protocol. /// the client's reported protocol.
#[test] #[test]
#[cfg(feature = "alpn")] #[cfg(all(feature = "alpn", not(ossl101)))]
fn test_alpn_server_select_none() { 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(); let localhost = listener.local_addr().unwrap();
// We create a different context instance for the server... // We create a different context instance for the server...
let listener_ctx = { 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_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]); ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]);
assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM) 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 _ = 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_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"http/2"]); ctx.set_alpn_protocols(&[b"http/2"]);
match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { match ctx.set_CA_file(&Path::new("test/root-ca.pem")) {
@ -875,7 +882,7 @@ fn handshake(res: Result<SslStream<TcpStream>, HandshakeError<TcpStream>>)
fn test_write_nonblocking() { fn test_write_nonblocking() {
let (_s, stream) = Server::new(); let (_s, stream) = Server::new();
stream.set_nonblocking(true).unwrap(); 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 stream = handshake(SslStream::connect(&cx, stream));
let mut iterations = 0; let mut iterations = 0;
@ -913,7 +920,7 @@ fn test_write_nonblocking() {
fn test_read_nonblocking() { fn test_read_nonblocking() {
let (_s, stream) = Server::new(); let (_s, stream) = Server::new();
stream.set_nonblocking(true).unwrap(); 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 stream = handshake(SslStream::connect(&cx, stream));
let mut iterations = 0; let mut iterations = 0;
@ -965,7 +972,6 @@ fn test_read_nonblocking() {
#[test] #[test]
#[should_panic(expected = "blammo")] #[should_panic(expected = "blammo")]
#[cfg(feature = "nightly")]
fn write_panic() { fn write_panic() {
struct ExplodingStream(TcpStream); struct ExplodingStream(TcpStream);
@ -988,13 +994,12 @@ fn write_panic() {
let (_s, stream) = Server::new(); let (_s, stream) = Server::new();
let stream = ExplodingStream(stream); let stream = ExplodingStream(stream);
let ctx = SslContext::new(SslMethod::Sslv23).unwrap(); let ctx = SslContext::new(SslMethod::Tls).unwrap();
let _ = SslStream::connect(&ctx, stream); let _ = SslStream::connect(&ctx, stream);
} }
#[test] #[test]
#[should_panic(expected = "blammo")] #[should_panic(expected = "blammo")]
#[cfg(feature = "nightly")]
fn read_panic() { fn read_panic() {
struct ExplodingStream(TcpStream); struct ExplodingStream(TcpStream);
@ -1017,13 +1022,12 @@ fn read_panic() {
let (_s, stream) = Server::new(); let (_s, stream) = Server::new();
let stream = ExplodingStream(stream); let stream = ExplodingStream(stream);
let ctx = SslContext::new(SslMethod::Sslv23).unwrap(); let ctx = SslContext::new(SslMethod::Tls).unwrap();
let _ = SslStream::connect(&ctx, stream); let _ = SslStream::connect(&ctx, stream);
} }
#[test] #[test]
#[should_panic(expected = "blammo")] #[should_panic(expected = "blammo")]
#[cfg(feature = "nightly")]
fn flush_panic() { fn flush_panic() {
struct ExplodingStream(TcpStream); struct ExplodingStream(TcpStream);
@ -1046,20 +1050,20 @@ fn flush_panic() {
let (_s, stream) = Server::new(); let (_s, stream) = Server::new();
let stream = ExplodingStream(stream); let stream = ExplodingStream(stream);
let ctx = SslContext::new(SslMethod::Sslv23).unwrap(); let ctx = SslContext::new(SslMethod::Tls).unwrap();
let mut stream = SslStream::connect(&ctx, stream).unwrap(); let mut stream = SslStream::connect(&ctx, stream).ok().unwrap();
let _ = stream.flush(); let _ = stream.flush();
} }
#[test] #[test]
fn refcount_ssl_context() { fn refcount_ssl_context() {
let mut ssl = { let mut ssl = {
let ctx = SslContext::new(SslMethod::Sslv23).unwrap(); let ctx = SslContext::new(SslMethod::Tls).unwrap();
ssl::Ssl::new(&ctx).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); let _new_ctx_b = ssl.set_ssl_context(&new_ctx_a);
} }
} }
@ -1067,7 +1071,7 @@ fn refcount_ssl_context() {
#[test] #[test]
#[cfg_attr(windows, ignore)] // don't have a trusted CA list easily available :( #[cfg_attr(windows, ignore)] // don't have a trusted CA list easily available :(
fn default_verify_paths() { 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_default_verify_paths().unwrap();
ctx.set_verify(SSL_VERIFY_PEER); ctx.set_verify(SSL_VERIFY_PEER);
let s = TcpStream::connect("google.com:443").unwrap(); let s = TcpStream::connect("google.com:443").unwrap();
@ -1086,6 +1090,6 @@ fn default_verify_paths() {
fn add_extra_chain_cert() { fn add_extra_chain_cert() {
let cert = include_bytes!("../../../test/cert.pem"); let cert = include_bytes!("../../../test/cert.pem");
let cert = X509::from_pem(cert).unwrap(); 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(); ctx.add_extra_chain_cert(&cert).unwrap();
} }

View File

@ -11,9 +11,26 @@
// limitations under the License. // limitations under the License.
// //
use ffi;
use std::ffi::CStr; 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: /// OPENSSL_VERSION_NUMBER is a numeric release version identifier:
/// ///
/// `MNNFFPPS: major minor fix patch status` /// `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. /// 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 { 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". /// 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 { 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 /// The compiler flags set for the compilation process in the form "compiler: ..." if available or
/// "compiler: information not available" otherwise. /// "compiler: information not available" otherwise.
pub fn c_flags() -> &'static str { 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. /// 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 { 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. /// The "Configure" target of the library build in the form "platform: ..." if available or "platform: information not available" otherwise.
pub fn platform() -> &'static str { 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. /// The "OPENSSLDIR" setting of the library build in the form "OPENSSLDIR: "..."" if available or "OPENSSLDIR: N/A" otherwise.
pub fn dir() -> &'static str { 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 /// This test ensures that we do not segfault when calling the functions of this module

View File

@ -12,7 +12,6 @@ use std::marker::PhantomData;
use HashTypeInternals; use HashTypeInternals;
use asn1::Asn1Time; use asn1::Asn1Time;
#[cfg(feature = "x509_expiry")]
use asn1::Asn1TimeRef; use asn1::Asn1TimeRef;
use bio::{MemBio, MemBioSlice}; use bio::{MemBio, MemBioSlice};
@ -24,6 +23,19 @@ use ffi;
use nid::Nid; use nid::Nid;
use error::ErrorStack; 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; pub mod extension;
use self::extension::{ExtensionType, Extension}; use self::extension::{ExtensionType, Extension};
@ -36,7 +48,7 @@ pub struct SslString(&'static str);
impl<'s> Drop for SslString { impl<'s> Drop for SslString {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { 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 { impl SslString {
unsafe fn new(buf: *const c_char, len: c_int) -> SslString { unsafe fn new(buf: *const u8, len: c_int) -> SslString {
let slice = slice::from_raw_parts(buf as *const _, len as usize); let slice = slice::from_raw_parts(buf, len as usize);
SslString(str::from_utf8_unchecked(slice)) SslString(str::from_utf8_unchecked(slice))
} }
} }
@ -311,11 +323,11 @@ impl X509Generator {
let not_before = try!(Asn1Time::days_from_now(0)); let not_before = try!(Asn1Time::days_from_now(0));
let not_after = try!(Asn1Time::days_from_now(self.days)); 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 // If prev line succeded - ownership should go to cert
mem::forget(not_before); 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 // If prev line succeded - ownership should go to cert
mem::forget(not_after); mem::forget(not_after);
@ -350,9 +362,6 @@ impl X509Generator {
} }
/// Obtain a certificate signing request (CSR) /// 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<X509Req, ErrorStack> { pub fn request(&self, p_key: &PKey) -> Result<X509Req, ErrorStack> {
let cert = match self.sign(p_key) { let cert = match self.sign(p_key) {
Ok(c) => c, Ok(c) => c,
@ -363,9 +372,9 @@ impl X509Generator {
let req = ffi::X509_to_X509_REQ(cert.as_ptr(), ptr::null_mut(), ptr::null()); let req = ffi::X509_to_X509_REQ(cert.as_ptr(), ptr::null_mut(), ptr::null());
try_ssl_null!(req); 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() { 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(); let hash_fn = self.hash_type.evp_md();
@ -438,22 +447,18 @@ impl<'a> X509Ref<'a> {
} }
/// Returns certificate Not After validity period. /// Returns certificate Not After validity period.
/// Requires the `x509_expiry` feature.
#[cfg(feature = "x509_expiry")]
pub fn not_after<'b>(&'b self) -> Asn1TimeRef<'b> { pub fn not_after<'b>(&'b self) -> Asn1TimeRef<'b> {
unsafe { 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()); assert!(!date.is_null());
Asn1TimeRef::from_ptr(date) Asn1TimeRef::from_ptr(date)
} }
} }
/// Returns certificate Not Before validity period. /// Returns certificate Not Before validity period.
/// Requires the `x509_expiry` feature.
#[cfg(feature = "x509_expiry")]
pub fn not_before<'b>(&'b self) -> Asn1TimeRef<'b> { pub fn not_before<'b>(&'b self) -> Asn1TimeRef<'b> {
unsafe { 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()); assert!(!date.is_null());
Asn1TimeRef::from_ptr(date) Asn1TimeRef::from_ptr(date)
} }
@ -496,7 +501,7 @@ impl X509 {
/// Reads a certificate from DER. /// Reads a certificate from DER.
pub fn from_der(buf: &[u8]) -> Result<X509, ErrorStack> { pub fn from_der(buf: &[u8]) -> Result<X509, ErrorStack> {
unsafe { 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 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)); let x509 = try_ssl_null!(ffi::d2i_X509(ptr::null_mut(), &mut ptr, len));
Ok(X509::from_ptr(x509)) Ok(X509::from_ptr(x509))
@ -524,13 +529,11 @@ impl Deref for X509 {
} }
} }
#[cfg(feature = "x509_clone")]
impl Clone for X509 { impl Clone for X509 {
/// Requires the `x509_clone` feature.
fn clone(&self) -> X509 { fn clone(&self) -> X509 {
unsafe { unsafe {
::c_helpers::rust_0_8_X509_clone(self.as_ptr()); compat::X509_up_ref(self.as_ptr());
X509::new(self.as_ptr()) X509::from_ptr(self.as_ptr())
} }
} }
} }
@ -561,7 +564,7 @@ impl<'x> X509Name<'x> {
return None; 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); let len = ffi::ASN1_STRING_to_UTF8(&mut str_from_asn1, asn1_str);
if len < 0 { if len < 0 {
@ -779,22 +782,43 @@ pub struct GeneralNames<'a> {
} }
impl<'a> Drop for GeneralNames<'a> { impl<'a> Drop for GeneralNames<'a> {
#[cfg(ossl10x)]
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
// This transmute is dubious but it's what openssl itself does... // 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 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 c_void) = mem::transmute(free);
ffi::sk_pop_free(&mut (*self.stack).stack, Some(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> { impl<'a> GeneralNames<'a> {
/// Returns the number of `GeneralName`s in this structure. /// Returns the number of `GeneralName`s in this structure.
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self._len()
}
#[cfg(ossl10x)]
fn _len(&self) -> usize {
unsafe { (*self.stack).stack.num as 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`. /// Returns the specified `GeneralName`.
/// ///
/// # Panics /// # Panics
@ -803,14 +827,23 @@ impl<'a> GeneralNames<'a> {
pub fn get(&self, idx: usize) -> GeneralName<'a> { pub fn get(&self, idx: usize) -> GeneralName<'a> {
unsafe { unsafe {
assert!(idx < self.len()); assert!(idx < self.len());
GeneralName { GeneralName {
name: *(*self.stack).stack.data.offset(idx as isize) as *const ffi::GENERAL_NAME, name: self._get(idx),
m: PhantomData, 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. /// Returns an iterator over the `GeneralName`s in this structure.
pub fn iter(&self) -> GeneralNamesIter { pub fn iter(&self) -> GeneralNamesIter {
GeneralNamesIter { GeneralNamesIter {
@ -870,7 +903,7 @@ impl<'a> GeneralName<'a> {
return None; 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 len = ffi::ASN1_STRING_length((*self.name).d as *mut _);
let slice = slice::from_raw_parts(ptr as *const u8, len as usize); let slice = slice::from_raw_parts(ptr as *const u8, len as usize);
@ -888,7 +921,7 @@ impl<'a> GeneralName<'a> {
return None; 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 len = ffi::ASN1_STRING_length((*self.name).d as *mut _);
Some(slice::from_raw_parts(ptr as *const u8, len as usize)) 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"); "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
}
}
}

View File

@ -69,7 +69,6 @@ fn test_cert_gen_extension_bad_ordering() {
} }
#[test] #[test]
#[cfg(feature = "x509_generator_request")]
fn test_req_gen() { fn test_req_gen() {
let pkey = pkey(); let pkey = pkey();
@ -93,7 +92,6 @@ fn test_cert_loading() {
} }
#[test] #[test]
#[cfg(feature = "x509_expiry")]
fn test_cert_issue_validity() { fn test_cert_issue_validity() {
let cert = include_bytes!("../../test/cert.pem"); let cert = include_bytes!("../../test/cert.pem");
let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");

View File

@ -1,33 +1,48 @@
#!/bin/bash #!/bin/bash
set -e
set -ex
MAX_REDIRECTS=5 MAX_REDIRECTS=5
OPENSSL=openssl-1.0.2h.tar.gz OPENSSL=openssl-$BUILD_OPENSSL_VERSION.tar.gz
OUT=/tmp/$OPENSSL 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 if [ "$TRAVIS_OS_NAME" == "osx" ]; then
exit 0 exit 0
fi fi
if [ "$TARGET" == "arm-unknown-linux-gnueabihf" ]; then if [ "$BUILD_OPENSSL_VERSION" == "" ]; then
export C_INCLUDE_PATH=/usr/arm-linux-gnueabihf/include exit 0
CROSS=arm-linux-gnueabihf- 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 OS_COMPILER=linux-armv4
export AR=arm-linux-gnueabihf-ar
export CC=arm-linux-gnueabihf-gcc
else else
OS_COMPILER=linux-x86_64 OS_COMPILER=linux-x86_64
fi fi
mkdir -p /tmp/openssl mkdir -p /tmp/openssl
cp $me /tmp/openssl/$myname
cd /tmp/openssl cd /tmp/openssl
curl -o $OUT -L --max-redirs $MAX_REDIRECTS https://openssl.org/source/$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 || 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 tar --strip-components=1 -xzf $OUT
./Configure --prefix=$HOME/openssl shared --cross-compile-prefix=$CROSS $OS_COMPILER ./Configure --prefix=$HOME/openssl $OS_COMPILER -fPIC $OS_FLAGS
make
make -j$(nproc)
make install make install
cp $myname $HOME/openssl/$myname

View File

@ -1,32 +1,15 @@
#!/bin/bash #!/bin/bash
set -e set -e
MAIN_TARGETS=https://static.rust-lang.org/dist if [ "$BUILD_OPENSSL_VERSION" != "" ]; then
FEATURES="aes_xts aes_ctr npn alpn rfc5114 ecdh_auto"
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"
fi fi
if [ "$TRAVIS_OS_NAME" != "osx" ]; then if [ -d "$HOME/openssl/lib" ]; then
export OPENSSL_LIB_DIR=$HOME/openssl/lib export OPENSSL_DIR=$HOME/openssl
export OPENSSL_INCLUDE_DIR=$HOME/openssl/include export PATH=$HOME/openssl/bin:$PATH
export LD_LIBRARY_PATH=$HOME/openssl/lib:$LD_LIBRARY_PATH
fi fi
if [ -n "$TARGET" ]; then cargo run --manifest-path systest/Cargo.toml --target $TARGET
FLAGS="--target=$TARGET" exec cargo test --manifest-path openssl/Cargo.toml --target $TARGET \
COMMAND="build" --features "$FEATURES"
# 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")

12
systest/Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "systest"
version = "0.1.0"
authors = ["Alex Crichton <alex@alexcrichton.com>"]
build = "build.rs"
[dependencies]
libc = "0.2"
openssl-sys = { path = "../openssl-sys" }
[build-dependencies]
ctest = "0.1"

110
systest/build.rs Normal file
View File

@ -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");
}

9
systest/src/main.rs Normal file
View File

@ -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"));