Merge branch 'release-v0.9.0' into release
This commit is contained in:
commit
a0b56c4378
104
.travis.yml
104
.travis.yml
|
|
@ -1,28 +1,86 @@
|
|||
language: rust
|
||||
sudo: false
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-arm-linux-gnueabihf
|
||||
rust:
|
||||
- nightly
|
||||
- 1.9.0
|
||||
os:
|
||||
- osx
|
||||
- linux
|
||||
sudo: required
|
||||
rust: stable
|
||||
dist: trusty
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- TEST_FEATURES=false
|
||||
- TEST_FEATURES=true
|
||||
global:
|
||||
- TARGET=x86_64-unknown-linux-gnu
|
||||
- BUILD_OPENSSL_VERSION=1.0.1u
|
||||
matrix:
|
||||
# include:
|
||||
# - os: linux
|
||||
# env: TARGET=arm-unknown-linux-gnueabihf TEST_FEATURES=true
|
||||
# rust: 1.7.0
|
||||
exclude:
|
||||
- os: osx
|
||||
env: TEST_FEATURES=true
|
||||
include:
|
||||
# ARM-bit version compat
|
||||
- env: >
|
||||
TARGET=arm-unknown-linux-gnueabihf
|
||||
BUILD_OPENSSL_VERSION=1.0.2h
|
||||
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc
|
||||
QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf
|
||||
RUST_TEST_THREADS=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-arm-linux-gnueabihf
|
||||
- qemu-user-static
|
||||
- libc6-dev-armhf-cross
|
||||
- binfmt-support
|
||||
- env: >
|
||||
TARGET=arm-unknown-linux-gnueabihf
|
||||
BUILD_OPENSSL_VERSION=1.1.0b
|
||||
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc
|
||||
QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf
|
||||
RUST_TEST_THREADS=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-arm-linux-gnueabihf
|
||||
- qemu-user-static
|
||||
- libc6-dev-armhf-cross
|
||||
- binfmt-support
|
||||
|
||||
# Minimum version supported
|
||||
- rust: 1.9.0
|
||||
|
||||
# beta/nightly channels
|
||||
- rust: beta
|
||||
- rust: nightly
|
||||
|
||||
# 64-bit version compat
|
||||
- env: BUILD_OPENSSL_VERSION=1.0.2h
|
||||
- env: BUILD_OPENSSL_VERSION=1.1.0b
|
||||
|
||||
# 32-bit version compat
|
||||
- env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.1u
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.2h
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.1.0b
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
|
||||
# osx 32/64
|
||||
- os: osx
|
||||
env: TARGET=x86_64-apple-darwin
|
||||
- os: osx
|
||||
env: TARGET=i686-apple-darwin
|
||||
install: brew uninstall openssl && brew install openssl --universal
|
||||
|
||||
|
||||
before_install:
|
||||
- ./openssl/test/build.sh
|
||||
- ./openssl/test/build.sh
|
||||
- curl https://static.rust-lang.org/rustup.sh |
|
||||
sh -s -- --add-target=$TARGET --disable-sudo -y --prefix=`rustc --print sysroot`
|
||||
script:
|
||||
- ./openssl/test/run.sh
|
||||
- ./openssl/test/run.sh
|
||||
|
||||
cache:
|
||||
cargo: true
|
||||
directories:
|
||||
- $HOME/openssl
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
[workspace]
|
||||
members = ["openssl", "openssl-sys"]
|
||||
members = ["openssl", "openssl-sys", "systest"]
|
||||
|
|
|
|||
120
README.md
120
README.md
|
|
@ -2,17 +2,26 @@
|
|||
|
||||
[](https://travis-ci.org/sfackler/rust-openssl)
|
||||
|
||||
[Documentation](https://sfackler.github.io/rust-openssl/doc/v0.8.3/openssl).
|
||||
[Documentation](https://sfackler.github.io/rust-openssl/doc/v0.9.0/openssl).
|
||||
|
||||
## Warning
|
||||
|
||||
This README does not correspond to rust-openssl 0.7.x. See
|
||||
[here](https://github.com/sfackler/rust-openssl/blob/b8fb29db5c246175a096260eacca38180cd77dd0/README.md)
|
||||
for that README.
|
||||
|
||||
## Building
|
||||
|
||||
rust-openssl depends on both the OpenSSL runtime libraries and headers.
|
||||
rust-openssl depends on the OpenSSL runtime libraries version 1.0.1 or above.
|
||||
Currently the libraries need to be present in the build environment before this
|
||||
crate is compiled, and some instructions of how to do this are in the sections
|
||||
below.
|
||||
|
||||
### Linux
|
||||
|
||||
On Linux, you can install OpenSSL via your package manager. The headers are
|
||||
sometimes provided in a separate package than the runtime libraries - look for
|
||||
something like `openssl-devel` or `libssl-dev`.
|
||||
On Linux, you can typically install OpenSSL via your package manager. The
|
||||
headers are sometimes provided in a separate package than the runtime libraries
|
||||
- look for something like `openssl-devel` or `libssl-dev`.
|
||||
|
||||
```bash
|
||||
# On Ubuntu
|
||||
|
|
@ -23,79 +32,78 @@ sudo pacman -S openssl
|
|||
sudo dnf install openssl-devel
|
||||
```
|
||||
|
||||
If installation via a package manager is not possible, or if you're cross
|
||||
compiling to a separate target, you'll typically need to compile OpenSSL from
|
||||
source. That can normally be done with:
|
||||
|
||||
```
|
||||
curl -O https://www.openssl.org/source/openssl-1.1.0b.tar.gz
|
||||
tar xf openssl-1.1.0b.tar.gz
|
||||
cd openssl-1.1.0b
|
||||
export CC=...
|
||||
./Configure --prefix=... linux-x86_64 -fPIC
|
||||
make -j$(nproc)
|
||||
make install
|
||||
```
|
||||
|
||||
### OSX
|
||||
|
||||
OpenSSL 0.9.8 is preinstalled on OSX. Some features are only available when
|
||||
linking against OpenSSL 1.0.0 or greater; see below on how to point
|
||||
rust-openssl to a separate installation. OSX releases starting at 10.11, "El
|
||||
Capitan", no longer include OpenSSL headers which will prevent the `openssl`
|
||||
crate from compiling.
|
||||
Although OpenSSL 0.9.8 is preinstalled on OSX this library is being phased out
|
||||
of OSX and this crate also does not support this version of OpenSSL. To use this
|
||||
crate on OSX you'll need to install OpenSSL via some alternate means, typically
|
||||
homebrew:
|
||||
|
||||
For OSX 10.11 you can use brew to install OpenSSL and then set the environment variables
|
||||
as described below.
|
||||
```bash
|
||||
brew install openssl
|
||||
export OPENSSL_INCLUDE_DIR=`brew --prefix openssl`/include
|
||||
export OPENSSL_LIB_DIR=`brew --prefix openssl`/lib
|
||||
```
|
||||
|
||||
May be necessary clean the repository with `cargo clean` before build again.
|
||||
### Windows MSVC
|
||||
|
||||
### Windows
|
||||
On MSVC it's unfortunately not always a trivial process acquiring OpenSSL.
|
||||
Perhaps the easiest way to do this right now is to download [precompiled
|
||||
binaries] and install them on your system. Currently it's recommended to
|
||||
install the 1.1.0b light installation if you're choosing this route.
|
||||
|
||||
On Windows, consider building with [mingw-w64](http://mingw-w64.org/).
|
||||
Build script will try to find mingw in `PATH` environment variable to provide
|
||||
Cargo with location where openssl libs from mingw-w64 package may be found.
|
||||
[precompiled binaries]: http://slproweb.com/products/Win32OpenSSL.html
|
||||
|
||||
mingw-w64 can be easily installed by using [MSYS2](http://msys2.github.io/). Install MSYS2 according to the instructions, and then, from an MSYS2 Shell, install mingw-w64:
|
||||
Once a precompiled binary is installed you can configure this crate to find the
|
||||
installation via an environment variable:
|
||||
|
||||
32-bit:
|
||||
```bash
|
||||
pacman -S mingw-w64-i686-gcc
|
||||
```
|
||||
|
||||
64-bit
|
||||
```bash
|
||||
pacman -S mingw-w64-x86_64-gcc
|
||||
```
|
||||
set OPENSSL_DIR=C:\OpenSSL-Win64
|
||||
```
|
||||
|
||||
and then install the mingw-w64 toolchain.
|
||||
After that, you're just a `cargo build` away!
|
||||
|
||||
32-bit:
|
||||
```bash
|
||||
pacman -S mingw-w64-i686-toolchain
|
||||
### Windows GNU (MinGW)
|
||||
|
||||
The easiest way to acquire OpenSSL when working with MinGW is to ensure you're
|
||||
using [MSYS2](http://msys2.github.io) and to then execute:
|
||||
|
||||
```
|
||||
# 32-bit
|
||||
pacman -S mingw-w64-i686-openssl
|
||||
|
||||
# 64-bit
|
||||
pacman -S mingw-w64-x86_64-openssl
|
||||
```
|
||||
|
||||
64-bit:
|
||||
```bash
|
||||
pacman -S mingw-w64-x86_64-toolchain
|
||||
```
|
||||
|
||||
Alternatively, install OpenSSL from [here][1]. Cargo will not be able to find OpenSSL if it's
|
||||
installed to the default location. You can either copy the `include/openssl`
|
||||
directory, `libssl32.dll`, and `libeay32.dll` to locations that Cargo can find
|
||||
or pass the location to Cargo via environment variables:
|
||||
|
||||
```bash
|
||||
env OPENSSL_LIB_DIR=C:/OpenSSL-Win64 OPENSSL_INCLUDE_DIR=C:/OpenSSL-Win64/include cargo build
|
||||
```
|
||||
And after that, a `cargo build` should be all you need!
|
||||
|
||||
### Manual configuration
|
||||
|
||||
rust-openssl's build script will by default attempt to locate OpenSSL via
|
||||
pkg-config. This will not work in some situations, for example, on systems that
|
||||
don't have pkg-config, when cross compiling, or when using a copy of OpenSSL
|
||||
pkg-config or other system-specific mechanisms. This will not work in some
|
||||
situations however, for example cross compiling or when using a copy of OpenSSL
|
||||
other than the normal system install.
|
||||
|
||||
The build script can be configured via environment variables:
|
||||
* `OPENSSL_LIB_DIR` - If specified, a directory that will be used to find
|
||||
OpenSSL runtime libraries.
|
||||
* `OPENSSL_INCLUDE_DIR` - If specified, a directory that will be used to find
|
||||
OpenSSL headers.
|
||||
|
||||
* `OPENSSL_DIR` - If specified, a directory that will be used to find
|
||||
OpenSSL installation. It's expected that under this directory the `include`
|
||||
folder has header files and a `lib` folder has the runtime libraries.
|
||||
* `OPENSSL_STATIC` - If specified, OpenSSL libraries will be statically rather
|
||||
than dynamically linked.
|
||||
than dynamically linked.
|
||||
|
||||
If either `OPENSSL_LIB_DIR` or `OPENSSL_INCLUDE_DIR` are specified, then the
|
||||
build script will skip the pkg-config step.
|
||||
|
||||
[1]: http://slproweb.com/products/Win32OpenSSL.html
|
||||
If `OPENSSL_DIR` is specified, then the build script will skip the pkg-config
|
||||
step.
|
||||
|
|
|
|||
50
appveyor.yml
50
appveyor.yml
|
|
@ -1,25 +1,45 @@
|
|||
environment:
|
||||
OPENSSL_INCLUDE_DIR: C:\OpenSSL\include
|
||||
OPENSSL_LIB_DIR: C:\OpenSSL\lib
|
||||
OPENSSL_LIBS: ssleay32:libeay32
|
||||
SSL_CERT_FILE: "C:\\OpenSSL\\cacert.pem"
|
||||
matrix:
|
||||
- TARGET: i686-pc-windows-gnu
|
||||
BITS: 32
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
BITS: 64
|
||||
# 1.1.0, 64/32 bit
|
||||
- TARGET: i686-pc-windows-gnu
|
||||
BITS: 32
|
||||
MSYS2: 1
|
||||
OPENSSL_VERSION: 1_1_0b
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
BITS: 64
|
||||
OPENSSL_VERSION: 1_1_0b
|
||||
OPENSSL_DIR: C:\OpenSSL
|
||||
|
||||
# 1.0.2, 64/32 bit
|
||||
- TARGET: x86_64-pc-windows-gnu
|
||||
BITS: 64
|
||||
MSYS2: 1
|
||||
OPENSSL_VERSION: 1_0_2j
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
BITS: 32
|
||||
OPENSSL_VERSION: 1_0_2j
|
||||
OPENSSL_DIR: C:\OpenSSL
|
||||
install:
|
||||
- ps: Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-1_0_2h.exe"
|
||||
- Win%BITS%OpenSSL-1_0_2h.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL"
|
||||
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.9.0-${env:TARGET}.exe"
|
||||
- rust-1.9.0-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
|
||||
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
|
||||
- SET PATH=%PATH%;C:\MinGW\bin
|
||||
# install OpenSSL
|
||||
- ps: Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-${env:OPENSSL_VERSION}.exe"
|
||||
- Win%BITS%OpenSSL-%OPENSSL_VERSION%.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL"
|
||||
- ps: Start-FileDownload "https://curl.haxx.se/ca/cacert.pem" -FileName "C:\OpenSSL\cacert.pem"
|
||||
|
||||
# Install Rust
|
||||
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
|
||||
- rustup-init.exe -y --default-host %TARGET%
|
||||
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
|
||||
- if defined MSYS2 set PATH=C:\msys64\mingw%BITS%\bin;%PATH%
|
||||
- rustc -V
|
||||
- cargo -V
|
||||
|
||||
build: false
|
||||
|
||||
# Don't run doctests due to rust-lang/cargo#1592
|
||||
test_script:
|
||||
- cargo test --lib --manifest-path openssl/Cargo.toml
|
||||
- cargo run --manifest-path systest/Cargo.toml --target %TARGET%
|
||||
- cargo test --manifest-path openssl/Cargo.toml --target %TARGET%
|
||||
|
||||
cache:
|
||||
- target
|
||||
- C:\Users\appveyor\.cargo\registry
|
||||
|
|
|
|||
|
|
@ -1,47 +1,21 @@
|
|||
[package]
|
||||
name = "openssl-sys"
|
||||
version = "0.7.17"
|
||||
version = "0.9.0"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>",
|
||||
"Steven Fackler <sfackler@gmail.com>"]
|
||||
license = "MIT"
|
||||
description = "FFI bindings to OpenSSL"
|
||||
repository = "https://github.com/sfackler/rust-openssl"
|
||||
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.17/openssl_sys"
|
||||
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.9.0/openssl_sys"
|
||||
links = "openssl"
|
||||
build = "build.rs"
|
||||
|
||||
[features]
|
||||
tlsv1_2 = []
|
||||
tlsv1_1 = []
|
||||
dtlsv1 = []
|
||||
dtlsv1_2 = []
|
||||
sslv2 = []
|
||||
sslv3 = []
|
||||
aes_xts = []
|
||||
aes_ctr = []
|
||||
npn = []
|
||||
alpn = []
|
||||
rfc5114 = []
|
||||
pkcs5_pbkdf2_hmac = []
|
||||
ecdh_auto = []
|
||||
hmac_clone = []
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[build-dependencies]
|
||||
pkg-config = "0.3"
|
||||
|
||||
[target.le32-unknown-nacl.dependencies]
|
||||
libressl-pnacl-sys = "2.1.0"
|
||||
[target.x86_64-unknown-nacl.dependencies]
|
||||
libressl-pnacl-sys = "2.1.0"
|
||||
[target.i686-unknown-nacl.dependencies]
|
||||
libressl-pnacl-sys = "2.1.0"
|
||||
[target.arm-unknown-nacl.dependencies]
|
||||
libressl-pnacl-sys = "2.1.0"
|
||||
|
||||
# Only here to make sure we link to these in a static build on Windows
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
user32-sys = "0.2"
|
||||
gdi32-sys = "0.2"
|
||||
|
|
|
|||
|
|
@ -1,86 +1,345 @@
|
|||
extern crate pkg_config;
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
||||
// libressl_pnacl_sys links the libs needed.
|
||||
if target.ends_with("nacl") { return; }
|
||||
let openssl_dir = env::var_os("OPENSSL_DIR").unwrap_or_else(|| {
|
||||
find_openssl_dir(&target)
|
||||
});
|
||||
|
||||
let lib_dir = env::var("OPENSSL_LIB_DIR").ok();
|
||||
let include_dir = env::var("OPENSSL_INCLUDE_DIR").ok();
|
||||
|
||||
if lib_dir.is_none() && include_dir.is_none() {
|
||||
// rustc doesn't seem to work with pkg-config's output in mingw64
|
||||
if !target.contains("windows") {
|
||||
if let Ok(info) = pkg_config::find_library("openssl") {
|
||||
// avoid empty include paths as they are not supported by GCC
|
||||
if info.include_paths.len() > 0 {
|
||||
let paths = env::join_paths(info.include_paths).unwrap();
|
||||
println!("cargo:include={}", paths.to_str().unwrap());
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if let Some(mingw_paths) = get_mingw_in_path() {
|
||||
for path in mingw_paths {
|
||||
println!("cargo:rustc-link-search=native={}", path);
|
||||
}
|
||||
}
|
||||
let lib_dir = Path::new(&openssl_dir).join("lib");
|
||||
let include_dir = Path::new(&openssl_dir).join("include");
|
||||
if !Path::new(&lib_dir).exists() {
|
||||
panic!("OpenSSL library directory does not exist: {}",
|
||||
lib_dir.to_string_lossy());
|
||||
}
|
||||
|
||||
let libs_env = env::var("OPENSSL_LIBS").ok();
|
||||
let libs = match libs_env {
|
||||
Some(ref v) => v.split(":").collect(),
|
||||
None => if target.contains("windows") {
|
||||
if get_mingw_in_path().is_some() && lib_dir.is_none() && include_dir.is_none() {
|
||||
vec!["ssleay32", "eay32"]
|
||||
} else {
|
||||
vec!["ssl32", "eay32"]
|
||||
}
|
||||
} else {
|
||||
vec!["ssl", "crypto"]
|
||||
}
|
||||
};
|
||||
if !Path::new(&include_dir).exists() {
|
||||
panic!("OpenSSL include directory does not exist: {}",
|
||||
include_dir.to_string_lossy());
|
||||
}
|
||||
|
||||
let mode = if env::var_os("OPENSSL_STATIC").is_some() {
|
||||
"static"
|
||||
println!("cargo:rustc-link-search=native={}", lib_dir.to_string_lossy());
|
||||
println!("cargo:include={}", include_dir.to_string_lossy());
|
||||
|
||||
let version = validate_headers(&[include_dir.clone().into()],
|
||||
&[lib_dir.clone().into()]);
|
||||
|
||||
let libs = if (version.contains("0x10001") ||
|
||||
version.contains("0x10002")) &&
|
||||
target.contains("windows") {
|
||||
["ssleay32", "libeay32"]
|
||||
} else if target.contains("windows") {
|
||||
["libssl", "libcrypto"]
|
||||
} else {
|
||||
"dylib"
|
||||
["ssl", "crypto"]
|
||||
};
|
||||
|
||||
if let Some(lib_dir) = lib_dir {
|
||||
println!("cargo:rustc-link-search=native={}", lib_dir);
|
||||
}
|
||||
|
||||
for lib in libs {
|
||||
println!("cargo:rustc-link-lib={}={}", mode, lib);
|
||||
}
|
||||
|
||||
if let Some(include_dir) = include_dir {
|
||||
println!("cargo:include={}", include_dir);
|
||||
let kind = determine_mode(Path::new(&lib_dir), &libs);
|
||||
for lib in libs.iter() {
|
||||
println!("cargo:rustc-link-lib={}={}", kind, lib);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mingw_in_path() -> Option<Vec<String>> {
|
||||
match env::var_os("PATH") {
|
||||
Some(env_path) => {
|
||||
let paths: Vec<String> = env::split_paths(&env_path).filter_map(|path| {
|
||||
use std::ascii::AsciiExt;
|
||||
fn find_openssl_dir(target: &str) -> OsString {
|
||||
let host = env::var("HOST").unwrap();
|
||||
|
||||
match path.to_str() {
|
||||
Some(path_str) => {
|
||||
if path_str.to_ascii_lowercase().contains("mingw") {
|
||||
Some(path_str.to_string())
|
||||
} else { None }
|
||||
},
|
||||
None => None
|
||||
if host.contains("apple-darwin") && target.contains("apple-darwin") {
|
||||
let homebrew = Path::new("/usr/local/opt/openssl@1.1");
|
||||
if homebrew.exists() {
|
||||
return homebrew.to_path_buf().into()
|
||||
}
|
||||
let homebrew = Path::new("/usr/local/opt/openssl");
|
||||
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:version=101");
|
||||
} else if version_text.contains("0x10002") {
|
||||
println!("cargo:rustc-cfg=ossl102");
|
||||
println!("cargo:version=102");
|
||||
} else if version_text.contains("0x10100") {
|
||||
println!("cargo:rustc-cfg=ossl110");
|
||||
println!("cargo:version=110");
|
||||
} 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.
|
||||
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 }
|
||||
},
|
||||
None => None
|
||||
// Look for `#define OPENSSL_FOO`, print out everything as our own
|
||||
// #[cfg] flag.
|
||||
let mut vars = vec![];
|
||||
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);
|
||||
vars.push(var);
|
||||
}
|
||||
}
|
||||
println!("cargo:conf={}", vars.join(","));
|
||||
|
||||
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
|
|
@ -0,0 +1,607 @@
|
|||
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};
|
||||
#[cfg(not(ossl101))]
|
||||
use libc::time_t;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct stack_st_ASN1_OBJECT {
|
||||
pub stack: _STACK,
|
||||
}
|
||||
|
||||
#[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,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[cfg(not(ossl101))]
|
||||
pub struct X509_VERIFY_PARAM {
|
||||
pub name: *mut c_char,
|
||||
pub check_time: time_t,
|
||||
pub inh_flags: c_ulong,
|
||||
pub flags: c_ulong,
|
||||
pub purpose: c_int,
|
||||
pub trust: c_int,
|
||||
pub depth: c_int,
|
||||
pub policies: *mut stack_st_ASN1_OBJECT,
|
||||
pub id: *mut X509_VERIFY_PARAM_ID,
|
||||
}
|
||||
|
||||
#[cfg(not(ossl101))]
|
||||
pub enum X509_VERIFY_PARAM_ID {}
|
||||
|
||||
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() {}
|
||||
|
||||
// macros
|
||||
#[cfg(ossl102)]
|
||||
pub unsafe fn SSL_CTX_set_ecdh_auto(ctx: *mut SSL_CTX, onoff: c_int) -> c_int {
|
||||
::SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ::std::ptr::null_mut()) as c_int
|
||||
}
|
||||
|
||||
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);
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_SSL3_METHOD"))]
|
||||
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 X509_STORE_CTX_get_chain(ctx: *mut ::X509_STORE_CTX) -> *mut stack_st_X509;
|
||||
pub fn X509V3_EXT_nconf_nid(conf: *mut ::CONF, ctx: *mut ::X509V3_CTX, ext_nid: c_int, value: *mut c_char) -> *mut ::X509_EXTENSION;
|
||||
pub fn X509V3_EXT_nconf(conf: *mut ::CONF, ctx: *mut ::X509V3_CTX, name: *mut c_char, value: *mut c_char) -> *mut ::X509_EXTENSION;
|
||||
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 EVP_MD_CTX_create() -> *mut EVP_MD_CTX;
|
||||
pub fn EVP_MD_CTX_destroy(ctx: *mut EVP_MD_CTX);
|
||||
|
||||
pub fn sk_num(st: *const _STACK) -> c_int;
|
||||
pub fn sk_value(st: *const _STACK, n: c_int) -> *mut c_void;
|
||||
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;
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
use libc::{c_int, c_void, c_char, c_uchar, c_ulong, c_long, c_uint};
|
||||
|
||||
pub enum BIGNUM {}
|
||||
pub enum BIO {}
|
||||
pub enum BIO_METHOD {}
|
||||
pub enum CRYPTO_EX_DATA {}
|
||||
pub enum DH {}
|
||||
pub enum DSA {}
|
||||
pub enum EVP_CIPHER {}
|
||||
pub enum EVP_MD_CTX {}
|
||||
pub enum EVP_PKEY {}
|
||||
pub enum HMAC_CTX {}
|
||||
pub enum OPENSSL_STACK {}
|
||||
pub enum RSA {}
|
||||
pub enum SSL_CTX {}
|
||||
pub enum stack_st_ASN1_OBJECT {}
|
||||
pub enum stack_st_GENERAL_NAME {}
|
||||
pub enum stack_st_OPENSSL_STRING {}
|
||||
pub enum stack_st_void {}
|
||||
pub enum stack_st_X509 {}
|
||||
pub enum stack_st_X509_ATTRIBUTE {}
|
||||
pub enum stack_st_X509_EXTENSION {}
|
||||
pub enum X509 {}
|
||||
pub enum X509_VERIFY_PARAM {}
|
||||
|
||||
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 const X509_CHECK_FLAG_NEVER_CHECK_SUBJECT: c_uint = 0x20;
|
||||
|
||||
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 X509V3_EXT_nconf_nid(conf: *mut ::CONF, ctx: *mut ::X509V3_CTX, ext_nid: c_int, value: *const c_char) -> *mut ::X509_EXTENSION;
|
||||
pub fn X509V3_EXT_nconf(conf: *mut ::CONF, ctx: *mut ::X509V3_CTX, name: *const c_char, value: *const c_char) -> *mut ::X509_EXTENSION;
|
||||
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 X509_STORE_CTX_get0_chain(ctx: *mut ::X509_STORE_CTX) -> *mut stack_st_X509;
|
||||
pub fn EVP_MD_CTX_new() -> *mut EVP_MD_CTX;
|
||||
pub fn EVP_MD_CTX_free(ctx: *mut EVP_MD_CTX);
|
||||
|
||||
pub fn OpenSSL_version_num() -> c_ulong;
|
||||
pub fn OpenSSL_version(key: c_int) -> *const c_char;
|
||||
pub fn OPENSSL_sk_free(st: *mut ::OPENSSL_STACK);
|
||||
pub fn OPENSSL_sk_pop_free(st: *mut ::OPENSSL_STACK, free: Option<unsafe extern "C" fn (*mut c_void)>);
|
||||
pub fn OPENSSL_sk_pop(st: *mut ::OPENSSL_STACK) -> *mut c_void;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,51 +1,29 @@
|
|||
[package]
|
||||
name = "openssl"
|
||||
version = "0.8.3"
|
||||
version = "0.9.0"
|
||||
authors = ["Steven Fackler <sfackler@gmail.com>"]
|
||||
license = "Apache-2.0"
|
||||
description = "OpenSSL bindings"
|
||||
repository = "https://github.com/sfackler/rust-openssl"
|
||||
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.8.3/openssl"
|
||||
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.9.0/openssl"
|
||||
readme = "../README.md"
|
||||
keywords = ["crypto", "tls", "ssl", "dtls"]
|
||||
build = "build.rs"
|
||||
exclude = ["test/*"]
|
||||
|
||||
[features]
|
||||
tlsv1_2 = ["openssl-sys/tlsv1_2"]
|
||||
tlsv1_1 = ["openssl-sys/tlsv1_1"]
|
||||
dtlsv1 = ["openssl-sys/dtlsv1"]
|
||||
dtlsv1_2 = ["openssl-sys/dtlsv1_2"]
|
||||
sslv2 = ["openssl-sys/sslv2"]
|
||||
sslv3 = ["openssl-sys/sslv3"]
|
||||
aes_xts = ["openssl-sys/aes_xts"]
|
||||
aes_ctr = ["openssl-sys/aes_ctr"]
|
||||
npn = ["openssl-sys/npn"]
|
||||
alpn = ["openssl-sys/alpn"]
|
||||
rfc5114 = ["openssl-sys/rfc5114"]
|
||||
ecdh_auto = ["openssl-sys/ecdh_auto"]
|
||||
pkcs5_pbkdf2_hmac = ["openssl-sys/pkcs5_pbkdf2_hmac"]
|
||||
hmac_clone = ["openssl-sys/hmac_clone"]
|
||||
|
||||
c_helpers = ["gcc"]
|
||||
x509_clone = ["c_helpers"]
|
||||
x509_generator_request = ["c_helpers"]
|
||||
x509_expiry = ["c_helpers"]
|
||||
ssl_context_clone = ["c_helpers"]
|
||||
hmac = ["c_helpers"]
|
||||
dh_from_params = ["c_helpers"]
|
||||
v101 = []
|
||||
v102 = []
|
||||
v110 = []
|
||||
|
||||
[dependencies]
|
||||
bitflags = "0.7"
|
||||
lazy_static = "0.2"
|
||||
libc = "0.2"
|
||||
openssl-sys = { version = "0.7.17", path = "../openssl-sys" }
|
||||
|
||||
[build-dependencies]
|
||||
gcc = { version = "0.3", optional = true }
|
||||
openssl-sys = { version = "0.9", path = "../openssl-sys" }
|
||||
|
||||
[dev-dependencies]
|
||||
rustc-serialize = "0.3"
|
||||
net2 = "0.2.16"
|
||||
tempdir = "0.3"
|
||||
winapi = "0.2"
|
||||
ws2_32-sys = "0.2"
|
||||
|
|
|
|||
|
|
@ -1,28 +1,24 @@
|
|||
#[cfg(feature = "c_helpers")]
|
||||
mod imp {
|
||||
extern crate gcc;
|
||||
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn main() {
|
||||
let mut config = gcc::Config::new();
|
||||
|
||||
if let Some(paths) = env::var_os("DEP_OPENSSL_INCLUDE") {
|
||||
for path in env::split_paths(&paths) {
|
||||
config.include(PathBuf::from(path));
|
||||
}
|
||||
}
|
||||
|
||||
config.file("src/c_helpers.c").compile("libc_helpers.a");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "c_helpers"))]
|
||||
mod imp {
|
||||
pub fn main() {}
|
||||
}
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
imp::main()
|
||||
match env::var("DEP_OPENSSL_VERSION") {
|
||||
Ok(ref v) if v == "101" => {
|
||||
println!("cargo:rustc-cfg=ossl101");
|
||||
println!("cargo:rustc-cfg=ossl10x");
|
||||
}
|
||||
Ok(ref v) if v == "102" => {
|
||||
println!("cargo:rustc-cfg=ossl102");
|
||||
println!("cargo:rustc-cfg=ossl10x");
|
||||
}
|
||||
Ok(ref v) if v == "110" => {
|
||||
println!("cargo:rustc-cfg=ossl110");
|
||||
}
|
||||
_ => panic!("Unable to detect OpenSSL version"),
|
||||
}
|
||||
|
||||
if let Ok(vars) = env::var("DEP_OPENSSL_CONF") {
|
||||
for var in vars.split(",") {
|
||||
println!("cargo:rustc-cfg=osslconf=\"{}\"", var);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
use ffi;
|
||||
use libc::c_long;
|
||||
use std::fmt;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
use std::str;
|
||||
|
||||
use {cvt, cvt_p};
|
||||
use bio::MemBio;
|
||||
use crypto::CryptoString;
|
||||
use error::ErrorStack;
|
||||
use types::{OpenSslType, OpenSslTypeRef};
|
||||
|
||||
type_!(Asn1Time, Asn1TimeRef, ffi::ASN1_TIME, ffi::ASN1_TIME_free);
|
||||
|
||||
impl fmt::Display for Asn1TimeRef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
unsafe {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
try!(cvt(ffi::ASN1_TIME_print(mem_bio.as_ptr(), self.as_ptr())));
|
||||
write!(f, "{}", str::from_utf8_unchecked(mem_bio.get_buf()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Asn1Time {
|
||||
fn from_period(period: c_long) -> Result<Asn1Time, ErrorStack> {
|
||||
ffi::init();
|
||||
|
||||
unsafe {
|
||||
let handle = try!(cvt_p(ffi::X509_gmtime_adj(ptr::null_mut(), period)));
|
||||
Ok(Asn1Time::from_ptr(handle))
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new time on specified interval in days from now
|
||||
pub fn days_from_now(days: u32) -> Result<Asn1Time, ErrorStack> {
|
||||
Asn1Time::from_period(days as c_long * 60 * 60 * 24)
|
||||
}
|
||||
}
|
||||
|
||||
type_!(Asn1String, Asn1StringRef, ffi::ASN1_STRING, ffi::ASN1_STRING_free);
|
||||
|
||||
impl Asn1StringRef {
|
||||
pub fn as_utf8(&self) -> Result<CryptoString, ErrorStack> {
|
||||
unsafe {
|
||||
let mut ptr = ptr::null_mut();
|
||||
let len = ffi::ASN1_STRING_to_UTF8(&mut ptr, self.as_ptr());
|
||||
if len < 0 {
|
||||
return Err(ErrorStack::get());
|
||||
}
|
||||
|
||||
Ok(CryptoString::from_raw_parts(ptr, len as usize))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
unsafe { slice::from_raw_parts(ASN1_STRING_data(self.as_ptr()), self.len()) }
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
unsafe { ffi::ASN1_STRING_length(self.as_ptr()) as usize }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(ossl101, ossl102))]
|
||||
use ffi::ASN1_STRING_data;
|
||||
|
||||
#[cfg(ossl110)]
|
||||
#[allow(bad_style)]
|
||||
unsafe fn ASN1_STRING_data(s: *mut ffi::ASN1_STRING) -> *mut ::libc::c_uchar {
|
||||
ffi::ASN1_STRING_get0_data(s) as *mut _
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
use libc::c_long;
|
||||
use std::{ptr, fmt};
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
|
||||
use bio::MemBio;
|
||||
use ffi;
|
||||
use error::ErrorStack;
|
||||
|
||||
/// Corresponds to the ASN.1 structure Time defined in RFC5280
|
||||
pub struct Asn1Time(Asn1TimeRef<'static>);
|
||||
|
||||
impl Asn1Time {
|
||||
/// Wraps existing ASN1_TIME and takes ownership
|
||||
pub unsafe fn from_ptr(handle: *mut ffi::ASN1_TIME) -> Asn1Time {
|
||||
Asn1Time(Asn1TimeRef::from_ptr(handle))
|
||||
}
|
||||
|
||||
fn from_period(period: c_long) -> Result<Asn1Time, ErrorStack> {
|
||||
ffi::init();
|
||||
|
||||
unsafe {
|
||||
let handle = try_ssl_null!(ffi::X509_gmtime_adj(ptr::null_mut(), period));
|
||||
Ok(Asn1Time::from_ptr(handle))
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new time on specified interval in days from now
|
||||
pub fn days_from_now(days: u32) -> Result<Asn1Time, ErrorStack> {
|
||||
Asn1Time::from_period(days as c_long * 60 * 60 * 24)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Asn1Time {
|
||||
type Target = Asn1TimeRef<'static>;
|
||||
|
||||
fn deref(&self) -> &Asn1TimeRef<'static> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// A borrowed Asn1Time
|
||||
pub struct Asn1TimeRef<'a>(*mut ffi::ASN1_TIME, PhantomData<&'a ()>);
|
||||
|
||||
impl<'a> Asn1TimeRef<'a> {
|
||||
/// Creates a new `Asn1TimeRef` wrapping the provided handle.
|
||||
pub unsafe fn from_ptr(handle: *mut ffi::ASN1_TIME) -> Asn1TimeRef<'a> {
|
||||
Asn1TimeRef(handle, PhantomData)
|
||||
}
|
||||
|
||||
/// Returns the raw handle
|
||||
pub fn as_ptr(&self) -> *mut ffi::ASN1_TIME {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for Asn1TimeRef<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
let as_str = unsafe {
|
||||
try_ssl!(ffi::ASN1_TIME_print(mem_bio.as_ptr(), self.0));
|
||||
String::from_utf8_unchecked(mem_bio.get_buf().to_owned())
|
||||
};
|
||||
write!(f, "{}", as_str)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Asn1Time {
|
||||
fn drop(&mut self) {
|
||||
unsafe { ffi::ASN1_TIME_free(self.as_ptr()) };
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ use std::slice;
|
|||
use libc::c_int;
|
||||
use ffi;
|
||||
|
||||
use cvt_p;
|
||||
use error::ErrorStack;
|
||||
|
||||
pub struct MemBioSlice<'a>(*mut ffi::BIO, PhantomData<&'a [u8]>);
|
||||
|
|
@ -21,9 +22,8 @@ impl<'a> MemBioSlice<'a> {
|
|||
ffi::init();
|
||||
|
||||
assert!(buf.len() <= c_int::max_value() as usize);
|
||||
let bio = unsafe {
|
||||
try_ssl_null!(ffi::BIO_new_mem_buf(buf.as_ptr() as *const _, buf.len() as c_int))
|
||||
};
|
||||
let bio =
|
||||
unsafe { try!(cvt_p(BIO_new_mem_buf(buf.as_ptr() as *const _, buf.len() as c_int))) };
|
||||
|
||||
Ok(MemBioSlice(bio, PhantomData))
|
||||
}
|
||||
|
|
@ -47,9 +47,7 @@ impl MemBio {
|
|||
pub fn new() -> Result<MemBio, ErrorStack> {
|
||||
ffi::init();
|
||||
|
||||
let bio = unsafe {
|
||||
try_ssl_null!(ffi::BIO_new(ffi::BIO_s_mem()))
|
||||
};
|
||||
let bio = unsafe { try!(cvt_p(ffi::BIO_new(ffi::BIO_s_mem()))) };
|
||||
Ok(MemBio(bio))
|
||||
}
|
||||
|
||||
|
|
@ -65,3 +63,12 @@ impl MemBio {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(ossl101))]
|
||||
use ffi::BIO_new_mem_buf;
|
||||
|
||||
#[cfg(ossl101)]
|
||||
#[allow(bad_style)]
|
||||
unsafe fn BIO_new_mem_buf(buf: *const ::libc::c_void, len: ::libc::c_int) -> *mut ffi::BIO {
|
||||
ffi::BIO_new_mem_buf(buf as *mut _, len)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,843 @@
|
|||
use ffi;
|
||||
use libc::c_int;
|
||||
use std::cmp::Ordering;
|
||||
use std::ffi::CString;
|
||||
use std::{fmt, ptr};
|
||||
use std::ops::{Add, Div, Mul, Neg, Rem, Shl, Shr, Sub, Deref};
|
||||
|
||||
use {cvt, cvt_p, cvt_n};
|
||||
use crypto::CryptoString;
|
||||
use error::ErrorStack;
|
||||
use types::{OpenSslType, OpenSslTypeRef};
|
||||
|
||||
/// Options for the most significant bits of a randomly generated `BigNum`.
|
||||
pub struct MsbOption(c_int);
|
||||
|
||||
/// The most significant bit of the number may be 0.
|
||||
pub const MSB_MAYBE_ZERO: MsbOption = MsbOption(-1);
|
||||
|
||||
/// The most significant bit of the number must be 1.
|
||||
pub const MSB_ONE: MsbOption = MsbOption(0);
|
||||
|
||||
/// The most significant two bits of the number must be 1.
|
||||
///
|
||||
/// The number of bits in the product of two such numbers will always be exactly twice the number
|
||||
/// of bits in the original numbers.
|
||||
pub const TWO_MSB_ONE: MsbOption = MsbOption(1);
|
||||
|
||||
type_!(BigNumContext, BigNumContextRef, ffi::BN_CTX, ffi::BN_CTX_free);
|
||||
|
||||
impl BigNumContext {
|
||||
/// Returns a new `BigNumContext`.
|
||||
pub fn new() -> Result<BigNumContext, ErrorStack> {
|
||||
unsafe { cvt_p(ffi::BN_CTX_new()).map(BigNumContext) }
|
||||
}
|
||||
}
|
||||
|
||||
impl BigNumRef {
|
||||
/// Erases the memory used by this `BigNum`, resetting its value to 0.
|
||||
///
|
||||
/// This can be used to destroy sensitive data such as keys when they are no longer needed.
|
||||
pub fn clear(&mut self) {
|
||||
unsafe { ffi::BN_clear(self.as_ptr()) }
|
||||
}
|
||||
|
||||
/// Adds a `u32` to `self`.
|
||||
pub fn add_word(&mut self, w: u32) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_add_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Subtracts a `u32` from `self`.
|
||||
pub fn sub_word(&mut self, w: u32) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_sub_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Multiplies a `u32` by `self`.
|
||||
pub fn mul_word(&mut self, w: u32) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_mul_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Divides `self` by a `u32`, returning the remainder.
|
||||
pub fn div_word(&mut self, w: u32) -> Result<u64, ErrorStack> {
|
||||
unsafe {
|
||||
let r = ffi::BN_div_word(self.as_ptr(), w.into());
|
||||
if r == ffi::BN_ULONG::max_value() {
|
||||
Err(ErrorStack::get())
|
||||
} else {
|
||||
Ok(r.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the result of `self` modulo `w`.
|
||||
pub fn mod_word(&self, w: u32) -> Result<u64, ErrorStack> {
|
||||
unsafe {
|
||||
let r = ffi::BN_mod_word(self.as_ptr(), w.into());
|
||||
if r == ffi::BN_ULONG::max_value() {
|
||||
Err(ErrorStack::get())
|
||||
} else {
|
||||
Ok(r.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Places a cryptographically-secure pseudo-random number nonnegative
|
||||
/// number less than `self` in `rnd`.
|
||||
pub fn rand_range(&self, rnd: &mut BigNumRef) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_rand_range(self.as_ptr(), rnd.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// The cryptographically weak counterpart to `rand_in_range`.
|
||||
pub fn pseudo_rand_range(&self, rnd: &mut BigNumRef) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_pseudo_rand_range(self.as_ptr(), rnd.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Sets bit `n`. Equivalent to `self |= (1 << n)`.
|
||||
///
|
||||
/// When setting a bit outside of `self`, it is expanded.
|
||||
pub fn set_bit(&mut self, n: i32) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_set_bit(self.as_ptr(), n.into())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Clears bit `n`, setting it to 0. Equivalent to `self &= ~(1 << n)`.
|
||||
///
|
||||
/// When clearing a bit outside of `self`, an error is returned.
|
||||
pub fn clear_bit(&mut self, n: i32) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_clear_bit(self.as_ptr(), n.into())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Returns `true` if the `n`th bit of `self` is set to 1, `false` otherwise.
|
||||
pub fn is_bit_set(&self, n: i32) -> bool {
|
||||
unsafe { ffi::BN_is_bit_set(self.as_ptr(), n.into()) == 1 }
|
||||
}
|
||||
|
||||
/// Truncates `self` to the lowest `n` bits.
|
||||
///
|
||||
/// An error occurs if `self` is already shorter than `n` bits.
|
||||
pub fn mask_bits(&mut self, n: i32) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_mask_bits(self.as_ptr(), n.into())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Places `a << 1` in `self`.
|
||||
pub fn lshift1(&mut self, a: &BigNumRef) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_lshift1(self.as_ptr(), a.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Places `a >> 1` in `self`.
|
||||
pub fn rshift1(&mut self, a: &BigNumRef) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_rshift1(self.as_ptr(), a.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Places `a + b` in `self`.
|
||||
pub fn checked_add(&mut self, a: &BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_add(self.as_ptr(), a.as_ptr(), b.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Places `a - b` in `self`.
|
||||
pub fn checked_sub(&mut self, a: &BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_sub(self.as_ptr(), a.as_ptr(), b.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Places `a << n` in `self`.
|
||||
pub fn lshift(&mut self, a: &BigNumRef, n: i32) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_lshift(self.as_ptr(), a.as_ptr(), n.into())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Places `a >> n` in `self`.
|
||||
pub fn rshift(&mut self, a: &BigNumRef, n: i32) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_rshift(self.as_ptr(), a.as_ptr(), n.into())).map(|_| ()) }
|
||||
}
|
||||
|
||||
pub fn to_owned(&self) -> Result<BigNum, ErrorStack> {
|
||||
unsafe { cvt_p(ffi::BN_dup(self.as_ptr())).map(|b| BigNum::from_ptr(b)) }
|
||||
}
|
||||
|
||||
/// Sets the sign of `self`.
|
||||
pub fn set_negative(&mut self, negative: bool) {
|
||||
unsafe { ffi::BN_set_negative(self.as_ptr(), negative as c_int) }
|
||||
}
|
||||
|
||||
/// Compare the absolute values of `self` and `oth`.
|
||||
///
|
||||
/// ```
|
||||
/// # use openssl::bn::BigNum;
|
||||
/// # use std::cmp::Ordering;
|
||||
/// let s = -BigNum::from_u32(8).unwrap();
|
||||
/// let o = BigNum::from_u32(8).unwrap();
|
||||
///
|
||||
/// assert_eq!(s.ucmp(&o), Ordering::Equal);
|
||||
/// ```
|
||||
pub fn ucmp(&self, oth: &BigNumRef) -> Ordering {
|
||||
unsafe { ffi::BN_ucmp(self.as_ptr(), oth.as_ptr()).cmp(&0) }
|
||||
}
|
||||
|
||||
pub fn is_negative(&self) -> bool {
|
||||
self._is_negative()
|
||||
}
|
||||
|
||||
#[cfg(ossl10x)]
|
||||
fn _is_negative(&self) -> bool {
|
||||
unsafe { (*self.as_ptr()).neg == 1 }
|
||||
}
|
||||
|
||||
#[cfg(ossl110)]
|
||||
fn _is_negative(&self) -> bool {
|
||||
unsafe { ffi::BN_is_negative(self.as_ptr()) == 1 }
|
||||
}
|
||||
|
||||
/// Returns the number of significant bits in `self`.
|
||||
pub fn num_bits(&self) -> i32 {
|
||||
unsafe { ffi::BN_num_bits(self.as_ptr()) as i32 }
|
||||
}
|
||||
|
||||
/// Returns the size of `self` in bytes.
|
||||
pub fn num_bytes(&self) -> i32 {
|
||||
(self.num_bits() + 7) / 8
|
||||
}
|
||||
|
||||
/// Generates a cryptographically strong pseudo-random `BigNum`, placing it in `self`.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `bits`: Length of the number in bits.
|
||||
/// * `msb`: The desired properties of the number.
|
||||
/// * `odd`: If `true`, the generated number will be odd.
|
||||
pub fn rand(&mut self, bits: i32, msb: MsbOption, odd: bool) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_rand(self.as_ptr(), bits.into(), msb.0, odd as c_int)).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// The cryptographically weak counterpart to `rand`.
|
||||
pub fn pseudo_rand(&mut self, bits: i32, msb: MsbOption, odd: bool) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::BN_pseudo_rand(self.as_ptr(), bits.into(), msb.0, odd as c_int)).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates a prime number, placing it in `self`.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `bits`: The length of the prime in bits (lower bound).
|
||||
/// * `safe`: If true, returns a "safe" prime `p` so that `(p-1)/2` is also prime.
|
||||
/// * `add`/`rem`: If `add` is set to `Some(add)`, `p % add == rem` will hold, where `p` is the
|
||||
/// generated prime and `rem` is `1` if not specified (`None`).
|
||||
pub fn generate_prime(&mut self,
|
||||
bits: i32,
|
||||
safe: bool,
|
||||
add: Option<&BigNumRef>,
|
||||
rem: Option<&BigNumRef>)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::BN_generate_prime_ex(self.as_ptr(),
|
||||
bits as c_int,
|
||||
safe as c_int,
|
||||
add.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut()),
|
||||
rem.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut()),
|
||||
ptr::null_mut()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Places the result of `a * b` in `self`.
|
||||
pub fn checked_mul(&mut self,
|
||||
a: &BigNumRef,
|
||||
b: &BigNumRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_mul(self.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Places the result of `a / b` in `self`.
|
||||
pub fn checked_div(&mut self,
|
||||
a: &BigNumRef,
|
||||
b: &BigNumRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::BN_div(self.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
a.as_ptr(),
|
||||
b.as_ptr(),
|
||||
ctx.as_ptr()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Places the result of `a % b` in `self`.
|
||||
pub fn checked_rem(&mut self,
|
||||
a: &BigNumRef,
|
||||
b: &BigNumRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::BN_div(ptr::null_mut(),
|
||||
self.as_ptr(),
|
||||
a.as_ptr(),
|
||||
b.as_ptr(),
|
||||
ctx.as_ptr()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Places the result of `a / b` in `self` and `a % b` in `rem`.
|
||||
pub fn div_rem(&mut self,
|
||||
rem: &mut BigNumRef,
|
||||
a: &BigNumRef,
|
||||
b: &BigNumRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::BN_div(self.as_ptr(),
|
||||
rem.as_ptr(),
|
||||
a.as_ptr(),
|
||||
b.as_ptr(),
|
||||
ctx.as_ptr()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Places the result of `a²` in `self`.
|
||||
pub fn sqr(&mut self, a: &BigNumRef, ctx: &mut BigNumContextRef) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_sqr(self.as_ptr(), a.as_ptr(), ctx.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Places the result of `a mod m` in `self`.
|
||||
pub fn nnmod(&mut self,
|
||||
a: &BigNumRef,
|
||||
m: &BigNumRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::BN_nnmod(self.as_ptr(), a.as_ptr(), m.as_ptr(), ctx.as_ptr())).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Places the result of `(a + b) mod m` in `self`.
|
||||
pub fn mod_add(&mut self,
|
||||
a: &BigNumRef,
|
||||
b: &BigNumRef,
|
||||
m: &BigNumRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::BN_mod_add(self.as_ptr(), a.as_ptr(), b.as_ptr(), m.as_ptr(), ctx.as_ptr()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Places the result of `(a - b) mod m` in `self`.
|
||||
pub fn mod_sub(&mut self,
|
||||
a: &BigNumRef,
|
||||
b: &BigNumRef,
|
||||
m: &BigNumRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::BN_mod_sub(self.as_ptr(), a.as_ptr(), b.as_ptr(), m.as_ptr(), ctx.as_ptr()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Places the result of `(a * b) mod m` in `self`.
|
||||
pub fn mod_mul(&mut self,
|
||||
a: &BigNumRef,
|
||||
b: &BigNumRef,
|
||||
m: &BigNumRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::BN_mod_mul(self.as_ptr(), a.as_ptr(), b.as_ptr(), m.as_ptr(), ctx.as_ptr()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Places the result of `a² mod m` in `self`.
|
||||
pub fn mod_sqr(&mut self,
|
||||
a: &BigNumRef,
|
||||
m: &BigNumRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::BN_mod_sqr(self.as_ptr(), a.as_ptr(), m.as_ptr(), ctx.as_ptr())).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Places the result of `a^p` in `self`.
|
||||
pub fn exp(&mut self,
|
||||
a: &BigNumRef,
|
||||
p: &BigNumRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_exp(self.as_ptr(), a.as_ptr(), p.as_ptr(), ctx.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Places the result of `a^p mod m` in `self`.
|
||||
pub fn mod_exp(&mut self,
|
||||
a: &BigNumRef,
|
||||
p: &BigNumRef,
|
||||
m: &BigNumRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::BN_mod_exp(self.as_ptr(), a.as_ptr(), p.as_ptr(), m.as_ptr(), ctx.as_ptr()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Places the inverse of `a` modulo `n` in `self`.
|
||||
pub fn mod_inverse(&mut self,
|
||||
a: &BigNumRef,
|
||||
n: &BigNumRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt_p(ffi::BN_mod_inverse(self.as_ptr(), a.as_ptr(), n.as_ptr(), ctx.as_ptr()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Places the greatest common denominator of `a` and `b` in `self`.
|
||||
pub fn gcd(&mut self,
|
||||
a: &BigNumRef,
|
||||
b: &BigNumRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::BN_gcd(self.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Checks whether `self` is prime.
|
||||
///
|
||||
/// Performs a Miller-Rabin probabilistic primality test with `checks` iterations.
|
||||
///
|
||||
/// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`.
|
||||
pub fn is_prime(&self, checks: i32, ctx: &mut BigNumContextRef) -> Result<bool, ErrorStack> {
|
||||
unsafe {
|
||||
cvt_n(ffi::BN_is_prime_ex(self.as_ptr(), checks.into(), ctx.as_ptr(), ptr::null_mut()))
|
||||
.map(|r| r != 0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether `self` is prime with optional trial division.
|
||||
///
|
||||
/// If `do_trial_division` is `true`, first performs trial division by a number of small primes.
|
||||
/// Then, like `is_prime`, performs a Miller-Rabin probabilistic primality test with `checks`
|
||||
/// iterations.
|
||||
///
|
||||
/// # Return Value
|
||||
///
|
||||
/// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`.
|
||||
pub fn is_prime_fasttest(&self,
|
||||
checks: i32,
|
||||
ctx: &mut BigNumContextRef,
|
||||
do_trial_division: bool)
|
||||
-> Result<bool, ErrorStack> {
|
||||
unsafe {
|
||||
cvt_n(ffi::BN_is_prime_fasttest_ex(self.as_ptr(),
|
||||
checks.into(),
|
||||
ctx.as_ptr(),
|
||||
do_trial_division as c_int,
|
||||
ptr::null_mut()))
|
||||
.map(|r| r != 0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a big-endian byte vector representation of the absolute value of `self`.
|
||||
///
|
||||
/// `self` can be recreated by using `new_from_slice`.
|
||||
///
|
||||
/// ```
|
||||
/// # use openssl::bn::BigNum;
|
||||
/// let s = -BigNum::from_u32(4543).unwrap();
|
||||
/// let r = BigNum::from_u32(4543).unwrap();
|
||||
///
|
||||
/// let s_vec = s.to_vec();
|
||||
/// assert_eq!(BigNum::from_slice(&s_vec).unwrap(), r);
|
||||
/// ```
|
||||
pub fn to_vec(&self) -> Vec<u8> {
|
||||
let size = self.num_bytes() as usize;
|
||||
let mut v = Vec::with_capacity(size);
|
||||
unsafe {
|
||||
ffi::BN_bn2bin(self.as_ptr(), v.as_mut_ptr());
|
||||
v.set_len(size);
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
/// Returns a decimal string representation of `self`.
|
||||
///
|
||||
/// ```
|
||||
/// # use openssl::bn::BigNum;
|
||||
/// let s = -BigNum::from_u32(12345).unwrap();
|
||||
///
|
||||
/// assert_eq!(&*s.to_dec_str().unwrap(), "-12345");
|
||||
/// ```
|
||||
pub fn to_dec_str(&self) -> Result<CryptoString, ErrorStack> {
|
||||
unsafe {
|
||||
let buf = try!(cvt_p(ffi::BN_bn2dec(self.as_ptr())));
|
||||
Ok(CryptoString::from_null_terminated(buf))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a hexadecimal string representation of `self`.
|
||||
///
|
||||
/// ```
|
||||
/// # use openssl::bn::BigNum;
|
||||
/// let s = -BigNum::from_u32(0x99ff).unwrap();
|
||||
///
|
||||
/// assert_eq!(&*s.to_hex_str().unwrap(), "-99FF");
|
||||
/// ```
|
||||
pub fn to_hex_str(&self) -> Result<CryptoString, ErrorStack> {
|
||||
unsafe {
|
||||
let buf = try!(cvt_p(ffi::BN_bn2hex(self.as_ptr())));
|
||||
Ok(CryptoString::from_null_terminated(buf))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type_!(BigNum, BigNumRef, ffi::BIGNUM, ffi::BN_free);
|
||||
|
||||
impl BigNum {
|
||||
/// Creates a new `BigNum` with the value 0.
|
||||
pub fn new() -> Result<BigNum, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
let v = try!(cvt_p(ffi::BN_new()));
|
||||
Ok(BigNum::from_ptr(v))
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `BigNum` with the given value.
|
||||
pub fn from_u32(n: u32) -> Result<BigNum, ErrorStack> {
|
||||
BigNum::new().and_then(|v| unsafe {
|
||||
cvt(ffi::BN_set_word(v.as_ptr(), n as ffi::BN_ULONG)).map(|_| v)
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a `BigNum` from a decimal string.
|
||||
pub fn from_dec_str(s: &str) -> Result<BigNum, ErrorStack> {
|
||||
unsafe {
|
||||
let c_str = CString::new(s.as_bytes()).unwrap();
|
||||
let mut bn = ptr::null_mut();
|
||||
try!(cvt(ffi::BN_dec2bn(&mut bn, c_str.as_ptr() as *const _)));
|
||||
Ok(BigNum::from_ptr(bn))
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a `BigNum` from a hexadecimal string.
|
||||
pub fn from_hex_str(s: &str) -> Result<BigNum, ErrorStack> {
|
||||
unsafe {
|
||||
let c_str = CString::new(s.as_bytes()).unwrap();
|
||||
let mut bn = ptr::null_mut();
|
||||
try!(cvt(ffi::BN_hex2bn(&mut bn, c_str.as_ptr() as *const _)));
|
||||
Ok(BigNum::from_ptr(bn))
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `BigNum` from an unsigned, big-endian encoded number of arbitrary length.
|
||||
///
|
||||
/// ```
|
||||
/// # use openssl::bn::BigNum;
|
||||
/// let bignum = BigNum::from_slice(&[0x12, 0x00, 0x34]).unwrap();
|
||||
///
|
||||
/// assert_eq!(bignum, BigNum::from_u32(0x120034).unwrap());
|
||||
/// ```
|
||||
pub fn from_slice(n: &[u8]) -> Result<BigNum, ErrorStack> {
|
||||
unsafe {
|
||||
assert!(n.len() <= c_int::max_value() as usize);
|
||||
cvt_p(ffi::BN_bin2bn(n.as_ptr(), n.len() as c_int, ptr::null_mut()))
|
||||
.map(|p| BigNum::from_ptr(p))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<BigNumRef> for BigNum {
|
||||
fn as_ref(&self) -> &BigNumRef {
|
||||
self.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for BigNumRef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.to_dec_str() {
|
||||
Ok(s) => f.write_str(&s),
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for BigNum {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.to_dec_str() {
|
||||
Ok(s) => f.write_str(&s),
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BigNumRef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.to_dec_str() {
|
||||
Ok(s) => f.write_str(&s),
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BigNum {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.to_dec_str() {
|
||||
Ok(s) => f.write_str(&s),
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<BigNumRef> for BigNumRef {
|
||||
fn eq(&self, oth: &BigNumRef) -> bool {
|
||||
self.cmp(oth) == Ordering::Equal
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<BigNum> for BigNumRef {
|
||||
fn eq(&self, oth: &BigNum) -> bool {
|
||||
self.eq(oth.deref())
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for BigNumRef {}
|
||||
|
||||
impl PartialEq for BigNum {
|
||||
fn eq(&self, oth: &BigNum) -> bool {
|
||||
self.deref().eq(oth)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<BigNumRef> for BigNum {
|
||||
fn eq(&self, oth: &BigNumRef) -> bool {
|
||||
self.deref().eq(oth)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for BigNum {}
|
||||
|
||||
impl PartialOrd<BigNumRef> for BigNumRef {
|
||||
fn partial_cmp(&self, oth: &BigNumRef) -> Option<Ordering> {
|
||||
Some(self.cmp(oth))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<BigNum> for BigNumRef {
|
||||
fn partial_cmp(&self, oth: &BigNum) -> Option<Ordering> {
|
||||
Some(self.cmp(oth.deref()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for BigNumRef {
|
||||
fn cmp(&self, oth: &BigNumRef) -> Ordering {
|
||||
unsafe { ffi::BN_cmp(self.as_ptr(), oth.as_ptr()).cmp(&0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for BigNum {
|
||||
fn partial_cmp(&self, oth: &BigNum) -> Option<Ordering> {
|
||||
self.deref().partial_cmp(oth.deref())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<BigNumRef> for BigNum {
|
||||
fn partial_cmp(&self, oth: &BigNumRef) -> Option<Ordering> {
|
||||
self.deref().partial_cmp(oth)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for BigNum {
|
||||
fn cmp(&self, oth: &BigNum) -> Ordering {
|
||||
self.deref().cmp(oth.deref())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! delegate {
|
||||
($t:ident, $m:ident) => {
|
||||
impl<'a, 'b> $t<&'b BigNum> for &'a BigNumRef {
|
||||
type Output = BigNum;
|
||||
|
||||
fn $m(self, oth: &BigNum) -> BigNum {
|
||||
$t::$m(self, oth.deref())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> $t<&'b BigNumRef> for &'a BigNum {
|
||||
type Output = BigNum;
|
||||
|
||||
fn $m(self, oth: &BigNumRef) -> BigNum {
|
||||
$t::$m(self.deref(), oth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> $t<&'b BigNum> for &'a BigNum {
|
||||
type Output = BigNum;
|
||||
|
||||
fn $m(self, oth: &BigNum) -> BigNum {
|
||||
$t::$m(self.deref(), oth.deref())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Add<&'b BigNumRef> for &'a BigNumRef {
|
||||
type Output = BigNum;
|
||||
|
||||
fn add(self, oth: &BigNumRef) -> BigNum {
|
||||
let mut r = BigNum::new().unwrap();
|
||||
r.checked_add(self, oth).unwrap();
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
delegate!(Add, add);
|
||||
|
||||
impl<'a, 'b> Sub<&'b BigNumRef> for &'a BigNumRef {
|
||||
type Output = BigNum;
|
||||
|
||||
fn sub(self, oth: &BigNumRef) -> BigNum {
|
||||
let mut r = BigNum::new().unwrap();
|
||||
r.checked_sub(self, oth).unwrap();
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
delegate!(Sub, sub);
|
||||
|
||||
impl<'a, 'b> Mul<&'b BigNumRef> for &'a BigNumRef {
|
||||
type Output = BigNum;
|
||||
|
||||
fn mul(self, oth: &BigNumRef) -> BigNum {
|
||||
let mut ctx = BigNumContext::new().unwrap();
|
||||
let mut r = BigNum::new().unwrap();
|
||||
r.checked_mul(self, oth, &mut ctx).unwrap();
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
delegate!(Mul, mul);
|
||||
|
||||
impl<'a, 'b> Div<&'b BigNumRef> for &'a BigNumRef {
|
||||
type Output = BigNum;
|
||||
|
||||
fn div(self, oth: &'b BigNumRef) -> BigNum {
|
||||
let mut ctx = BigNumContext::new().unwrap();
|
||||
let mut r = BigNum::new().unwrap();
|
||||
r.checked_div(self, oth, &mut ctx).unwrap();
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
delegate!(Div, div);
|
||||
|
||||
impl<'a, 'b> Rem<&'b BigNumRef> for &'a BigNumRef {
|
||||
type Output = BigNum;
|
||||
|
||||
fn rem(self, oth: &'b BigNumRef) -> BigNum {
|
||||
let mut ctx = BigNumContext::new().unwrap();
|
||||
let mut r = BigNum::new().unwrap();
|
||||
r.checked_rem(self, oth, &mut ctx).unwrap();
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
delegate!(Rem, rem);
|
||||
|
||||
impl<'a> Shl<i32> for &'a BigNumRef {
|
||||
type Output = BigNum;
|
||||
|
||||
fn shl(self, n: i32) -> BigNum {
|
||||
let mut r = BigNum::new().unwrap();
|
||||
r.lshift(self, n).unwrap();
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Shl<i32> for &'a BigNum {
|
||||
type Output = BigNum;
|
||||
|
||||
fn shl(self, n: i32) -> BigNum {
|
||||
self.deref().shl(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Shr<i32> for &'a BigNumRef {
|
||||
type Output = BigNum;
|
||||
|
||||
fn shr(self, n: i32) -> BigNum {
|
||||
let mut r = BigNum::new().unwrap();
|
||||
r.rshift(self, n).unwrap();
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Shr<i32> for &'a BigNum {
|
||||
type Output = BigNum;
|
||||
|
||||
fn shr(self, n: i32) -> BigNum {
|
||||
self.deref().shl(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Neg for &'a BigNumRef {
|
||||
type Output = BigNum;
|
||||
|
||||
fn neg(self) -> BigNum {
|
||||
self.to_owned().unwrap().neg()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Neg for &'a BigNum {
|
||||
type Output = BigNum;
|
||||
|
||||
fn neg(self) -> BigNum {
|
||||
self.deref().neg()
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for BigNum {
|
||||
type Output = BigNum;
|
||||
|
||||
fn neg(mut self) -> BigNum {
|
||||
let negative = self.is_negative();
|
||||
self.set_negative(!negative);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use bn::{BigNumContext, BigNum};
|
||||
|
||||
#[test]
|
||||
fn test_to_from_slice() {
|
||||
let v0 = BigNum::from_u32(10203004).unwrap();
|
||||
let vec = v0.to_vec();
|
||||
let v1 = BigNum::from_slice(&vec).unwrap();
|
||||
|
||||
assert!(v0 == v1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negation() {
|
||||
let a = BigNum::from_u32(909829283).unwrap();
|
||||
|
||||
assert!(!a.is_negative());
|
||||
assert!((-a).is_negative());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_prime_numbers() {
|
||||
let a = BigNum::from_u32(19029017).unwrap();
|
||||
let mut p = BigNum::new().unwrap();
|
||||
p.generate_prime(128, true, None, Some(&a)).unwrap();
|
||||
|
||||
let mut ctx = BigNumContext::new().unwrap();
|
||||
assert!(p.is_prime(100, &mut ctx).unwrap());
|
||||
assert!(p.is_prime_fasttest(100, &mut ctx, true).unwrap());
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
use libc::{c_char, c_int, c_void};
|
||||
use std::fmt;
|
||||
use std::ffi::CStr;
|
||||
use std::slice;
|
||||
use std::ops::Deref;
|
||||
use std::str;
|
||||
|
||||
pub struct CryptoString(&'static str);
|
||||
|
||||
impl Drop for CryptoString {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
CRYPTO_free(self.0.as_ptr() as *mut c_void,
|
||||
concat!(file!(), "\0").as_ptr() as *const c_char,
|
||||
line!() as c_int);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for CryptoString {
|
||||
type Target = str;
|
||||
|
||||
fn deref(&self) -> &str {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl CryptoString {
|
||||
pub unsafe fn from_raw_parts(buf: *mut u8, len: usize) -> CryptoString {
|
||||
let slice = slice::from_raw_parts(buf, len);
|
||||
CryptoString(str::from_utf8_unchecked(slice))
|
||||
}
|
||||
|
||||
pub unsafe fn from_null_terminated(buf: *mut c_char) -> CryptoString {
|
||||
let slice = CStr::from_ptr(buf).to_bytes();
|
||||
CryptoString(str::from_utf8_unchecked(slice))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CryptoString {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for CryptoString {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(ossl110))]
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn CRYPTO_free(buf: *mut c_void, _: *const c_char, _: c_int) {
|
||||
::ffi::CRYPTO_free(buf);
|
||||
}
|
||||
|
||||
#[cfg(ossl110)]
|
||||
use ffi::CRYPTO_free;
|
||||
|
|
@ -1,338 +0,0 @@
|
|||
use ffi;
|
||||
use std::fmt;
|
||||
use error::ErrorStack;
|
||||
use std::ptr;
|
||||
use libc::{c_uint, c_int, c_char, c_void};
|
||||
|
||||
use bn::BigNumRef;
|
||||
use bio::{MemBio, MemBioSlice};
|
||||
use crypto::hash;
|
||||
use HashTypeInternals;
|
||||
use crypto::util::{CallbackState, invoke_passwd_cb};
|
||||
|
||||
|
||||
/// Builder for upfront DSA parameter generateration
|
||||
pub struct DSAParams(*mut ffi::DSA);
|
||||
|
||||
impl DSAParams {
|
||||
pub fn with_size(size: u32) -> Result<DSAParams, ErrorStack> {
|
||||
unsafe {
|
||||
// Wrap it so that if we panic we'll call the dtor
|
||||
let dsa = DSAParams(try_ssl_null!(ffi::DSA_new()));
|
||||
try_ssl!(ffi::DSA_generate_parameters_ex(dsa.0, size as c_int, ptr::null(), 0,
|
||||
ptr::null_mut(), ptr::null_mut(), ptr::null()));
|
||||
Ok(dsa)
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a key pair from the initialized parameters
|
||||
pub fn generate(self) -> Result<DSA, ErrorStack> {
|
||||
unsafe {
|
||||
try_ssl!(ffi::DSA_generate_key(self.0));
|
||||
let dsa = DSA(self.0);
|
||||
::std::mem::forget(self);
|
||||
Ok(dsa)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DSAParams {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ffi::DSA_free(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DSA(*mut ffi::DSA);
|
||||
|
||||
impl Drop for DSA {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ffi::DSA_free(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DSA {
|
||||
pub unsafe fn from_ptr(dsa: *mut ffi::DSA) -> DSA {
|
||||
DSA(dsa)
|
||||
}
|
||||
|
||||
/// Generate a DSA key pair
|
||||
/// For more complicated key generation scenarios see the `DSAParams` type
|
||||
pub fn generate(size: u32) -> Result<DSA, ErrorStack> {
|
||||
let params = try!(DSAParams::with_size(size));
|
||||
params.generate()
|
||||
}
|
||||
|
||||
/// Reads a DSA private key from PEM formatted data.
|
||||
pub fn private_key_from_pem(buf: &[u8]) -> Result<DSA, ErrorStack> {
|
||||
ffi::init();
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
|
||||
unsafe {
|
||||
let dsa = try_ssl_null!(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut()));
|
||||
let dsa = DSA(dsa);
|
||||
assert!(dsa.has_private_key());
|
||||
Ok(dsa)
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a private key from PEM supplying a password callback to be invoked if the private key
|
||||
/// is encrypted.
|
||||
///
|
||||
/// The callback will be passed the password buffer and should return the number of characters
|
||||
/// placed into the buffer.
|
||||
pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<DSA, ErrorStack>
|
||||
where F: FnOnce(&mut [c_char]) -> usize
|
||||
{
|
||||
ffi::init();
|
||||
let mut cb = CallbackState::new(pass_cb);
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
|
||||
unsafe {
|
||||
let cb_ptr = &mut cb as *mut _ as *mut c_void;
|
||||
let dsa = try_ssl_null!(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
Some(invoke_passwd_cb::<F>),
|
||||
cb_ptr));
|
||||
let dsa = DSA(dsa);
|
||||
assert!(dsa.has_private_key());
|
||||
Ok(dsa)
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes an DSA private key as unencrypted PEM formatted data
|
||||
pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack>
|
||||
{
|
||||
assert!(self.has_private_key());
|
||||
let mem_bio = try!(MemBio::new());
|
||||
|
||||
unsafe {
|
||||
try_ssl!(ffi::PEM_write_bio_DSAPrivateKey(mem_bio.as_ptr(), self.0,
|
||||
ptr::null(), ptr::null_mut(), 0,
|
||||
None, ptr::null_mut()))
|
||||
};
|
||||
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
/// Reads an DSA public key from PEM formatted data.
|
||||
pub fn public_key_from_pem(buf: &[u8]) -> Result<DSA, ErrorStack>
|
||||
{
|
||||
ffi::init();
|
||||
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let dsa = try_ssl_null!(ffi::PEM_read_bio_DSA_PUBKEY(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut()));
|
||||
Ok(DSA(dsa))
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes an DSA public key as PEM formatted data
|
||||
pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
unsafe { try_ssl!(ffi::PEM_write_bio_DSA_PUBKEY(mem_bio.as_ptr(), self.0)) };
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
pub fn size(&self) -> Option<u32> {
|
||||
if self.q().is_some() {
|
||||
unsafe { Some(ffi::DSA_size(self.0) as u32) }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sign(&self, hash: hash::Type, message: &[u8]) -> Result<Vec<u8>, ErrorStack> {
|
||||
let k_len = self.size().expect("DSA missing a q") as c_uint;
|
||||
let mut sig = vec![0; k_len as usize];
|
||||
let mut sig_len = k_len;
|
||||
assert!(self.has_private_key());
|
||||
|
||||
unsafe {
|
||||
try_ssl!(ffi::DSA_sign(hash.as_nid() as c_int,
|
||||
message.as_ptr(),
|
||||
message.len() as c_int,
|
||||
sig.as_mut_ptr(),
|
||||
&mut sig_len,
|
||||
self.0));
|
||||
sig.set_len(sig_len as usize);
|
||||
sig.shrink_to_fit();
|
||||
Ok(sig)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify(&self, hash: hash::Type, message: &[u8], sig: &[u8]) -> Result<bool, ErrorStack> {
|
||||
unsafe {
|
||||
let result = ffi::DSA_verify(hash.as_nid() as c_int,
|
||||
message.as_ptr(),
|
||||
message.len() as c_int,
|
||||
sig.as_ptr(),
|
||||
sig.len() as c_int,
|
||||
self.0);
|
||||
|
||||
try_ssl_if!(result == -1);
|
||||
Ok(result == 1)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *mut ffi::DSA {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn p<'a>(&'a self) -> Option<BigNumRef<'a>> {
|
||||
unsafe {
|
||||
let p = (*self.0).p;
|
||||
if p.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr((*self.0).p))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn q<'a>(&'a self) -> Option<BigNumRef<'a>> {
|
||||
unsafe {
|
||||
let q = (*self.0).q;
|
||||
if q.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr((*self.0).q))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn g<'a>(&'a self) -> Option<BigNumRef<'a>> {
|
||||
unsafe {
|
||||
let g = (*self.0).g;
|
||||
if g.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr((*self.0).g))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_public_key(&self) -> bool {
|
||||
unsafe { !(*self.0).pub_key.is_null() }
|
||||
}
|
||||
|
||||
pub fn has_private_key(&self) -> bool {
|
||||
unsafe { !(*self.0).priv_key.is_null() }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for DSA {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DSA")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::io::Write;
|
||||
use libc::c_char;
|
||||
|
||||
use super::*;
|
||||
use crypto::hash::*;
|
||||
|
||||
#[test]
|
||||
pub fn test_generate() {
|
||||
let key = DSA::generate(1024).unwrap();
|
||||
|
||||
key.public_key_to_pem().unwrap();
|
||||
key.private_key_to_pem().unwrap();
|
||||
|
||||
let input: Vec<u8> = (0..25).cycle().take(1024).collect();
|
||||
|
||||
let digest = {
|
||||
let mut sha = Hasher::new(Type::SHA1).unwrap();
|
||||
sha.write_all(&input).unwrap();
|
||||
sha.finish().unwrap()
|
||||
};
|
||||
|
||||
let sig = key.sign(Type::SHA1, &digest).unwrap();
|
||||
let verified = key.verify(Type::SHA1, &digest, &sig).unwrap();
|
||||
assert!(verified);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_sign_verify() {
|
||||
let input: Vec<u8> = (0..25).cycle().take(1024).collect();
|
||||
|
||||
let private_key = {
|
||||
let key = include_bytes!("../../test/dsa.pem");
|
||||
DSA::private_key_from_pem(key).unwrap()
|
||||
};
|
||||
|
||||
let public_key = {
|
||||
let key = include_bytes!("../../test/dsa.pem.pub");
|
||||
DSA::public_key_from_pem(key).unwrap()
|
||||
};
|
||||
|
||||
let digest = {
|
||||
let mut sha = Hasher::new(Type::SHA1).unwrap();
|
||||
sha.write_all(&input).unwrap();
|
||||
sha.finish().unwrap()
|
||||
};
|
||||
|
||||
let sig = private_key.sign(Type::SHA1, &digest).unwrap();
|
||||
let verified = public_key.verify(Type::SHA1, &digest, &sig).unwrap();
|
||||
assert!(verified);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_sign_verify_fail() {
|
||||
let input: Vec<u8> = (0..25).cycle().take(128).collect();
|
||||
let private_key = {
|
||||
let key = include_bytes!("../../test/dsa.pem");
|
||||
DSA::private_key_from_pem(key).unwrap()
|
||||
};
|
||||
|
||||
let public_key = {
|
||||
let key = include_bytes!("../../test/dsa.pem.pub");
|
||||
DSA::public_key_from_pem(key).unwrap()
|
||||
};
|
||||
|
||||
let digest = {
|
||||
let mut sha = Hasher::new(Type::SHA1).unwrap();
|
||||
sha.write_all(&input).unwrap();
|
||||
sha.finish().unwrap()
|
||||
};
|
||||
|
||||
let mut sig = private_key.sign(Type::SHA1, &digest).unwrap();
|
||||
// tamper with the sig this should cause a failure
|
||||
let len = sig.len();
|
||||
sig[len / 2] = 0;
|
||||
sig[len - 1] = 0;
|
||||
if let Ok(true) = public_key.verify(Type::SHA1, &digest, &sig) {
|
||||
panic!("Tampered with signatures should not verify!");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_password() {
|
||||
let mut password_queried = false;
|
||||
let key = include_bytes!("../../test/dsa-encrypted.pem");
|
||||
DSA::private_key_from_pem_cb(key, |password| {
|
||||
password_queried = true;
|
||||
password[0] = b'm' as c_char;
|
||||
password[1] = b'y' as c_char;
|
||||
password[2] = b'p' as c_char;
|
||||
password[3] = b'a' as c_char;
|
||||
password[4] = b's' as c_char;
|
||||
password[5] = b's' as c_char;
|
||||
6
|
||||
}).unwrap();
|
||||
|
||||
assert!(password_queried);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,511 +0,0 @@
|
|||
// Copyright 2013 Jack Lloyd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
use libc::{c_int, c_uint};
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::cmp;
|
||||
use ffi;
|
||||
|
||||
use HashTypeInternals;
|
||||
use crypto::hash::Type;
|
||||
use error::ErrorStack;
|
||||
use c_helpers;
|
||||
|
||||
#[derive(PartialEq, Copy, Clone)]
|
||||
enum State {
|
||||
Reset,
|
||||
Updated,
|
||||
Finalized,
|
||||
}
|
||||
|
||||
use self::State::*;
|
||||
|
||||
/// Provides HMAC computation.
|
||||
///
|
||||
/// Requires the `hmac` feature.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Calculate a HMAC in one go.
|
||||
///
|
||||
/// ```
|
||||
/// use openssl::crypto::hash::Type;
|
||||
/// use openssl::crypto::hmac::hmac;
|
||||
/// let key = b"Jefe";
|
||||
/// let data = b"what do ya want for nothing?";
|
||||
/// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38";
|
||||
/// let res = hmac(Type::MD5, key, data).unwrap();
|
||||
/// assert_eq!(res, spec);
|
||||
/// ```
|
||||
///
|
||||
/// Use the `Write` trait to supply the input in chunks.
|
||||
///
|
||||
/// ```
|
||||
/// use openssl::crypto::hash::Type;
|
||||
/// use openssl::crypto::hmac::HMAC;
|
||||
/// let key = b"Jefe";
|
||||
/// let data: &[&[u8]] = &[b"what do ya ", b"want for nothing?"];
|
||||
/// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38";
|
||||
/// let mut h = HMAC::new(Type::MD5, &*key).unwrap();
|
||||
/// h.update(data[0]).unwrap();
|
||||
/// h.update(data[1]).unwrap();
|
||||
/// let res = h.finish().unwrap();
|
||||
/// assert_eq!(res, spec);
|
||||
/// ```
|
||||
pub struct HMAC {
|
||||
ctx: ffi::HMAC_CTX,
|
||||
state: State,
|
||||
}
|
||||
|
||||
impl HMAC {
|
||||
/// Creates a new `HMAC` with the specified hash type using the `key`.
|
||||
pub fn new(ty: Type, key: &[u8]) -> Result<HMAC, ErrorStack> {
|
||||
ffi::init();
|
||||
|
||||
let ctx = unsafe {
|
||||
let mut ctx = ::std::mem::uninitialized();
|
||||
ffi::HMAC_CTX_init(&mut ctx);
|
||||
ctx
|
||||
};
|
||||
let md = ty.evp_md();
|
||||
|
||||
let mut h = HMAC {
|
||||
ctx: ctx,
|
||||
state: Finalized,
|
||||
};
|
||||
try!(h.init_once(md, key));
|
||||
Ok(h)
|
||||
}
|
||||
|
||||
fn init_once(&mut self, md: *const ffi::EVP_MD, key: &[u8]) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
try_ssl!(c_helpers::rust_0_8_HMAC_Init_ex(&mut self.ctx,
|
||||
key.as_ptr() as *const _,
|
||||
key.len() as c_int,
|
||||
md,
|
||||
0 as *mut _));
|
||||
}
|
||||
self.state = Reset;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init(&mut self) -> Result<(), ErrorStack> {
|
||||
match self.state {
|
||||
Reset => return Ok(()),
|
||||
Updated => {
|
||||
try!(self.finish());
|
||||
}
|
||||
Finalized => (),
|
||||
}
|
||||
// If the key and/or md is not supplied it's reused from the last time
|
||||
// avoiding redundant initializations
|
||||
unsafe {
|
||||
try_ssl!(c_helpers::rust_0_8_HMAC_Init_ex(&mut self.ctx,
|
||||
0 as *const _,
|
||||
0,
|
||||
0 as *const _,
|
||||
0 as *mut _));
|
||||
}
|
||||
self.state = Reset;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update(&mut self, mut data: &[u8]) -> Result<(), ErrorStack> {
|
||||
if self.state == Finalized {
|
||||
try!(self.init());
|
||||
}
|
||||
while !data.is_empty() {
|
||||
let len = cmp::min(data.len(), c_uint::max_value() as usize);
|
||||
unsafe {
|
||||
try_ssl!(c_helpers::rust_0_8_HMAC_Update(&mut self.ctx, data.as_ptr(), len as c_uint));
|
||||
}
|
||||
data = &data[len..];
|
||||
}
|
||||
self.state = Updated;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the hash of the data written since creation or
|
||||
/// the last `finish` and resets the hasher.
|
||||
pub fn finish(&mut self) -> Result<Vec<u8>, ErrorStack> {
|
||||
if self.state == Finalized {
|
||||
try!(self.init());
|
||||
}
|
||||
unsafe {
|
||||
let mut len = ffi::EVP_MAX_MD_SIZE;
|
||||
let mut res = vec![0; len as usize];
|
||||
try_ssl!(c_helpers::rust_0_8_HMAC_Final(&mut self.ctx, res.as_mut_ptr(), &mut len));
|
||||
res.truncate(len as usize);
|
||||
self.state = Finalized;
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for HMAC {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
try!(self.update(buf));
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "hmac_clone")]
|
||||
impl Clone for HMAC {
|
||||
/// Requires the `hmac_clone` feature.
|
||||
fn clone(&self) -> HMAC {
|
||||
let mut ctx: ffi::HMAC_CTX;
|
||||
unsafe {
|
||||
ctx = ::std::mem::uninitialized();
|
||||
let r = ffi::HMAC_CTX_copy(&mut ctx, &self.ctx);
|
||||
assert_eq!(r, 1);
|
||||
}
|
||||
HMAC {
|
||||
ctx: ctx,
|
||||
state: self.state,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for HMAC {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if self.state != Finalized {
|
||||
drop(self.finish());
|
||||
}
|
||||
ffi::HMAC_CTX_cleanup(&mut self.ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the HMAC of the `data` with the hash `t` and `key`.
|
||||
pub fn hmac(t: Type, key: &[u8], data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mut h = try!(HMAC::new(t, key));
|
||||
try!(h.update(data));
|
||||
h.finish()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::iter::repeat;
|
||||
use serialize::hex::FromHex;
|
||||
use crypto::hash::Type;
|
||||
use crypto::hash::Type::*;
|
||||
use super::{hmac, HMAC};
|
||||
use std::io::prelude::*;
|
||||
|
||||
fn test_hmac(ty: Type, tests: &[(Vec<u8>, Vec<u8>, Vec<u8>)]) {
|
||||
for &(ref key, ref data, ref res) in tests.iter() {
|
||||
assert_eq!(hmac(ty, &**key, &**data).unwrap(), *res);
|
||||
}
|
||||
}
|
||||
|
||||
fn test_hmac_recycle(h: &mut HMAC, test: &(Vec<u8>, Vec<u8>, Vec<u8>)) {
|
||||
let &(_, ref data, ref res) = test;
|
||||
h.write_all(&**data).unwrap();
|
||||
assert_eq!(h.finish().unwrap(), *res);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hmac_md5() {
|
||||
// test vectors from RFC 2202
|
||||
let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 7] =
|
||||
[(repeat(0x0b_u8).take(16).collect(),
|
||||
b"Hi There".to_vec(),
|
||||
"9294727a3638bb1c13f48ef8158bfc9d".from_hex().unwrap()),
|
||||
(b"Jefe".to_vec(),
|
||||
b"what do ya want for nothing?".to_vec(),
|
||||
"750c783e6ab0b503eaa86e310a5db738".from_hex().unwrap()),
|
||||
(repeat(0xaa_u8).take(16).collect(),
|
||||
repeat(0xdd_u8).take(50).collect(),
|
||||
"56be34521d144c88dbb8c733f0e8b3f6".from_hex().unwrap()),
|
||||
("0102030405060708090a0b0c0d0e0f10111213141516171819".from_hex().unwrap(),
|
||||
repeat(0xcd_u8).take(50).collect(),
|
||||
"697eaf0aca3a3aea3a75164746ffaa79".from_hex().unwrap()),
|
||||
(repeat(0x0c_u8).take(16).collect(),
|
||||
b"Test With Truncation".to_vec(),
|
||||
"56461ef2342edc00f9bab995690efd4c".from_hex().unwrap()),
|
||||
(repeat(0xaa_u8).take(80).collect(),
|
||||
b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
|
||||
"6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap()),
|
||||
(repeat(0xaa_u8).take(80).collect(),
|
||||
b"Test Using Larger Than Block-Size Key \
|
||||
and Larger Than One Block-Size Data"
|
||||
.to_vec(),
|
||||
"6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())];
|
||||
|
||||
test_hmac(MD5, &tests);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hmac_md5_recycle() {
|
||||
let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 2] =
|
||||
[(repeat(0xaa_u8).take(80).collect(),
|
||||
b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
|
||||
"6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap()),
|
||||
(repeat(0xaa_u8).take(80).collect(),
|
||||
b"Test Using Larger Than Block-Size Key \
|
||||
and Larger Than One Block-Size Data"
|
||||
.to_vec(),
|
||||
"6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())];
|
||||
|
||||
let mut h = HMAC::new(MD5, &*tests[0].0).unwrap();
|
||||
for i in 0..100usize {
|
||||
let test = &tests[i % 2];
|
||||
test_hmac_recycle(&mut h, test);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_finish_twice() {
|
||||
let test: (Vec<u8>, Vec<u8>, Vec<u8>) =
|
||||
(repeat(0xaa_u8).take(80).collect(),
|
||||
b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
|
||||
"6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap());
|
||||
|
||||
let mut h = HMAC::new(Type::MD5, &*test.0).unwrap();
|
||||
h.write_all(&*test.1).unwrap();
|
||||
h.finish().unwrap();
|
||||
let res = h.finish().unwrap();
|
||||
let null = hmac(Type::MD5, &*test.0, &[]).unwrap();
|
||||
assert_eq!(res, null);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "hmac_clone")]
|
||||
fn test_clone() {
|
||||
let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 2] =
|
||||
[(repeat(0xaa_u8).take(80).collect(),
|
||||
b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
|
||||
"6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap()),
|
||||
(repeat(0xaa_u8).take(80).collect(),
|
||||
b"Test Using Larger Than Block-Size Key \
|
||||
and Larger Than One Block-Size Data"
|
||||
.to_vec(),
|
||||
"6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())];
|
||||
let p = tests[0].0.len() / 2;
|
||||
let h0 = HMAC::new(Type::MD5, &*tests[0].0).unwrap();
|
||||
|
||||
println!("Clone a new hmac");
|
||||
let mut h1 = h0.clone();
|
||||
h1.write_all(&tests[0].1[..p]).unwrap();
|
||||
{
|
||||
println!("Clone an updated hmac");
|
||||
let mut h2 = h1.clone();
|
||||
h2.write_all(&tests[0].1[p..]).unwrap();
|
||||
let res = h2.finish().unwrap();
|
||||
assert_eq!(res, tests[0].2);
|
||||
}
|
||||
h1.write_all(&tests[0].1[p..]).unwrap();
|
||||
let res = h1.finish().unwrap();
|
||||
assert_eq!(res, tests[0].2);
|
||||
|
||||
println!("Clone a finished hmac");
|
||||
let mut h3 = h1.clone();
|
||||
h3.write_all(&*tests[1].1).unwrap();
|
||||
let res = h3.finish().unwrap();
|
||||
assert_eq!(res, tests[1].2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hmac_sha1() {
|
||||
// test vectors from RFC 2202
|
||||
let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 7] =
|
||||
[(repeat(0x0b_u8).take(20).collect(),
|
||||
b"Hi There".to_vec(),
|
||||
"b617318655057264e28bc0b6fb378c8ef146be00".from_hex().unwrap()),
|
||||
(b"Jefe".to_vec(),
|
||||
b"what do ya want for nothing?".to_vec(),
|
||||
"effcdf6ae5eb2fa2d27416d5f184df9c259a7c79".from_hex().unwrap()),
|
||||
(repeat(0xaa_u8).take(20).collect(),
|
||||
repeat(0xdd_u8).take(50).collect(),
|
||||
"125d7342b9ac11cd91a39af48aa17b4f63f175d3".from_hex().unwrap()),
|
||||
("0102030405060708090a0b0c0d0e0f10111213141516171819".from_hex().unwrap(),
|
||||
repeat(0xcd_u8).take(50).collect(),
|
||||
"4c9007f4026250c6bc8414f9bf50c86c2d7235da".from_hex().unwrap()),
|
||||
(repeat(0x0c_u8).take(20).collect(),
|
||||
b"Test With Truncation".to_vec(),
|
||||
"4c1a03424b55e07fe7f27be1d58bb9324a9a5a04".from_hex().unwrap()),
|
||||
(repeat(0xaa_u8).take(80).collect(),
|
||||
b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
|
||||
"aa4ae5e15272d00e95705637ce8a3b55ed402112".from_hex().unwrap()),
|
||||
(repeat(0xaa_u8).take(80).collect(),
|
||||
b"Test Using Larger Than Block-Size Key \
|
||||
and Larger Than One Block-Size Data"
|
||||
.to_vec(),
|
||||
"e8e99d0f45237d786d6bbaa7965c7808bbff1a91".from_hex().unwrap())];
|
||||
|
||||
test_hmac(SHA1, &tests);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hmac_sha1_recycle() {
|
||||
let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 2] =
|
||||
[(repeat(0xaa_u8).take(80).collect(),
|
||||
b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
|
||||
"aa4ae5e15272d00e95705637ce8a3b55ed402112".from_hex().unwrap()),
|
||||
(repeat(0xaa_u8).take(80).collect(),
|
||||
b"Test Using Larger Than Block-Size Key \
|
||||
and Larger Than One Block-Size Data"
|
||||
.to_vec(),
|
||||
"e8e99d0f45237d786d6bbaa7965c7808bbff1a91".from_hex().unwrap())];
|
||||
|
||||
let mut h = HMAC::new(SHA1, &*tests[0].0).unwrap();
|
||||
for i in 0..100usize {
|
||||
let test = &tests[i % 2];
|
||||
test_hmac_recycle(&mut h, test);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn test_sha2(ty: Type, results: &[Vec<u8>]) {
|
||||
// test vectors from RFC 4231
|
||||
let tests: [(Vec<u8>, Vec<u8>); 6] =
|
||||
[(repeat(0xb_u8).take(20).collect(), b"Hi There".to_vec()),
|
||||
(b"Jefe".to_vec(), b"what do ya want for nothing?".to_vec()),
|
||||
(repeat(0xaa_u8).take(20).collect(), repeat(0xdd_u8).take(50).collect()),
|
||||
("0102030405060708090a0b0c0d0e0f10111213141516171819".from_hex().unwrap(),
|
||||
repeat(0xcd_u8).take(50).collect()),
|
||||
(repeat(0xaa_u8).take(131).collect(),
|
||||
b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec()),
|
||||
(repeat(0xaa_u8).take(131).collect(),
|
||||
b"This is a test using a larger than block-size key and a \
|
||||
larger than block-size data. The key needs to be hashed \
|
||||
before being used by the HMAC algorithm."
|
||||
.to_vec())];
|
||||
|
||||
for (&(ref key, ref data), res) in tests.iter().zip(results.iter()) {
|
||||
assert_eq!(hmac(ty, &**key, &**data).unwrap(), *res);
|
||||
}
|
||||
|
||||
// recycle test
|
||||
let mut h = HMAC::new(ty, &*tests[5].0).unwrap();
|
||||
for i in 0..100usize {
|
||||
let test = &tests[4 + i % 2];
|
||||
let tup = (test.0.clone(), test.1.clone(), results[4 + i % 2].clone());
|
||||
test_hmac_recycle(&mut h, &tup);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hmac_sha224() {
|
||||
let results = ["896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1"
|
||||
.from_hex()
|
||||
.unwrap()];
|
||||
test_sha2(SHA224, &results);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hmac_sha256() {
|
||||
let results = ["b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2"
|
||||
.from_hex()
|
||||
.unwrap()];
|
||||
test_sha2(SHA256, &results);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hmac_sha384() {
|
||||
let results = ["afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea90\
|
||||
76ede7f4af152e8b2fa9cb6"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5\
|
||||
e69e2c78b3239ecfab21649"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc\
|
||||
13814b94e3ab6e101a34f27"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e6801dd23c\
|
||||
4a7d679ccf8a386c674cffb"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c60c2ef6ab4\
|
||||
030fe8296248df163f44952"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5a678cc31e\
|
||||
799176d3860e6110c46523e"
|
||||
.from_hex()
|
||||
.unwrap()];
|
||||
test_sha2(SHA384, &results);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hmac_sha512() {
|
||||
let results = ["87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d\
|
||||
6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c\
|
||||
05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e84827\
|
||||
9a722c806b485a47e67c807b946a337bee8942674278859e13292fb"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11\
|
||||
aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e\
|
||||
05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
"e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3\
|
||||
c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58"
|
||||
.from_hex()
|
||||
.unwrap()];
|
||||
test_sha2(SHA512, &results);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
// Copyright 2011 Google Inc.
|
||||
// 2013 Jack Lloyd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
pub mod hash;
|
||||
#[cfg(feature = "hmac")]
|
||||
pub mod hmac;
|
||||
pub mod pkcs5;
|
||||
pub mod pkcs12;
|
||||
pub mod pkey;
|
||||
pub mod rand;
|
||||
pub mod symm;
|
||||
pub mod memcmp;
|
||||
pub mod rsa;
|
||||
pub mod dsa;
|
||||
mod util;
|
||||
|
|
@ -1,245 +0,0 @@
|
|||
use libc::c_int;
|
||||
use std::ptr;
|
||||
use ffi;
|
||||
|
||||
use HashTypeInternals;
|
||||
use crypto::hash;
|
||||
use crypto::symm;
|
||||
use error::ErrorStack;
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct KeyIvPair {
|
||||
pub key: Vec<u8>,
|
||||
pub iv: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Derives a key and an IV from various parameters.
|
||||
///
|
||||
/// If specified `salt` must be 8 bytes in length.
|
||||
///
|
||||
/// If the total key and IV length is less than 16 bytes and MD5 is used then
|
||||
/// the algorithm is compatible with the key derivation algorithm from PKCS#5
|
||||
/// v1.5 or PBKDF1 from PKCS#5 v2.0.
|
||||
///
|
||||
/// New applications should not use this and instead use `pbkdf2_hmac_sha1` or
|
||||
/// another more modern key derivation algorithm.
|
||||
pub fn evp_bytes_to_key_pbkdf1_compatible(typ: symm::Type,
|
||||
message_digest_type: hash::Type,
|
||||
data: &[u8],
|
||||
salt: Option<&[u8]>,
|
||||
count: u32)
|
||||
-> Result<KeyIvPair, ErrorStack> {
|
||||
unsafe {
|
||||
let salt_ptr = match salt {
|
||||
Some(salt) => {
|
||||
assert_eq!(salt.len(), ffi::PKCS5_SALT_LEN as usize);
|
||||
salt.as_ptr()
|
||||
}
|
||||
None => ptr::null(),
|
||||
};
|
||||
|
||||
ffi::init();
|
||||
|
||||
let typ = typ.as_ptr();
|
||||
let message_digest_type = message_digest_type.evp_md();
|
||||
|
||||
let len = ffi::EVP_BytesToKey(typ,
|
||||
message_digest_type,
|
||||
salt_ptr,
|
||||
data.as_ptr(),
|
||||
data.len() as c_int,
|
||||
count as c_int,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut());
|
||||
if len == 0 {
|
||||
return Err(ErrorStack::get());
|
||||
}
|
||||
|
||||
let mut key = vec![0; len as usize];
|
||||
let mut iv = vec![0; len as usize];
|
||||
|
||||
try_ssl!(ffi::EVP_BytesToKey(typ,
|
||||
message_digest_type,
|
||||
salt_ptr,
|
||||
data.as_ptr(),
|
||||
data.len() as c_int,
|
||||
count as c_int,
|
||||
key.as_mut_ptr(),
|
||||
iv.as_mut_ptr()));
|
||||
|
||||
Ok(KeyIvPair { key: key, iv: iv })
|
||||
}
|
||||
}
|
||||
|
||||
/// Derives a key from a password and salt using the PBKDF2-HMAC-SHA1 algorithm.
|
||||
pub fn pbkdf2_hmac_sha1(pass: &[u8],
|
||||
salt: &[u8],
|
||||
iter: usize,
|
||||
keylen: usize)
|
||||
-> Result<Vec<u8>, ErrorStack> {
|
||||
unsafe {
|
||||
let mut out = vec![0; keylen];
|
||||
|
||||
ffi::init();
|
||||
|
||||
try_ssl!(ffi::PKCS5_PBKDF2_HMAC_SHA1(pass.as_ptr(),
|
||||
pass.len() as c_int,
|
||||
salt.as_ptr(),
|
||||
salt.len() as c_int,
|
||||
iter as c_int,
|
||||
keylen as c_int,
|
||||
out.as_mut_ptr()));
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
|
||||
/// Derives a key from a password and salt using the PBKDF2-HMAC algorithm with a digest function.
|
||||
#[cfg(feature = "pkcs5_pbkdf2_hmac")]
|
||||
pub fn pbkdf2_hmac(pass: &[u8],
|
||||
salt: &[u8],
|
||||
iter: usize,
|
||||
hash: hash::Type,
|
||||
keylen: usize)
|
||||
-> Result<Vec<u8>, ErrorStack> {
|
||||
unsafe {
|
||||
let mut out = vec![0; keylen];
|
||||
ffi::init();
|
||||
try_ssl!(ffi::PKCS5_PBKDF2_HMAC(pass.as_ptr(),
|
||||
pass.len() as c_int,
|
||||
salt.as_ptr(),
|
||||
salt.len() as c_int,
|
||||
iter as c_int,
|
||||
hash.evp_md(),
|
||||
keylen as c_int,
|
||||
out.as_mut_ptr()));
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crypto::hash;
|
||||
use crypto::symm;
|
||||
|
||||
// Test vectors from
|
||||
// http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06
|
||||
#[test]
|
||||
fn test_pbkdf2_hmac_sha1() {
|
||||
assert_eq!(super::pbkdf2_hmac_sha1(b"password", b"salt", 1, 20).unwrap(),
|
||||
vec![0x0c_u8, 0x60_u8, 0xc8_u8, 0x0f_u8, 0x96_u8, 0x1f_u8, 0x0e_u8, 0x71_u8,
|
||||
0xf3_u8, 0xa9_u8, 0xb5_u8, 0x24_u8, 0xaf_u8, 0x60_u8, 0x12_u8, 0x06_u8,
|
||||
0x2f_u8, 0xe0_u8, 0x37_u8, 0xa6_u8]);
|
||||
|
||||
assert_eq!(super::pbkdf2_hmac_sha1(b"password", b"salt", 2, 20).unwrap(),
|
||||
vec![0xea_u8, 0x6c_u8, 0x01_u8, 0x4d_u8, 0xc7_u8, 0x2d_u8, 0x6f_u8, 0x8c_u8,
|
||||
0xcd_u8, 0x1e_u8, 0xd9_u8, 0x2a_u8, 0xce_u8, 0x1d_u8, 0x41_u8, 0xf0_u8,
|
||||
0xd8_u8, 0xde_u8, 0x89_u8, 0x57_u8]);
|
||||
|
||||
assert_eq!(super::pbkdf2_hmac_sha1(b"password", b"salt", 4096, 20).unwrap(),
|
||||
vec![0x4b_u8, 0x00_u8, 0x79_u8, 0x01_u8, 0xb7_u8, 0x65_u8, 0x48_u8, 0x9a_u8,
|
||||
0xbe_u8, 0xad_u8, 0x49_u8, 0xd9_u8, 0x26_u8, 0xf7_u8, 0x21_u8, 0xd0_u8,
|
||||
0x65_u8, 0xa4_u8, 0x29_u8, 0xc1_u8]);
|
||||
|
||||
assert_eq!(super::pbkdf2_hmac_sha1(b"password", b"salt", 16777216, 20).unwrap(),
|
||||
vec![0xee_u8, 0xfe_u8, 0x3d_u8, 0x61_u8, 0xcd_u8, 0x4d_u8, 0xa4_u8, 0xe4_u8,
|
||||
0xe9_u8, 0x94_u8, 0x5b_u8, 0x3d_u8, 0x6b_u8, 0xa2_u8, 0x15_u8, 0x8c_u8,
|
||||
0x26_u8, 0x34_u8, 0xe9_u8, 0x84_u8]);
|
||||
|
||||
assert_eq!(super::pbkdf2_hmac_sha1(b"passwordPASSWORDpassword",
|
||||
b"saltSALTsaltSALTsaltSALTsaltSALTsalt",
|
||||
4096,
|
||||
25).unwrap(),
|
||||
vec![0x3d_u8, 0x2e_u8, 0xec_u8, 0x4f_u8, 0xe4_u8, 0x1c_u8, 0x84_u8, 0x9b_u8,
|
||||
0x80_u8, 0xc8_u8, 0xd8_u8, 0x36_u8, 0x62_u8, 0xc0_u8, 0xe4_u8, 0x4a_u8,
|
||||
0x8b_u8, 0x29_u8, 0x1a_u8, 0x96_u8, 0x4c_u8, 0xf2_u8, 0xf0_u8, 0x70_u8,
|
||||
0x38_u8]);
|
||||
|
||||
assert_eq!(super::pbkdf2_hmac_sha1(b"pass\x00word", b"sa\x00lt", 4096, 16).unwrap(),
|
||||
vec![0x56_u8, 0xfa_u8, 0x6a_u8, 0xa7_u8, 0x55_u8, 0x48_u8, 0x09_u8, 0x9d_u8,
|
||||
0xcc_u8, 0x37_u8, 0xd7_u8, 0xf0_u8, 0x34_u8, 0x25_u8, 0xe0_u8, 0xc3_u8]);
|
||||
}
|
||||
|
||||
// Test vectors from
|
||||
// https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c
|
||||
#[test]
|
||||
#[cfg(feature = "pkcs5_pbkdf2_hmac")]
|
||||
fn test_pbkdf2_hmac_sha256() {
|
||||
assert_eq!(super::pbkdf2_hmac(b"passwd", b"salt", 1, hash::Type::SHA256, 16).unwrap(),
|
||||
vec![0x55_u8, 0xac_u8, 0x04_u8, 0x6e_u8, 0x56_u8, 0xe3_u8, 0x08_u8, 0x9f_u8,
|
||||
0xec_u8, 0x16_u8, 0x91_u8, 0xc2_u8, 0x25_u8, 0x44_u8, 0xb6_u8, 0x05_u8]);
|
||||
|
||||
assert_eq!(super::pbkdf2_hmac(b"Password", b"NaCl", 80000, hash::Type::SHA256, 16).unwrap(),
|
||||
vec![0x4d_u8, 0xdc_u8, 0xd8_u8, 0xf6_u8, 0x0b_u8, 0x98_u8, 0xbe_u8, 0x21_u8,
|
||||
0x83_u8, 0x0c_u8, 0xee_u8, 0x5e_u8, 0xf2_u8, 0x27_u8, 0x01_u8, 0xf9_u8]);
|
||||
}
|
||||
|
||||
// Test vectors from
|
||||
// https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c
|
||||
#[test]
|
||||
#[cfg(feature = "pkcs5_pbkdf2_hmac")]
|
||||
fn test_pbkdf2_hmac_sha512() {
|
||||
assert_eq!(super::pbkdf2_hmac(b"password", b"NaCL", 1, hash::Type::SHA512, 64).unwrap(),
|
||||
vec![0x73_u8, 0xde_u8, 0xcf_u8, 0xa5_u8, 0x8a_u8, 0xa2_u8, 0xe8_u8, 0x4f_u8,
|
||||
0x94_u8, 0x77_u8, 0x1a_u8, 0x75_u8, 0x73_u8, 0x6b_u8, 0xb8_u8, 0x8b_u8,
|
||||
0xd3_u8, 0xc7_u8, 0xb3_u8, 0x82_u8, 0x70_u8, 0xcf_u8, 0xb5_u8, 0x0c_u8,
|
||||
0xb3_u8, 0x90_u8, 0xed_u8, 0x78_u8, 0xb3_u8, 0x05_u8, 0x65_u8, 0x6a_u8,
|
||||
0xf8_u8, 0x14_u8, 0x8e_u8, 0x52_u8, 0x45_u8, 0x2b_u8, 0x22_u8, 0x16_u8,
|
||||
0xb2_u8, 0xb8_u8, 0x09_u8, 0x8b_u8, 0x76_u8, 0x1f_u8, 0xc6_u8, 0x33_u8,
|
||||
0x60_u8, 0x60_u8, 0xa0_u8, 0x9f_u8, 0x76_u8, 0x41_u8, 0x5e_u8, 0x9f_u8,
|
||||
0x71_u8, 0xea_u8, 0x47_u8, 0xf9_u8, 0xe9_u8, 0x06_u8, 0x43_u8, 0x06_u8]);
|
||||
|
||||
assert_eq!(super::pbkdf2_hmac(b"pass\0word", b"sa\0lt", 1, hash::Type::SHA512, 64).unwrap(),
|
||||
vec![0x71_u8, 0xa0_u8, 0xec_u8, 0x84_u8, 0x2a_u8, 0xbd_u8, 0x5c_u8, 0x67_u8,
|
||||
0x8b_u8, 0xcf_u8, 0xd1_u8, 0x45_u8, 0xf0_u8, 0x9d_u8, 0x83_u8, 0x52_u8,
|
||||
0x2f_u8, 0x93_u8, 0x36_u8, 0x15_u8, 0x60_u8, 0x56_u8, 0x3c_u8, 0x4d_u8,
|
||||
0x0d_u8, 0x63_u8, 0xb8_u8, 0x83_u8, 0x29_u8, 0x87_u8, 0x10_u8, 0x90_u8,
|
||||
0xe7_u8, 0x66_u8, 0x04_u8, 0xa4_u8, 0x9a_u8, 0xf0_u8, 0x8f_u8, 0xe7_u8,
|
||||
0xc9_u8, 0xf5_u8, 0x71_u8, 0x56_u8, 0xc8_u8, 0x79_u8, 0x09_u8, 0x96_u8,
|
||||
0xb2_u8, 0x0f_u8, 0x06_u8, 0xbc_u8, 0x53_u8, 0x5e_u8, 0x5a_u8, 0xb5_u8,
|
||||
0x44_u8, 0x0d_u8, 0xf7_u8, 0xe8_u8, 0x78_u8, 0x29_u8, 0x6f_u8, 0xa7_u8]);
|
||||
|
||||
assert_eq!(super::pbkdf2_hmac(b"passwordPASSWORDpassword",
|
||||
b"salt\0\0\0",
|
||||
50,
|
||||
hash::Type::SHA512,
|
||||
64).unwrap(),
|
||||
vec![0x01_u8, 0x68_u8, 0x71_u8, 0xa4_u8, 0xc4_u8, 0xb7_u8, 0x5f_u8, 0x96_u8,
|
||||
0x85_u8, 0x7f_u8, 0xd2_u8, 0xb9_u8, 0xf8_u8, 0xca_u8, 0x28_u8, 0x02_u8,
|
||||
0x3b_u8, 0x30_u8, 0xee_u8, 0x2a_u8, 0x39_u8, 0xf5_u8, 0xad_u8, 0xca_u8,
|
||||
0xc8_u8, 0xc9_u8, 0x37_u8, 0x5f_u8, 0x9b_u8, 0xda_u8, 0x1c_u8, 0xcd_u8,
|
||||
0x1b_u8, 0x6f_u8, 0x0b_u8, 0x2f_u8, 0xc3_u8, 0xad_u8, 0xda_u8, 0x50_u8,
|
||||
0x54_u8, 0x12_u8, 0xe7_u8, 0x9d_u8, 0x89_u8, 0x00_u8, 0x56_u8, 0xc6_u8,
|
||||
0x2e_u8, 0x52_u8, 0x4c_u8, 0x7d_u8, 0x51_u8, 0x15_u8, 0x4b_u8, 0x1a_u8,
|
||||
0x85_u8, 0x34_u8, 0x57_u8, 0x5b_u8, 0xd0_u8, 0x2d_u8, 0xee_u8, 0x39_u8]);
|
||||
}
|
||||
#[test]
|
||||
fn test_evp_bytes_to_key_pbkdf1_compatible() {
|
||||
let salt = [16_u8, 34_u8, 19_u8, 23_u8, 141_u8, 4_u8, 207_u8, 221_u8];
|
||||
|
||||
let data = [143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8, 241_u8, 242_u8, 31_u8,
|
||||
154_u8, 56_u8, 198_u8, 145_u8, 192_u8, 64_u8, 2_u8, 245_u8, 167_u8, 220_u8,
|
||||
55_u8, 119_u8, 233_u8, 136_u8, 139_u8, 27_u8, 71_u8, 242_u8, 119_u8, 175_u8,
|
||||
65_u8, 207_u8];
|
||||
|
||||
|
||||
|
||||
let expected_key = vec![249_u8, 115_u8, 114_u8, 97_u8, 32_u8, 213_u8, 165_u8, 146_u8,
|
||||
58_u8, 87_u8, 234_u8, 3_u8, 43_u8, 250_u8, 97_u8, 114_u8, 26_u8,
|
||||
98_u8, 245_u8, 246_u8, 238_u8, 177_u8, 229_u8, 161_u8, 183_u8,
|
||||
224_u8, 174_u8, 3_u8, 6_u8, 244_u8, 236_u8, 255_u8];
|
||||
let expected_iv = vec![4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8,
|
||||
69_u8, 98_u8, 107_u8, 208_u8, 14_u8, 236_u8, 60_u8, 0_u8, 0_u8,
|
||||
0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8,
|
||||
0_u8, 0_u8, 0_u8];
|
||||
|
||||
assert_eq!(super::evp_bytes_to_key_pbkdf1_compatible(symm::Type::AES_256_CBC,
|
||||
hash::Type::SHA1,
|
||||
&data,
|
||||
Some(&salt),
|
||||
1).unwrap(),
|
||||
super::KeyIvPair {
|
||||
key: expected_key,
|
||||
iv: expected_iv,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
use libc::{c_void, c_char};
|
||||
use std::ptr;
|
||||
use std::mem;
|
||||
use ffi;
|
||||
|
||||
use bio::{MemBio, MemBioSlice};
|
||||
use crypto::rsa::RSA;
|
||||
use error::ErrorStack;
|
||||
use crypto::util::{CallbackState, invoke_passwd_cb};
|
||||
|
||||
pub struct PKey(*mut ffi::EVP_PKEY);
|
||||
|
||||
unsafe impl Send for PKey {}
|
||||
unsafe impl Sync for PKey {}
|
||||
|
||||
/// Represents a public key, optionally with a private key attached.
|
||||
impl PKey {
|
||||
/// Create a new `PKey` containing an RSA key.
|
||||
pub fn from_rsa(rsa: RSA) -> Result<PKey, ErrorStack> {
|
||||
unsafe {
|
||||
let evp = try_ssl_null!(ffi::EVP_PKEY_new());
|
||||
let pkey = PKey(evp);
|
||||
try_ssl!(ffi::EVP_PKEY_assign(pkey.0, ffi::EVP_PKEY_RSA, rsa.as_ptr() as *mut _));
|
||||
mem::forget(rsa);
|
||||
Ok(pkey)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn from_ptr(handle: *mut ffi::EVP_PKEY) -> PKey {
|
||||
PKey(handle)
|
||||
}
|
||||
|
||||
/// Reads private key from PEM, takes ownership of handle
|
||||
pub fn private_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
|
||||
ffi::init();
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut()));
|
||||
Ok(PKey::from_ptr(evp))
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a private key from PEM, supplying a password callback to be invoked if the private key
|
||||
/// is encrypted.
|
||||
///
|
||||
/// The callback will be passed the password buffer and should return the number of characters
|
||||
/// placed into the buffer.
|
||||
pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<PKey, ErrorStack>
|
||||
where F: FnOnce(&mut [c_char]) -> usize
|
||||
{
|
||||
ffi::init();
|
||||
let mut cb = CallbackState::new(pass_cb);
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
Some(invoke_passwd_cb::<F>),
|
||||
&mut cb as *mut _ as *mut c_void));
|
||||
Ok(PKey::from_ptr(evp))
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads public key from PEM, takes ownership of handle
|
||||
pub fn public_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
|
||||
ffi::init();
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let evp = try_ssl_null!(ffi::PEM_read_bio_PUBKEY(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut()));
|
||||
Ok(PKey::from_ptr(evp))
|
||||
}
|
||||
}
|
||||
|
||||
/// assign RSA key to this pkey
|
||||
pub fn set_rsa(&mut self, rsa: &RSA) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
// this needs to be a reference as the set1_RSA ups the reference count
|
||||
let rsa_ptr = rsa.as_ptr();
|
||||
try_ssl!(ffi::EVP_PKEY_set1_RSA(self.0, rsa_ptr));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a reference to the interal RSA key for direct access to the key components
|
||||
pub fn get_rsa(&self) -> Result<RSA, ErrorStack> {
|
||||
unsafe {
|
||||
let rsa = try_ssl_null!(ffi::EVP_PKEY_get1_RSA(self.0));
|
||||
// this is safe as the ffi increments a reference counter to the internal key
|
||||
Ok(RSA::from_ptr(rsa))
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores private key as a PEM
|
||||
// FIXME: also add password and encryption
|
||||
pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
unsafe {
|
||||
try_ssl!(ffi::PEM_write_bio_PrivateKey(mem_bio.as_ptr(),
|
||||
self.0,
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
-1,
|
||||
None,
|
||||
ptr::null_mut()));
|
||||
|
||||
}
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
/// Stores public key as a PEM
|
||||
pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
unsafe { try_ssl!(ffi::PEM_write_bio_PUBKEY(mem_bio.as_ptr(), self.0)) }
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *mut ffi::EVP_PKEY {
|
||||
return self.0;
|
||||
}
|
||||
|
||||
pub fn public_eq(&self, other: &PKey) -> bool {
|
||||
unsafe { ffi::EVP_PKEY_cmp(self.0, other.0) == 1 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PKey {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ffi::EVP_PKEY_free(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn test_private_key_from_pem() {
|
||||
let key = include_bytes!("../../test/key.pem");
|
||||
super::PKey::private_key_from_pem(key).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_public_key_from_pem() {
|
||||
let key = include_bytes!("../../test/key.pem.pub");
|
||||
super::PKey::public_key_from_pem(key).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pem() {
|
||||
let key = include_bytes!("../../test/key.pem");
|
||||
let key = super::PKey::private_key_from_pem(key).unwrap();
|
||||
|
||||
let priv_key = key.private_key_to_pem().unwrap();
|
||||
let pub_key = key.public_key_to_pem().unwrap();
|
||||
|
||||
// As a super-simple verification, just check that the buffers contain
|
||||
// the `PRIVATE KEY` or `PUBLIC KEY` strings.
|
||||
assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY"));
|
||||
assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY"));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,337 +0,0 @@
|
|||
use ffi;
|
||||
use std::fmt;
|
||||
use std::ptr;
|
||||
use std::mem;
|
||||
use libc::{c_int, c_void, c_char, c_ulong};
|
||||
|
||||
use bn::{BigNum, BigNumRef};
|
||||
use bio::{MemBio, MemBioSlice};
|
||||
use error::ErrorStack;
|
||||
use HashTypeInternals;
|
||||
use crypto::hash;
|
||||
use crypto::util::{CallbackState, invoke_passwd_cb};
|
||||
|
||||
pub struct RSA(*mut ffi::RSA);
|
||||
|
||||
impl Drop for RSA {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ffi::RSA_free(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RSA {
|
||||
/// only useful for associating the key material directly with the key, it's safer to use
|
||||
/// the supplied load and save methods for DER formatted keys.
|
||||
pub fn from_public_components(n: BigNum, e: BigNum) -> Result<RSA, ErrorStack> {
|
||||
unsafe {
|
||||
let rsa = try_ssl_null!(ffi::RSA_new());
|
||||
(*rsa).n = n.as_ptr();
|
||||
(*rsa).e = e.as_ptr();
|
||||
mem::forget(n);
|
||||
mem::forget(e);
|
||||
Ok(RSA(rsa))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_private_components(n: BigNum,
|
||||
e: BigNum,
|
||||
d: BigNum,
|
||||
p: BigNum,
|
||||
q: BigNum,
|
||||
dp: BigNum,
|
||||
dq: BigNum,
|
||||
qi: BigNum)
|
||||
-> Result<RSA, ErrorStack> {
|
||||
unsafe {
|
||||
let rsa = try_ssl_null!(ffi::RSA_new());
|
||||
(*rsa).n = n.as_ptr();
|
||||
(*rsa).e = e.as_ptr();
|
||||
(*rsa).d = d.as_ptr();
|
||||
(*rsa).p = p.as_ptr();
|
||||
(*rsa).q = q.as_ptr();
|
||||
(*rsa).dmp1 = dp.as_ptr();
|
||||
(*rsa).dmq1 = dq.as_ptr();
|
||||
(*rsa).iqmp = qi.as_ptr();
|
||||
mem::forget(n);
|
||||
mem::forget(e);
|
||||
mem::forget(d);
|
||||
mem::forget(p);
|
||||
mem::forget(q);
|
||||
mem::forget(dp);
|
||||
mem::forget(dq);
|
||||
mem::forget(qi);
|
||||
Ok(RSA(rsa))
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn from_ptr(rsa: *mut ffi::RSA) -> RSA {
|
||||
RSA(rsa)
|
||||
}
|
||||
|
||||
/// Generates a public/private key pair with the specified size.
|
||||
///
|
||||
/// The public exponent will be 65537.
|
||||
pub fn generate(bits: u32) -> Result<RSA, ErrorStack> {
|
||||
unsafe {
|
||||
let rsa = try_ssl_null!(ffi::RSA_new());
|
||||
let rsa = RSA(rsa);
|
||||
let e = try!(BigNum::new_from(ffi::RSA_F4 as c_ulong));
|
||||
|
||||
try_ssl!(ffi::RSA_generate_key_ex(rsa.0, bits as c_int, e.as_ptr(), ptr::null_mut()));
|
||||
|
||||
Ok(rsa)
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads an RSA private key from PEM formatted data.
|
||||
pub fn private_key_from_pem(buf: &[u8]) -> Result<RSA, ErrorStack> {
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut()));
|
||||
Ok(RSA(rsa))
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads an RSA private key from PEM formatted data and supplies a password callback.
|
||||
pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<RSA, ErrorStack>
|
||||
where F: FnOnce(&mut [c_char]) -> usize
|
||||
{
|
||||
let mut cb = CallbackState::new(pass_cb);
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
|
||||
unsafe {
|
||||
let cb_ptr = &mut cb as *mut _ as *mut c_void;
|
||||
let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
Some(invoke_passwd_cb::<F>),
|
||||
cb_ptr));
|
||||
|
||||
Ok(RSA(rsa))
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads an RSA public key from PEM formatted data.
|
||||
pub fn public_key_from_pem(buf: &[u8]) -> Result<RSA, ErrorStack> {
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let rsa = try_ssl_null!(ffi::PEM_read_bio_RSA_PUBKEY(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut()));
|
||||
Ok(RSA(rsa))
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes an RSA private key as unencrypted PEM formatted data
|
||||
pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
|
||||
unsafe {
|
||||
try_ssl!(ffi::PEM_write_bio_RSAPrivateKey(mem_bio.as_ptr(),
|
||||
self.0,
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
None,
|
||||
ptr::null_mut()));
|
||||
}
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
/// Writes an RSA public key as PEM formatted data
|
||||
pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
|
||||
unsafe {
|
||||
try_ssl!(ffi::PEM_write_bio_RSA_PUBKEY(mem_bio.as_ptr(), self.0))
|
||||
};
|
||||
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
pub fn size(&self) -> Option<u32> {
|
||||
if self.n().is_some() {
|
||||
unsafe { Some(ffi::RSA_size(self.0) as u32) }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sign(&self, hash: hash::Type, message: &[u8]) -> Result<Vec<u8>, ErrorStack> {
|
||||
let k_len = self.size().expect("RSA missing an n");
|
||||
let mut sig = vec![0; k_len as usize];
|
||||
let mut sig_len = k_len;
|
||||
|
||||
unsafe {
|
||||
try_ssl!(ffi::RSA_sign(hash.as_nid() as c_int,
|
||||
message.as_ptr(),
|
||||
message.len() as u32,
|
||||
sig.as_mut_ptr(),
|
||||
&mut sig_len,
|
||||
self.0));
|
||||
assert!(sig_len == k_len);
|
||||
Ok(sig)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify(&self, hash: hash::Type, message: &[u8], sig: &[u8]) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
try_ssl!(ffi::RSA_verify(hash.as_nid() as c_int,
|
||||
message.as_ptr(),
|
||||
message.len() as u32,
|
||||
sig.as_ptr(),
|
||||
sig.len() as u32,
|
||||
self.0));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *mut ffi::RSA {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn n<'a>(&'a self) -> Option<BigNumRef<'a>> {
|
||||
unsafe {
|
||||
let n = (*self.0).n;
|
||||
if n.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(n))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn d<'a>(&self) -> Option<BigNumRef<'a>> {
|
||||
unsafe {
|
||||
let d = (*self.0).d;
|
||||
if d.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(d))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn e<'a>(&'a self) -> Option<BigNumRef<'a>> {
|
||||
unsafe {
|
||||
let e = (*self.0).e;
|
||||
if e.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn p<'a>(&'a self) -> Option<BigNumRef<'a>> {
|
||||
unsafe {
|
||||
let p = (*self.0).p;
|
||||
if p.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(p))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn q<'a>(&'a self) -> Option<BigNumRef<'a>> {
|
||||
unsafe {
|
||||
let q = (*self.0).q;
|
||||
if q.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(q))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for RSA {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "RSA")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::io::Write;
|
||||
use libc::c_char;
|
||||
|
||||
use super::*;
|
||||
use crypto::hash::*;
|
||||
|
||||
fn signing_input_rs256() -> Vec<u8> {
|
||||
vec![101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 83, 85, 122, 73, 49, 78, 105, 74, 57,
|
||||
46, 101, 121, 74, 112, 99, 51, 77, 105, 79, 105, 74, 113, 98, 50, 85, 105, 76, 65, 48,
|
||||
75, 73, 67, 74, 108, 101, 72, 65, 105, 79, 106, 69, 122, 77, 68, 65, 52, 77, 84, 107,
|
||||
122, 79, 68, 65, 115, 68, 81, 111, 103, 73, 109, 104, 48, 100, 72, 65, 54, 76, 121,
|
||||
57, 108, 101, 71, 70, 116, 99, 71, 120, 108, 76, 109, 78, 118, 98, 83, 57, 112, 99,
|
||||
49, 57, 121, 98, 50, 57, 48, 73, 106, 112, 48, 99, 110, 86, 108, 102, 81]
|
||||
}
|
||||
|
||||
fn signature_rs256() -> Vec<u8> {
|
||||
vec![112, 46, 33, 137, 67, 232, 143, 209, 30, 181, 216, 45, 191, 120, 69, 243, 65, 6, 174,
|
||||
27, 129, 255, 247, 115, 17, 22, 173, 209, 113, 125, 131, 101, 109, 66, 10, 253, 60,
|
||||
150, 238, 221, 115, 162, 102, 62, 81, 102, 104, 123, 0, 11, 135, 34, 110, 1, 135, 237,
|
||||
16, 115, 249, 69, 229, 130, 173, 252, 239, 22, 216, 90, 121, 142, 232, 198, 109, 219,
|
||||
61, 184, 151, 91, 23, 208, 148, 2, 190, 237, 213, 217, 217, 112, 7, 16, 141, 178, 129,
|
||||
96, 213, 248, 4, 12, 167, 68, 87, 98, 184, 31, 190, 127, 249, 217, 46, 10, 231, 111,
|
||||
36, 242, 91, 51, 187, 230, 244, 74, 230, 30, 177, 4, 10, 203, 32, 4, 77, 62, 249, 18,
|
||||
142, 212, 1, 48, 121, 91, 212, 189, 59, 65, 238, 202, 208, 102, 171, 101, 25, 129,
|
||||
253, 228, 141, 247, 127, 55, 45, 195, 139, 159, 175, 221, 59, 239, 177, 139, 93, 163,
|
||||
204, 60, 46, 176, 47, 158, 58, 65, 214, 18, 202, 173, 21, 145, 18, 115, 160, 95, 35,
|
||||
185, 232, 56, 250, 175, 132, 157, 105, 132, 41, 239, 90, 30, 136, 121, 130, 54, 195,
|
||||
212, 14, 96, 69, 34, 165, 68, 200, 242, 122, 122, 45, 184, 6, 99, 209, 108, 247, 202,
|
||||
234, 86, 222, 64, 92, 178, 33, 90, 69, 178, 194, 85, 102, 181, 90, 193, 167, 72, 160,
|
||||
112, 223, 200, 163, 42, 70, 149, 67, 208, 25, 238, 251, 71]
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_sign() {
|
||||
let key = include_bytes!("../../test/rsa.pem");
|
||||
let private_key = RSA::private_key_from_pem(key).unwrap();
|
||||
|
||||
let mut sha = Hasher::new(Type::SHA256).unwrap();
|
||||
sha.write_all(&signing_input_rs256()).unwrap();
|
||||
let digest = sha.finish().unwrap();
|
||||
|
||||
let result = private_key.sign(Type::SHA256, &digest).unwrap();
|
||||
|
||||
assert_eq!(result, signature_rs256());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_verify() {
|
||||
let key = include_bytes!("../../test/rsa.pem.pub");
|
||||
let public_key = RSA::public_key_from_pem(key).unwrap();
|
||||
|
||||
let mut sha = Hasher::new(Type::SHA256).unwrap();
|
||||
sha.write_all(&signing_input_rs256()).unwrap();
|
||||
let digest = sha.finish().unwrap();
|
||||
|
||||
assert!(public_key.verify(Type::SHA256, &digest, &signature_rs256()).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_password() {
|
||||
let mut password_queried = false;
|
||||
let key = include_bytes!("../../test/rsa-encrypted.pem");
|
||||
RSA::private_key_from_pem_cb(key, |password| {
|
||||
password_queried = true;
|
||||
password[0] = b'm' as c_char;
|
||||
password[1] = b'y' as c_char;
|
||||
password[2] = b'p' as c_char;
|
||||
password[3] = b'a' as c_char;
|
||||
password[4] = b's' as c_char;
|
||||
password[5] = b's' as c_char;
|
||||
6
|
||||
}).unwrap();
|
||||
|
||||
assert!(password_queried);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
use ffi;
|
||||
use error::ErrorStack;
|
||||
use bio::MemBioSlice;
|
||||
use std::ptr;
|
||||
use std::mem;
|
||||
|
||||
use {cvt, cvt_p};
|
||||
use bio::MemBio;
|
||||
use bn::BigNum;
|
||||
use types::OpenSslTypeRef;
|
||||
|
||||
type_!(Dh, DhRef, ffi::DH, ffi::DH_free);
|
||||
|
||||
impl DhRef {
|
||||
/// Encodes the parameters to PEM.
|
||||
pub fn to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
|
||||
unsafe {
|
||||
try!(cvt(ffi::PEM_write_bio_DHparams(mem_bio.as_ptr(), self.as_ptr())));
|
||||
}
|
||||
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl Dh {
|
||||
pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result<Dh, ErrorStack> {
|
||||
unsafe {
|
||||
let dh = Dh(try!(cvt_p(ffi::DH_new())));
|
||||
try!(cvt(compat::DH_set0_pqg(dh.0, p.as_ptr(), q.as_ptr(), g.as_ptr())));
|
||||
mem::forget((p, g, q));
|
||||
Ok(dh)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_pem(buf: &[u8]) -> Result<Dh, ErrorStack> {
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
cvt_p(ffi::PEM_read_bio_DHparams(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut()))
|
||||
.map(Dh)
|
||||
}
|
||||
}
|
||||
|
||||
/// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
|
||||
#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
|
||||
pub fn get_1024_160() -> Result<Dh, ErrorStack> {
|
||||
unsafe { cvt_p(ffi::DH_get_1024_160()).map(Dh) }
|
||||
}
|
||||
|
||||
/// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
|
||||
#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
|
||||
pub fn get_2048_224() -> Result<Dh, ErrorStack> {
|
||||
unsafe { cvt_p(ffi::DH_get_2048_224()).map(Dh) }
|
||||
}
|
||||
|
||||
/// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
|
||||
#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
|
||||
pub fn get_2048_256() -> Result<Dh, ErrorStack> {
|
||||
unsafe { cvt_p(ffi::DH_get_2048_256()).map(Dh) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(ossl110)]
|
||||
mod compat {
|
||||
pub use ffi::DH_set0_pqg;
|
||||
}
|
||||
|
||||
#[cfg(ossl10x)]
|
||||
#[allow(bad_style)]
|
||||
mod compat {
|
||||
use ffi;
|
||||
use libc::c_int;
|
||||
|
||||
pub unsafe fn DH_set0_pqg(dh: *mut ffi::DH,
|
||||
p: *mut ffi::BIGNUM,
|
||||
q: *mut ffi::BIGNUM,
|
||||
g: *mut ffi::BIGNUM)
|
||||
-> c_int {
|
||||
(*dh).p = p;
|
||||
(*dh).q = q;
|
||||
(*dh).g = g;
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use dh::Dh;
|
||||
use bn::BigNum;
|
||||
use ssl::{SslMethod, SslContext};
|
||||
|
||||
#[test]
|
||||
#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
|
||||
fn test_dh_rfc5114() {
|
||||
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
||||
let dh1 = Dh::get_1024_160().unwrap();
|
||||
ctx.set_tmp_dh(&dh1).unwrap();
|
||||
let dh2 = Dh::get_2048_224().unwrap();
|
||||
ctx.set_tmp_dh(&dh2).unwrap();
|
||||
let dh3 = Dh::get_2048_256().unwrap();
|
||||
ctx.set_tmp_dh(&dh3).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dh() {
|
||||
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
||||
let p = BigNum::from_hex_str("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435\
|
||||
E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF429\
|
||||
6D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C02\
|
||||
2E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF1230\
|
||||
7F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9\
|
||||
A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251C\
|
||||
CACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE\
|
||||
621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D227\
|
||||
6E11715F693877FAD7EF09CADB094AE91E1A1597")
|
||||
.unwrap();
|
||||
let g = BigNum::from_hex_str("3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0\
|
||||
BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773\
|
||||
BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2D\
|
||||
DF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428E\
|
||||
BC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BF\
|
||||
FE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7\
|
||||
D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92\
|
||||
B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148\
|
||||
D47954515E2327CFEF98C582664B4C0F6CC41659")
|
||||
.unwrap();
|
||||
let q = BigNum::from_hex_str("8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F\
|
||||
5FBD3")
|
||||
.unwrap();
|
||||
let dh = Dh::from_params(p, g, q).unwrap();
|
||||
ctx.set_tmp_dh(&dh).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dh_from_pem() {
|
||||
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
||||
let params = include_bytes!("../test/dhparams.pem");
|
||||
let dh = Dh::from_pem(params).ok().expect("Failed to load PEM");
|
||||
ctx.set_tmp_dh(&dh).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
use ffi;
|
||||
use error::ErrorStack;
|
||||
use bio::MemBioSlice;
|
||||
use std::ptr;
|
||||
|
||||
#[cfg(feature = "dh_from_params")]
|
||||
use bn::BigNum;
|
||||
#[cfg(feature = "dh_from_params")]
|
||||
use std::mem;
|
||||
|
||||
pub struct DH(*mut ffi::DH);
|
||||
|
||||
impl DH {
|
||||
/// Requires the `dh_from_params` feature.
|
||||
#[cfg(feature = "dh_from_params")]
|
||||
pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result<DH, ErrorStack> {
|
||||
let dh = unsafe {
|
||||
try_ssl_null!(::c_helpers::rust_0_8_DH_new_from_params(p.as_ptr(), g.as_ptr(), q.as_ptr()))
|
||||
};
|
||||
mem::forget(p);
|
||||
mem::forget(g);
|
||||
mem::forget(q);
|
||||
Ok(DH(dh))
|
||||
}
|
||||
|
||||
pub fn from_pem(buf: &[u8]) -> Result<DH, ErrorStack> {
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
let dh = unsafe {
|
||||
ffi::PEM_read_bio_DHparams(mem_bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut())
|
||||
};
|
||||
try_ssl_null!(dh);
|
||||
Ok(DH(dh))
|
||||
}
|
||||
|
||||
#[cfg(feature = "rfc5114")]
|
||||
pub fn get_1024_160() -> Result<DH, ErrorStack> {
|
||||
let dh = try_ssl_null!(unsafe { ffi::DH_get_1024_160() });
|
||||
Ok(DH(dh))
|
||||
}
|
||||
|
||||
#[cfg(feature = "rfc5114")]
|
||||
pub fn get_2048_224() -> Result<DH, ErrorStack> {
|
||||
let dh = try_ssl_null!(unsafe { ffi::DH_get_2048_224() });
|
||||
Ok(DH(dh))
|
||||
}
|
||||
|
||||
#[cfg(feature = "rfc5114")]
|
||||
pub fn get_2048_256() -> Result<DH, ErrorStack> {
|
||||
let dh = try_ssl_null!(unsafe { ffi::DH_get_2048_256() });
|
||||
Ok(DH(dh))
|
||||
}
|
||||
|
||||
pub unsafe fn as_ptr(&self) -> *mut ffi::DH {
|
||||
let DH(n) = *self;
|
||||
n
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DH {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ffi::DH_free(self.as_ptr())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DH;
|
||||
use bn::BigNum;
|
||||
use ssl::SslContext;
|
||||
use ssl::SslMethod::Sslv23;
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "rfc5114")]
|
||||
fn test_dh_rfc5114() {
|
||||
let mut ctx = SslContext::new(Sslv23).unwrap();
|
||||
let dh1 = DH::get_1024_160().unwrap();
|
||||
ctx.set_tmp_dh(&dh1).unwrap();
|
||||
let dh2 = DH::get_2048_224().unwrap();
|
||||
ctx.set_tmp_dh(&dh2).unwrap();
|
||||
let dh3 = DH::get_2048_256().unwrap();
|
||||
ctx.set_tmp_dh(&dh3).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "dh_from_params")]
|
||||
fn test_dh() {
|
||||
let mut ctx = SslContext::new(Sslv23).unwrap();
|
||||
let p = BigNum::from_hex_str("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435\
|
||||
E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF429\
|
||||
6D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C02\
|
||||
2E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF1230\
|
||||
7F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9\
|
||||
A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251C\
|
||||
CACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE\
|
||||
621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D227\
|
||||
6E11715F693877FAD7EF09CADB094AE91E1A1597")
|
||||
.unwrap();
|
||||
let g = BigNum::from_hex_str("3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0\
|
||||
BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773\
|
||||
BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2D\
|
||||
DF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428E\
|
||||
BC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BF\
|
||||
FE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7\
|
||||
D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92\
|
||||
B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148\
|
||||
D47954515E2327CFEF98C582664B4C0F6CC41659")
|
||||
.unwrap();
|
||||
let q = BigNum::from_hex_str("8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F\
|
||||
5FBD3")
|
||||
.unwrap();
|
||||
let dh = DH::from_params(p, g, q).unwrap();
|
||||
ctx.set_tmp_dh(&dh).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dh_from_pem() {
|
||||
let mut ctx = SslContext::new(Sslv23).unwrap();
|
||||
let params = include_bytes!("../../test/dhparams.pem");
|
||||
let dh = DH::from_pem(params).ok().expect("Failed to load PEM");
|
||||
ctx.set_tmp_dh(&dh).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
use error::ErrorStack;
|
||||
use ffi;
|
||||
use libc::{c_int, c_char, c_void};
|
||||
use std::fmt;
|
||||
use std::ptr;
|
||||
|
||||
use bio::{MemBio, MemBioSlice};
|
||||
use bn::BigNumRef;
|
||||
use {cvt, cvt_p};
|
||||
use types::OpenSslTypeRef;
|
||||
use util::{CallbackState, invoke_passwd_cb};
|
||||
|
||||
type_!(Dsa, DsaRef, ffi::DSA, ffi::DSA_free);
|
||||
|
||||
impl DsaRef {
|
||||
/// Writes an DSA private key as unencrypted PEM formatted data
|
||||
pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
assert!(self.has_private_key());
|
||||
let mem_bio = try!(MemBio::new());
|
||||
|
||||
unsafe {
|
||||
try!(cvt(ffi::PEM_write_bio_DSAPrivateKey(mem_bio.as_ptr(), self.as_ptr(),
|
||||
ptr::null(), ptr::null_mut(), 0,
|
||||
None, ptr::null_mut())))
|
||||
};
|
||||
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
/// Writes an DSA public key as PEM formatted data
|
||||
pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
unsafe {
|
||||
try!(cvt(ffi::PEM_write_bio_DSA_PUBKEY(mem_bio.as_ptr(), self.as_ptr())));
|
||||
}
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
pub fn size(&self) -> Option<u32> {
|
||||
if self.q().is_some() {
|
||||
unsafe { Some(ffi::DSA_size(self.as_ptr()) as u32) }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn p(&self) -> Option<&BigNumRef> {
|
||||
unsafe {
|
||||
let p = compat::pqg(self.as_ptr())[0];
|
||||
if p.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(p as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn q(&self) -> Option<&BigNumRef> {
|
||||
unsafe {
|
||||
let q = compat::pqg(self.as_ptr())[1];
|
||||
if q.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(q as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn g(&self) -> Option<&BigNumRef> {
|
||||
unsafe {
|
||||
let g = compat::pqg(self.as_ptr())[2];
|
||||
if g.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(g as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_public_key(&self) -> bool {
|
||||
unsafe { !compat::keys(self.as_ptr())[0].is_null() }
|
||||
}
|
||||
|
||||
pub fn has_private_key(&self) -> bool {
|
||||
unsafe { !compat::keys(self.as_ptr())[1].is_null() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Dsa {
|
||||
/// Generate a DSA key pair.
|
||||
pub fn generate(bits: u32) -> Result<Dsa, ErrorStack> {
|
||||
unsafe {
|
||||
let dsa = Dsa(try!(cvt_p(ffi::DSA_new())));
|
||||
try!(cvt(ffi::DSA_generate_parameters_ex(dsa.0,
|
||||
bits as c_int,
|
||||
ptr::null(),
|
||||
0,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut())));
|
||||
try!(cvt(ffi::DSA_generate_key(dsa.0)));
|
||||
Ok(dsa)
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a DSA private key from PEM formatted data.
|
||||
pub fn private_key_from_pem(buf: &[u8]) -> Result<Dsa, ErrorStack> {
|
||||
ffi::init();
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
|
||||
unsafe {
|
||||
let dsa = try!(cvt_p(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut())));
|
||||
Ok(Dsa(dsa))
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a private key from PEM supplying a password callback to be invoked if the private key
|
||||
/// is encrypted.
|
||||
///
|
||||
/// The callback will be passed the password buffer and should return the number of characters
|
||||
/// placed into the buffer.
|
||||
pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<Dsa, ErrorStack>
|
||||
where F: FnOnce(&mut [c_char]) -> usize
|
||||
{
|
||||
ffi::init();
|
||||
let mut cb = CallbackState::new(pass_cb);
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
|
||||
unsafe {
|
||||
let cb_ptr = &mut cb as *mut _ as *mut c_void;
|
||||
let dsa = try!(cvt_p(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
Some(invoke_passwd_cb::<F>),
|
||||
cb_ptr)));
|
||||
Ok(Dsa(dsa))
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads an DSA public key from PEM formatted data.
|
||||
pub fn public_key_from_pem(buf: &[u8]) -> Result<Dsa, ErrorStack> {
|
||||
ffi::init();
|
||||
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let dsa = try!(cvt_p(ffi::PEM_read_bio_DSA_PUBKEY(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut())));
|
||||
Ok(Dsa(dsa))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Dsa {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DSA")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(ossl110)]
|
||||
mod compat {
|
||||
use std::ptr;
|
||||
use ffi::{self, BIGNUM, DSA};
|
||||
|
||||
pub unsafe fn pqg(d: *const DSA) -> [*const BIGNUM; 3] {
|
||||
let (mut p, mut q, mut g) = (ptr::null(), ptr::null(), ptr::null());
|
||||
ffi::DSA_get0_pqg(d, &mut p, &mut q, &mut g);
|
||||
[p, q, g]
|
||||
}
|
||||
|
||||
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]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use libc::c_char;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
pub fn test_generate() {
|
||||
Dsa::generate(1024).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_password() {
|
||||
let mut password_queried = false;
|
||||
let key = include_bytes!("../test/dsa-encrypted.pem");
|
||||
Dsa::private_key_from_pem_cb(key, |password| {
|
||||
password_queried = true;
|
||||
password[0] = b'm' as c_char;
|
||||
password[1] = b'y' as c_char;
|
||||
password[2] = b'p' as c_char;
|
||||
password[3] = b'a' as c_char;
|
||||
password[4] = b's' as c_char;
|
||||
password[5] = b's' as c_char;
|
||||
6
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert!(password_queried);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
use ffi;
|
||||
|
||||
use cvt_p;
|
||||
use error::ErrorStack;
|
||||
use nid::Nid;
|
||||
|
||||
type_!(EcKey, EcKeyRef, ffi::EC_KEY, ffi::EC_KEY_free);
|
||||
|
||||
impl EcKey {
|
||||
pub fn new_by_curve_name(nid: Nid) -> Result<EcKey, ErrorStack> {
|
||||
unsafe { cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(EcKey) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use nid;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn new_by_curve_name() {
|
||||
EcKey::new_by_curve_name(nid::X9_62_PRIME256V1).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
@ -71,44 +71,84 @@ impl Error {
|
|||
|
||||
match unsafe { ffi::ERR_get_error() } {
|
||||
0 => None,
|
||||
err => Some((Error(err))),
|
||||
err => Some(Error(err)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the raw OpenSSL error code for this error.
|
||||
pub fn error_code(&self) -> c_ulong {
|
||||
pub fn code(&self) -> c_ulong {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Returns the name of the library reporting the error.
|
||||
pub fn library(&self) -> &'static str {
|
||||
get_lib(self.0)
|
||||
/// Returns the name of the library reporting the error, if available.
|
||||
pub fn library(&self) -> Option<&'static str> {
|
||||
unsafe {
|
||||
let cstr = ffi::ERR_lib_error_string(self.0);
|
||||
if cstr.is_null() {
|
||||
return None;
|
||||
}
|
||||
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
|
||||
Some(str::from_utf8(bytes).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the name of the function reporting the error.
|
||||
pub fn function(&self) -> &'static str {
|
||||
get_func(self.0)
|
||||
pub fn function(&self) -> Option<&'static str> {
|
||||
unsafe {
|
||||
let cstr = ffi::ERR_func_error_string(self.0);
|
||||
if cstr.is_null() {
|
||||
return None;
|
||||
}
|
||||
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
|
||||
Some(str::from_utf8(bytes).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the reason for the error.
|
||||
pub fn reason(&self) -> &'static str {
|
||||
get_reason(self.0)
|
||||
pub fn reason(&self) -> Option<&'static str> {
|
||||
unsafe {
|
||||
let cstr = ffi::ERR_reason_error_string(self.0);
|
||||
if cstr.is_null() {
|
||||
return None;
|
||||
}
|
||||
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
|
||||
Some(str::from_utf8(bytes).unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Error {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("Error")
|
||||
.field("library", &self.library())
|
||||
.field("function", &self.function())
|
||||
.field("reason", &self.reason())
|
||||
.finish()
|
||||
let mut builder = fmt.debug_struct("Error");
|
||||
builder.field("code", &self.code());
|
||||
if let Some(library) = self.library() {
|
||||
builder.field("library", &library);
|
||||
}
|
||||
if let Some(function) = self.function() {
|
||||
builder.field("function", &function);
|
||||
}
|
||||
if let Some(reason) = self.reason() {
|
||||
builder.field("reason", &reason);
|
||||
}
|
||||
builder.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.write_str(&self.reason())
|
||||
try!(write!(fmt, "error:{:08X}", self.0));
|
||||
match self.library() {
|
||||
Some(l) => try!(write!(fmt, ":{}", l)),
|
||||
None => try!(write!(fmt, ":lib({})", ffi::ERR_GET_LIB(self.0))),
|
||||
}
|
||||
match self.function() {
|
||||
Some(f) => try!(write!(fmt, ":{}", f)),
|
||||
None => try!(write!(fmt, ":func({})", ffi::ERR_GET_FUNC(self.0))),
|
||||
}
|
||||
match self.reason() {
|
||||
Some(r) => write!(fmt, ":{}", r),
|
||||
None => write!(fmt, ":reason({})", ffi::ERR_GET_FUNC(self.0)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,28 +157,3 @@ impl error::Error for Error {
|
|||
"An OpenSSL error"
|
||||
}
|
||||
}
|
||||
|
||||
fn get_lib(err: c_ulong) -> &'static str {
|
||||
unsafe {
|
||||
let cstr = ffi::ERR_lib_error_string(err);
|
||||
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
|
||||
str::from_utf8(bytes).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_func(err: c_ulong) -> &'static str {
|
||||
unsafe {
|
||||
let cstr = ffi::ERR_func_error_string(err);
|
||||
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
|
||||
str::from_utf8(bytes).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_reason(err: c_ulong) -> &'static str {
|
||||
unsafe {
|
||||
let cstr = ffi::ERR_reason_error_string(err);
|
||||
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
|
||||
str::from_utf8(bytes).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,51 +1,49 @@
|
|||
use libc::c_uint;
|
||||
use std::io::prelude::*;
|
||||
use std::io;
|
||||
use std::ptr;
|
||||
use std::cmp;
|
||||
use ffi;
|
||||
|
||||
use HashTypeInternals;
|
||||
#[cfg(ossl110)]
|
||||
use ffi::{EVP_MD_CTX_new, EVP_MD_CTX_free};
|
||||
#[cfg(any(ossl101, ossl102))]
|
||||
use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free};
|
||||
|
||||
use {cvt, cvt_p};
|
||||
use error::ErrorStack;
|
||||
use nid::Nid;
|
||||
|
||||
/// Message digest (hash) type.
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Type {
|
||||
MD5,
|
||||
SHA1,
|
||||
SHA224,
|
||||
SHA256,
|
||||
SHA384,
|
||||
SHA512,
|
||||
RIPEMD160,
|
||||
}
|
||||
pub struct MessageDigest(*const ffi::EVP_MD);
|
||||
|
||||
impl HashTypeInternals for Type {
|
||||
fn as_nid(&self) -> Nid {
|
||||
match *self {
|
||||
Type::MD5 => Nid::MD5,
|
||||
Type::SHA1 => Nid::SHA1,
|
||||
Type::SHA224 => Nid::SHA224,
|
||||
Type::SHA256 => Nid::SHA256,
|
||||
Type::SHA384 => Nid::SHA384,
|
||||
Type::SHA512 => Nid::SHA512,
|
||||
Type::RIPEMD160 => Nid::RIPEMD160,
|
||||
}
|
||||
impl MessageDigest {
|
||||
pub fn md5() -> MessageDigest {
|
||||
unsafe { MessageDigest(ffi::EVP_md5()) }
|
||||
}
|
||||
|
||||
fn evp_md(&self) -> *const ffi::EVP_MD {
|
||||
unsafe {
|
||||
match *self {
|
||||
Type::MD5 => ffi::EVP_md5(),
|
||||
Type::SHA1 => ffi::EVP_sha1(),
|
||||
Type::SHA224 => ffi::EVP_sha224(),
|
||||
Type::SHA256 => ffi::EVP_sha256(),
|
||||
Type::SHA384 => ffi::EVP_sha384(),
|
||||
Type::SHA512 => ffi::EVP_sha512(),
|
||||
Type::RIPEMD160 => ffi::EVP_ripemd160(),
|
||||
}
|
||||
}
|
||||
pub fn sha1() -> MessageDigest {
|
||||
unsafe { MessageDigest(ffi::EVP_sha1()) }
|
||||
}
|
||||
|
||||
pub fn sha224() -> MessageDigest {
|
||||
unsafe { MessageDigest(ffi::EVP_sha224()) }
|
||||
}
|
||||
|
||||
pub fn sha256() -> MessageDigest {
|
||||
unsafe { MessageDigest(ffi::EVP_sha256()) }
|
||||
}
|
||||
|
||||
pub fn sha384() -> MessageDigest {
|
||||
unsafe { MessageDigest(ffi::EVP_sha384()) }
|
||||
}
|
||||
|
||||
pub fn sha512() -> MessageDigest {
|
||||
unsafe { MessageDigest(ffi::EVP_sha512()) }
|
||||
}
|
||||
|
||||
pub fn ripemd160() -> MessageDigest {
|
||||
unsafe { MessageDigest(ffi::EVP_ripemd160()) }
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *const ffi::EVP_MD {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,20 +63,22 @@ use self::State::*;
|
|||
/// Calculate a hash in one go.
|
||||
///
|
||||
/// ```
|
||||
/// use openssl::crypto::hash::{hash, Type};
|
||||
/// use openssl::hash::{hash, MessageDigest};
|
||||
///
|
||||
/// let data = b"\x42\xF4\x97\xE0";
|
||||
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
|
||||
/// let res = hash(Type::MD5, data).unwrap();
|
||||
/// let res = hash(MessageDigest::md5(), data).unwrap();
|
||||
/// assert_eq!(res, spec);
|
||||
/// ```
|
||||
///
|
||||
/// Use the `Write` trait to supply the input in chunks.
|
||||
///
|
||||
/// ```
|
||||
/// use openssl::crypto::hash::{Hasher, Type};
|
||||
/// use openssl::hash::{Hasher, MessageDigest};
|
||||
///
|
||||
/// let data = [b"\x42\xF4", b"\x97\xE0"];
|
||||
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
|
||||
/// let mut h = Hasher::new(Type::MD5).unwrap();
|
||||
/// let mut h = Hasher::new(MessageDigest::md5()).unwrap();
|
||||
/// h.update(data[0]).unwrap();
|
||||
/// h.update(data[1]).unwrap();
|
||||
/// let res = h.finish().unwrap();
|
||||
|
|
@ -89,25 +89,24 @@ use self::State::*;
|
|||
///
|
||||
/// Don't actually use MD5 and SHA-1 hashes, they're not secure anymore.
|
||||
///
|
||||
/// Don't ever hash passwords, use `crypto::pkcs5` or bcrypt/scrypt instead.
|
||||
/// Don't ever hash passwords, use the functions in the `pkcs5` module or bcrypt/scrypt instead.
|
||||
pub struct Hasher {
|
||||
ctx: *mut ffi::EVP_MD_CTX,
|
||||
md: *const ffi::EVP_MD,
|
||||
type_: Type,
|
||||
type_: MessageDigest,
|
||||
state: State,
|
||||
}
|
||||
|
||||
impl Hasher {
|
||||
/// Creates a new `Hasher` with the specified hash type.
|
||||
pub fn new(ty: Type) -> Result<Hasher, ErrorStack> {
|
||||
pub fn new(ty: MessageDigest) -> Result<Hasher, ErrorStack> {
|
||||
ffi::init();
|
||||
|
||||
let ctx = unsafe { try_ssl_null!(ffi::EVP_MD_CTX_create()) };
|
||||
let md = ty.evp_md();
|
||||
let ctx = unsafe { try!(cvt_p(EVP_MD_CTX_new())) };
|
||||
|
||||
let mut h = Hasher {
|
||||
ctx: ctx,
|
||||
md: md,
|
||||
md: ty.as_ptr(),
|
||||
type_: ty,
|
||||
state: Finalized,
|
||||
};
|
||||
|
|
@ -123,22 +122,20 @@ impl Hasher {
|
|||
}
|
||||
Finalized => (),
|
||||
}
|
||||
unsafe { try_ssl!(ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *const _)); }
|
||||
unsafe {
|
||||
try!(cvt(ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *mut _)));
|
||||
}
|
||||
self.state = Reset;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Feeds data into the hasher.
|
||||
pub fn update(&mut self, mut data: &[u8]) -> Result<(), ErrorStack> {
|
||||
pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
|
||||
if self.state == Finalized {
|
||||
try!(self.init());
|
||||
}
|
||||
while !data.is_empty() {
|
||||
let len = cmp::min(data.len(), c_uint::max_value() as usize);
|
||||
unsafe {
|
||||
try_ssl!(ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), len as c_uint));
|
||||
}
|
||||
data = &data[len..];
|
||||
unsafe {
|
||||
try!(cvt(ffi::EVP_DigestUpdate(self.ctx, data.as_ptr() as *mut _, data.len())));
|
||||
}
|
||||
self.state = Updated;
|
||||
Ok(())
|
||||
|
|
@ -153,7 +150,7 @@ impl Hasher {
|
|||
unsafe {
|
||||
let mut len = ffi::EVP_MAX_MD_SIZE;
|
||||
let mut res = vec![0; len as usize];
|
||||
try_ssl!(ffi::EVP_DigestFinal_ex(self.ctx, res.as_mut_ptr(), &mut len));
|
||||
try!(cvt(ffi::EVP_DigestFinal_ex(self.ctx, res.as_mut_ptr(), &mut len)));
|
||||
res.truncate(len as usize);
|
||||
self.state = Finalized;
|
||||
Ok(res)
|
||||
|
|
@ -176,7 +173,7 @@ impl Write for Hasher {
|
|||
impl Clone for Hasher {
|
||||
fn clone(&self) -> Hasher {
|
||||
let ctx = unsafe {
|
||||
let ctx = ffi::EVP_MD_CTX_create();
|
||||
let ctx = EVP_MD_CTX_new();
|
||||
assert!(!ctx.is_null());
|
||||
let r = ffi::EVP_MD_CTX_copy_ex(ctx, self.ctx);
|
||||
assert_eq!(r, 1);
|
||||
|
|
@ -197,13 +194,13 @@ impl Drop for Hasher {
|
|||
if self.state != Finalized {
|
||||
drop(self.finish());
|
||||
}
|
||||
ffi::EVP_MD_CTX_destroy(self.ctx);
|
||||
EVP_MD_CTX_free(self.ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the hash of the `data` with the hash `t`.
|
||||
pub fn hash(t: Type, data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
|
||||
pub fn hash(t: MessageDigest, data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mut h = try!(Hasher::new(t));
|
||||
try!(h.update(data));
|
||||
h.finish()
|
||||
|
|
@ -212,10 +209,10 @@ pub fn hash(t: Type, data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serialize::hex::{FromHex, ToHex};
|
||||
use super::{hash, Hasher, Type};
|
||||
use super::{hash, Hasher, MessageDigest};
|
||||
use std::io::prelude::*;
|
||||
|
||||
fn hash_test(hashtype: Type, hashtest: &(&str, &str)) {
|
||||
fn hash_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
|
||||
let res = hash(hashtype, &*hashtest.0.from_hex().unwrap()).unwrap();
|
||||
assert_eq!(res.to_hex(), hashtest.1);
|
||||
}
|
||||
|
|
@ -228,43 +225,31 @@ mod tests {
|
|||
|
||||
// Test vectors from http://www.nsrl.nist.gov/testdata/
|
||||
#[allow(non_upper_case_globals)]
|
||||
const md5_tests: [(&'static str, &'static str); 13] = [("",
|
||||
"d41d8cd98f00b204e9800998ecf8427e"),
|
||||
("7F",
|
||||
"83acb6e67e50e31db6ed341dd2de1595"),
|
||||
("EC9C",
|
||||
"0b07f0d4ca797d8ac58874f887cb0b68"),
|
||||
("FEE57A",
|
||||
"e0d583171eb06d56198fc0ef22173907"),
|
||||
("42F497E0",
|
||||
"7c430f178aefdf1487fee7144e9641e2"),
|
||||
("C53B777F1C",
|
||||
"75ef141d64cb37ec423da2d9d440c925"),
|
||||
("89D5B576327B",
|
||||
"ebbaf15eb0ed784c6faa9dc32831bf33"),
|
||||
("5D4CCE781EB190",
|
||||
"ce175c4b08172019f05e6b5279889f2c"),
|
||||
("81901FE94932D7B9",
|
||||
"cd4d2f62b8cdb3a0cf968a735a239281"),
|
||||
("C9FFDEE7788EFB4EC9",
|
||||
"e0841a231ab698db30c6c0f3f246c014"),
|
||||
("66AC4B7EBA95E53DC10B",
|
||||
"a3b3cea71910d9af56742aa0bb2fe329"),
|
||||
("A510CD18F7A56852EB0319",
|
||||
"577e216843dd11573574d3fb209b97d8"),
|
||||
("AAED18DBE8938C19ED734A8D",
|
||||
"6f80fb775f27e0a4ce5c2f42fc72c5f1")];
|
||||
const md5_tests: [(&'static str, &'static str); 13] =
|
||||
[("", "d41d8cd98f00b204e9800998ecf8427e"),
|
||||
("7F", "83acb6e67e50e31db6ed341dd2de1595"),
|
||||
("EC9C", "0b07f0d4ca797d8ac58874f887cb0b68"),
|
||||
("FEE57A", "e0d583171eb06d56198fc0ef22173907"),
|
||||
("42F497E0", "7c430f178aefdf1487fee7144e9641e2"),
|
||||
("C53B777F1C", "75ef141d64cb37ec423da2d9d440c925"),
|
||||
("89D5B576327B", "ebbaf15eb0ed784c6faa9dc32831bf33"),
|
||||
("5D4CCE781EB190", "ce175c4b08172019f05e6b5279889f2c"),
|
||||
("81901FE94932D7B9", "cd4d2f62b8cdb3a0cf968a735a239281"),
|
||||
("C9FFDEE7788EFB4EC9", "e0841a231ab698db30c6c0f3f246c014"),
|
||||
("66AC4B7EBA95E53DC10B", "a3b3cea71910d9af56742aa0bb2fe329"),
|
||||
("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"),
|
||||
("AAED18DBE8938C19ED734A8D", "6f80fb775f27e0a4ce5c2f42fc72c5f1")];
|
||||
|
||||
#[test]
|
||||
fn test_md5() {
|
||||
for test in md5_tests.iter() {
|
||||
hash_test(Type::MD5, test);
|
||||
hash_test(MessageDigest::md5(), test);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_md5_recycle() {
|
||||
let mut h = Hasher::new(Type::MD5).unwrap();
|
||||
let mut h = Hasher::new(MessageDigest::md5()).unwrap();
|
||||
for test in md5_tests.iter() {
|
||||
hash_recycle_test(&mut h, test);
|
||||
}
|
||||
|
|
@ -272,11 +257,11 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_finish_twice() {
|
||||
let mut h = Hasher::new(Type::MD5).unwrap();
|
||||
let mut h = Hasher::new(MessageDigest::md5()).unwrap();
|
||||
h.write_all(&*md5_tests[6].0.from_hex().unwrap()).unwrap();
|
||||
h.finish().unwrap();
|
||||
let res = h.finish().unwrap();
|
||||
let null = hash(Type::MD5, &[]).unwrap();
|
||||
let null = hash(MessageDigest::md5(), &[]).unwrap();
|
||||
assert_eq!(res, null);
|
||||
}
|
||||
|
||||
|
|
@ -286,7 +271,7 @@ mod tests {
|
|||
let inp = md5_tests[i].0.from_hex().unwrap();
|
||||
assert!(inp.len() > 2);
|
||||
let p = inp.len() / 2;
|
||||
let h0 = Hasher::new(Type::MD5).unwrap();
|
||||
let h0 = Hasher::new(MessageDigest::md5()).unwrap();
|
||||
|
||||
println!("Clone a new hasher");
|
||||
let mut h1 = h0.clone();
|
||||
|
|
@ -314,7 +299,7 @@ mod tests {
|
|||
let tests = [("616263", "a9993e364706816aba3e25717850c26c9cd0d89d")];
|
||||
|
||||
for test in tests.iter() {
|
||||
hash_test(Type::SHA1, test);
|
||||
hash_test(MessageDigest::sha1(), test);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -324,7 +309,7 @@ mod tests {
|
|||
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")];
|
||||
|
||||
for test in tests.iter() {
|
||||
hash_test(Type::SHA256, test);
|
||||
hash_test(MessageDigest::sha256(), test);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -333,7 +318,7 @@ mod tests {
|
|||
let tests = [("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")];
|
||||
|
||||
for test in tests.iter() {
|
||||
hash_test(Type::RIPEMD160, test);
|
||||
hash_test(MessageDigest::ripemd160(), test);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.8.3")]
|
||||
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.9.0")]
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
|
|
@ -11,29 +11,99 @@ extern crate openssl_sys as ffi;
|
|||
extern crate rustc_serialize as serialize;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate net2;
|
||||
extern crate tempdir;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use ffi::init;
|
||||
|
||||
use nid::Nid;
|
||||
use libc::c_int;
|
||||
|
||||
mod macros;
|
||||
use error::ErrorStack;
|
||||
|
||||
macro_rules! type_ {
|
||||
($n:ident, $r:ident, $c:path, $d:path) => {
|
||||
pub struct $n(*mut $c);
|
||||
|
||||
impl ::types::OpenSslType for $n {
|
||||
type CType = $c;
|
||||
type Ref = $r;
|
||||
|
||||
unsafe fn from_ptr(ptr: *mut $c) -> $n {
|
||||
$n(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for $n {
|
||||
fn drop(&mut self) {
|
||||
unsafe { $d(self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Deref for $n {
|
||||
type Target = $r;
|
||||
|
||||
fn deref(&self) -> &$r {
|
||||
unsafe { ::types::OpenSslTypeRef::from_ptr(self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::DerefMut for $n {
|
||||
fn deref_mut(&mut self) -> &mut $r {
|
||||
unsafe { ::types::OpenSslTypeRef::from_ptr_mut(self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct $r(::util::Opaque);
|
||||
|
||||
impl ::types::OpenSslTypeRef for $r {
|
||||
type CType = $c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod asn1;
|
||||
mod bio;
|
||||
mod util;
|
||||
pub mod asn1;
|
||||
pub mod bn;
|
||||
#[cfg(feature = "c_helpers")]
|
||||
mod c_helpers;
|
||||
pub mod crypto;
|
||||
pub mod dh;
|
||||
pub mod dsa;
|
||||
pub mod ec_key;
|
||||
pub mod error;
|
||||
pub mod hash;
|
||||
pub mod memcmp;
|
||||
pub mod nid;
|
||||
pub mod pkcs12;
|
||||
pub mod pkcs5;
|
||||
pub mod pkey;
|
||||
pub mod rand;
|
||||
pub mod types;
|
||||
pub mod rsa;
|
||||
pub mod sign;
|
||||
pub mod ssl;
|
||||
pub mod symm;
|
||||
pub mod version;
|
||||
pub mod x509;
|
||||
pub mod stack;
|
||||
#[cfg(any(ossl102, ossl110))]
|
||||
mod verify;
|
||||
|
||||
trait HashTypeInternals {
|
||||
fn as_nid(&self) -> Nid;
|
||||
fn evp_md(&self) -> *const ffi::EVP_MD;
|
||||
fn cvt_p<T>(r: *mut T) -> Result<*mut T, ErrorStack> {
|
||||
if r.is_null() {
|
||||
Err(ErrorStack::get())
|
||||
} else {
|
||||
Ok(r)
|
||||
}
|
||||
}
|
||||
|
||||
fn cvt(r: c_int) -> Result<c_int, ErrorStack> {
|
||||
if r <= 0 {
|
||||
Err(ErrorStack::get())
|
||||
} else {
|
||||
Ok(r)
|
||||
}
|
||||
}
|
||||
|
||||
fn cvt_n(r: c_int) -> Result<c_int, ErrorStack> {
|
||||
if r < 0 { Err(ErrorStack::get()) } else { Ok(r) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
#![macro_use]
|
||||
|
||||
macro_rules! try_ssl_stream {
|
||||
($e:expr) => (
|
||||
match $e {
|
||||
Ok(ok) => ok,
|
||||
Err(err) => return Err(StreamError(err))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Shortcut return with SSL error if something went wrong
|
||||
macro_rules! try_ssl_if {
|
||||
($e:expr) => (
|
||||
if $e {
|
||||
return Err(::error::ErrorStack::get().into())
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Shortcut return with SSL error if last error result is 0
|
||||
/// (default)
|
||||
macro_rules! try_ssl{
|
||||
($e:expr) => (try_ssl_if!($e == 0))
|
||||
}
|
||||
|
||||
/// Shortcut return with SSL if got a null result
|
||||
macro_rules! try_ssl_null{
|
||||
($e:expr) => ({
|
||||
let t = $e;
|
||||
try_ssl_if!(t == ptr::null_mut());
|
||||
t
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/// Lifts current SSL error code into Result<(), Error>
|
||||
/// if expression is true
|
||||
/// Lifting is actually a shortcut of the following form:
|
||||
///
|
||||
/// ```ignore
|
||||
/// let _ = try!(something)
|
||||
/// Ok(())
|
||||
/// ```
|
||||
macro_rules! lift_ssl_if{
|
||||
($e:expr) => ( {
|
||||
if $e {
|
||||
Err(::error::ErrorStack::get().into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Lifts current SSL error code into Result<(), Error>
|
||||
/// if SSL returned 0 (default error indication)
|
||||
macro_rules! lift_ssl {
|
||||
($e:expr) => (lift_ssl_if!($e == 0))
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ use ffi;
|
|||
/// This operation takes an amount of time dependent on the length of the two
|
||||
/// arrays given, but is independent of the contents of a and b.
|
||||
///
|
||||
/// # Failure
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic the current task if `a` and `b` do not have the same
|
||||
/// length.
|
||||
1144
openssl/src/nid.rs
1144
openssl/src/nid.rs
File diff suppressed because it is too large
Load Diff
|
|
@ -6,18 +6,14 @@ use std::cmp;
|
|||
use std::ptr;
|
||||
use std::ffi::CString;
|
||||
|
||||
use crypto::pkey::PKey;
|
||||
use {cvt, cvt_p};
|
||||
use pkey::PKey;
|
||||
use error::ErrorStack;
|
||||
use x509::X509;
|
||||
use types::{OpenSslType, OpenSslTypeRef};
|
||||
use stack::Stack;
|
||||
|
||||
/// A PKCS #12 archive.
|
||||
pub struct Pkcs12(*mut ffi::PKCS12);
|
||||
|
||||
impl Drop for Pkcs12 {
|
||||
fn drop(&mut self) {
|
||||
unsafe { ffi::PKCS12_free(self.0); }
|
||||
}
|
||||
}
|
||||
type_!(Pkcs12, Pkcs12Ref, ffi::PKCS12, ffi::PKCS12_free);
|
||||
|
||||
impl Pkcs12 {
|
||||
/// Deserializes a `Pkcs12` structure from DER-encoded data.
|
||||
|
|
@ -26,11 +22,13 @@ impl Pkcs12 {
|
|||
ffi::init();
|
||||
let mut ptr = der.as_ptr() as *const c_uchar;
|
||||
let length = cmp::min(der.len(), c_long::max_value() as usize) as c_long;
|
||||
let p12 = try_ssl_null!(ffi::d2i_PKCS12(ptr::null_mut(), &mut ptr, length));
|
||||
let p12 = try!(cvt_p(ffi::d2i_PKCS12(ptr::null_mut(), &mut ptr, length)));
|
||||
Ok(Pkcs12(p12))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Pkcs12Ref {
|
||||
/// Extracts the contents of the `Pkcs12`.
|
||||
pub fn parse(&self, pass: &str) -> Result<ParsedPkcs12, ErrorStack> {
|
||||
unsafe {
|
||||
|
|
@ -40,23 +38,20 @@ impl Pkcs12 {
|
|||
let mut cert = ptr::null_mut();
|
||||
let mut chain = ptr::null_mut();
|
||||
|
||||
try_ssl!(ffi::PKCS12_parse(self.0, pass.as_ptr(), &mut pkey, &mut cert, &mut chain));
|
||||
try!(cvt(ffi::PKCS12_parse(self.as_ptr(),
|
||||
pass.as_ptr(),
|
||||
&mut pkey,
|
||||
&mut cert,
|
||||
&mut chain)));
|
||||
|
||||
let pkey = PKey::from_ptr(pkey);
|
||||
let cert = X509::from_ptr(cert);
|
||||
|
||||
let mut chain_out = vec![];
|
||||
for i in 0..(*chain).stack.num {
|
||||
let x509 = *(*chain).stack.data.offset(i as isize) as *mut _;
|
||||
chain_out.push(X509::from_ptr(x509));
|
||||
}
|
||||
ffi::sk_free(&mut (*chain).stack);
|
||||
let chain = Stack::from_ptr(chain);
|
||||
|
||||
Ok(ParsedPkcs12 {
|
||||
pkey: pkey,
|
||||
cert: cert,
|
||||
chain: chain_out,
|
||||
_p: (),
|
||||
chain: chain,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -65,28 +60,27 @@ impl Pkcs12 {
|
|||
pub struct ParsedPkcs12 {
|
||||
pub pkey: PKey,
|
||||
pub cert: X509,
|
||||
pub chain: Vec<X509>,
|
||||
_p: (),
|
||||
pub chain: Stack<X509>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crypto::hash::Type::SHA1;
|
||||
use hash::MessageDigest;
|
||||
use serialize::hex::ToHex;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse() {
|
||||
let der = include_bytes!("../../test/identity.p12");
|
||||
let der = include_bytes!("../test/identity.p12");
|
||||
let pkcs12 = Pkcs12::from_der(der).unwrap();
|
||||
let parsed = pkcs12.parse("mypass").unwrap();
|
||||
|
||||
assert_eq!(parsed.cert.fingerprint(SHA1).unwrap().to_hex(),
|
||||
assert_eq!(parsed.cert.fingerprint(MessageDigest::sha1()).unwrap().to_hex(),
|
||||
"59172d9313e84459bcff27f967e79e6e9217e584");
|
||||
|
||||
assert_eq!(parsed.chain.len(), 1);
|
||||
assert_eq!(parsed.chain[0].fingerprint(SHA1).unwrap().to_hex(),
|
||||
assert_eq!(parsed.chain[0].fingerprint(MessageDigest::sha1()).unwrap().to_hex(),
|
||||
"c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
use libc::c_int;
|
||||
use std::ptr;
|
||||
use ffi;
|
||||
|
||||
use cvt;
|
||||
use hash::MessageDigest;
|
||||
use symm::Cipher;
|
||||
use error::ErrorStack;
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct KeyIvPair {
|
||||
pub key: Vec<u8>,
|
||||
pub iv: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
/// Derives a key and an IV from various parameters.
|
||||
///
|
||||
/// If specified, `salt` must be 8 bytes in length.
|
||||
///
|
||||
/// If the total key and IV length is less than 16 bytes and MD5 is used then
|
||||
/// the algorithm is compatible with the key derivation algorithm from PKCS#5
|
||||
/// v1.5 or PBKDF1 from PKCS#5 v2.0.
|
||||
///
|
||||
/// New applications should not use this and instead use
|
||||
/// `pkcs5_pbkdf2_hmac_sha1` or another more modern key derivation algorithm.
|
||||
pub fn bytes_to_key(cipher: Cipher,
|
||||
digest: MessageDigest,
|
||||
data: &[u8],
|
||||
salt: Option<&[u8]>,
|
||||
count: i32)
|
||||
-> Result<KeyIvPair, ErrorStack> {
|
||||
unsafe {
|
||||
assert!(data.len() <= c_int::max_value() as usize);
|
||||
let salt_ptr = match salt {
|
||||
Some(salt) => {
|
||||
assert_eq!(salt.len(), ffi::PKCS5_SALT_LEN as usize);
|
||||
salt.as_ptr()
|
||||
}
|
||||
None => ptr::null(),
|
||||
};
|
||||
|
||||
ffi::init();
|
||||
|
||||
let mut iv = cipher.iv_len().map(|l| vec![0; l]);
|
||||
|
||||
let cipher = cipher.as_ptr();
|
||||
let digest = digest.as_ptr();
|
||||
|
||||
let len = try!(cvt(ffi::EVP_BytesToKey(cipher,
|
||||
digest,
|
||||
salt_ptr,
|
||||
ptr::null(),
|
||||
data.len() as c_int,
|
||||
count.into(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut())));
|
||||
|
||||
let mut key = vec![0; len as usize];
|
||||
let iv_ptr = iv.as_mut().map(|v| v.as_mut_ptr()).unwrap_or(ptr::null_mut());
|
||||
|
||||
try!(cvt(ffi::EVP_BytesToKey(cipher,
|
||||
digest,
|
||||
salt_ptr,
|
||||
data.as_ptr(),
|
||||
data.len() as c_int,
|
||||
count as c_int,
|
||||
key.as_mut_ptr(),
|
||||
iv_ptr)));
|
||||
|
||||
Ok(KeyIvPair { key: key, iv: iv })
|
||||
}
|
||||
}
|
||||
|
||||
/// Derives a key from a password and salt using the PBKDF2-HMAC algorithm with a digest function.
|
||||
pub fn pbkdf2_hmac(pass: &[u8],
|
||||
salt: &[u8],
|
||||
iter: usize,
|
||||
hash: MessageDigest,
|
||||
key: &mut [u8])
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
assert!(pass.len() <= c_int::max_value() as usize);
|
||||
assert!(salt.len() <= c_int::max_value() as usize);
|
||||
assert!(key.len() <= c_int::max_value() as usize);
|
||||
|
||||
ffi::init();
|
||||
cvt(ffi::PKCS5_PBKDF2_HMAC(pass.as_ptr() as *const _,
|
||||
pass.len() as c_int,
|
||||
salt.as_ptr(),
|
||||
salt.len() as c_int,
|
||||
iter as c_int,
|
||||
hash.as_ptr(),
|
||||
key.len() as c_int,
|
||||
key.as_mut_ptr()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use hash::MessageDigest;
|
||||
use symm::Cipher;
|
||||
|
||||
// Test vectors from
|
||||
// https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c
|
||||
#[test]
|
||||
fn pbkdf2_hmac_sha256() {
|
||||
let mut buf = [0; 16];
|
||||
|
||||
super::pbkdf2_hmac(b"passwd", b"salt", 1, MessageDigest::sha256(), &mut buf).unwrap();
|
||||
assert_eq!(buf,
|
||||
&[0x55_u8, 0xac_u8, 0x04_u8, 0x6e_u8, 0x56_u8, 0xe3_u8, 0x08_u8, 0x9f_u8,
|
||||
0xec_u8, 0x16_u8, 0x91_u8, 0xc2_u8, 0x25_u8, 0x44_u8, 0xb6_u8, 0x05_u8][..]);
|
||||
|
||||
super::pbkdf2_hmac(b"Password",
|
||||
b"NaCl",
|
||||
80000,
|
||||
MessageDigest::sha256(),
|
||||
&mut buf)
|
||||
.unwrap();
|
||||
assert_eq!(buf,
|
||||
&[0x4d_u8, 0xdc_u8, 0xd8_u8, 0xf6_u8, 0x0b_u8, 0x98_u8, 0xbe_u8, 0x21_u8,
|
||||
0x83_u8, 0x0c_u8, 0xee_u8, 0x5e_u8, 0xf2_u8, 0x27_u8, 0x01_u8, 0xf9_u8][..]);
|
||||
}
|
||||
|
||||
// Test vectors from
|
||||
// https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c
|
||||
#[test]
|
||||
fn pbkdf2_hmac_sha512() {
|
||||
let mut buf = [0; 64];
|
||||
|
||||
super::pbkdf2_hmac(b"password", b"NaCL", 1, MessageDigest::sha512(), &mut buf).unwrap();
|
||||
assert_eq!(&buf[..],
|
||||
&[0x73_u8, 0xde_u8, 0xcf_u8, 0xa5_u8, 0x8a_u8, 0xa2_u8, 0xe8_u8, 0x4f_u8,
|
||||
0x94_u8, 0x77_u8, 0x1a_u8, 0x75_u8, 0x73_u8, 0x6b_u8, 0xb8_u8, 0x8b_u8,
|
||||
0xd3_u8, 0xc7_u8, 0xb3_u8, 0x82_u8, 0x70_u8, 0xcf_u8, 0xb5_u8, 0x0c_u8,
|
||||
0xb3_u8, 0x90_u8, 0xed_u8, 0x78_u8, 0xb3_u8, 0x05_u8, 0x65_u8, 0x6a_u8,
|
||||
0xf8_u8, 0x14_u8, 0x8e_u8, 0x52_u8, 0x45_u8, 0x2b_u8, 0x22_u8, 0x16_u8,
|
||||
0xb2_u8, 0xb8_u8, 0x09_u8, 0x8b_u8, 0x76_u8, 0x1f_u8, 0xc6_u8, 0x33_u8,
|
||||
0x60_u8, 0x60_u8, 0xa0_u8, 0x9f_u8, 0x76_u8, 0x41_u8, 0x5e_u8, 0x9f_u8,
|
||||
0x71_u8, 0xea_u8, 0x47_u8, 0xf9_u8, 0xe9_u8, 0x06_u8, 0x43_u8, 0x06_u8][..]);
|
||||
|
||||
super::pbkdf2_hmac(b"pass\0word",
|
||||
b"sa\0lt",
|
||||
1,
|
||||
MessageDigest::sha512(),
|
||||
&mut buf)
|
||||
.unwrap();
|
||||
assert_eq!(&buf[..],
|
||||
&[0x71_u8, 0xa0_u8, 0xec_u8, 0x84_u8, 0x2a_u8, 0xbd_u8, 0x5c_u8, 0x67_u8,
|
||||
0x8b_u8, 0xcf_u8, 0xd1_u8, 0x45_u8, 0xf0_u8, 0x9d_u8, 0x83_u8, 0x52_u8,
|
||||
0x2f_u8, 0x93_u8, 0x36_u8, 0x15_u8, 0x60_u8, 0x56_u8, 0x3c_u8, 0x4d_u8,
|
||||
0x0d_u8, 0x63_u8, 0xb8_u8, 0x83_u8, 0x29_u8, 0x87_u8, 0x10_u8, 0x90_u8,
|
||||
0xe7_u8, 0x66_u8, 0x04_u8, 0xa4_u8, 0x9a_u8, 0xf0_u8, 0x8f_u8, 0xe7_u8,
|
||||
0xc9_u8, 0xf5_u8, 0x71_u8, 0x56_u8, 0xc8_u8, 0x79_u8, 0x09_u8, 0x96_u8,
|
||||
0xb2_u8, 0x0f_u8, 0x06_u8, 0xbc_u8, 0x53_u8, 0x5e_u8, 0x5a_u8, 0xb5_u8,
|
||||
0x44_u8, 0x0d_u8, 0xf7_u8, 0xe8_u8, 0x78_u8, 0x29_u8, 0x6f_u8, 0xa7_u8][..]);
|
||||
|
||||
super::pbkdf2_hmac(b"passwordPASSWORDpassword",
|
||||
b"salt\0\0\0",
|
||||
50,
|
||||
MessageDigest::sha512(),
|
||||
&mut buf)
|
||||
.unwrap();
|
||||
assert_eq!(&buf[..],
|
||||
&[0x01_u8, 0x68_u8, 0x71_u8, 0xa4_u8, 0xc4_u8, 0xb7_u8, 0x5f_u8, 0x96_u8,
|
||||
0x85_u8, 0x7f_u8, 0xd2_u8, 0xb9_u8, 0xf8_u8, 0xca_u8, 0x28_u8, 0x02_u8,
|
||||
0x3b_u8, 0x30_u8, 0xee_u8, 0x2a_u8, 0x39_u8, 0xf5_u8, 0xad_u8, 0xca_u8,
|
||||
0xc8_u8, 0xc9_u8, 0x37_u8, 0x5f_u8, 0x9b_u8, 0xda_u8, 0x1c_u8, 0xcd_u8,
|
||||
0x1b_u8, 0x6f_u8, 0x0b_u8, 0x2f_u8, 0xc3_u8, 0xad_u8, 0xda_u8, 0x50_u8,
|
||||
0x54_u8, 0x12_u8, 0xe7_u8, 0x9d_u8, 0x89_u8, 0x00_u8, 0x56_u8, 0xc6_u8,
|
||||
0x2e_u8, 0x52_u8, 0x4c_u8, 0x7d_u8, 0x51_u8, 0x15_u8, 0x4b_u8, 0x1a_u8,
|
||||
0x85_u8, 0x34_u8, 0x57_u8, 0x5b_u8, 0xd0_u8, 0x2d_u8, 0xee_u8, 0x39_u8][..]);
|
||||
}
|
||||
#[test]
|
||||
fn bytes_to_key() {
|
||||
let salt = [16_u8, 34_u8, 19_u8, 23_u8, 141_u8, 4_u8, 207_u8, 221_u8];
|
||||
|
||||
let data = [143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8, 241_u8, 242_u8, 31_u8,
|
||||
154_u8, 56_u8, 198_u8, 145_u8, 192_u8, 64_u8, 2_u8, 245_u8, 167_u8, 220_u8,
|
||||
55_u8, 119_u8, 233_u8, 136_u8, 139_u8, 27_u8, 71_u8, 242_u8, 119_u8, 175_u8,
|
||||
65_u8, 207_u8];
|
||||
|
||||
|
||||
|
||||
let expected_key = vec![249_u8, 115_u8, 114_u8, 97_u8, 32_u8, 213_u8, 165_u8, 146_u8,
|
||||
58_u8, 87_u8, 234_u8, 3_u8, 43_u8, 250_u8, 97_u8, 114_u8, 26_u8,
|
||||
98_u8, 245_u8, 246_u8, 238_u8, 177_u8, 229_u8, 161_u8, 183_u8,
|
||||
224_u8, 174_u8, 3_u8, 6_u8, 244_u8, 236_u8, 255_u8];
|
||||
let expected_iv = vec![4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8,
|
||||
69_u8, 98_u8, 107_u8, 208_u8, 14_u8, 236_u8, 60_u8];
|
||||
|
||||
assert_eq!(super::bytes_to_key(Cipher::aes_256_cbc(),
|
||||
MessageDigest::sha1(),
|
||||
&data,
|
||||
Some(&salt),
|
||||
1).unwrap(),
|
||||
super::KeyIvPair {
|
||||
key: expected_key,
|
||||
iv: Some(expected_iv),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
use libc::{c_void, c_char, c_int};
|
||||
use std::ptr;
|
||||
use std::mem;
|
||||
use ffi;
|
||||
|
||||
use {cvt, cvt_p};
|
||||
use bio::{MemBio, MemBioSlice};
|
||||
use dsa::Dsa;
|
||||
use rsa::Rsa;
|
||||
use error::ErrorStack;
|
||||
use util::{CallbackState, invoke_passwd_cb};
|
||||
use types::{OpenSslType, OpenSslTypeRef};
|
||||
|
||||
type_!(PKey, PKeyRef, ffi::EVP_PKEY, ffi::EVP_PKEY_free);
|
||||
|
||||
impl PKeyRef {
|
||||
/// Get a reference to the interal RSA key for direct access to the key components
|
||||
pub fn rsa(&self) -> Result<Rsa, ErrorStack> {
|
||||
unsafe {
|
||||
let rsa = try!(cvt_p(ffi::EVP_PKEY_get1_RSA(self.as_ptr())));
|
||||
// this is safe as the ffi increments a reference counter to the internal key
|
||||
Ok(Rsa::from_ptr(rsa))
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores private key as a PEM
|
||||
// FIXME: also add password and encryption
|
||||
pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
unsafe {
|
||||
try!(cvt(ffi::PEM_write_bio_PrivateKey(mem_bio.as_ptr(),
|
||||
self.as_ptr(),
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
-1,
|
||||
None,
|
||||
ptr::null_mut())));
|
||||
|
||||
}
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
/// Encode public key in PEM format
|
||||
pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
unsafe {
|
||||
try!(cvt(ffi::PEM_write_bio_PUBKEY(mem_bio.as_ptr(), self.as_ptr())));
|
||||
}
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
/// Encode public key in DER format
|
||||
pub fn public_key_to_der(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
unsafe {
|
||||
try!(cvt(ffi::i2d_PUBKEY_bio(mem_bio.as_ptr(), self.as_ptr())));
|
||||
}
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
pub fn public_eq(&self, other: &PKeyRef) -> bool {
|
||||
unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for PKey {}
|
||||
unsafe impl Sync for PKey {}
|
||||
|
||||
impl PKey {
|
||||
/// Create a new `PKey` containing an RSA key.
|
||||
pub fn from_rsa(rsa: Rsa) -> Result<PKey, ErrorStack> {
|
||||
unsafe {
|
||||
let evp = try!(cvt_p(ffi::EVP_PKEY_new()));
|
||||
let pkey = PKey(evp);
|
||||
try!(cvt(ffi::EVP_PKEY_assign(pkey.0, ffi::EVP_PKEY_RSA, rsa.as_ptr() as *mut _)));
|
||||
mem::forget(rsa);
|
||||
Ok(pkey)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `PKey` containing a DSA key.
|
||||
pub fn from_dsa(dsa: Dsa) -> Result<PKey, ErrorStack> {
|
||||
unsafe {
|
||||
let evp = try!(cvt_p(ffi::EVP_PKEY_new()));
|
||||
let pkey = PKey(evp);
|
||||
try!(cvt(ffi::EVP_PKEY_assign(pkey.0, ffi::EVP_PKEY_DSA, dsa.as_ptr() as *mut _)));
|
||||
mem::forget(dsa);
|
||||
Ok(pkey)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `PKey` containing an HMAC key.
|
||||
pub fn hmac(key: &[u8]) -> Result<PKey, ErrorStack> {
|
||||
unsafe {
|
||||
assert!(key.len() <= c_int::max_value() as usize);
|
||||
let key = try!(cvt_p(ffi::EVP_PKEY_new_mac_key(ffi::EVP_PKEY_HMAC,
|
||||
ptr::null_mut(),
|
||||
key.as_ptr() as *const _,
|
||||
key.len() as c_int)));
|
||||
Ok(PKey(key))
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads private key from PEM, takes ownership of handle
|
||||
pub fn private_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
|
||||
ffi::init();
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let evp = try!(cvt_p(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut())));
|
||||
Ok(PKey::from_ptr(evp))
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a private key from PEM, supplying a password callback to be invoked if the private key
|
||||
/// is encrypted.
|
||||
///
|
||||
/// The callback will be passed the password buffer and should return the number of characters
|
||||
/// placed into the buffer.
|
||||
pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<PKey, ErrorStack>
|
||||
where F: FnOnce(&mut [c_char]) -> usize
|
||||
{
|
||||
ffi::init();
|
||||
let mut cb = CallbackState::new(pass_cb);
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let evp = try!(cvt_p(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
Some(invoke_passwd_cb::<F>),
|
||||
&mut cb as *mut _ as *mut c_void)));
|
||||
Ok(PKey::from_ptr(evp))
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads public key from PEM, takes ownership of handle
|
||||
pub fn public_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
|
||||
ffi::init();
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let evp = try!(cvt_p(ffi::PEM_read_bio_PUBKEY(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut())));
|
||||
Ok(PKey::from_ptr(evp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn test_private_key_from_pem() {
|
||||
let key = include_bytes!("../test/key.pem");
|
||||
super::PKey::private_key_from_pem(key).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_public_key_from_pem() {
|
||||
let key = include_bytes!("../test/key.pem.pub");
|
||||
super::PKey::public_key_from_pem(key).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pem() {
|
||||
let key = include_bytes!("../test/key.pem");
|
||||
let key = super::PKey::private_key_from_pem(key).unwrap();
|
||||
|
||||
let priv_key = key.private_key_to_pem().unwrap();
|
||||
let pub_key = key.public_key_to_pem().unwrap();
|
||||
|
||||
// As a super-simple verification, just check that the buffers contain
|
||||
// the `PRIVATE KEY` or `PUBLIC KEY` strings.
|
||||
assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY"));
|
||||
assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY"));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
use libc::c_int;
|
||||
use ffi;
|
||||
|
||||
use cvt;
|
||||
use error::ErrorStack;
|
||||
|
||||
pub fn rand_bytes(buf: &mut [u8]) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
assert!(buf.len() <= c_int::max_value() as usize);
|
||||
try_ssl_if!(ffi::RAND_bytes(buf.as_mut_ptr(), buf.len() as c_int) != 1);
|
||||
Ok(())
|
||||
cvt(ffi::RAND_bytes(buf.as_mut_ptr(), buf.len() as c_int)).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,457 @@
|
|||
use ffi;
|
||||
use std::fmt;
|
||||
use std::ptr;
|
||||
use std::mem;
|
||||
use libc::{c_int, c_void, c_char};
|
||||
|
||||
use {cvt, cvt_p, cvt_n};
|
||||
use bn::{BigNum, BigNumRef};
|
||||
use bio::{MemBio, MemBioSlice};
|
||||
use error::ErrorStack;
|
||||
use util::{CallbackState, invoke_passwd_cb};
|
||||
use types::OpenSslTypeRef;
|
||||
|
||||
/// Type of encryption padding to use.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Padding(c_int);
|
||||
|
||||
pub const NO_PADDING: Padding = Padding(ffi::RSA_NO_PADDING);
|
||||
pub const PKCS1_PADDING: Padding = Padding(ffi::RSA_PKCS1_PADDING);
|
||||
pub const PKCS1_OAEP_PADDING: Padding = Padding(ffi::RSA_PKCS1_OAEP_PADDING);
|
||||
|
||||
type_!(Rsa, RsaRef, ffi::RSA, ffi::RSA_free);
|
||||
|
||||
impl RsaRef {
|
||||
/// Writes an RSA private key as unencrypted PEM formatted data
|
||||
pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
|
||||
unsafe {
|
||||
try!(cvt(ffi::PEM_write_bio_RSAPrivateKey(mem_bio.as_ptr(),
|
||||
self.as_ptr(),
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
None,
|
||||
ptr::null_mut())));
|
||||
}
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
/// Writes an RSA public key as PEM formatted data
|
||||
pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
|
||||
unsafe {
|
||||
try!(cvt(ffi::PEM_write_bio_RSA_PUBKEY(mem_bio.as_ptr(), self.as_ptr())));
|
||||
}
|
||||
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
unsafe {
|
||||
assert!(self.n().is_some());
|
||||
|
||||
ffi::RSA_size(self.as_ptr()) as usize
|
||||
}
|
||||
}
|
||||
|
||||
/// Decrypts data using the private key, returning the number of decrypted bytes.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `self` has no private components, or if `to` is smaller
|
||||
/// than `self.size()`.
|
||||
pub fn private_decrypt(&self,
|
||||
from: &[u8],
|
||||
to: &mut [u8],
|
||||
padding: Padding)
|
||||
-> Result<usize, ErrorStack> {
|
||||
assert!(self.d().is_some(), "private components missing");
|
||||
assert!(from.len() <= i32::max_value() as usize);
|
||||
assert!(to.len() >= self.size());
|
||||
|
||||
unsafe {
|
||||
let len = try!(cvt_n(ffi::RSA_private_decrypt(from.len() as c_int,
|
||||
from.as_ptr(),
|
||||
to.as_mut_ptr(),
|
||||
self.as_ptr(),
|
||||
padding.0)));
|
||||
Ok(len as usize)
|
||||
}
|
||||
}
|
||||
|
||||
/// Encrypts data using the private key, returning the number of encrypted bytes.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `self` has no private components, or if `to` is smaller
|
||||
/// than `self.size()`.
|
||||
pub fn private_encrypt(&self,
|
||||
from: &[u8],
|
||||
to: &mut [u8],
|
||||
padding: Padding)
|
||||
-> Result<usize, ErrorStack> {
|
||||
assert!(self.d().is_some(), "private components missing");
|
||||
assert!(from.len() <= i32::max_value() as usize);
|
||||
assert!(to.len() >= self.size());
|
||||
|
||||
unsafe {
|
||||
let len = try!(cvt_n(ffi::RSA_private_encrypt(from.len() as c_int,
|
||||
from.as_ptr(),
|
||||
to.as_mut_ptr(),
|
||||
self.as_ptr(),
|
||||
padding.0)));
|
||||
Ok(len as usize)
|
||||
}
|
||||
}
|
||||
|
||||
/// Decrypts data using the public key, returning the number of decrypted bytes.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `to` is smaller than `self.size()`.
|
||||
pub fn public_decrypt(&self,
|
||||
from: &[u8],
|
||||
to: &mut [u8],
|
||||
padding: Padding)
|
||||
-> Result<usize, ErrorStack> {
|
||||
assert!(from.len() <= i32::max_value() as usize);
|
||||
assert!(to.len() >= self.size());
|
||||
|
||||
unsafe {
|
||||
let len = try!(cvt_n(ffi::RSA_public_decrypt(from.len() as c_int,
|
||||
from.as_ptr(),
|
||||
to.as_mut_ptr(),
|
||||
self.as_ptr(),
|
||||
padding.0)));
|
||||
Ok(len as usize)
|
||||
}
|
||||
}
|
||||
|
||||
/// Encrypts data using the private key, returning the number of encrypted bytes.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `to` is smaller than `self.size()`.
|
||||
pub fn public_encrypt(&self,
|
||||
from: &[u8],
|
||||
to: &mut [u8],
|
||||
padding: Padding)
|
||||
-> Result<usize, ErrorStack> {
|
||||
assert!(from.len() <= i32::max_value() as usize);
|
||||
assert!(to.len() >= self.size());
|
||||
|
||||
unsafe {
|
||||
let len = try!(cvt_n(ffi::RSA_public_encrypt(from.len() as c_int,
|
||||
from.as_ptr(),
|
||||
to.as_mut_ptr(),
|
||||
self.as_ptr(),
|
||||
padding.0)));
|
||||
Ok(len as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn n(&self) -> Option<&BigNumRef> {
|
||||
unsafe {
|
||||
let n = compat::key(self.as_ptr())[0];
|
||||
if n.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(n as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn d(&self) -> Option<&BigNumRef> {
|
||||
unsafe {
|
||||
let d = compat::key(self.as_ptr())[2];
|
||||
if d.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(d as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn e(&self) -> Option<&BigNumRef> {
|
||||
unsafe {
|
||||
let e = compat::key(self.as_ptr())[1];
|
||||
if e.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(e as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn p(&self) -> Option<&BigNumRef> {
|
||||
unsafe {
|
||||
let p = compat::factors(self.as_ptr())[0];
|
||||
if p.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(p as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn q(&self) -> Option<&BigNumRef> {
|
||||
unsafe {
|
||||
let q = compat::factors(self.as_ptr())[1];
|
||||
if q.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(q as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rsa {
|
||||
/// only useful for associating the key material directly with the key, it's safer to use
|
||||
/// the supplied load and save methods for DER formatted keys.
|
||||
pub fn from_public_components(n: BigNum, e: BigNum) -> Result<Rsa, ErrorStack> {
|
||||
unsafe {
|
||||
let rsa = Rsa(try!(cvt_p(ffi::RSA_new())));
|
||||
try!(cvt(compat::set_key(rsa.0,
|
||||
n.as_ptr(),
|
||||
e.as_ptr(),
|
||||
ptr::null_mut())));
|
||||
mem::forget((n, e));
|
||||
Ok(rsa)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_private_components(n: BigNum,
|
||||
e: BigNum,
|
||||
d: BigNum,
|
||||
p: BigNum,
|
||||
q: BigNum,
|
||||
dp: BigNum,
|
||||
dq: BigNum,
|
||||
qi: BigNum)
|
||||
-> Result<Rsa, ErrorStack> {
|
||||
unsafe {
|
||||
let rsa = Rsa(try!(cvt_p(ffi::RSA_new())));
|
||||
try!(cvt(compat::set_key(rsa.0, n.as_ptr(), e.as_ptr(), d.as_ptr())));
|
||||
mem::forget((n, e, d));
|
||||
try!(cvt(compat::set_factors(rsa.0, p.as_ptr(), q.as_ptr())));
|
||||
mem::forget((p, q));
|
||||
try!(cvt(compat::set_crt_params(rsa.0, dp.as_ptr(), dq.as_ptr(),
|
||||
qi.as_ptr())));
|
||||
mem::forget((dp, dq, qi));
|
||||
Ok(rsa)
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates a public/private key pair with the specified size.
|
||||
///
|
||||
/// The public exponent will be 65537.
|
||||
pub fn generate(bits: u32) -> Result<Rsa, ErrorStack> {
|
||||
unsafe {
|
||||
let rsa = Rsa(try!(cvt_p(ffi::RSA_new())));
|
||||
let e = try!(BigNum::from_u32(ffi::RSA_F4 as u32));
|
||||
try!(cvt(ffi::RSA_generate_key_ex(rsa.0, bits as c_int, e.as_ptr(), ptr::null_mut())));
|
||||
Ok(rsa)
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads an RSA private key from PEM formatted data.
|
||||
pub fn private_key_from_pem(buf: &[u8]) -> Result<Rsa, ErrorStack> {
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let rsa = try!(cvt_p(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut())));
|
||||
Ok(Rsa(rsa))
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads an RSA private key from PEM formatted data and supplies a password callback.
|
||||
pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<Rsa, ErrorStack>
|
||||
where F: FnOnce(&mut [c_char]) -> usize
|
||||
{
|
||||
let mut cb = CallbackState::new(pass_cb);
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
|
||||
unsafe {
|
||||
let cb_ptr = &mut cb as *mut _ as *mut c_void;
|
||||
let rsa = try!(cvt_p(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
Some(invoke_passwd_cb::<F>),
|
||||
cb_ptr)));
|
||||
Ok(Rsa(rsa))
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads an RSA public key from PEM formatted data.
|
||||
pub fn public_key_from_pem(buf: &[u8]) -> Result<Rsa, ErrorStack> {
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let rsa = try!(cvt_p(ffi::PEM_read_bio_RSA_PUBKEY(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut())));
|
||||
Ok(Rsa(rsa))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Rsa {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Rsa")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(ossl110)]
|
||||
mod compat {
|
||||
use std::ptr;
|
||||
|
||||
use ffi::{self, BIGNUM, RSA};
|
||||
use libc::c_int;
|
||||
|
||||
pub unsafe fn key(r: *const RSA) -> [*const BIGNUM; 3] {
|
||||
let (mut n, mut e, mut d) = (ptr::null(), ptr::null(), ptr::null());
|
||||
ffi::RSA_get0_key(r, &mut n, &mut e, &mut d);
|
||||
[n, e, d]
|
||||
}
|
||||
|
||||
pub unsafe fn factors(r: *const RSA) -> [*const BIGNUM; 2] {
|
||||
let (mut p, mut q) = (ptr::null(), ptr::null());
|
||||
ffi::RSA_get0_factors(r, &mut p, &mut q);
|
||||
[p, q]
|
||||
}
|
||||
|
||||
pub unsafe fn set_key(r: *mut RSA, n: *mut BIGNUM, e: *mut BIGNUM, d: *mut BIGNUM) -> c_int {
|
||||
ffi::RSA_set0_key(r, n, e, d)
|
||||
}
|
||||
|
||||
pub unsafe fn set_factors(r: *mut RSA, p: *mut BIGNUM, q: *mut BIGNUM) -> c_int {
|
||||
ffi::RSA_set0_factors(r, p, q)
|
||||
}
|
||||
|
||||
pub unsafe fn set_crt_params(r: *mut RSA,
|
||||
dmp1: *mut BIGNUM,
|
||||
dmq1: *mut BIGNUM,
|
||||
iqmp: *mut BIGNUM)
|
||||
-> c_int {
|
||||
ffi::RSA_set0_crt_params(r, dmp1, dmq1, iqmp)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(ossl10x)]
|
||||
mod compat {
|
||||
use libc::c_int;
|
||||
use ffi::{BIGNUM, RSA};
|
||||
|
||||
pub unsafe fn key(r: *const RSA) -> [*const BIGNUM; 3] {
|
||||
[(*r).n, (*r).e, (*r).d]
|
||||
}
|
||||
|
||||
pub unsafe fn factors(r: *const RSA) -> [*const BIGNUM; 2] {
|
||||
[(*r).p, (*r).q]
|
||||
}
|
||||
|
||||
pub unsafe fn set_key(r: *mut RSA, n: *mut BIGNUM, e: *mut BIGNUM, d: *mut BIGNUM) -> c_int {
|
||||
(*r).n = n;
|
||||
(*r).e = e;
|
||||
(*r).d = d;
|
||||
1 // TODO: is this right? should it be 0? what's success?
|
||||
}
|
||||
|
||||
pub unsafe fn set_factors(r: *mut RSA, p: *mut BIGNUM, q: *mut BIGNUM) -> c_int {
|
||||
(*r).p = p;
|
||||
(*r).q = q;
|
||||
1 // TODO: is this right? should it be 0? what's success?
|
||||
}
|
||||
|
||||
pub unsafe fn set_crt_params(r: *mut RSA,
|
||||
dmp1: *mut BIGNUM,
|
||||
dmq1: *mut BIGNUM,
|
||||
iqmp: *mut BIGNUM)
|
||||
-> c_int {
|
||||
(*r).dmp1 = dmp1;
|
||||
(*r).dmq1 = dmq1;
|
||||
(*r).iqmp = iqmp;
|
||||
1 // TODO: is this right? should it be 0? what's success?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use libc::c_char;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
pub fn test_password() {
|
||||
let mut password_queried = false;
|
||||
let key = include_bytes!("../test/rsa-encrypted.pem");
|
||||
Rsa::private_key_from_pem_cb(key, |password| {
|
||||
password_queried = true;
|
||||
password[0] = b'm' as c_char;
|
||||
password[1] = b'y' as c_char;
|
||||
password[2] = b'p' as c_char;
|
||||
password[3] = b'a' as c_char;
|
||||
password[4] = b's' as c_char;
|
||||
password[5] = b's' as c_char;
|
||||
6
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert!(password_queried);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_public_encrypt_private_decrypt_with_padding() {
|
||||
let key = include_bytes!("../test/rsa.pem.pub");
|
||||
let public_key = Rsa::public_key_from_pem(key).unwrap();
|
||||
|
||||
let mut result = vec![0; public_key.size()];
|
||||
let original_data = b"This is test";
|
||||
let len = public_key.public_encrypt(original_data, &mut result, PKCS1_PADDING).unwrap();
|
||||
assert_eq!(len, 256);
|
||||
|
||||
let pkey = include_bytes!("../test/rsa.pem");
|
||||
let private_key = Rsa::private_key_from_pem(pkey).unwrap();
|
||||
let mut dec_result = vec![0; private_key.size()];
|
||||
let len = private_key.private_decrypt(&result, &mut dec_result, PKCS1_PADDING).unwrap();
|
||||
|
||||
assert_eq!(&dec_result[..len], original_data);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_private_encrypt() {
|
||||
let k0 = super::Rsa::generate(512).unwrap();
|
||||
let k0pkey = k0.public_key_to_pem().unwrap();
|
||||
let k1 = super::Rsa::public_key_from_pem(&k0pkey).unwrap();
|
||||
|
||||
let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
|
||||
|
||||
let mut emesg = vec![0; k0.size()];
|
||||
k0.private_encrypt(&msg, &mut emesg, PKCS1_PADDING).unwrap();
|
||||
let mut dmesg = vec![0; k1.size()];
|
||||
let len = k1.public_decrypt(&emesg, &mut dmesg, PKCS1_PADDING).unwrap();
|
||||
assert_eq!(msg, &dmesg[..len]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_public_encrypt() {
|
||||
let k0 = super::Rsa::generate(512).unwrap();
|
||||
let k0pkey = k0.private_key_to_pem().unwrap();
|
||||
let k1 = super::Rsa::private_key_from_pem(&k0pkey).unwrap();
|
||||
|
||||
let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
|
||||
|
||||
let mut emesg = vec![0; k0.size()];
|
||||
k0.public_encrypt(&msg, &mut emesg, PKCS1_PADDING).unwrap();
|
||||
let mut dmesg = vec![0; k1.size()];
|
||||
let len = k1.private_decrypt(&emesg, &mut dmesg, PKCS1_PADDING).unwrap();
|
||||
assert_eq!(msg, &dmesg[..len]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,397 @@
|
|||
//! Message signatures.
|
||||
//!
|
||||
//! The `Signer` allows for the computation of cryptographic signatures of
|
||||
//! data given a private key. The `Verifier` can then be used with the
|
||||
//! corresponding public key to verify the integrity and authenticity of that
|
||||
//! data given the signature.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Sign and verify data given an RSA keypair:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use openssl::sign::{Signer, Verifier};
|
||||
//! use openssl::rsa::Rsa;
|
||||
//! use openssl::pkey::PKey;
|
||||
//! use openssl::hash::MessageDigest;
|
||||
//!
|
||||
//! // Generate a keypair
|
||||
//! let keypair = Rsa::generate(2048).unwrap();
|
||||
//! let keypair = PKey::from_rsa(keypair).unwrap();
|
||||
//!
|
||||
//! let data = b"hello, world!";
|
||||
//! let data2 = b"hola, mundo!";
|
||||
//!
|
||||
//! // Sign the data
|
||||
//! let mut signer = Signer::new(MessageDigest::sha256(), &keypair).unwrap();
|
||||
//! signer.update(data).unwrap();
|
||||
//! signer.update(data2).unwrap();
|
||||
//! let signature = signer.finish().unwrap();
|
||||
//!
|
||||
//! // Verify the data
|
||||
//! let mut verifier = Verifier::new(MessageDigest::sha256(), &keypair).unwrap();
|
||||
//! verifier.update(data).unwrap();
|
||||
//! verifier.update(data2).unwrap();
|
||||
//! assert!(verifier.finish(&signature).unwrap());
|
||||
//! ```
|
||||
//!
|
||||
//! Compute an HMAC (note that `Verifier` cannot be used with HMACs):
|
||||
//!
|
||||
//! ```rust
|
||||
//! use openssl::sign::Signer;
|
||||
//! use openssl::pkey::PKey;
|
||||
//! use openssl::hash::MessageDigest;
|
||||
//!
|
||||
//! // Create a PKey
|
||||
//! let key = PKey::hmac(b"my secret").unwrap();
|
||||
//!
|
||||
//! let data = b"hello, world!";
|
||||
//! let data2 = b"hola, mundo!";
|
||||
//!
|
||||
//! // Compute the HMAC
|
||||
//! let mut signer = Signer::new(MessageDigest::sha256(), &key).unwrap();
|
||||
//! signer.update(data).unwrap();
|
||||
//! signer.update(data2).unwrap();
|
||||
//! let hmac = signer.finish().unwrap();
|
||||
//! ```
|
||||
use ffi;
|
||||
use std::io::{self, Write};
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr;
|
||||
|
||||
use {cvt, cvt_p};
|
||||
use hash::MessageDigest;
|
||||
use pkey::PKeyRef;
|
||||
use error::ErrorStack;
|
||||
use types::OpenSslTypeRef;
|
||||
|
||||
#[cfg(ossl110)]
|
||||
use ffi::{EVP_MD_CTX_new, EVP_MD_CTX_free};
|
||||
#[cfg(any(ossl101, ossl102))]
|
||||
use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free};
|
||||
|
||||
pub struct Signer<'a>(*mut ffi::EVP_MD_CTX, PhantomData<&'a PKeyRef>);
|
||||
|
||||
impl<'a> Drop for Signer<'a> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
EVP_MD_CTX_free(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Signer<'a> {
|
||||
pub fn new(type_: MessageDigest, pkey: &'a PKeyRef) -> Result<Signer<'a>, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
|
||||
let ctx = try!(cvt_p(EVP_MD_CTX_new()));
|
||||
let r = ffi::EVP_DigestSignInit(ctx,
|
||||
ptr::null_mut(),
|
||||
type_.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
pkey.as_ptr());
|
||||
if r != 1 {
|
||||
EVP_MD_CTX_free(ctx);
|
||||
return Err(ErrorStack::get());
|
||||
}
|
||||
Ok(Signer(ctx, PhantomData))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::EVP_DigestUpdate(self.0, buf.as_ptr() as *const _, buf.len())).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finish(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
unsafe {
|
||||
let mut len = 0;
|
||||
try!(cvt(ffi::EVP_DigestSignFinal(self.0, ptr::null_mut(), &mut len)));
|
||||
let mut buf = vec![0; len];
|
||||
try!(cvt(ffi::EVP_DigestSignFinal(self.0, buf.as_mut_ptr() as *mut _, &mut len)));
|
||||
// The advertised length is not always equal to the real length for things like DSA
|
||||
buf.truncate(len);
|
||||
Ok(buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Write for Signer<'a> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
try!(self.update(buf));
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Verifier<'a>(*mut ffi::EVP_MD_CTX, PhantomData<&'a PKeyRef>);
|
||||
|
||||
impl<'a> Drop for Verifier<'a> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
EVP_MD_CTX_free(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Verifier<'a> {
|
||||
pub fn new(type_: MessageDigest, pkey: &'a PKeyRef) -> Result<Verifier<'a>, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
|
||||
let ctx = try!(cvt_p(EVP_MD_CTX_new()));
|
||||
let r = ffi::EVP_DigestVerifyInit(ctx,
|
||||
ptr::null_mut(),
|
||||
type_.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
pkey.as_ptr());
|
||||
if r != 1 {
|
||||
EVP_MD_CTX_free(ctx);
|
||||
return Err(ErrorStack::get());
|
||||
}
|
||||
|
||||
Ok(Verifier(ctx, PhantomData))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::EVP_DigestUpdate(self.0, buf.as_ptr() as *const _, buf.len())).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finish(&self, signature: &[u8]) -> Result<bool, ErrorStack> {
|
||||
unsafe {
|
||||
let r = EVP_DigestVerifyFinal(self.0, signature.as_ptr() as *const _, signature.len());
|
||||
match r {
|
||||
1 => Ok(true),
|
||||
0 => {
|
||||
ErrorStack::get(); // discard error stack
|
||||
Ok(false)
|
||||
}
|
||||
_ => Err(ErrorStack::get()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Write for Verifier<'a> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
try!(self.update(buf));
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(ossl101))]
|
||||
use ffi::EVP_DigestVerifyFinal;
|
||||
|
||||
#[cfg(ossl101)]
|
||||
#[allow(bad_style)]
|
||||
unsafe fn EVP_DigestVerifyFinal(ctx: *mut ffi::EVP_MD_CTX,
|
||||
sigret: *const ::libc::c_uchar,
|
||||
siglen: ::libc::size_t)
|
||||
-> ::libc::c_int {
|
||||
ffi::EVP_DigestVerifyFinal(ctx, sigret as *mut _, siglen)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use serialize::hex::FromHex;
|
||||
use std::iter;
|
||||
|
||||
use hash::MessageDigest;
|
||||
use sign::{Signer, Verifier};
|
||||
use rsa::Rsa;
|
||||
use dsa::Dsa;
|
||||
use pkey::PKey;
|
||||
|
||||
static INPUT: &'static [u8] =
|
||||
&[101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 83, 85, 122, 73, 49, 78, 105, 74, 57,
|
||||
46, 101, 121, 74, 112, 99, 51, 77, 105, 79, 105, 74, 113, 98, 50, 85, 105, 76, 65, 48,
|
||||
75, 73, 67, 74, 108, 101, 72, 65, 105, 79, 106, 69, 122, 77, 68, 65, 52, 77, 84, 107,
|
||||
122, 79, 68, 65, 115, 68, 81, 111, 103, 73, 109, 104, 48, 100, 72, 65, 54, 76, 121, 57,
|
||||
108, 101, 71, 70, 116, 99, 71, 120, 108, 76, 109, 78, 118, 98, 83, 57, 112, 99, 49, 57,
|
||||
121, 98, 50, 57, 48, 73, 106, 112, 48, 99, 110, 86, 108, 102, 81];
|
||||
|
||||
static SIGNATURE: &'static [u8] =
|
||||
&[112, 46, 33, 137, 67, 232, 143, 209, 30, 181, 216, 45, 191, 120, 69, 243, 65, 6, 174,
|
||||
27, 129, 255, 247, 115, 17, 22, 173, 209, 113, 125, 131, 101, 109, 66, 10, 253, 60, 150,
|
||||
238, 221, 115, 162, 102, 62, 81, 102, 104, 123, 0, 11, 135, 34, 110, 1, 135, 237, 16,
|
||||
115, 249, 69, 229, 130, 173, 252, 239, 22, 216, 90, 121, 142, 232, 198, 109, 219, 61,
|
||||
184, 151, 91, 23, 208, 148, 2, 190, 237, 213, 217, 217, 112, 7, 16, 141, 178, 129, 96,
|
||||
213, 248, 4, 12, 167, 68, 87, 98, 184, 31, 190, 127, 249, 217, 46, 10, 231, 111, 36,
|
||||
242, 91, 51, 187, 230, 244, 74, 230, 30, 177, 4, 10, 203, 32, 4, 77, 62, 249, 18, 142,
|
||||
212, 1, 48, 121, 91, 212, 189, 59, 65, 238, 202, 208, 102, 171, 101, 25, 129, 253, 228,
|
||||
141, 247, 127, 55, 45, 195, 139, 159, 175, 221, 59, 239, 177, 139, 93, 163, 204, 60, 46,
|
||||
176, 47, 158, 58, 65, 214, 18, 202, 173, 21, 145, 18, 115, 160, 95, 35, 185, 232, 56,
|
||||
250, 175, 132, 157, 105, 132, 41, 239, 90, 30, 136, 121, 130, 54, 195, 212, 14, 96, 69,
|
||||
34, 165, 68, 200, 242, 122, 122, 45, 184, 6, 99, 209, 108, 247, 202, 234, 86, 222, 64,
|
||||
92, 178, 33, 90, 69, 178, 194, 85, 102, 181, 90, 193, 167, 72, 160, 112, 223, 200, 163,
|
||||
42, 70, 149, 67, 208, 25, 238, 251, 71];
|
||||
|
||||
#[test]
|
||||
fn rsa_sign() {
|
||||
let key = include_bytes!("../test/rsa.pem");
|
||||
let private_key = Rsa::private_key_from_pem(key).unwrap();
|
||||
let pkey = PKey::from_rsa(private_key).unwrap();
|
||||
|
||||
let mut signer = Signer::new(MessageDigest::sha256(), &pkey).unwrap();
|
||||
signer.update(INPUT).unwrap();
|
||||
let result = signer.finish().unwrap();
|
||||
|
||||
assert_eq!(result, SIGNATURE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rsa_verify_ok() {
|
||||
let key = include_bytes!("../test/rsa.pem");
|
||||
let private_key = Rsa::private_key_from_pem(key).unwrap();
|
||||
let pkey = PKey::from_rsa(private_key).unwrap();
|
||||
|
||||
let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap();
|
||||
verifier.update(INPUT).unwrap();
|
||||
assert!(verifier.finish(SIGNATURE).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rsa_verify_invalid() {
|
||||
let key = include_bytes!("../test/rsa.pem");
|
||||
let private_key = Rsa::private_key_from_pem(key).unwrap();
|
||||
let pkey = PKey::from_rsa(private_key).unwrap();
|
||||
|
||||
let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap();
|
||||
verifier.update(INPUT).unwrap();
|
||||
verifier.update(b"foobar").unwrap();
|
||||
assert!(!verifier.finish(SIGNATURE).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn dsa_sign_verify() {
|
||||
let input: Vec<u8> = (0..25).cycle().take(1024).collect();
|
||||
|
||||
let private_key = {
|
||||
let key = include_bytes!("../test/dsa.pem");
|
||||
PKey::from_dsa(Dsa::private_key_from_pem(key).unwrap()).unwrap()
|
||||
};
|
||||
|
||||
let public_key = {
|
||||
let key = include_bytes!("../test/dsa.pem.pub");
|
||||
PKey::from_dsa(Dsa::public_key_from_pem(key).unwrap()).unwrap()
|
||||
};
|
||||
|
||||
let mut signer = Signer::new(MessageDigest::sha1(), &private_key).unwrap();
|
||||
signer.update(&input).unwrap();
|
||||
let sig = signer.finish().unwrap();
|
||||
|
||||
let mut verifier = Verifier::new(MessageDigest::sha1(), &public_key).unwrap();
|
||||
verifier.update(&input).unwrap();
|
||||
assert!(verifier.finish(&sig).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn dsa_sign_verify_fail() {
|
||||
let input: Vec<u8> = (0..25).cycle().take(1024).collect();
|
||||
|
||||
let private_key = {
|
||||
let key = include_bytes!("../test/dsa.pem");
|
||||
PKey::from_dsa(Dsa::private_key_from_pem(key).unwrap()).unwrap()
|
||||
};
|
||||
|
||||
let public_key = {
|
||||
let key = include_bytes!("../test/dsa.pem.pub");
|
||||
PKey::from_dsa(Dsa::public_key_from_pem(key).unwrap()).unwrap()
|
||||
};
|
||||
|
||||
let mut signer = Signer::new(MessageDigest::sha1(), &private_key).unwrap();
|
||||
signer.update(&input).unwrap();
|
||||
let mut sig = signer.finish().unwrap();
|
||||
sig[0] -= 1;
|
||||
|
||||
let mut verifier = Verifier::new(MessageDigest::sha1(), &public_key).unwrap();
|
||||
verifier.update(&input).unwrap();
|
||||
match verifier.finish(&sig) {
|
||||
Ok(true) => panic!("unexpected success"),
|
||||
Ok(false) | Err(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_hmac(ty: MessageDigest, tests: &[(Vec<u8>, Vec<u8>, Vec<u8>)]) {
|
||||
for &(ref key, ref data, ref res) in tests.iter() {
|
||||
let pkey = PKey::hmac(key).unwrap();
|
||||
let mut signer = Signer::new(ty, &pkey).unwrap();
|
||||
signer.update(data).unwrap();
|
||||
assert_eq!(signer.finish().unwrap(), *res);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hmac_md5() {
|
||||
// test vectors from RFC 2202
|
||||
let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 7] =
|
||||
[(iter::repeat(0x0b_u8).take(16).collect(),
|
||||
b"Hi There".to_vec(),
|
||||
"9294727a3638bb1c13f48ef8158bfc9d".from_hex().unwrap()),
|
||||
(b"Jefe".to_vec(),
|
||||
b"what do ya want for nothing?".to_vec(),
|
||||
"750c783e6ab0b503eaa86e310a5db738".from_hex().unwrap()),
|
||||
(iter::repeat(0xaa_u8).take(16).collect(),
|
||||
iter::repeat(0xdd_u8).take(50).collect(),
|
||||
"56be34521d144c88dbb8c733f0e8b3f6".from_hex().unwrap()),
|
||||
("0102030405060708090a0b0c0d0e0f10111213141516171819".from_hex().unwrap(),
|
||||
iter::repeat(0xcd_u8).take(50).collect(),
|
||||
"697eaf0aca3a3aea3a75164746ffaa79".from_hex().unwrap()),
|
||||
(iter::repeat(0x0c_u8).take(16).collect(),
|
||||
b"Test With Truncation".to_vec(),
|
||||
"56461ef2342edc00f9bab995690efd4c".from_hex().unwrap()),
|
||||
(iter::repeat(0xaa_u8).take(80).collect(),
|
||||
b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
|
||||
"6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap()),
|
||||
(iter::repeat(0xaa_u8).take(80).collect(),
|
||||
b"Test Using Larger Than Block-Size Key \
|
||||
and Larger Than One Block-Size Data"
|
||||
.to_vec(),
|
||||
"6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())];
|
||||
|
||||
test_hmac(MessageDigest::md5(), &tests);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hmac_sha1() {
|
||||
// test vectors from RFC 2202
|
||||
let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 7] =
|
||||
[(iter::repeat(0x0b_u8).take(20).collect(),
|
||||
b"Hi There".to_vec(),
|
||||
"b617318655057264e28bc0b6fb378c8ef146be00".from_hex().unwrap()),
|
||||
(b"Jefe".to_vec(),
|
||||
b"what do ya want for nothing?".to_vec(),
|
||||
"effcdf6ae5eb2fa2d27416d5f184df9c259a7c79".from_hex().unwrap()),
|
||||
(iter::repeat(0xaa_u8).take(20).collect(),
|
||||
iter::repeat(0xdd_u8).take(50).collect(),
|
||||
"125d7342b9ac11cd91a39af48aa17b4f63f175d3".from_hex().unwrap()),
|
||||
("0102030405060708090a0b0c0d0e0f10111213141516171819".from_hex().unwrap(),
|
||||
iter::repeat(0xcd_u8).take(50).collect(),
|
||||
"4c9007f4026250c6bc8414f9bf50c86c2d7235da".from_hex().unwrap()),
|
||||
(iter::repeat(0x0c_u8).take(20).collect(),
|
||||
b"Test With Truncation".to_vec(),
|
||||
"4c1a03424b55e07fe7f27be1d58bb9324a9a5a04".from_hex().unwrap()),
|
||||
(iter::repeat(0xaa_u8).take(80).collect(),
|
||||
b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
|
||||
"aa4ae5e15272d00e95705637ce8a3b55ed402112".from_hex().unwrap()),
|
||||
(iter::repeat(0xaa_u8).take(80).collect(),
|
||||
b"Test Using Larger Than Block-Size Key \
|
||||
and Larger Than One Block-Size Data"
|
||||
.to_vec(),
|
||||
"e8e99d0f45237d786d6bbaa7965c7808bbff1a91".from_hex().unwrap())];
|
||||
|
||||
test_hmac(MessageDigest::sha1(), &tests);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
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,
|
||||
BIO_set_retry_read, BIO_set_retry_write};
|
||||
use ffi::{BIO, BIO_CTRL_FLUSH, BIO_new, BIO_clear_retry_flags, BIO_set_retry_read,
|
||||
BIO_set_retry_write};
|
||||
use std::any::Any;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
use std::sync::Arc;
|
||||
|
||||
use cvt_p;
|
||||
use error::ErrorStack;
|
||||
|
||||
pub struct StreamState<S> {
|
||||
|
|
@ -18,29 +18,19 @@ pub struct StreamState<S> {
|
|||
}
|
||||
|
||||
/// Safe wrapper for BIO_METHOD
|
||||
pub struct BioMethod(ffi::BIO_METHOD);
|
||||
pub struct BioMethod(compat::BIO_METHOD);
|
||||
|
||||
impl BioMethod {
|
||||
pub fn new<S: Read + Write>() -> BioMethod {
|
||||
BioMethod(ffi::BIO_METHOD {
|
||||
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,
|
||||
})
|
||||
fn new<S: Read + Write>() -> BioMethod {
|
||||
BioMethod(compat::BIO_METHOD::new::<S>())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for BioMethod {}
|
||||
unsafe impl Send for BioMethod {}
|
||||
|
||||
pub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, Arc<BioMethod>), ErrorStack> {
|
||||
let method = Arc::new(BioMethod::new::<S>());
|
||||
pub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, BioMethod), ErrorStack> {
|
||||
let method = BioMethod::new::<S>();
|
||||
|
||||
let state = Box::new(StreamState {
|
||||
stream: stream,
|
||||
|
|
@ -49,9 +39,9 @@ pub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, Arc<BioMethod>), Err
|
|||
});
|
||||
|
||||
unsafe {
|
||||
let bio = try_ssl_null!(BIO_new(&method.0));
|
||||
(*bio).ptr = Box::into_raw(state) as *mut _;
|
||||
(*bio).init = 1;
|
||||
let bio = try!(cvt_p(BIO_new(method.0.get())));
|
||||
compat::BIO_set_data(bio, Box::into_raw(state) as *mut _);
|
||||
compat::BIO_set_init(bio, 1);
|
||||
|
||||
return Ok((bio, method));
|
||||
}
|
||||
|
|
@ -62,14 +52,13 @@ pub unsafe fn take_error<S>(bio: *mut BIO) -> Option<io::Error> {
|
|||
state.error.take()
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "nightly"), allow(dead_code))]
|
||||
pub unsafe fn take_panic<S>(bio: *mut BIO) -> Option<Box<Any + Send>> {
|
||||
let state = state::<S>(bio);
|
||||
state.panic.take()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -78,23 +67,15 @@ 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> {
|
||||
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>>
|
||||
where F: FnOnce() -> T
|
||||
{
|
||||
::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(f))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
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);
|
||||
|
||||
|
|
@ -176,10 +157,10 @@ unsafe extern "C" fn ctrl<S: Write>(bio: *mut BIO,
|
|||
}
|
||||
|
||||
unsafe extern "C" fn create(bio: *mut BIO) -> c_int {
|
||||
(*bio).init = 0;
|
||||
(*bio).num = 0;
|
||||
(*bio).ptr = ptr::null_mut();
|
||||
(*bio).flags = 0;
|
||||
compat::BIO_set_init(bio, 0);
|
||||
compat::BIO_set_num(bio, 0);
|
||||
compat::BIO_set_data(bio, ptr::null_mut());
|
||||
compat::BIO_set_flags(bio, 0);
|
||||
1
|
||||
}
|
||||
|
||||
|
|
@ -188,9 +169,115 @@ unsafe extern "C" fn destroy<S>(bio: *mut BIO) -> c_int {
|
|||
return 0;
|
||||
}
|
||||
|
||||
assert!(!(*bio).ptr.is_null());
|
||||
Box::<StreamState<S>>::from_raw((*bio).ptr as *mut _);
|
||||
(*bio).ptr = ptr::null_mut();
|
||||
(*bio).init = 0;
|
||||
let data = compat::BIO_get_data(bio);
|
||||
assert!(!data.is_null());
|
||||
Box::<StreamState<S>>::from_raw(data as *mut _);
|
||||
compat::BIO_set_data(bio, ptr::null_mut());
|
||||
compat::BIO_set_init(bio, 0);
|
||||
1
|
||||
}
|
||||
|
||||
#[cfg(ossl110)]
|
||||
#[allow(bad_style)]
|
||||
mod compat {
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use libc::c_int;
|
||||
use ffi;
|
||||
pub use ffi::{BIO_set_init, BIO_set_flags, BIO_set_data, BIO_get_data};
|
||||
|
||||
pub unsafe fn BIO_set_num(_bio: *mut ffi::BIO, _num: c_int) {}
|
||||
|
||||
pub struct BIO_METHOD(*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(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.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for BIO_METHOD {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ffi::BIO_meth_free(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(ossl10x)]
|
||||
#[allow(bad_style)]
|
||||
mod compat {
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use ffi;
|
||||
use libc::{c_int, c_void};
|
||||
|
||||
pub struct BIO_METHOD(*mut ffi::BIO_METHOD);
|
||||
|
||||
impl BIO_METHOD {
|
||||
pub fn new<S: Read + Write>() -> BIO_METHOD {
|
||||
let ptr = Box::new(ffi::BIO_METHOD {
|
||||
type_: ffi::BIO_TYPE_NONE,
|
||||
name: b"rust\0".as_ptr() as *const _,
|
||||
bwrite: Some(super::bwrite::<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,
|
||||
});
|
||||
|
||||
BIO_METHOD(Box::into_raw(ptr))
|
||||
}
|
||||
|
||||
pub fn get(&self) -> *mut ffi::BIO_METHOD {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for BIO_METHOD {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
Box::<ffi::BIO_METHOD>::from_raw(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn BIO_set_init(bio: *mut ffi::BIO, init: c_int) {
|
||||
(*bio).init = init;
|
||||
}
|
||||
|
||||
pub unsafe fn BIO_set_flags(bio: *mut ffi::BIO, flags: c_int) {
|
||||
(*bio).flags = flags;
|
||||
}
|
||||
|
||||
pub unsafe fn BIO_get_data(bio: *mut ffi::BIO) -> *mut c_void {
|
||||
(*bio).ptr
|
||||
}
|
||||
|
||||
pub unsafe fn BIO_set_data(bio: *mut ffi::BIO, data: *mut c_void) {
|
||||
(*bio).ptr = data;
|
||||
}
|
||||
|
||||
pub unsafe fn BIO_set_num(bio: *mut ffi::BIO, num: c_int) {
|
||||
(*bio).num = num;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,452 @@
|
|||
use std::io::{Read, Write};
|
||||
|
||||
use dh::Dh;
|
||||
use error::ErrorStack;
|
||||
use ssl::{self, SslMethod, SslContextBuilder, SslContext, Ssl, SSL_VERIFY_PEER, SslStream,
|
||||
HandshakeError};
|
||||
use pkey::PKeyRef;
|
||||
use x509::X509Ref;
|
||||
|
||||
// Serialized form of DH_get_2048_256
|
||||
#[cfg(any(ossl101, all(test, any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))))]
|
||||
const DHPARAM_PEM: &'static str = r#"
|
||||
-----BEGIN DH PARAMETERS-----
|
||||
MIICCQKCAQEAh6jmHbS2Zjz/u9GcZRlZmYzu9ghmDdDyXSzu1ENeOwDgDfjx1hlX
|
||||
1Pr330VhsqowFsPZETQJb6o79Cltgw6afCCeDGSXUXq9WoqdMGvPZ+2R+eZyW0dY
|
||||
wCLgse9Cdb97bFv8EdRfkIi5QfVOseWbuLw5oL8SMH9cT9twxYGyP3a2Osrhyqa3
|
||||
kC1SUmc1SIoO8TxtmlG/pKs62DR3llJNjvahZ7WkGCXZZ+FE5RQFZCUcysuD5rSG
|
||||
9rPKP3lxUGAmwLhX9omWKFbe1AEKvQvmIcOjlgpU5xDDdfJjddcBQQOktUMwwZiv
|
||||
EmEW0iduEXFfaTh3+tfvCcrbCUrpHhoVlwKCAQA/syybcxNNCy53UGZg7b1ITKex
|
||||
jyHvIFQH9Hk6GguhJRDbwVB3vkY//0/tSqwLtVW+OmwbDGtHsbw3c79+jG9ikBIo
|
||||
+MKMuxilWuMTQQAKZQGW+THHelfy3fRj5ensFEt3feYqqrioYorDdtKC1u04ZOZ5
|
||||
gkKOvIMdFDSPby+Rk7UEWvJ2cWTh38lnwfs/LlWkvRv/6DucgNBSuYXRguoK2yo7
|
||||
cxPT/hTISEseBSWIubfSu9LfAWGZ7NBuFVfNCRWzNTu7ZODsN3/QKDcN+StSx4kU
|
||||
KM3GfrYYS1I9HbJGwy9jB4SQ8A741kfRSNR5VFFeIyfP75jFgmZLTA9sxBZZ
|
||||
-----END DH PARAMETERS-----
|
||||
"#;
|
||||
|
||||
fn ctx(method: SslMethod) -> Result<SslContextBuilder, ErrorStack> {
|
||||
let mut ctx = try!(SslContextBuilder::new(method));
|
||||
|
||||
let mut opts = ssl::SSL_OP_ALL;
|
||||
opts |= ssl::SSL_OP_NO_TICKET;
|
||||
opts |= ssl::SSL_OP_NO_COMPRESSION;
|
||||
opts &= !ssl::SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
|
||||
opts &= !ssl::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
|
||||
opts |= ssl::SSL_OP_NO_SSLV2;
|
||||
opts |= ssl::SSL_OP_NO_SSLV3;
|
||||
opts |= ssl::SSL_OP_SINGLE_DH_USE;
|
||||
opts |= ssl::SSL_OP_SINGLE_ECDH_USE;
|
||||
opts |= ssl::SSL_OP_CIPHER_SERVER_PREFERENCE;
|
||||
ctx.set_options(opts);
|
||||
|
||||
let mode = ssl::SSL_MODE_AUTO_RETRY | ssl::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
|
||||
ssl::SSL_MODE_ENABLE_PARTIAL_WRITE;
|
||||
ctx.set_mode(mode);
|
||||
|
||||
Ok(ctx)
|
||||
}
|
||||
|
||||
/// A builder for `SslConnector`s.
|
||||
pub struct SslConnectorBuilder(SslContextBuilder);
|
||||
|
||||
impl SslConnectorBuilder {
|
||||
/// Creates a new builder for TLS connections.
|
||||
///
|
||||
/// The default configuration is subject to change, and is currently derived from Python.
|
||||
pub fn new(method: SslMethod) -> Result<SslConnectorBuilder, ErrorStack> {
|
||||
let mut ctx = try!(ctx(method));
|
||||
try!(ctx.set_default_verify_paths());
|
||||
// From https://github.com/python/cpython/blob/c30098c8c6014f3340a369a31df9c74bdbacc269/Lib/ssl.py#L191
|
||||
try!(ctx.set_cipher_list("ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:\
|
||||
DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:RSA+AESGCM:\
|
||||
RSA+AES:RSA+HIGH:!aNULL:!eNULL:!MD5:!3DES"));
|
||||
|
||||
Ok(SslConnectorBuilder(ctx))
|
||||
}
|
||||
|
||||
/// Returns a shared reference to the inner `SslContextBuilder`.
|
||||
pub fn builder(&self) -> &SslContextBuilder {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the inner `SslContextBuilder`.
|
||||
pub fn builder_mut(&mut self) -> &mut SslContextBuilder {
|
||||
&mut self.0
|
||||
}
|
||||
|
||||
/// Consumes the builder, returning a `SslConnector`.
|
||||
pub fn build(self) -> SslConnector {
|
||||
SslConnector(self.0.build())
|
||||
}
|
||||
}
|
||||
|
||||
/// A type which wraps client-side streams in a TLS session.
|
||||
///
|
||||
/// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL
|
||||
/// structures, configuring cipher suites, session options, hostname verification, and more.
|
||||
///
|
||||
/// OpenSSL's built in hostname verification is used when linking against OpenSSL 1.0.2 or 1.1.0,
|
||||
/// and a custom implementation is used when linking against OpenSSL 1.0.1.
|
||||
pub struct SslConnector(SslContext);
|
||||
|
||||
impl SslConnector {
|
||||
/// Initiates a client-side TLS session on a stream.
|
||||
///
|
||||
/// The domain is used for SNI and hostname verification.
|
||||
pub fn connect<S>(&self, domain: &str, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
|
||||
where S: Read + Write
|
||||
{
|
||||
let mut ssl = try!(Ssl::new(&self.0));
|
||||
try!(ssl.set_hostname(domain));
|
||||
try!(setup_verify(&mut ssl, domain));
|
||||
|
||||
ssl.connect(stream)
|
||||
}
|
||||
}
|
||||
|
||||
/// A builder for `SslAcceptor`s.
|
||||
pub struct SslAcceptorBuilder(SslContextBuilder);
|
||||
|
||||
impl SslAcceptorBuilder {
|
||||
/// Creates a new builder configured to connect to non-legacy clients. This should generally be
|
||||
/// considered a reasonable default choice.
|
||||
///
|
||||
/// This corresponds to the intermediate configuration of Mozilla's server side TLS
|
||||
/// recommendations. See its [documentation][docs] for more details on specifics.
|
||||
///
|
||||
/// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS
|
||||
pub fn mozilla_intermediate<I>(method: SslMethod,
|
||||
private_key: &PKeyRef,
|
||||
certificate: &X509Ref,
|
||||
chain: I)
|
||||
-> Result<SslAcceptorBuilder, ErrorStack>
|
||||
where I: IntoIterator,
|
||||
I::Item: AsRef<X509Ref>
|
||||
{
|
||||
let mut ctx = try!(ctx(method));
|
||||
let dh = try!(get_dh());
|
||||
try!(ctx.set_tmp_dh(&dh));
|
||||
try!(setup_curves(&mut ctx));
|
||||
try!(ctx.set_cipher_list("ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\
|
||||
ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\
|
||||
ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\
|
||||
DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:\
|
||||
ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:\
|
||||
ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:\
|
||||
ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:\
|
||||
ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:\
|
||||
DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:\
|
||||
DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:\
|
||||
ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:\
|
||||
EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:\
|
||||
AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:\
|
||||
DES-CBC3-SHA:!DSS"));
|
||||
SslAcceptorBuilder::finish_setup(ctx, private_key, certificate, chain)
|
||||
}
|
||||
|
||||
/// Creates a new builder configured to connect to modern clients.
|
||||
///
|
||||
/// This corresponds to the modern configuration of Mozilla's server side TLS recommendations.
|
||||
/// See its [documentation][docs] for more details on specifics.
|
||||
///
|
||||
/// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS
|
||||
pub fn mozilla_modern<I>(method: SslMethod,
|
||||
private_key: &PKeyRef,
|
||||
certificate: &X509Ref,
|
||||
chain: I)
|
||||
-> Result<SslAcceptorBuilder, ErrorStack>
|
||||
where I: IntoIterator,
|
||||
I::Item: AsRef<X509Ref>
|
||||
{
|
||||
let mut ctx = try!(ctx(method));
|
||||
try!(setup_curves(&mut ctx));
|
||||
try!(ctx.set_cipher_list("ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\
|
||||
ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\
|
||||
ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\
|
||||
ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:\
|
||||
ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"));
|
||||
SslAcceptorBuilder::finish_setup(ctx, private_key, certificate, chain)
|
||||
}
|
||||
|
||||
fn finish_setup<I>(mut ctx: SslContextBuilder,
|
||||
private_key: &PKeyRef,
|
||||
certificate: &X509Ref,
|
||||
chain: I)
|
||||
-> Result<SslAcceptorBuilder, ErrorStack>
|
||||
where I: IntoIterator,
|
||||
I::Item: AsRef<X509Ref>
|
||||
{
|
||||
try!(ctx.set_private_key(private_key));
|
||||
try!(ctx.set_certificate(certificate));
|
||||
try!(ctx.check_private_key());
|
||||
for cert in chain {
|
||||
try!(ctx.add_extra_chain_cert(cert.as_ref().to_owned()));
|
||||
}
|
||||
Ok(SslAcceptorBuilder(ctx))
|
||||
}
|
||||
|
||||
/// Returns a shared reference to the inner `SslContextBuilder`.
|
||||
pub fn builder(&self) -> &SslContextBuilder {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the inner `SslContextBuilder`.
|
||||
pub fn builder_mut(&mut self) -> &mut SslContextBuilder {
|
||||
&mut self.0
|
||||
}
|
||||
|
||||
/// Consumes the builder, returning a `SslAcceptor`.
|
||||
pub fn build(self) -> SslAcceptor {
|
||||
SslAcceptor(self.0.build())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(ossl101)]
|
||||
fn get_dh() -> Result<Dh, ErrorStack> {
|
||||
Dh::from_pem(DHPARAM_PEM.as_bytes())
|
||||
}
|
||||
|
||||
#[cfg(not(ossl101))]
|
||||
fn get_dh() -> Result<Dh, ErrorStack> {
|
||||
use ffi;
|
||||
|
||||
use cvt_p;
|
||||
use types::OpenSslType;
|
||||
|
||||
// manually call into ffi to avoid forcing the features
|
||||
unsafe { cvt_p(ffi::DH_get_2048_256()).map(|p| Dh::from_ptr(p)) }
|
||||
}
|
||||
|
||||
#[cfg(ossl101)]
|
||||
fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> {
|
||||
use ec_key::EcKey;
|
||||
use nid;
|
||||
|
||||
let curve = try!(EcKey::new_by_curve_name(nid::X9_62_PRIME256V1));
|
||||
ctx.set_tmp_ecdh(&curve)
|
||||
}
|
||||
|
||||
#[cfg(ossl102)]
|
||||
fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> {
|
||||
ctx._set_ecdh_auto(true)
|
||||
}
|
||||
|
||||
#[cfg(ossl110)]
|
||||
fn setup_curves(_: &mut SslContextBuilder) -> Result<(), ErrorStack> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// A type which wraps server-side streams in a TLS session.
|
||||
///
|
||||
/// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL
|
||||
/// structures, configuring cipher suites, session options, and more.
|
||||
pub struct SslAcceptor(SslContext);
|
||||
|
||||
impl SslAcceptor {
|
||||
/// Initiates a server-side TLS session on a stream.
|
||||
pub fn accept<S>(&self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
|
||||
where S: Read + Write
|
||||
{
|
||||
let ssl = try!(Ssl::new(&self.0));
|
||||
ssl.accept(stream)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(ossl102, ossl110))]
|
||||
fn setup_verify(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> {
|
||||
ssl.set_verify(SSL_VERIFY_PEER);
|
||||
let param = ssl._param_mut();
|
||||
param.set_hostflags(::verify::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
|
||||
param.set_host(domain)
|
||||
}
|
||||
|
||||
#[cfg(ossl101)]
|
||||
fn setup_verify(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> {
|
||||
let domain = domain.to_owned();
|
||||
ssl.set_verify_callback(SSL_VERIFY_PEER,
|
||||
move |p, x| verify::verify_callback(&domain, p, x));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(ossl101)]
|
||||
mod verify {
|
||||
use std::net::IpAddr;
|
||||
use std::str;
|
||||
|
||||
use nid;
|
||||
use x509::{X509StoreContextRef, X509Ref, X509NameRef, GeneralName};
|
||||
use stack::Stack;
|
||||
use types::OpenSslTypeRef;
|
||||
|
||||
pub fn verify_callback(domain: &str,
|
||||
preverify_ok: bool,
|
||||
x509_ctx: &X509StoreContextRef)
|
||||
-> bool {
|
||||
if !preverify_ok || x509_ctx.error_depth() != 0 {
|
||||
return preverify_ok;
|
||||
}
|
||||
|
||||
match x509_ctx.current_cert() {
|
||||
Some(x509) => verify_hostname(domain, &x509),
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_hostname(domain: &str, cert: &X509Ref) -> bool {
|
||||
match cert.subject_alt_names() {
|
||||
Some(names) => verify_subject_alt_names(domain, names),
|
||||
None => verify_subject_name(domain, &cert.subject_name()),
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_subject_alt_names(domain: &str, names: Stack<GeneralName>) -> bool {
|
||||
let ip = domain.parse();
|
||||
|
||||
for name in &names {
|
||||
match ip {
|
||||
Ok(ip) => {
|
||||
if let Some(actual) = name.ipaddress() {
|
||||
if matches_ip(&ip, actual) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
if let Some(pattern) = name.dnsname() {
|
||||
if matches_dns(pattern, domain, false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn verify_subject_name(domain: &str, subject_name: &X509NameRef) -> bool {
|
||||
if let Some(pattern) = subject_name.entries_by_nid(nid::COMMONNAME).next() {
|
||||
let pattern = match str::from_utf8(pattern.data().as_slice()) {
|
||||
Ok(pattern) => pattern,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
// Unlike with SANs, IP addresses in the subject name don't have a
|
||||
// different encoding. We need to pass this down to matches_dns to
|
||||
// disallow wildcard matches with bogus patterns like *.0.0.1
|
||||
let is_ip = domain.parse::<IpAddr>().is_ok();
|
||||
|
||||
if matches_dns(&pattern, domain, is_ip) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn matches_dns(mut pattern: &str, mut hostname: &str, is_ip: bool) -> bool {
|
||||
// first strip trailing . off of pattern and hostname to normalize
|
||||
if pattern.ends_with('.') {
|
||||
pattern = &pattern[..pattern.len() - 1];
|
||||
}
|
||||
if hostname.ends_with('.') {
|
||||
hostname = &hostname[..hostname.len() - 1];
|
||||
}
|
||||
|
||||
matches_wildcard(pattern, hostname, is_ip).unwrap_or_else(|| pattern == hostname)
|
||||
}
|
||||
|
||||
fn matches_wildcard(pattern: &str, hostname: &str, is_ip: bool) -> Option<bool> {
|
||||
// IP addresses and internationalized domains can't involved in wildcards
|
||||
if is_ip || pattern.starts_with("xn--") {
|
||||
return None;
|
||||
}
|
||||
|
||||
let wildcard_location = match pattern.find('*') {
|
||||
Some(l) => l,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
let mut dot_idxs = pattern.match_indices('.').map(|(l, _)| l);
|
||||
let wildcard_end = match dot_idxs.next() {
|
||||
Some(l) => l,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
// Never match wildcards if the pattern has less than 2 '.'s (no *.com)
|
||||
//
|
||||
// This is a bit dubious, as it doesn't disallow other TLDs like *.co.uk.
|
||||
// Chrome has a black- and white-list for this, but Firefox (via NSS) does
|
||||
// the same thing we do here.
|
||||
//
|
||||
// The Public Suffix (https://www.publicsuffix.org/) list could
|
||||
// potentically be used here, but it's both huge and updated frequently
|
||||
// enough that management would be a PITA.
|
||||
if dot_idxs.next().is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Wildcards can only be in the first component
|
||||
if wildcard_location > wildcard_end {
|
||||
return None;
|
||||
}
|
||||
|
||||
let hostname_label_end = match hostname.find('.') {
|
||||
Some(l) => l,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
// check that the non-wildcard parts are identical
|
||||
if pattern[wildcard_end..] != hostname[hostname_label_end..] {
|
||||
return Some(false);
|
||||
}
|
||||
|
||||
let wildcard_prefix = &pattern[..wildcard_location];
|
||||
let wildcard_suffix = &pattern[wildcard_location + 1..wildcard_end];
|
||||
|
||||
let hostname_label = &hostname[..hostname_label_end];
|
||||
|
||||
// check the prefix of the first label
|
||||
if !hostname_label.starts_with(wildcard_prefix) {
|
||||
return Some(false);
|
||||
}
|
||||
|
||||
// and the suffix
|
||||
if !hostname_label[wildcard_prefix.len()..].ends_with(wildcard_suffix) {
|
||||
return Some(false);
|
||||
}
|
||||
|
||||
Some(true)
|
||||
}
|
||||
|
||||
fn matches_ip(expected: &IpAddr, actual: &[u8]) -> bool {
|
||||
match (expected, actual.len()) {
|
||||
(&IpAddr::V4(ref addr), 4) => actual == addr.octets(),
|
||||
(&IpAddr::V6(ref addr), 16) => {
|
||||
let segments = [((actual[0] as u16) << 8) | actual[1] as u16,
|
||||
((actual[2] as u16) << 8) | actual[3] as u16,
|
||||
((actual[4] as u16) << 8) | actual[5] as u16,
|
||||
((actual[6] as u16) << 8) | actual[7] as u16,
|
||||
((actual[8] as u16) << 8) | actual[9] as u16,
|
||||
((actual[10] as u16) << 8) | actual[11] as u16,
|
||||
((actual[12] as u16) << 8) | actual[13] as u16,
|
||||
((actual[14] as u16) << 8) | actual[15] as u16];
|
||||
segments == addr.segments()
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
|
||||
#[test]
|
||||
fn check_dhparam() {
|
||||
use dh::Dh;
|
||||
|
||||
let expected = String::from_utf8(Dh::get_2048_256().unwrap().to_pem().unwrap()).unwrap();
|
||||
assert_eq!(expected.trim(), super::DHPARAM_PEM.trim());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,11 @@
|
|||
use std::any::Any;
|
||||
use std::error;
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
|
||||
use error::ErrorStack;
|
||||
use ssl::MidHandshakeSslStream;
|
||||
|
||||
/// An SSL error.
|
||||
#[derive(Debug)]
|
||||
|
|
@ -62,3 +65,55 @@ impl From<ErrorStack> for Error {
|
|||
Error::Ssl(e)
|
||||
}
|
||||
}
|
||||
|
||||
/// An error or intermediate state after a TLS handshake attempt.
|
||||
#[derive(Debug)]
|
||||
pub enum HandshakeError<S> {
|
||||
/// Setup failed.
|
||||
SetupFailure(ErrorStack),
|
||||
/// The handshake failed.
|
||||
Failure(MidHandshakeSslStream<S>),
|
||||
/// The handshake was interrupted midway through.
|
||||
Interrupted(MidHandshakeSslStream<S>),
|
||||
}
|
||||
|
||||
impl<S: Any + fmt::Debug> StdError for HandshakeError<S> {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
HandshakeError::SetupFailure(_) => "stream setup failed",
|
||||
HandshakeError::Failure(_) => "the handshake failed",
|
||||
HandshakeError::Interrupted(_) => "the handshake was interrupted",
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&StdError> {
|
||||
match *self {
|
||||
HandshakeError::SetupFailure(ref e) => Some(e),
|
||||
HandshakeError::Failure(ref s) |
|
||||
HandshakeError::Interrupted(ref s) => Some(s.error()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Any + fmt::Debug> fmt::Display for HandshakeError<S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(f.write_str(StdError::description(self)));
|
||||
match *self {
|
||||
HandshakeError::SetupFailure(ref e) => try!(write!(f, ": {}", e)),
|
||||
HandshakeError::Failure(ref s) |
|
||||
HandshakeError::Interrupted(ref s) => {
|
||||
try!(write!(f, ": {}", s.error()));
|
||||
if let Some(err) = s.ssl().verify_result() {
|
||||
try!(write!(f, ": {}", err));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> From<ErrorStack> for HandshakeError<S> {
|
||||
fn from(e: ErrorStack) -> HandshakeError<S> {
|
||||
HandshakeError::SetupFailure(e)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,331 @@
|
|||
use std::ops::{Deref, DerefMut, Index, IndexMut};
|
||||
use std::iter;
|
||||
use std::borrow::Borrow;
|
||||
use std::convert::AsRef;
|
||||
use std::marker::PhantomData;
|
||||
use libc::c_int;
|
||||
use std::mem;
|
||||
|
||||
use types::{OpenSslType, OpenSslTypeRef};
|
||||
use util::Opaque;
|
||||
|
||||
#[cfg(ossl10x)]
|
||||
use ffi::{sk_pop as OPENSSL_sk_pop, sk_free as OPENSSL_sk_free, sk_num as OPENSSL_sk_num,
|
||||
sk_value as OPENSSL_sk_value, _STACK as OPENSSL_STACK};
|
||||
#[cfg(ossl110)]
|
||||
use ffi::{OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value, OPENSSL_STACK};
|
||||
|
||||
/// Trait implemented by types which can be placed in a stack.
|
||||
///
|
||||
/// Like `OpenSslType`, it should not be implemented for any type outside
|
||||
/// of this crate.
|
||||
pub trait Stackable: OpenSslType {
|
||||
/// The C stack type for this element.
|
||||
///
|
||||
/// Generally called `stack_st_{ELEMENT_TYPE}`, normally hidden by the
|
||||
/// `STACK_OF(ELEMENT_TYPE)` macro in the OpenSSL API.
|
||||
type StackType;
|
||||
}
|
||||
|
||||
/// An owned stack of `T`.
|
||||
pub struct Stack<T: Stackable>(*mut T::StackType);
|
||||
|
||||
impl<T: Stackable> Stack<T> {
|
||||
/// Return a new Stack<T>, taking ownership of the handle
|
||||
pub unsafe fn from_ptr(stack: *mut T::StackType) -> Stack<T> {
|
||||
Stack(stack)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Stackable> Drop for Stack<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
while let Some(_) = self.pop() {}
|
||||
OPENSSL_sk_free(self.0 as *mut _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Stackable> iter::IntoIterator for Stack<T> {
|
||||
type IntoIter = IntoIter<T>;
|
||||
type Item = T;
|
||||
|
||||
fn into_iter(self) -> IntoIter<T> {
|
||||
let it = IntoIter {
|
||||
stack: self.0,
|
||||
idx: 0,
|
||||
};
|
||||
mem::forget(self);
|
||||
it
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Stackable> AsRef<StackRef<T>> for Stack<T> {
|
||||
fn as_ref(&self) -> &StackRef<T> {
|
||||
&*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Stackable> Borrow<StackRef<T>> for Stack<T> {
|
||||
fn borrow(&self) -> &StackRef<T> {
|
||||
&*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Stackable> OpenSslType for Stack<T> {
|
||||
type CType = T::StackType;
|
||||
type Ref = StackRef<T>;
|
||||
|
||||
unsafe fn from_ptr(ptr: *mut T::StackType) -> Stack<T> {
|
||||
Stack(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Stackable> Deref for Stack<T> {
|
||||
type Target = StackRef<T>;
|
||||
|
||||
fn deref(&self) -> &StackRef<T> {
|
||||
unsafe { StackRef::from_ptr(self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Stackable> DerefMut for Stack<T> {
|
||||
fn deref_mut(&mut self) -> &mut StackRef<T> {
|
||||
unsafe { StackRef::from_ptr_mut(self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IntoIter<T: Stackable> {
|
||||
stack: *mut T::StackType,
|
||||
idx: c_int,
|
||||
}
|
||||
|
||||
impl<T: Stackable> IntoIter<T> {
|
||||
fn stack_len(&self) -> c_int {
|
||||
unsafe { OPENSSL_sk_num(self.stack as *mut _) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Stackable> Drop for IntoIter<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
while let Some(_) = self.next() {}
|
||||
OPENSSL_sk_free(self.stack as *mut _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Stackable> Iterator for IntoIter<T> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
unsafe {
|
||||
if self.idx == self.stack_len() {
|
||||
None
|
||||
} else {
|
||||
let ptr = OPENSSL_sk_value(self.stack as *mut _, self.idx);
|
||||
self.idx += 1;
|
||||
Some(T::from_ptr(ptr as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let size = (self.stack_len() - self.idx) as usize;
|
||||
(size, Some(size))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Stackable> ExactSizeIterator for IntoIter<T> {}
|
||||
|
||||
pub struct StackRef<T: Stackable>(Opaque, PhantomData<T>);
|
||||
|
||||
impl<T: Stackable> OpenSslTypeRef for StackRef<T> {
|
||||
type CType = T::StackType;
|
||||
}
|
||||
|
||||
impl<T: Stackable> StackRef<T> {
|
||||
fn as_stack(&self) -> *mut OPENSSL_STACK {
|
||||
self.as_ptr() as *mut _
|
||||
}
|
||||
|
||||
/// Returns the number of items in the stack
|
||||
pub fn len(&self) -> usize {
|
||||
unsafe { OPENSSL_sk_num(self.as_stack()) as usize }
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Iter<T> {
|
||||
// Unfortunately we can't simply convert the stack into a
|
||||
// slice and use that because OpenSSL 1.1.0 doesn't directly
|
||||
// expose the stack data (we have to use `OPENSSL_sk_value`
|
||||
// instead). We have to rewrite the entire iteration framework
|
||||
// instead.
|
||||
|
||||
Iter {
|
||||
stack: self,
|
||||
pos: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> IterMut<T> {
|
||||
IterMut {
|
||||
stack: self,
|
||||
pos: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the element at the given index in the
|
||||
/// stack or `None` if the index is out of bounds
|
||||
pub fn get(&self, idx: usize) -> Option<&T::Ref> {
|
||||
unsafe {
|
||||
if idx >= self.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(T::Ref::from_ptr(self._get(idx)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the element at the given index in the
|
||||
/// stack or `None` if the index is out of bounds
|
||||
pub fn get_mut(&mut self, idx: usize) -> Option<&mut T::Ref> {
|
||||
unsafe {
|
||||
if idx >= self.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(T::Ref::from_ptr_mut(self._get(idx)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the last element from the stack and returns it.
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
unsafe {
|
||||
let ptr = OPENSSL_sk_pop(self.as_stack());
|
||||
if ptr.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(T::from_ptr(ptr as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn _get(&self, idx: usize) -> *mut T::CType {
|
||||
OPENSSL_sk_value(self.as_stack(), idx as c_int) as *mut _
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Stackable> Index<usize> for StackRef<T> {
|
||||
type Output = T::Ref;
|
||||
|
||||
fn index(&self, index: usize) -> &T::Ref {
|
||||
self.get(index).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Stackable> IndexMut<usize> for StackRef<T> {
|
||||
fn index_mut(&mut self, index: usize) -> &mut T::Ref {
|
||||
self.get_mut(index).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Stackable> iter::IntoIterator for &'a StackRef<T> {
|
||||
type Item = &'a T::Ref;
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
||||
fn into_iter(self) -> Iter<'a, T> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Stackable> iter::IntoIterator for &'a mut StackRef<T> {
|
||||
type Item = &'a mut T::Ref;
|
||||
type IntoIter = IterMut<'a, T>;
|
||||
|
||||
fn into_iter(self) -> IterMut<'a, T> {
|
||||
self.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Stackable> iter::IntoIterator for &'a Stack<T> {
|
||||
type Item = &'a T::Ref;
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
||||
fn into_iter(self) -> Iter<'a, T> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Stackable> iter::IntoIterator for &'a mut Stack<T> {
|
||||
type Item = &'a mut T::Ref;
|
||||
type IntoIter = IterMut<'a, T>;
|
||||
|
||||
fn into_iter(self) -> IterMut<'a, T> {
|
||||
self.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the stack's contents.
|
||||
pub struct Iter<'a, T: Stackable>
|
||||
where T: 'a
|
||||
{
|
||||
stack: &'a StackRef<T>,
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl<'a, T: Stackable> iter::Iterator for Iter<'a, T> {
|
||||
type Item = &'a T::Ref;
|
||||
|
||||
fn next(&mut self) -> Option<&'a T::Ref> {
|
||||
let n = self.stack.get(self.pos);
|
||||
|
||||
if n.is_some() {
|
||||
self.pos += 1;
|
||||
}
|
||||
|
||||
n
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let rem = self.stack.len() - self.pos;
|
||||
|
||||
(rem, Some(rem))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Stackable> iter::ExactSizeIterator for Iter<'a, T> {}
|
||||
|
||||
/// A mutable iterator over the stack's contents.
|
||||
pub struct IterMut<'a, T: Stackable + 'a> {
|
||||
stack: &'a mut StackRef<T>,
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl<'a, T: Stackable> iter::Iterator for IterMut<'a, T> {
|
||||
type Item = &'a mut T::Ref;
|
||||
|
||||
fn next(&mut self) -> Option<&'a mut T::Ref> {
|
||||
if self.pos >= self.stack.len() {
|
||||
None
|
||||
} else {
|
||||
// Rust won't allow us to get a mutable reference into
|
||||
// `stack` in this situation since it can't statically
|
||||
// guarantee that we won't return several references to
|
||||
// the same object, so we have to use unsafe code for
|
||||
// mutable iterators.
|
||||
let n = unsafe { Some(T::Ref::from_ptr_mut(self.stack._get(self.pos))) };
|
||||
|
||||
self.pos += 1;
|
||||
|
||||
n
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let rem = self.stack.len() - self.pos;
|
||||
|
||||
(rem, Some(rem))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Stackable> iter::ExactSizeIterator for IterMut<'a, T> {}
|
||||
|
|
@ -3,6 +3,7 @@ use std::ptr;
|
|||
use libc::c_int;
|
||||
use ffi;
|
||||
|
||||
use {cvt, cvt_p};
|
||||
use error::ErrorStack;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
|
@ -11,90 +12,105 @@ pub enum Mode {
|
|||
Decrypt,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Type {
|
||||
AES_128_ECB,
|
||||
AES_128_CBC,
|
||||
/// Requires the `aes_xts` feature
|
||||
#[cfg(feature = "aes_xts")]
|
||||
AES_128_XTS,
|
||||
#[cfg(feature = "aes_ctr")]
|
||||
AES_128_CTR,
|
||||
// AES_128_GCM,
|
||||
AES_128_CFB1,
|
||||
AES_128_CFB128,
|
||||
AES_128_CFB8,
|
||||
pub struct Cipher(*const ffi::EVP_CIPHER);
|
||||
|
||||
AES_256_ECB,
|
||||
AES_256_CBC,
|
||||
/// Requires the `aes_xts` feature
|
||||
#[cfg(feature = "aes_xts")]
|
||||
AES_256_XTS,
|
||||
#[cfg(feature = "aes_ctr")]
|
||||
AES_256_CTR,
|
||||
// AES_256_GCM,
|
||||
AES_256_CFB1,
|
||||
AES_256_CFB128,
|
||||
AES_256_CFB8,
|
||||
impl Cipher {
|
||||
pub fn aes_128_ecb() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_aes_128_ecb()) }
|
||||
}
|
||||
|
||||
DES_CBC,
|
||||
DES_ECB,
|
||||
pub fn aes_128_cbc() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_aes_128_cbc()) }
|
||||
}
|
||||
|
||||
RC4_128,
|
||||
}
|
||||
pub fn aes_128_xts() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_aes_128_xts()) }
|
||||
}
|
||||
|
||||
pub fn aes_128_ctr() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_aes_128_ctr()) }
|
||||
}
|
||||
|
||||
pub fn aes_128_cfb1() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_aes_128_cfb1()) }
|
||||
}
|
||||
|
||||
pub fn aes_128_cfb128() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_aes_128_cfb128()) }
|
||||
}
|
||||
|
||||
pub fn aes_128_cfb8() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_aes_128_cfb8()) }
|
||||
}
|
||||
|
||||
pub fn aes_128_gcm() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_aes_128_gcm()) }
|
||||
}
|
||||
|
||||
pub fn aes_256_ecb() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_aes_256_ecb()) }
|
||||
}
|
||||
|
||||
pub fn aes_256_cbc() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_aes_256_cbc()) }
|
||||
}
|
||||
|
||||
pub fn aes_256_xts() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_aes_256_xts()) }
|
||||
}
|
||||
|
||||
pub fn aes_256_ctr() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_aes_256_ctr()) }
|
||||
}
|
||||
|
||||
pub fn aes_256_cfb1() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_aes_256_cfb1()) }
|
||||
}
|
||||
|
||||
pub fn aes_256_cfb128() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_aes_256_cfb128()) }
|
||||
}
|
||||
|
||||
pub fn aes_256_cfb8() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_aes_256_cfb8()) }
|
||||
}
|
||||
|
||||
pub fn aes_256_gcm() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_aes_256_gcm()) }
|
||||
}
|
||||
|
||||
pub fn des_cbc() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_des_cbc()) }
|
||||
}
|
||||
|
||||
pub fn des_ecb() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_des_ecb()) }
|
||||
}
|
||||
|
||||
pub fn rc4() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_rc4()) }
|
||||
}
|
||||
|
||||
pub unsafe fn from_ptr(ptr: *const ffi::EVP_CIPHER) -> Cipher {
|
||||
Cipher(ptr)
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn as_ptr(&self) -> *const ffi::EVP_CIPHER {
|
||||
unsafe {
|
||||
match *self {
|
||||
Type::AES_128_ECB => ffi::EVP_aes_128_ecb(),
|
||||
Type::AES_128_CBC => ffi::EVP_aes_128_cbc(),
|
||||
#[cfg(feature = "aes_xts")]
|
||||
Type::AES_128_XTS => ffi::EVP_aes_128_xts(),
|
||||
#[cfg(feature = "aes_ctr")]
|
||||
Type::AES_128_CTR => ffi::EVP_aes_128_ctr(),
|
||||
// AES_128_GCM => (EVP_aes_128_gcm(), 16, 16),
|
||||
Type::AES_128_CFB1 => ffi::EVP_aes_128_cfb1(),
|
||||
Type::AES_128_CFB128 => ffi::EVP_aes_128_cfb128(),
|
||||
Type::AES_128_CFB8 => ffi::EVP_aes_128_cfb8(),
|
||||
|
||||
Type::AES_256_ECB => ffi::EVP_aes_256_ecb(),
|
||||
Type::AES_256_CBC => ffi::EVP_aes_256_cbc(),
|
||||
#[cfg(feature = "aes_xts")]
|
||||
Type::AES_256_XTS => ffi::EVP_aes_256_xts(),
|
||||
#[cfg(feature = "aes_ctr")]
|
||||
Type::AES_256_CTR => ffi::EVP_aes_256_ctr(),
|
||||
// AES_256_GCM => (EVP_aes_256_gcm(), 32, 16),
|
||||
Type::AES_256_CFB1 => ffi::EVP_aes_256_cfb1(),
|
||||
Type::AES_256_CFB128 => ffi::EVP_aes_256_cfb128(),
|
||||
Type::AES_256_CFB8 => ffi::EVP_aes_256_cfb8(),
|
||||
|
||||
Type::DES_CBC => ffi::EVP_des_cbc(),
|
||||
Type::DES_ECB => ffi::EVP_des_ecb(),
|
||||
|
||||
Type::RC4_128 => ffi::EVP_rc4(),
|
||||
}
|
||||
}
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Returns the length of keys used with this cipher.
|
||||
pub fn key_len(&self) -> usize {
|
||||
unsafe {
|
||||
ffi::EVP_CIPHER_key_length(self.as_ptr()) as usize
|
||||
}
|
||||
unsafe { EVP_CIPHER_key_length(self.0) as usize }
|
||||
}
|
||||
|
||||
/// Returns the length of the IV used with this cipher, or `None` if the
|
||||
/// cipher does not use an IV.
|
||||
pub fn iv_len(&self) -> Option<usize> {
|
||||
unsafe {
|
||||
let len = ffi::EVP_CIPHER_iv_length(self.as_ptr()) as usize;
|
||||
if len == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(len)
|
||||
}
|
||||
let len = EVP_CIPHER_iv_length(self.0) as usize;
|
||||
if len == 0 { None } else { Some(len) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -104,9 +120,7 @@ impl Type {
|
|||
///
|
||||
/// Stream ciphers such as RC4 have a block size of 1.
|
||||
pub fn block_size(&self) -> usize {
|
||||
unsafe {
|
||||
ffi::EVP_CIPHER_block_size(self.as_ptr()) as usize
|
||||
}
|
||||
unsafe { EVP_CIPHER_block_size(self.0) as usize }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -122,12 +136,16 @@ impl Crypter {
|
|||
/// # Panics
|
||||
///
|
||||
/// Panics if an IV is required by the cipher but not provided, or if the
|
||||
/// IV's length does not match the expected length (see `Type::iv_len`).
|
||||
pub fn new(t: Type, mode: Mode, key: &[u8], iv: Option<&[u8]>) -> Result<Crypter, ErrorStack> {
|
||||
/// IV's length does not match the expected length (see `Cipher::iv_len`).
|
||||
pub fn new(t: Cipher,
|
||||
mode: Mode,
|
||||
key: &[u8],
|
||||
iv: Option<&[u8]>)
|
||||
-> Result<Crypter, ErrorStack> {
|
||||
ffi::init();
|
||||
|
||||
unsafe {
|
||||
let ctx = try_ssl_null!(ffi::EVP_CIPHER_CTX_new());
|
||||
let ctx = try!(cvt_p(ffi::EVP_CIPHER_CTX_new()));
|
||||
let crypter = Crypter {
|
||||
ctx: ctx,
|
||||
block_size: t.block_size(),
|
||||
|
|
@ -138,15 +156,15 @@ impl Crypter {
|
|||
Mode::Decrypt => 0,
|
||||
};
|
||||
|
||||
try_ssl!(ffi::EVP_CipherInit_ex(crypter.ctx,
|
||||
t.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
mode));
|
||||
try!(cvt(ffi::EVP_CipherInit_ex(crypter.ctx,
|
||||
t.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
mode)));
|
||||
|
||||
assert!(key.len() <= c_int::max_value() as usize);
|
||||
try_ssl!(ffi::EVP_CIPHER_CTX_set_key_length(crypter.ctx, key.len() as c_int));
|
||||
try!(cvt(ffi::EVP_CIPHER_CTX_set_key_length(crypter.ctx, key.len() as c_int)));
|
||||
|
||||
let key = key.as_ptr() as *mut _;
|
||||
let iv = match (iv, t.iv_len()) {
|
||||
|
|
@ -157,12 +175,12 @@ impl Crypter {
|
|||
(Some(_), None) | (None, None) => ptr::null_mut(),
|
||||
(None, Some(_)) => panic!("an IV is required for this cipher"),
|
||||
};
|
||||
try_ssl!(ffi::EVP_CipherInit_ex(crypter.ctx,
|
||||
try!(cvt(ffi::EVP_CipherInit_ex(crypter.ctx,
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
key,
|
||||
iv,
|
||||
mode));
|
||||
mode)));
|
||||
|
||||
Ok(crypter)
|
||||
}
|
||||
|
|
@ -173,7 +191,9 @@ impl Crypter {
|
|||
/// If padding is disabled, total amount of data encrypted/decrypted must
|
||||
/// be a multiple of the cipher's block size.
|
||||
pub fn pad(&mut self, padding: bool) {
|
||||
unsafe { ffi::EVP_CIPHER_CTX_set_padding(self.ctx, padding as c_int); }
|
||||
unsafe {
|
||||
ffi::EVP_CIPHER_CTX_set_padding(self.ctx, padding as c_int);
|
||||
}
|
||||
}
|
||||
|
||||
/// Feeds data from `input` through the cipher, writing encrypted/decrypted
|
||||
|
|
@ -185,7 +205,7 @@ impl Crypter {
|
|||
/// # Panics
|
||||
///
|
||||
/// Panics if `output.len() < input.len() + block_size` where
|
||||
/// `block_size` is the block size of the cipher (see `Type::block_size`),
|
||||
/// `block_size` is the block size of the cipher (see `Cipher::block_size`),
|
||||
/// or if `output.len() > c_int::max_value()`.
|
||||
pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result<usize, ErrorStack> {
|
||||
unsafe {
|
||||
|
|
@ -194,11 +214,11 @@ impl Crypter {
|
|||
let mut outl = output.len() as c_int;
|
||||
let inl = input.len() as c_int;
|
||||
|
||||
try_ssl!(ffi::EVP_CipherUpdate(self.ctx,
|
||||
try!(cvt(ffi::EVP_CipherUpdate(self.ctx,
|
||||
output.as_mut_ptr(),
|
||||
&mut outl,
|
||||
input.as_ptr(),
|
||||
inl));
|
||||
inl)));
|
||||
|
||||
Ok(outl as usize)
|
||||
}
|
||||
|
|
@ -219,7 +239,7 @@ impl Crypter {
|
|||
assert!(output.len() >= self.block_size);
|
||||
let mut outl = cmp::min(output.len(), c_int::max_value() as usize) as c_int;
|
||||
|
||||
try_ssl!(ffi::EVP_CipherFinal(self.ctx, output.as_mut_ptr(), &mut outl));
|
||||
try!(cvt(ffi::EVP_CipherFinal(self.ctx, output.as_mut_ptr(), &mut outl)));
|
||||
|
||||
Ok(outl as usize)
|
||||
}
|
||||
|
|
@ -238,7 +258,7 @@ impl Drop for Crypter {
|
|||
* Encrypts data, using the specified crypter type in encrypt mode with the
|
||||
* specified key and iv; returns the resulting (encrypted) data.
|
||||
*/
|
||||
pub fn encrypt(t: Type,
|
||||
pub fn encrypt(t: Cipher,
|
||||
key: &[u8],
|
||||
iv: Option<&[u8]>,
|
||||
data: &[u8])
|
||||
|
|
@ -250,7 +270,7 @@ pub fn encrypt(t: Type,
|
|||
* Decrypts data, using the specified crypter type in decrypt mode with the
|
||||
* specified key and iv; returns the resulting (decrypted) data.
|
||||
*/
|
||||
pub fn decrypt(t: Type,
|
||||
pub fn decrypt(t: Cipher,
|
||||
key: &[u8],
|
||||
iv: Option<&[u8]>,
|
||||
data: &[u8])
|
||||
|
|
@ -258,7 +278,7 @@ pub fn decrypt(t: Type,
|
|||
cipher(t, Mode::Decrypt, key, iv, data)
|
||||
}
|
||||
|
||||
fn cipher(t: Type,
|
||||
fn cipher(t: Cipher,
|
||||
mode: Mode,
|
||||
key: &[u8],
|
||||
iv: Option<&[u8]>,
|
||||
|
|
@ -272,6 +292,30 @@ fn cipher(t: Type,
|
|||
Ok(out)
|
||||
}
|
||||
|
||||
#[cfg(ossl110)]
|
||||
use ffi::{EVP_CIPHER_iv_length, EVP_CIPHER_block_size, EVP_CIPHER_key_length};
|
||||
|
||||
#[cfg(ossl10x)]
|
||||
#[allow(bad_style)]
|
||||
mod compat {
|
||||
use libc::c_int;
|
||||
use ffi::EVP_CIPHER;
|
||||
|
||||
pub unsafe fn EVP_CIPHER_iv_length(ptr: *const EVP_CIPHER) -> c_int {
|
||||
(*ptr).iv_len
|
||||
}
|
||||
|
||||
pub unsafe fn EVP_CIPHER_block_size(ptr: *const EVP_CIPHER) -> c_int {
|
||||
(*ptr).block_size
|
||||
}
|
||||
|
||||
pub unsafe fn EVP_CIPHER_key_length(ptr: *const EVP_CIPHER) -> c_int {
|
||||
(*ptr).key_len
|
||||
}
|
||||
}
|
||||
#[cfg(ossl10x)]
|
||||
use self::compat::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serialize::hex::{FromHex, ToHex};
|
||||
|
|
@ -288,23 +332,25 @@ mod tests {
|
|||
0xaau8, 0xbbu8, 0xccu8, 0xddu8, 0xeeu8, 0xffu8];
|
||||
let c0 = [0x8eu8, 0xa2u8, 0xb7u8, 0xcau8, 0x51u8, 0x67u8, 0x45u8, 0xbfu8, 0xeau8, 0xfcu8,
|
||||
0x49u8, 0x90u8, 0x4bu8, 0x49u8, 0x60u8, 0x89u8];
|
||||
let mut c = super::Crypter::new(super::Type::AES_256_ECB,
|
||||
let mut c = super::Crypter::new(super::Cipher::aes_256_ecb(),
|
||||
super::Mode::Encrypt,
|
||||
&k0,
|
||||
None).unwrap();
|
||||
None)
|
||||
.unwrap();
|
||||
c.pad(false);
|
||||
let mut r0 = vec![0; c0.len() + super::Type::AES_256_ECB.block_size()];
|
||||
let mut r0 = vec![0; c0.len() + super::Cipher::aes_256_ecb().block_size()];
|
||||
let count = c.update(&p0, &mut r0).unwrap();
|
||||
let rest = c.finalize(&mut r0[count..]).unwrap();
|
||||
r0.truncate(count + rest);
|
||||
assert_eq!(r0.to_hex(), c0.to_hex());
|
||||
|
||||
let mut c = super::Crypter::new(super::Type::AES_256_ECB,
|
||||
let mut c = super::Crypter::new(super::Cipher::aes_256_ecb(),
|
||||
super::Mode::Decrypt,
|
||||
&k0,
|
||||
None).unwrap();
|
||||
None)
|
||||
.unwrap();
|
||||
c.pad(false);
|
||||
let mut p1 = vec![0; r0.len() + super::Type::AES_256_ECB.block_size()];
|
||||
let mut p1 = vec![0; r0.len() + super::Cipher::aes_256_ecb().block_size()];
|
||||
let count = c.update(&r0, &mut p1).unwrap();
|
||||
let rest = c.finalize(&mut p1[count..]).unwrap();
|
||||
p1.truncate(count + rest);
|
||||
|
|
@ -322,12 +368,13 @@ mod tests {
|
|||
let ciphered_data = [0x4a_u8, 0x2e_u8, 0xe5_u8, 0x6_u8, 0xbf_u8, 0xcf_u8, 0xf2_u8,
|
||||
0xd7_u8, 0xea_u8, 0x2d_u8, 0xb1_u8, 0x85_u8, 0x6c_u8, 0x93_u8,
|
||||
0x65_u8, 0x6f_u8];
|
||||
let mut cr = super::Crypter::new(super::Type::AES_256_CBC,
|
||||
let mut cr = super::Crypter::new(super::Cipher::aes_256_cbc(),
|
||||
super::Mode::Decrypt,
|
||||
&data,
|
||||
Some(&iv)).unwrap();
|
||||
Some(&iv))
|
||||
.unwrap();
|
||||
cr.pad(false);
|
||||
let mut unciphered_data = vec![0; data.len() + super::Type::AES_256_CBC.block_size()];
|
||||
let mut unciphered_data = vec![0; data.len() + super::Cipher::aes_256_cbc().block_size()];
|
||||
let count = cr.update(&ciphered_data, &mut unciphered_data).unwrap();
|
||||
let rest = cr.finalize(&mut unciphered_data[count..]).unwrap();
|
||||
unciphered_data.truncate(count + rest);
|
||||
|
|
@ -337,7 +384,7 @@ mod tests {
|
|||
assert_eq!(&unciphered_data, expected_unciphered_data);
|
||||
}
|
||||
|
||||
fn cipher_test(ciphertype: super::Type, pt: &str, ct: &str, key: &str, iv: &str) {
|
||||
fn cipher_test(ciphertype: super::Cipher, pt: &str, ct: &str, key: &str, iv: &str) {
|
||||
use serialize::hex::ToHex;
|
||||
|
||||
let pt = pt.from_hex().unwrap();
|
||||
|
|
@ -368,11 +415,10 @@ mod tests {
|
|||
let key = "97CD440324DA5FD1F7955C1C13B6B466";
|
||||
let iv = "";
|
||||
|
||||
cipher_test(super::Type::RC4_128, pt, ct, key, iv);
|
||||
cipher_test(super::Cipher::rc4(), pt, ct, key, iv);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "aes_xts")]
|
||||
fn test_aes256_xts() {
|
||||
// Test case 174 from
|
||||
// http://csrc.nist.gov/groups/STM/cavp/documents/aes/XTSTestVectors.zip
|
||||
|
|
@ -384,11 +430,10 @@ mod tests {
|
|||
4180026ad640b74243b3133e7b9fae629403f6733423dae28";
|
||||
let iv = "db200efb7eaaa737dbdf40babb68953f";
|
||||
|
||||
cipher_test(super::Type::AES_256_XTS, pt, ct, key, iv);
|
||||
cipher_test(super::Cipher::aes_256_xts(), pt, ct, key, iv);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "aes_ctr")]
|
||||
fn test_aes128_ctr() {
|
||||
|
||||
let pt = "6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411\
|
||||
|
|
@ -398,20 +443,9 @@ mod tests {
|
|||
let key = "2B7E151628AED2A6ABF7158809CF4F3C";
|
||||
let iv = "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF";
|
||||
|
||||
cipher_test(super::Type::AES_128_CTR, pt, ct, key, iv);
|
||||
cipher_test(super::Cipher::aes_128_ctr(), pt, ct, key, iv);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_aes128_gcm() {
|
||||
// Test case 3 in GCM spec
|
||||
// let pt = ~"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255";
|
||||
// let ct = ~"42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62cf35abd2ba6fab4";
|
||||
// let key = ~"feffe9928665731c6d6a8f9467308308";
|
||||
// let iv = ~"cafebabefacedbaddecaf888";
|
||||
//
|
||||
// cipher_test(super::AES_128_GCM, pt, ct, key, iv);
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn test_aes128_cfb1() {
|
||||
// Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
|
||||
|
|
@ -421,7 +455,7 @@ mod tests {
|
|||
let key = "2b7e151628aed2a6abf7158809cf4f3c";
|
||||
let iv = "000102030405060708090a0b0c0d0e0f";
|
||||
|
||||
cipher_test(super::Type::AES_128_CFB1, pt, ct, key, iv);
|
||||
cipher_test(super::Cipher::aes_128_cfb1(), pt, ct, key, iv);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -432,7 +466,7 @@ mod tests {
|
|||
let key = "2b7e151628aed2a6abf7158809cf4f3c";
|
||||
let iv = "000102030405060708090a0b0c0d0e0f";
|
||||
|
||||
cipher_test(super::Type::AES_128_CFB128, pt, ct, key, iv);
|
||||
cipher_test(super::Cipher::aes_128_cfb128(), pt, ct, key, iv);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -443,7 +477,7 @@ mod tests {
|
|||
let key = "2b7e151628aed2a6abf7158809cf4f3c";
|
||||
let iv = "000102030405060708090a0b0c0d0e0f";
|
||||
|
||||
cipher_test(super::Type::AES_128_CFB8, pt, ct, key, iv);
|
||||
cipher_test(super::Cipher::aes_128_cfb8(), pt, ct, key, iv);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -454,7 +488,7 @@ mod tests {
|
|||
let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4";
|
||||
let iv = "000102030405060708090a0b0c0d0e0f";
|
||||
|
||||
cipher_test(super::Type::AES_256_CFB1, pt, ct, key, iv);
|
||||
cipher_test(super::Cipher::aes_256_cfb1(), pt, ct, key, iv);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -465,7 +499,7 @@ mod tests {
|
|||
let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4";
|
||||
let iv = "000102030405060708090a0b0c0d0e0f";
|
||||
|
||||
cipher_test(super::Type::AES_256_CFB128, pt, ct, key, iv);
|
||||
cipher_test(super::Cipher::aes_256_cfb128(), pt, ct, key, iv);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -476,7 +510,7 @@ mod tests {
|
|||
let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4";
|
||||
let iv = "000102030405060708090a0b0c0d0e0f";
|
||||
|
||||
cipher_test(super::Type::AES_256_CFB8, pt, ct, key, iv);
|
||||
cipher_test(super::Cipher::aes_256_cfb8(), pt, ct, key, iv);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -487,7 +521,7 @@ mod tests {
|
|||
let key = "7cb66337f3d3c0fe";
|
||||
let iv = "0001020304050607";
|
||||
|
||||
cipher_test(super::Type::DES_CBC, pt, ct, key, iv);
|
||||
cipher_test(super::Cipher::des_cbc(), pt, ct, key, iv);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -498,6 +532,6 @@ mod tests {
|
|||
let key = "7cb66337f3d3c0fe";
|
||||
let iv = "0001020304050607";
|
||||
|
||||
cipher_test(super::Type::DES_ECB, pt, ct, key, iv);
|
||||
cipher_test(super::Cipher::des_ecb(), pt, ct, key, iv);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
//! Items used by other types.
|
||||
|
||||
/// A type implemented by wrappers over OpenSSL types.
|
||||
///
|
||||
/// This should not be implemented by anything outside of this crate; new methods may be added at
|
||||
/// any time.
|
||||
pub trait OpenSslType: Sized {
|
||||
/// The raw C type.
|
||||
type CType;
|
||||
|
||||
/// The type representing a reference to this type.
|
||||
type Ref: OpenSslTypeRef<CType = Self::CType>;
|
||||
|
||||
/// Constructs an instance of this type from its raw type.
|
||||
unsafe fn from_ptr(ptr: *mut Self::CType) -> Self;
|
||||
}
|
||||
|
||||
/// A trait implemented by types which reference borrowed OpenSSL types.
|
||||
///
|
||||
/// This should not be implemented by anything outside of this crate; new methods may be added at
|
||||
/// any time.
|
||||
pub trait OpenSslTypeRef: Sized {
|
||||
/// The raw C type.
|
||||
type CType;
|
||||
|
||||
/// Constructs a shared instance of this type from its raw type.
|
||||
unsafe fn from_ptr<'a>(ptr: *mut Self::CType) -> &'a Self {
|
||||
&*(ptr as *mut _)
|
||||
}
|
||||
|
||||
/// Constructs a mutable reference of this type from its raw type.
|
||||
unsafe fn from_ptr_mut<'a>(ptr: *mut Self::CType) -> &'a mut Self {
|
||||
&mut *(ptr as *mut _)
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the wrapped value.
|
||||
fn as_ptr(&self) -> *mut Self::CType {
|
||||
self as *const _ as *mut _
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
use libc::{c_int, c_char, c_void};
|
||||
|
||||
use std::any::Any;
|
||||
use std::panic;
|
||||
use std::cell::UnsafeCell;
|
||||
use std::panic::{self, AssertUnwindSafe};
|
||||
use std::slice;
|
||||
|
||||
/// Wraps a user-supplied callback and a slot for panics thrown inside the callback (while FFI
|
||||
|
|
@ -36,23 +36,32 @@ impl<F> Drop for CallbackState<F> {
|
|||
/// Password callback function, passed to private key loading functions.
|
||||
///
|
||||
/// `cb_state` is expected to be a pointer to a `CallbackState`.
|
||||
pub extern "C" fn invoke_passwd_cb<F>(buf: *mut c_char,
|
||||
size: c_int,
|
||||
_rwflag: c_int,
|
||||
cb_state: *mut c_void)
|
||||
-> c_int
|
||||
where F: FnOnce(&mut [c_char]) -> usize {
|
||||
let result = panic::catch_unwind(|| {
|
||||
pub unsafe extern "C" fn invoke_passwd_cb<F>(buf: *mut c_char,
|
||||
size: c_int,
|
||||
_rwflag: c_int,
|
||||
cb_state: *mut c_void)
|
||||
-> c_int
|
||||
where F: FnOnce(&mut [c_char]) -> usize
|
||||
{
|
||||
let callback = &mut *(cb_state as *mut CallbackState<F>);
|
||||
|
||||
let result = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||
// build a `i8` slice to pass to the user callback
|
||||
let pass_slice = unsafe { slice::from_raw_parts_mut(buf, size as usize) };
|
||||
let callback = unsafe { &mut *(cb_state as *mut CallbackState<F>) };
|
||||
let pass_slice = slice::from_raw_parts_mut(buf, size as usize);
|
||||
|
||||
callback.cb.take().unwrap()(pass_slice)
|
||||
});
|
||||
}));
|
||||
|
||||
if let Ok(len) = result {
|
||||
return len as c_int;
|
||||
} else {
|
||||
return 0;
|
||||
match result {
|
||||
Ok(len) => len as c_int,
|
||||
Err(err) => {
|
||||
callback.panic = Some(err);
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This is intended to be used as the inner type for `FooRef` types converted from raw C pointers.
|
||||
/// It has an `UnsafeCell` internally to inform the compiler about aliasability and doesn't
|
||||
/// implement `Copy`, so it can't be dereferenced.
|
||||
pub struct Opaque(UnsafeCell<()>);
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
use libc::c_uint;
|
||||
use ffi;
|
||||
|
||||
use cvt;
|
||||
use error::ErrorStack;
|
||||
use types::OpenSslTypeRef;
|
||||
|
||||
bitflags! {
|
||||
pub flags X509CheckFlags: c_uint {
|
||||
const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT,
|
||||
const X509_CHECK_FLAG_NO_WILDCARDS = ffi::X509_CHECK_FLAG_NO_WILDCARDS,
|
||||
const X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS = ffi::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS,
|
||||
const X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS = ffi::X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS,
|
||||
const X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS
|
||||
= ffi::X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS,
|
||||
/// Requires the `v110` feature and OpenSSL 1.1.0.
|
||||
#[cfg(all(feature = "v110", ossl110))]
|
||||
const X509_CHECK_FLAG_NEVER_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_NEVER_CHECK_SUBJECT,
|
||||
}
|
||||
}
|
||||
|
||||
type_!(X509VerifyParam, X509VerifyParamRef, ffi::X509_VERIFY_PARAM, ffi::X509_VERIFY_PARAM_free);
|
||||
|
||||
impl X509VerifyParamRef {
|
||||
pub fn set_hostflags(&mut self, hostflags: X509CheckFlags) {
|
||||
unsafe {
|
||||
ffi::X509_VERIFY_PARAM_set_hostflags(self.as_ptr(), hostflags.bits);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_host(&mut self, host: &str) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::X509_VERIFY_PARAM_set1_host(self.as_ptr(),
|
||||
host.as_ptr() as *const _,
|
||||
host.len()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,9 +11,21 @@
|
|||
// limitations under the License.
|
||||
//
|
||||
|
||||
use ffi;
|
||||
use std::ffi::CStr;
|
||||
|
||||
#[cfg(ossl10x)]
|
||||
use ffi::{SSLEAY_VERSION as OPENSSL_VERSION, SSLEAY_CFLAGS as OPENSSL_CFLAGS,
|
||||
SSLEAY_BUILT_ON as OPENSSL_BUILT_ON, SSLEAY_PLATFORM as OPENSSL_PLATFORM,
|
||||
SSLEAY_DIR as OPENSSL_DIR, SSLeay as OpenSSL_version_num,
|
||||
SSLeay_version as OpenSSL_version};
|
||||
|
||||
#[cfg(ossl110)]
|
||||
use ffi::{OPENSSL_VERSION, OPENSSL_CFLAGS};
|
||||
#[cfg(ossl110)]
|
||||
use ffi::{OPENSSL_BUILT_ON, OPENSSL_PLATFORM, OPENSSL_DIR};
|
||||
#[cfg(ossl110)]
|
||||
use ffi::{OpenSSL_version_num, OpenSSL_version};
|
||||
|
||||
/// OPENSSL_VERSION_NUMBER is a numeric release version identifier:
|
||||
///
|
||||
/// `MNNFFPPS: major minor fix patch status`
|
||||
|
|
@ -39,34 +51,34 @@ use std::ffi::CStr;
|
|||
///
|
||||
/// The return value of this function can be compared to the macro to make sure that the correct version of the library has been loaded, especially when using DLLs on Windows systems.
|
||||
pub fn number() -> i64 {
|
||||
unsafe { ffi::SSLeay() as i64 }
|
||||
unsafe { OpenSSL_version_num() as i64 }
|
||||
}
|
||||
|
||||
|
||||
/// The text variant of the version number and the release date. For example, "OpenSSL 0.9.5a 1 Apr 2000".
|
||||
pub fn version() -> &'static str {
|
||||
unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_VERSION)).to_str().unwrap() }
|
||||
unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_VERSION)).to_str().unwrap() }
|
||||
}
|
||||
|
||||
/// The compiler flags set for the compilation process in the form "compiler: ..." if available or
|
||||
/// "compiler: information not available" otherwise.
|
||||
pub fn c_flags() -> &'static str {
|
||||
unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_CFLAGS)).to_str().unwrap() }
|
||||
unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_CFLAGS)).to_str().unwrap() }
|
||||
}
|
||||
|
||||
/// The date of the build process in the form "built on: ..." if available or "built on: date not available" otherwise.
|
||||
pub fn built_on() -> &'static str {
|
||||
unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_BUILT_ON)).to_str().unwrap() }
|
||||
unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_BUILT_ON)).to_str().unwrap() }
|
||||
}
|
||||
|
||||
/// The "Configure" target of the library build in the form "platform: ..." if available or "platform: information not available" otherwise.
|
||||
pub fn platform() -> &'static str {
|
||||
unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_PLATFORM)).to_str().unwrap() }
|
||||
unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_PLATFORM)).to_str().unwrap() }
|
||||
}
|
||||
|
||||
/// The "OPENSSLDIR" setting of the library build in the form "OPENSSLDIR: "..."" if available or "OPENSSLDIR: N/A" otherwise.
|
||||
pub fn dir() -> &'static str {
|
||||
unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_DIR)).to_str().unwrap() }
|
||||
unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_DIR)).to_str().unwrap() }
|
||||
}
|
||||
|
||||
/// This test ensures that we do not segfault when calling the functions of this module
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::fmt;
|
||||
|
||||
use nid::Nid;
|
||||
use nid::{self, Nid};
|
||||
|
||||
/// Type-only version of the `Extension` enum.
|
||||
///
|
||||
|
|
@ -36,10 +36,10 @@ pub enum Extension {
|
|||
///
|
||||
/// ```
|
||||
/// use openssl::x509::extension::Extension::*;
|
||||
/// use openssl::nid::Nid;
|
||||
/// use openssl::nid;
|
||||
///
|
||||
/// # let generator = openssl::x509::X509Generator::new();
|
||||
/// generator.add_extension(OtherNid(Nid::BasicConstraints,"critical,CA:TRUE".to_owned()));
|
||||
/// generator.add_extension(OtherNid(nid::BASIC_CONSTRAINTS,"critical,CA:TRUE".to_owned()));
|
||||
/// ```
|
||||
OtherNid(Nid, String),
|
||||
/// Arbitrary extensions by OID string. See `man ASN1_generate_nconf` for value syntax.
|
||||
|
|
@ -71,10 +71,10 @@ impl Extension {
|
|||
impl ExtensionType {
|
||||
pub fn get_nid(&self) -> Option<Nid> {
|
||||
match self {
|
||||
&ExtensionType::KeyUsage => Some(Nid::KeyUsage),
|
||||
&ExtensionType::ExtKeyUsage => Some(Nid::ExtendedKeyUsage),
|
||||
&ExtensionType::SubjectAltName => Some(Nid::SubjectAltName),
|
||||
&ExtensionType::IssuerAltName => Some(Nid::IssuerAltName),
|
||||
&ExtensionType::KeyUsage => Some(nid::KEY_USAGE),
|
||||
&ExtensionType::ExtKeyUsage => Some(nid::EXT_KEY_USAGE),
|
||||
&ExtensionType::SubjectAltName => Some(nid::SUBJECT_ALT_NAME),
|
||||
&ExtensionType::IssuerAltName => Some(nid::ISSUER_ALT_NAME),
|
||||
&ExtensionType::OtherNid(nid) => Some(nid),
|
||||
&ExtensionType::OtherStr(_) => None,
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,31 +1,31 @@
|
|||
use serialize::hex::FromHex;
|
||||
|
||||
use crypto::hash::Type::SHA1;
|
||||
use crypto::pkey::PKey;
|
||||
use crypto::rsa::RSA;
|
||||
use hash::MessageDigest;
|
||||
use pkey::PKey;
|
||||
use rsa::Rsa;
|
||||
use x509::{X509, X509Generator};
|
||||
use x509::extension::Extension::{KeyUsage, ExtKeyUsage, SubjectAltName, OtherNid, OtherStr};
|
||||
use x509::extension::AltNameOption as SAN;
|
||||
use x509::extension::KeyUsageOption::{DigitalSignature, KeyEncipherment};
|
||||
use x509::extension::ExtKeyUsageOption::{self, ClientAuth, ServerAuth};
|
||||
use nid::Nid;
|
||||
use nid;
|
||||
|
||||
fn get_generator() -> X509Generator {
|
||||
X509Generator::new()
|
||||
.set_valid_period(365 * 2)
|
||||
.add_name("CN".to_string(), "test_me".to_string())
|
||||
.set_sign_hash(SHA1)
|
||||
.set_sign_hash(MessageDigest::sha1())
|
||||
.add_extension(KeyUsage(vec![DigitalSignature, KeyEncipherment]))
|
||||
.add_extension(ExtKeyUsage(vec![ClientAuth,
|
||||
ServerAuth,
|
||||
ExtKeyUsageOption::Other("2.999.1".to_owned())]))
|
||||
.add_extension(SubjectAltName(vec![(SAN::DNS, "example.com".to_owned())]))
|
||||
.add_extension(OtherNid(Nid::BasicConstraints, "critical,CA:TRUE".to_owned()))
|
||||
.add_extension(OtherNid(nid::BASIC_CONSTRAINTS, "critical,CA:TRUE".to_owned()))
|
||||
.add_extension(OtherStr("2.999.2".to_owned(), "ASN1:UTF8:example value".to_owned()))
|
||||
}
|
||||
|
||||
fn pkey() -> PKey {
|
||||
let rsa = RSA::generate(2048).unwrap();
|
||||
let rsa = Rsa::generate(2048).unwrap();
|
||||
PKey::from_rsa(rsa).unwrap()
|
||||
}
|
||||
|
||||
|
|
@ -48,8 +48,8 @@ fn test_cert_gen() {
|
|||
fn test_cert_gen_extension_ordering() {
|
||||
let pkey = pkey();
|
||||
get_generator()
|
||||
.add_extension(OtherNid(Nid::SubjectKeyIdentifier, "hash".to_owned()))
|
||||
.add_extension(OtherNid(Nid::AuthorityKeyIdentifier, "keyid:always".to_owned()))
|
||||
.add_extension(OtherNid(nid::SUBJECT_KEY_IDENTIFIER, "hash".to_owned()))
|
||||
.add_extension(OtherNid(nid::AUTHORITY_KEY_IDENTIFIER, "keyid:always".to_owned()))
|
||||
.sign(&pkey)
|
||||
.expect("Failed to generate cert with order-dependent extensions");
|
||||
}
|
||||
|
|
@ -60,16 +60,14 @@ fn test_cert_gen_extension_ordering() {
|
|||
fn test_cert_gen_extension_bad_ordering() {
|
||||
let pkey = pkey();
|
||||
let result = get_generator()
|
||||
.add_extension(OtherNid(Nid::AuthorityKeyIdentifier,
|
||||
"keyid:always".to_owned()))
|
||||
.add_extension(OtherNid(Nid::SubjectKeyIdentifier, "hash".to_owned()))
|
||||
.sign(&pkey);
|
||||
.add_extension(OtherNid(nid::AUTHORITY_KEY_IDENTIFIER, "keyid:always".to_owned()))
|
||||
.add_extension(OtherNid(nid::SUBJECT_KEY_IDENTIFIER, "hash".to_owned()))
|
||||
.sign(&pkey);
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "x509_generator_request")]
|
||||
fn test_req_gen() {
|
||||
let pkey = pkey();
|
||||
|
||||
|
|
@ -84,7 +82,7 @@ fn test_req_gen() {
|
|||
fn test_cert_loading() {
|
||||
let cert = include_bytes!("../../test/cert.pem");
|
||||
let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
|
||||
let fingerprint = cert.fingerprint(SHA1).unwrap();
|
||||
let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap();
|
||||
|
||||
let hash_str = "59172d9313e84459bcff27f967e79e6e9217e584";
|
||||
let hash_vec = hash_str.from_hex().unwrap();
|
||||
|
|
@ -93,7 +91,6 @@ fn test_cert_loading() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "x509_expiry")]
|
||||
fn test_cert_issue_validity() {
|
||||
let cert = include_bytes!("../../test/cert.pem");
|
||||
let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
|
||||
|
|
@ -116,65 +113,49 @@ fn test_save_der() {
|
|||
#[test]
|
||||
fn test_subject_read_cn() {
|
||||
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).unwrap();
|
||||
let subject = cert.subject_name();
|
||||
let cn = match subject.text_by_nid(Nid::CN) {
|
||||
Some(x) => x,
|
||||
None => panic!("Failed to read CN from cert"),
|
||||
};
|
||||
|
||||
assert_eq!(&cn as &str, "foobar.com")
|
||||
let cn = subject.entries_by_nid(nid::COMMONNAME).next().unwrap();
|
||||
assert_eq!(cn.data().as_slice(), b"foobar.com")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nid_values() {
|
||||
let cert = include_bytes!("../../test/nid_test_cert.pem");
|
||||
let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
|
||||
let cert = X509::from_pem(cert).unwrap();
|
||||
let subject = cert.subject_name();
|
||||
|
||||
let cn = match subject.text_by_nid(Nid::CN) {
|
||||
Some(x) => x,
|
||||
None => panic!("Failed to read CN from cert"),
|
||||
};
|
||||
assert_eq!(&cn as &str, "example.com");
|
||||
let cn = subject.entries_by_nid(nid::COMMONNAME).next().unwrap();
|
||||
assert_eq!(cn.data().as_slice(), b"example.com");
|
||||
|
||||
let email = match subject.text_by_nid(Nid::Email) {
|
||||
Some(x) => x,
|
||||
None => panic!("Failed to read subject email address from cert"),
|
||||
};
|
||||
assert_eq!(&email as &str, "test@example.com");
|
||||
let email = subject.entries_by_nid(nid::PKCS9_EMAILADDRESS).next().unwrap();
|
||||
assert_eq!(email.data().as_slice(), b"test@example.com");
|
||||
|
||||
let friendly = match subject.text_by_nid(Nid::FriendlyName) {
|
||||
Some(x) => x,
|
||||
None => panic!("Failed to read subject friendly name from cert"),
|
||||
};
|
||||
assert_eq!(&friendly as &str, "Example");
|
||||
let friendly = subject.entries_by_nid(nid::FRIENDLYNAME).next().unwrap();
|
||||
assert_eq!(&*friendly.data().as_utf8().unwrap(), "Example");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nid_uid_value() {
|
||||
let cert = include_bytes!("../../test/nid_uid_test_cert.pem");
|
||||
let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
|
||||
let cert = X509::from_pem(cert).unwrap();
|
||||
let subject = cert.subject_name();
|
||||
|
||||
let cn = match subject.text_by_nid(Nid::UserId) {
|
||||
Some(x) => x,
|
||||
None => panic!("Failed to read UID from cert"),
|
||||
};
|
||||
assert_eq!(&cn as &str, "this is the userId");
|
||||
let cn = subject.entries_by_nid(nid::USERID).next().unwrap();
|
||||
assert_eq!(cn.data().as_slice(), b"this is the userId");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_subject_alt_name() {
|
||||
let cert = include_bytes!("../../test/alt_name_cert.pem");
|
||||
let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
|
||||
let cert = X509::from_pem(cert).unwrap();
|
||||
|
||||
let subject_alt_names = cert.subject_alt_names().unwrap();
|
||||
assert_eq!(3, subject_alt_names.len());
|
||||
assert_eq!(Some("foobar.com"), subject_alt_names.get(0).dnsname());
|
||||
assert_eq!(subject_alt_names.get(1).ipaddress(),
|
||||
assert_eq!(Some("foobar.com"), subject_alt_names[0].dnsname());
|
||||
assert_eq!(subject_alt_names[1].ipaddress(),
|
||||
Some(&[127, 0, 0, 1][..]));
|
||||
assert_eq!(subject_alt_names.get(2).ipaddress(),
|
||||
assert_eq!(subject_alt_names[2].ipaddress(),
|
||||
Some(&b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"[..]));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
//! X509 certificate verification
|
||||
//!
|
||||
//! Requires the `v102` or `v110` features and OpenSSL 1.0.2 or 1.1.0.
|
||||
|
||||
pub use ::verify::*;
|
||||
|
|
@ -1,33 +1,48 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
set -ex
|
||||
|
||||
MAX_REDIRECTS=5
|
||||
OPENSSL=openssl-1.0.2h.tar.gz
|
||||
OPENSSL=openssl-$BUILD_OPENSSL_VERSION.tar.gz
|
||||
OUT=/tmp/$OPENSSL
|
||||
SHA1="577585f5f5d299c44dd3c993d3c0ac7a219e4949"
|
||||
|
||||
me=$0
|
||||
myname=`basename $me`
|
||||
|
||||
cmp --silent $me $HOME/openssl/$myname && exit 0 || echo "cache is busted"
|
||||
|
||||
rm -rf $HOME/openssl
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$TARGET" == "arm-unknown-linux-gnueabihf" ]; then
|
||||
export C_INCLUDE_PATH=/usr/arm-linux-gnueabihf/include
|
||||
CROSS=arm-linux-gnueabihf-
|
||||
if [ "$BUILD_OPENSSL_VERSION" == "" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$TARGET" == "i686-unknown-linux-gnu" ]; then
|
||||
OS_COMPILER=linux-elf
|
||||
OS_FLAGS=-m32
|
||||
elif [ "$TARGET" == "arm-unknown-linux-gnueabihf" ]; then
|
||||
OS_COMPILER=linux-armv4
|
||||
export AR=arm-linux-gnueabihf-ar
|
||||
export CC=arm-linux-gnueabihf-gcc
|
||||
else
|
||||
OS_COMPILER=linux-x86_64
|
||||
fi
|
||||
|
||||
mkdir -p /tmp/openssl
|
||||
cp $me /tmp/openssl/$myname
|
||||
cd /tmp/openssl
|
||||
|
||||
curl -o $OUT -L --max-redirs $MAX_REDIRECTS https://openssl.org/source/$OPENSSL \
|
||||
|| curl -o $OUT -L --max-redirs ${MAX_REDIRECTS} http://mirrors.ibiblio.org/openssl/source/$OPENSSL
|
||||
|
||||
echo "$SHA1 $OUT" | sha1sum -c -
|
||||
|
||||
tar --strip-components=1 -xzf $OUT
|
||||
|
||||
./Configure --prefix=$HOME/openssl shared --cross-compile-prefix=$CROSS $OS_COMPILER
|
||||
make
|
||||
./Configure --prefix=$HOME/openssl $OS_COMPILER -fPIC $OS_FLAGS
|
||||
|
||||
make -j$(nproc)
|
||||
make install
|
||||
cp $myname $HOME/openssl/$myname
|
||||
|
|
|
|||
|
|
@ -1,32 +1,26 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
MAIN_TARGETS=https://static.rust-lang.org/dist
|
||||
case "$BUILD_OPENSSL_VERSION" in
|
||||
1.0.2*)
|
||||
FEATURES="v102"
|
||||
;;
|
||||
1.1.0*)
|
||||
FEATURES="v110"
|
||||
;;
|
||||
esac
|
||||
|
||||
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"
|
||||
echo Using features: $FEATURES
|
||||
|
||||
if [ -d "$HOME/openssl/lib" ]; then
|
||||
export OPENSSL_DIR=$HOME/openssl
|
||||
export PATH=$HOME/openssl/bin:$PATH
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" != "osx" ]; then
|
||||
export OPENSSL_LIB_DIR=$HOME/openssl/lib
|
||||
export OPENSSL_INCLUDE_DIR=$HOME/openssl/include
|
||||
export LD_LIBRARY_PATH=$HOME/openssl/lib:$LD_LIBRARY_PATH
|
||||
if [ "$TARGET" == "arm-unknown-linux-gnueabihf" ]; then
|
||||
FLAGS="--no-run"
|
||||
fi
|
||||
|
||||
if [ -n "$TARGET" ]; then
|
||||
FLAGS="--target=$TARGET"
|
||||
COMMAND="build"
|
||||
|
||||
# Download the rustlib folder from the relevant portion of main distribution's
|
||||
# tarballs.
|
||||
dir=rust-std-$TARGET
|
||||
pkg=rust-std
|
||||
curl -s $MAIN_TARGETS/$pkg-$TRAVIS_RUST_VERSION-$TARGET.tar.gz | \
|
||||
tar xzf - -C $HOME/rust/lib/rustlib --strip-components=4 \
|
||||
$pkg-$TRAVIS_RUST_VERSION-$TARGET/$dir/lib/rustlib/$TARGET
|
||||
else
|
||||
COMMAND="test"
|
||||
fi
|
||||
|
||||
export PATH=$HOME/openssl/bin:$PATH
|
||||
(cd openssl && RUST_BACKTRACE=1 cargo $COMMAND $FLAGS --features "$FEATURES")
|
||||
cargo run --manifest-path systest/Cargo.toml --target $TARGET
|
||||
exec cargo test --manifest-path openssl/Cargo.toml --target $TARGET \
|
||||
--features "$FEATURES" $FLAGS
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
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");
|
||||
}
|
||||
}
|
||||
|
||||
cfg.cfg(&format!("ossl{}", env::var("DEP_OPENSSL_VERSION").unwrap()), None);
|
||||
if let Ok(vars) = env::var("DEP_OPENSSL_CONF") {
|
||||
for var in vars.split(",") {
|
||||
cfg.cfg("osslconf", Some(var));
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
|
|
@ -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"));
|
||||
Loading…
Reference in New Issue