Merge remote-tracking branch 'origin/master' into x509-builder
This commit is contained in:
commit
f2c69ae7e9
31
.travis.yml
31
.travis.yml
|
|
@ -9,10 +9,17 @@ env:
|
|||
- BUILD_OPENSSL_VERSION=1.0.1u
|
||||
matrix:
|
||||
include:
|
||||
# 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 --without-test
|
||||
|
||||
# ARM-bit version compat
|
||||
- env: >
|
||||
TARGET=arm-unknown-linux-gnueabihf
|
||||
BUILD_OPENSSL_VERSION=1.0.2h
|
||||
BUILD_OPENSSL_VERSION=1.0.2k
|
||||
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc
|
||||
QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf
|
||||
RUST_TEST_THREADS=1
|
||||
|
|
@ -25,7 +32,7 @@ matrix:
|
|||
- binfmt-support
|
||||
- env: >
|
||||
TARGET=arm-unknown-linux-gnueabihf
|
||||
BUILD_OPENSSL_VERSION=1.1.0b
|
||||
BUILD_OPENSSL_VERSION=1.1.0d
|
||||
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc
|
||||
QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf
|
||||
RUST_TEST_THREADS=1
|
||||
|
|
@ -38,15 +45,15 @@ matrix:
|
|||
- binfmt-support
|
||||
|
||||
# Minimum version supported
|
||||
- rust: 1.9.0
|
||||
- rust: 1.10.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
|
||||
- env: BUILD_OPENSSL_VERSION=1.0.2k
|
||||
- env: BUILD_OPENSSL_VERSION=1.1.0d
|
||||
|
||||
# 32-bit version compat
|
||||
- env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.1u
|
||||
|
|
@ -54,24 +61,19 @@ matrix:
|
|||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.2h
|
||||
- env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.2k
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.1.0b
|
||||
- env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.1.0d
|
||||
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
|
||||
|
||||
# LibreSSL
|
||||
- env: BUILD_LIBRESSL_VERSION=2.5.0
|
||||
|
||||
before_install:
|
||||
- ./openssl/test/build.sh
|
||||
|
|
@ -83,4 +85,5 @@ script:
|
|||
cache:
|
||||
cargo: true
|
||||
directories:
|
||||
- $HOME/libressl
|
||||
- $HOME/openssl
|
||||
|
|
|
|||
47
README.md
47
README.md
|
|
@ -2,18 +2,18 @@
|
|||
|
||||
[](https://travis-ci.org/sfackler/rust-openssl)
|
||||
|
||||
[Documentation](https://sfackler.github.io/rust-openssl/doc/v0.9.0/openssl).
|
||||
[Documentation](https://docs.rs/openssl).
|
||||
|
||||
## Warning
|
||||
|
||||
This README does not correspond to rust-openssl 0.7.x. See
|
||||
This README does not correspond to rust-openssl 0.7.x or 0.8.x. See
|
||||
[here](https://github.com/sfackler/rust-openssl/blob/b8fb29db5c246175a096260eacca38180cd77dd0/README.md)
|
||||
for that README.
|
||||
|
||||
## Building
|
||||
|
||||
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
|
||||
rust-openssl depends on OpenSSL version 1.0.1 or above, or LibreSSL. Both the
|
||||
libraries and headers 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.
|
||||
|
||||
|
|
@ -37,9 +37,9 @@ 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
|
||||
curl -O https://www.openssl.org/source/openssl-1.1.0c.tar.gz
|
||||
tar xf openssl-1.1.0c.tar.gz
|
||||
cd openssl-1.1.0c
|
||||
export CC=...
|
||||
./Configure --prefix=... linux-x86_64 -fPIC
|
||||
make -j$(nproc)
|
||||
|
|
@ -49,20 +49,29 @@ make install
|
|||
### OSX
|
||||
|
||||
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
|
||||
of OSX and this crate also does not support that version of OpenSSL. To use this
|
||||
crate on OSX you'll need to install OpenSSL via some alternate means, typically
|
||||
homebrew:
|
||||
Homebrew:
|
||||
|
||||
```bash
|
||||
brew install openssl
|
||||
```
|
||||
|
||||
> Occasionally an update of XCode or MacOS will cause the linker to fail after compilation, to rectify this you may want to try and run:
|
||||
|
||||
```bash
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
If Homebrew is installed to the default location of `/usr/local`, OpenSSL will be
|
||||
automatically detected.
|
||||
|
||||
### Windows MSVC
|
||||
|
||||
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.
|
||||
install the 1.1.0 (non-light) installation if you're choosing this route.
|
||||
|
||||
[precompiled binaries]: http://slproweb.com/products/Win32OpenSSL.html
|
||||
|
||||
|
|
@ -73,6 +82,18 @@ installation via an environment variable:
|
|||
set OPENSSL_DIR=C:\OpenSSL-Win64
|
||||
```
|
||||
|
||||
Note that this OpenSSL distribution does not ship with any root certificates.
|
||||
So to make requests to servers on the internet, you have to install them
|
||||
manually. Download the [cacert.pem file from here], copy it somewhere safe
|
||||
(`C:\OpenSSL-Win64\certs` is a good place) and point the `SSL_CERT_FILE`
|
||||
environment variable there:
|
||||
|
||||
```
|
||||
set SSL_CERT_FILE=C:\OpenSSL-Win64\certs\cacert.pem
|
||||
```
|
||||
|
||||
[cacert.pem file from here]: https://curl.haxx.se/docs/caextract.html
|
||||
|
||||
After that, you're just a `cargo build` away!
|
||||
|
||||
### Windows GNU (MinGW)
|
||||
|
|
@ -102,6 +123,12 @@ The build script can be configured via environment variables:
|
|||
* `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_LIB_DIR` - If specified, a directory that will be used to find
|
||||
OpenSSL libraries. Overrides the `lib` folder implied by `OPENSSL_DIR`
|
||||
(if specified).
|
||||
* `OPENSSL_INCLUDE_DIR` - If specified, a directory that will be used to find
|
||||
OpenSSL header files. Overrides the `include` folder implied by `OPENSSL_DIR`
|
||||
(if specified).
|
||||
* `OPENSSL_STATIC` - If specified, OpenSSL libraries will be statically rather
|
||||
than dynamically linked.
|
||||
|
||||
|
|
|
|||
|
|
@ -5,20 +5,20 @@ environment:
|
|||
- TARGET: i686-pc-windows-gnu
|
||||
BITS: 32
|
||||
MSYS2: 1
|
||||
OPENSSL_VERSION: 1_1_0b
|
||||
OPENSSL_VERSION: 1_1_0d
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
BITS: 64
|
||||
OPENSSL_VERSION: 1_1_0b
|
||||
OPENSSL_VERSION: 1_1_0d
|
||||
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
|
||||
OPENSSL_VERSION: 1_0_2k
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
BITS: 32
|
||||
OPENSSL_VERSION: 1_0_2j
|
||||
OPENSSL_VERSION: 1_0_2k
|
||||
OPENSSL_DIR: C:\OpenSSL
|
||||
install:
|
||||
# install OpenSSL
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
[package]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.0"
|
||||
version = "0.9.6"
|
||||
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.9.0/openssl_sys"
|
||||
documentation = "https://docs.rs/openssl-sys/0.9.6/openssl_sys"
|
||||
categories = ["cryptography", "external-ffi-bindings"]
|
||||
links = "openssl"
|
||||
build = "build.rs"
|
||||
|
||||
|
|
@ -14,8 +15,13 @@ build = "build.rs"
|
|||
libc = "0.2"
|
||||
|
||||
[build-dependencies]
|
||||
pkg-config = "0.3"
|
||||
pkg-config = "0.3.9"
|
||||
gcc = "0.3.42"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
user32-sys = "0.2"
|
||||
gdi32-sys = "0.2"
|
||||
|
||||
# We don't actually use metadeps for annoying reasons but this is still here for tooling
|
||||
[package.metadata.pkg-config]
|
||||
openssl = "1.0.1"
|
||||
|
|
|
|||
|
|
@ -1,27 +1,60 @@
|
|||
extern crate pkg_config;
|
||||
extern crate gcc;
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::io::{BufWriter, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::panic::{self, AssertUnwindSafe};
|
||||
use std::process::Command;
|
||||
|
||||
// The set of `OPENSSL_NO_<FOO>`s that we care about.
|
||||
const DEFINES: &'static [&'static str] = &[
|
||||
"OPENSSL_NO_BUF_FREELISTS",
|
||||
"OPENSSL_NO_COMP",
|
||||
"OPENSSL_NO_EC",
|
||||
"OPENSSL_NO_ENGINE",
|
||||
"OPENSSL_NO_KRB5",
|
||||
"OPENSSL_NO_NEXTPROTONEG",
|
||||
"OPENSSL_NO_PSK",
|
||||
"OPENSSL_NO_RFC3779",
|
||||
"OPENSSL_NO_SHA",
|
||||
"OPENSSL_NO_SRP",
|
||||
"OPENSSL_NO_SSL3_METHOD",
|
||||
"OPENSSL_NO_TLSEXT",
|
||||
];
|
||||
|
||||
enum Version {
|
||||
Openssl110,
|
||||
Openssl102,
|
||||
Openssl101,
|
||||
Libressl,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
||||
let lib_dir = env::var_os("OPENSSL_LIB_DIR").map(PathBuf::from);
|
||||
let include_dir = env::var_os("OPENSSL_INCLUDE_DIR").map(PathBuf::from);
|
||||
|
||||
let (lib_dir, include_dir) = if lib_dir.is_none() || include_dir.is_none() {
|
||||
let openssl_dir = env::var_os("OPENSSL_DIR").unwrap_or_else(|| {
|
||||
find_openssl_dir(&target)
|
||||
});
|
||||
let openssl_dir = Path::new(&openssl_dir);
|
||||
let lib_dir = lib_dir.unwrap_or_else(|| openssl_dir.join("lib"));
|
||||
let include_dir = include_dir.unwrap_or_else(|| openssl_dir.join("include"));
|
||||
(lib_dir, include_dir)
|
||||
} else {
|
||||
(lib_dir.unwrap(), include_dir.unwrap())
|
||||
};
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
if !Path::new(&include_dir).exists() {
|
||||
panic!("OpenSSL include directory does not exist: {}",
|
||||
include_dir.to_string_lossy());
|
||||
|
|
@ -30,17 +63,14 @@ fn main() {
|
|||
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 version = validate_headers(&[include_dir.clone().into()]);
|
||||
|
||||
let libs = if (version.contains("0x10001") ||
|
||||
version.contains("0x10002")) &&
|
||||
target.contains("windows") {
|
||||
let libs = match version {
|
||||
Version::Openssl101 | Version::Openssl102 if target.contains("windows") => {
|
||||
["ssleay32", "libeay32"]
|
||||
} else if target.contains("windows") {
|
||||
["libssl", "libcrypto"]
|
||||
} else {
|
||||
["ssl", "crypto"]
|
||||
}
|
||||
Version::Openssl110 if target.contains("windows") => ["libssl", "libcrypto"],
|
||||
_ => ["ssl", "crypto"],
|
||||
};
|
||||
|
||||
let kind = determine_mode(Path::new(&lib_dir), &libs);
|
||||
|
|
@ -160,29 +190,12 @@ fn try_pkg_config() {
|
|||
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 = pkg_config::Config::new()
|
||||
.print_system_libs(false)
|
||||
.find("openssl")
|
||||
.unwrap();
|
||||
|
||||
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);
|
||||
validate_headers(&lib.include_paths);
|
||||
|
||||
for include in lib.include_paths.iter() {
|
||||
println!("cargo:include={}", include.display());
|
||||
|
|
@ -193,65 +206,11 @@ pointing to your OpenSSL installation.
|
|||
|
||||
/// 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 {
|
||||
fn validate_headers(include_dirs: &[PathBuf]) -> Version {
|
||||
// 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.
|
||||
|
|
@ -260,56 +219,105 @@ The build is now aborting due to this version mismatch.
|
|||
// 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);
|
||||
let mut path = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
path.push("expando.c");
|
||||
let mut file = BufWriter::new(File::create(&path).unwrap());
|
||||
|
||||
write!(file, "\
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/opensslconf.h>
|
||||
|
||||
#ifdef LIBRESSL_VERSION_NUMBER
|
||||
RUST_LIBRESSL
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x10200000
|
||||
RUST_OPENSSL_NEW
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x10100000
|
||||
RUST_OPENSSL_110
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x10002000
|
||||
RUST_OPENSSL_102
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x10001000
|
||||
RUST_OPENSSL_101
|
||||
#else
|
||||
RUST_OPENSSL_OLD
|
||||
#endif
|
||||
").unwrap();
|
||||
|
||||
for define in DEFINES {
|
||||
write!(file, "\
|
||||
#ifdef {define}
|
||||
RUST_{define}
|
||||
#endif
|
||||
", define = define).unwrap();
|
||||
}
|
||||
|
||||
file.flush().unwrap();
|
||||
drop(file);
|
||||
|
||||
let mut gcc = gcc::Config::new();
|
||||
for include_dir in include_dirs {
|
||||
gcc.include(include_dir);
|
||||
}
|
||||
// https://github.com/alexcrichton/gcc-rs/issues/133
|
||||
let expanded = match panic::catch_unwind(AssertUnwindSafe(|| gcc.file(&path).expand())) {
|
||||
Ok(expanded) => expanded,
|
||||
Err(_) => {
|
||||
panic!("
|
||||
Failed to find OpenSSL development headers.
|
||||
|
||||
You can try fixing this setting the `OPENSSL_DIR` environment variable
|
||||
pointing to your OpenSSL installation or installing OpenSSL headers package
|
||||
specific to your distribution:
|
||||
|
||||
# On Ubuntu
|
||||
sudo apt-get install libssl-dev
|
||||
# On Arch Linux
|
||||
sudo pacman -S openssl
|
||||
# On Fedora
|
||||
sudo dnf install openssl-devel
|
||||
|
||||
See rust-openssl README for more information:
|
||||
|
||||
https://github.com/sfackler/rust-openssl#linux
|
||||
");
|
||||
}
|
||||
};
|
||||
f.read_to_string(&mut conf_header).unwrap();
|
||||
let expanded = String::from_utf8(expanded).unwrap();
|
||||
|
||||
// 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);
|
||||
let mut enabled = vec![];
|
||||
for &define in DEFINES {
|
||||
if expanded.contains(&format!("RUST_{}", define)) {
|
||||
println!("cargo:rustc-cfg=osslconf=\"{}\"", define);
|
||||
enabled.push(define);
|
||||
}
|
||||
}
|
||||
println!("cargo:conf={}", vars.join(","));
|
||||
println!("cargo:conf={}", enabled.join(","));
|
||||
|
||||
return version_text.to_string()
|
||||
if expanded.contains("RUST_LIBRESSL") {
|
||||
println!("cargo:rustc-cfg=libressl");
|
||||
println!("cargo:libressl=true");
|
||||
println!("cargo:version=101");
|
||||
Version::Libressl
|
||||
} else if expanded.contains("RUST_OPENSSL_110") {
|
||||
println!("cargo:rustc-cfg=ossl110");
|
||||
println!("cargo:version=110");
|
||||
Version::Openssl110
|
||||
} else if expanded.contains("RUST_OPENSSL_102") {
|
||||
println!("cargo:rustc-cfg=ossl102");
|
||||
println!("cargo:version=102");
|
||||
Version::Openssl102
|
||||
} else if expanded.contains("RUST_OPENSSL_101") {
|
||||
println!("cargo:rustc-cfg=ossl101");
|
||||
println!("cargo:version=101");
|
||||
Version::Openssl101
|
||||
} else {
|
||||
panic!("
|
||||
|
||||
This crate is only compatible with OpenSSL 1.0.1, 1.0.2, and 1.1.0, or LibreSSL,
|
||||
but a different version of OpenSSL was found. The build is now aborting due to
|
||||
this version mismatch.
|
||||
|
||||
");
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a libdir for OpenSSL (where artifacts are located) as well as the name
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
#![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)]
|
||||
#![allow(dead_code, overflowing_literals)]
|
||||
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.9.0")]
|
||||
#![doc(html_root_url="https://docs.rs/openssl-sys/0.9.6")]
|
||||
|
||||
extern crate libc;
|
||||
|
||||
use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t, FILE};
|
||||
use std::ptr;
|
||||
use std::mem;
|
||||
|
||||
#[cfg(any(ossl101, ossl102))]
|
||||
mod ossl10x;
|
||||
|
|
@ -17,46 +18,72 @@ mod ossl110;
|
|||
#[cfg(ossl110)]
|
||||
pub use ossl110::*;
|
||||
|
||||
#[cfg(libressl)]
|
||||
mod libressl;
|
||||
#[cfg(libressl)]
|
||||
pub use libressl::*;
|
||||
|
||||
pub enum ASN1_INTEGER {}
|
||||
pub enum ASN1_GENERALIZEDTIME {}
|
||||
pub enum ASN1_STRING {}
|
||||
pub enum ASN1_BIT_STRING {}
|
||||
pub enum ASN1_TIME {}
|
||||
pub enum ASN1_TYPE {}
|
||||
pub enum ASN1_OBJECT {}
|
||||
pub enum BN_CTX {}
|
||||
pub enum BN_GENCB {}
|
||||
pub enum CONF {}
|
||||
pub enum CONF_METHOD {}
|
||||
pub enum COMP_METHOD {}
|
||||
pub enum EC_KEY {}
|
||||
pub enum EC_GROUP {}
|
||||
pub enum EC_METHOD {}
|
||||
pub enum EC_POINT {}
|
||||
pub enum ENGINE {}
|
||||
pub enum EVP_CIPHER_CTX {}
|
||||
pub enum EVP_MD {}
|
||||
pub enum EVP_PKEY_CTX {}
|
||||
pub enum SSL {}
|
||||
pub enum OCSP_BASICRESP {}
|
||||
pub enum OCSP_CERTID {}
|
||||
pub enum OCSP_RESPONSE {}
|
||||
pub enum OCSP_REQUEST {}
|
||||
pub enum OCSP_ONEREQ {}
|
||||
pub enum SSL_CIPHER {}
|
||||
pub enum SSL_METHOD {}
|
||||
pub enum X509_CRL {}
|
||||
pub enum X509_EXTENSION {}
|
||||
pub enum X509_NAME {}
|
||||
pub enum X509_NAME_ENTRY {}
|
||||
pub enum X509_REQ {}
|
||||
pub enum X509_STORE {}
|
||||
pub enum X509_STORE_CTX {}
|
||||
pub enum bio_st {}
|
||||
pub enum PKCS12 {}
|
||||
pub enum DH_METHOD {}
|
||||
|
||||
pub type bio_info_cb = Option<unsafe extern "C" fn(*mut BIO,
|
||||
c_int,
|
||||
*const c_char,
|
||||
c_int,
|
||||
c_long,
|
||||
c_long)>;
|
||||
|
||||
pub enum RSA_METHOD {}
|
||||
pub enum BN_MONT_CTX {}
|
||||
pub enum BN_BLINDING {}
|
||||
pub enum DSA_METHOD {}
|
||||
pub enum EVP_PKEY_ASN1_METHOD {}
|
||||
|
||||
pub type bio_info_cb = Option<unsafe extern fn(*mut BIO, c_int, *const c_char, c_int, c_long, c_long)>;
|
||||
pub type GEN_SESSION_CB = Option<unsafe extern fn(*const SSL, *mut c_uchar, *mut c_uint) -> c_int>;
|
||||
pub type tls_session_ticket_ext_cb_fn = Option<unsafe extern fn(*mut SSL, *const c_uchar, c_int, *mut c_void) -> c_int>;
|
||||
pub type tls_session_secret_cb_fn = Option<unsafe extern fn(*mut SSL, *mut c_void, *mut c_int, *mut stack_st_SSL_CIPHER, *mut *mut SSL_CIPHER, *mut c_void) -> c_int>;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum point_conversion_form_t {
|
||||
POINT_CONVERSION_COMPRESSED = 2,
|
||||
POINT_CONVERSION_UNCOMPRESSED = 4,
|
||||
POINT_CONVERSION_HYBRID = 6,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct AES_KEY {
|
||||
// There is some business with AES_LONG which is there to ensure the values here are 32 bits
|
||||
rd_key: [u32; 4 * (AES_MAXNR as usize + 1)],
|
||||
rounds: c_int,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct GENERAL_NAME {
|
||||
pub type_: c_int,
|
||||
|
|
@ -95,6 +122,12 @@ pub type PasswordCallback = unsafe extern fn(buf: *mut c_char, size: c_int,
|
|||
rwflag: c_int, user_data: *mut c_void)
|
||||
-> c_int;
|
||||
|
||||
pub const AES_ENCRYPT: c_int = 1;
|
||||
pub const AES_DECRYPT: c_int = 0;
|
||||
|
||||
pub const AES_MAXNR: c_int = 14;
|
||||
pub const AES_BLOCK_SIZE: c_int = 16;
|
||||
|
||||
pub const BIO_TYPE_NONE: c_int = 0;
|
||||
|
||||
pub const BIO_CTRL_EOF: c_int = 2;
|
||||
|
|
@ -110,10 +143,25 @@ pub const BIO_FLAGS_SHOULD_RETRY: c_int = 0x08;
|
|||
|
||||
pub const CRYPTO_LOCK: c_int = 1;
|
||||
|
||||
pub const ERR_LIB_PEM: c_int = 9;
|
||||
pub const PEM_R_NO_START_LINE: c_int = 108;
|
||||
|
||||
pub const EVP_MAX_MD_SIZE: c_uint = 64;
|
||||
pub const EVP_PKEY_RSA: c_int = NID_rsaEncryption;
|
||||
pub const EVP_PKEY_HMAC: c_int = NID_hmac;
|
||||
pub const EVP_PKEY_DSA: c_int = NID_dsa;
|
||||
pub const EVP_PKEY_DH: c_int = NID_dhKeyAgreement;
|
||||
pub const EVP_PKEY_EC: c_int = NID_X9_62_id_ecPublicKey;
|
||||
|
||||
pub const EVP_PKEY_ALG_CTRL: c_int = 0x1000;
|
||||
|
||||
pub const EVP_PKEY_CTRL_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 1;
|
||||
|
||||
pub const EVP_PKEY_CTRL_GET_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 6;
|
||||
|
||||
pub const EVP_CTRL_GCM_SET_IVLEN: c_int = 0x9;
|
||||
pub const EVP_CTRL_GCM_GET_TAG: c_int = 0x10;
|
||||
pub const EVP_CTRL_GCM_SET_TAG: c_int = 0x11;
|
||||
|
||||
pub const MBSTRING_ASC: c_int = MBSTRING_FLAG | 1;
|
||||
pub const MBSTRING_BMP: c_int = MBSTRING_FLAG | 2;
|
||||
|
|
@ -1034,7 +1082,44 @@ pub const NID_aes_128_cbc_hmac_sha1: c_int = 916;
|
|||
pub const NID_aes_192_cbc_hmac_sha1: c_int = 917;
|
||||
pub const NID_aes_256_cbc_hmac_sha1: c_int = 918;
|
||||
|
||||
pub const OCSP_NOCERTS: c_ulong = 0x1;
|
||||
pub const OCSP_NOINTERN: c_ulong = 0x2;
|
||||
pub const OCSP_NOSIGS: c_ulong = 0x4;
|
||||
pub const OCSP_NOCHAIN: c_ulong = 0x8;
|
||||
pub const OCSP_NOVERIFY: c_ulong = 0x10;
|
||||
pub const OCSP_NOEXPLICIT: c_ulong = 0x20;
|
||||
pub const OCSP_NOCASIGN: c_ulong = 0x40;
|
||||
pub const OCSP_NODELEGATED: c_ulong = 0x80;
|
||||
pub const OCSP_NOCHECKS: c_ulong = 0x100;
|
||||
pub const OCSP_TRUSTOTHER: c_ulong = 0x200;
|
||||
pub const OCSP_RESPID_KEY: c_ulong = 0x400;
|
||||
pub const OCSP_NOTIME: c_ulong = 0x800;
|
||||
|
||||
pub const V_OCSP_CERTSTATUS_GOOD: c_int = 0;
|
||||
pub const V_OCSP_CERTSTATUS_REVOKED: c_int = 1;
|
||||
pub const V_OCSP_CERTSTATUS_UNKNOWN: c_int = 2;
|
||||
|
||||
pub const OCSP_REVOKED_STATUS_NOSTATUS: c_int = -1;
|
||||
pub const OCSP_REVOKED_STATUS_UNSPECIFIED: c_int = 0;
|
||||
pub const OCSP_REVOKED_STATUS_KEYCOMPROMISE: c_int = 1;
|
||||
pub const OCSP_REVOKED_STATUS_CACOMPROMISE: c_int = 2;
|
||||
pub const OCSP_REVOKED_STATUS_AFFILIATIONCHANGED: c_int = 3;
|
||||
pub const OCSP_REVOKED_STATUS_SUPERSEDED: c_int = 4;
|
||||
pub const OCSP_REVOKED_STATUS_CESSATIONOFOPERATION: c_int = 5;
|
||||
pub const OCSP_REVOKED_STATUS_CERTIFICATEHOLD: c_int = 6;
|
||||
pub const OCSP_REVOKED_STATUS_REMOVEFROMCRL: c_int = 8;
|
||||
|
||||
pub const OCSP_RESPONSE_STATUS_SUCCESSFUL: c_int = 0;
|
||||
pub const OCSP_RESPONSE_STATUS_MALFORMEDREQUEST: c_int = 1;
|
||||
pub const OCSP_RESPONSE_STATUS_INTERNALERROR: c_int = 2;
|
||||
pub const OCSP_RESPONSE_STATUS_TRYLATER: c_int = 3;
|
||||
pub const OCSP_RESPONSE_STATUS_SIGREQUIRED: c_int = 5;
|
||||
pub const OCSP_RESPONSE_STATUS_UNAUTHORIZED: c_int = 6;
|
||||
|
||||
pub const OPENSSL_EC_NAMED_CURVE: c_int = 1;
|
||||
|
||||
pub const PKCS5_SALT_LEN: c_int = 8;
|
||||
pub const PKCS12_DEFAULT_ITER: c_int = 2048;
|
||||
|
||||
pub const RSA_F4: c_long = 0x10001;
|
||||
|
||||
|
|
@ -1052,14 +1137,23 @@ pub const SSL_CTRL_SET_READ_AHEAD: c_int = 41;
|
|||
pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_CB: c_int = 53;
|
||||
pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG: c_int = 54;
|
||||
pub const SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55;
|
||||
pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB: c_int = 63;
|
||||
pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG: c_int = 64;
|
||||
pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE: c_int = 65;
|
||||
pub const SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP: c_int = 70;
|
||||
pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP: c_int = 71;
|
||||
pub const SSL_CTRL_GET_EXTRA_CHAIN_CERTS: c_int = 82;
|
||||
|
||||
pub const SSL_MODE_ENABLE_PARTIAL_WRITE: c_long = 0x1;
|
||||
pub const SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER: c_long = 0x2;
|
||||
pub const SSL_MODE_AUTO_RETRY: c_long = 0x4;
|
||||
pub const SSL_MODE_NO_AUTO_CHAIN: c_long = 0x8;
|
||||
pub const SSL_MODE_RELEASE_BUFFERS: c_long = 0x10;
|
||||
#[cfg(not(libressl))]
|
||||
pub const SSL_MODE_SEND_CLIENTHELLO_TIME: c_long = 0x20;
|
||||
#[cfg(not(libressl))]
|
||||
pub const SSL_MODE_SEND_SERVERHELLO_TIME: c_long = 0x40;
|
||||
#[cfg(not(libressl))]
|
||||
pub const SSL_MODE_SEND_FALLBACK_SCSV: c_long = 0x80;
|
||||
|
||||
pub const SSL_ERROR_NONE: c_int = 0;
|
||||
|
|
@ -1078,31 +1172,38 @@ pub const SSL_VERIFY_FAIL_IF_NO_PEER_CERT: c_int = 2;
|
|||
#[cfg(not(ossl101))]
|
||||
pub const SSL_OP_TLSEXT_PADDING: c_ulong = 0x00000010;
|
||||
pub const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: c_ulong = 0x00000800;
|
||||
#[cfg(not(libressl))]
|
||||
pub const SSL_OP_ALL: c_ulong = 0x80000BFF;
|
||||
pub const SSL_OP_NO_QUERY_MTU: c_ulong = 0x00001000;
|
||||
pub const SSL_OP_COOKIE_EXCHANGE: c_ulong = 0x00002000;
|
||||
pub const SSL_OP_NO_TICKET: c_ulong = 0x00004000;
|
||||
#[cfg(not(libressl))]
|
||||
pub const SSL_OP_CISCO_ANYCONNECT: c_ulong = 0x00008000;
|
||||
pub const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION: c_ulong = 0x00010000;
|
||||
#[cfg(not(libressl))]
|
||||
pub const SSL_OP_NO_COMPRESSION: c_ulong = 0x00020000;
|
||||
#[cfg(not(libressl))]
|
||||
pub const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: c_ulong = 0x00040000;
|
||||
pub const SSL_OP_CIPHER_SERVER_PREFERENCE: c_ulong = 0x00400000;
|
||||
pub const SSL_OP_TLS_ROLLBACK_BUG: c_ulong = 0x00800000;
|
||||
#[cfg(not(libressl))]
|
||||
pub const SSL_OP_NO_SSLv3: c_ulong = 0x02000000;
|
||||
pub const SSL_OP_NO_TLSv1: c_ulong = 0x04000000;
|
||||
pub const SSL_OP_NO_TLSv1_2: c_ulong = 0x08000000;
|
||||
pub const SSL_OP_NO_TLSv1_1: c_ulong = 0x10000000;
|
||||
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub const SSL_OP_NO_DTLSv1: c_ulong = 0x04000000;
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub const SSL_OP_NO_DTLSv1_2: c_ulong = 0x08000000;
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub const SSL_OP_NO_SSL_MASK: c_ulong = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
||||
SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
|
||||
|
||||
pub const TLSEXT_NAMETYPE_host_name: c_int = 0;
|
||||
|
||||
pub const TLSEXT_STATUSTYPE_ocsp: c_int = 1;
|
||||
|
||||
pub const SSL_TLSEXT_ERR_OK: c_int = 0;
|
||||
pub const SSL_TLSEXT_ERR_ALERT_WARNING: c_int = 1;
|
||||
pub const SSL_TLSEXT_ERR_ALERT_FATAL: c_int = 2;
|
||||
|
|
@ -1173,15 +1274,15 @@ pub const X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: c_int = 45;
|
|||
pub const X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53;
|
||||
pub const X509_V_OK: c_int = 0;
|
||||
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT: c_uint = 0x1;
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub const X509_CHECK_FLAG_NO_WILDCARDS: c_uint = 0x2;
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub const X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS: c_uint = 0x4;
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub const X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS: c_uint = 0x8;
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub const X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS: c_uint = 0x10;
|
||||
|
||||
pub const GEN_OTHERNAME: c_int = 0;
|
||||
|
|
@ -1211,6 +1312,15 @@ pub unsafe fn BIO_set_retry_write(b: *mut BIO) {
|
|||
BIO_set_flags(b, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY)
|
||||
}
|
||||
|
||||
// EVP_PKEY_CTX_ctrl macros
|
||||
pub unsafe fn EVP_PKEY_CTX_set_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad: c_int) -> c_int {
|
||||
EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_RSA_PADDING, pad, ptr::null_mut())
|
||||
}
|
||||
|
||||
pub unsafe fn EVP_PKEY_CTX_get_rsa_padding(ctx: *mut EVP_PKEY_CTX, ppad: *mut c_int) -> c_int {
|
||||
EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_GET_RSA_PADDING, 0, ppad as *mut c_void)
|
||||
}
|
||||
|
||||
pub unsafe fn SSL_CTX_set_mode(ctx: *mut SSL_CTX, op: c_long) -> c_long {
|
||||
SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, op, ptr::null_mut())
|
||||
}
|
||||
|
|
@ -1227,12 +1337,20 @@ pub unsafe fn SSL_CTX_set_tmp_ecdh(ctx: *mut SSL_CTX, key: *mut EC_KEY) -> c_lon
|
|||
SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TMP_ECDH, 0, key as *mut c_void)
|
||||
}
|
||||
|
||||
pub unsafe fn SSL_set_tmp_dh(ssl: *mut SSL, dh: *mut DH) -> c_long {
|
||||
SSL_ctrl(ssl, SSL_CTRL_SET_TMP_DH, 0, dh as *mut c_void)
|
||||
}
|
||||
|
||||
pub unsafe fn SSL_set_tmp_ecdh(ssl: *mut SSL, key: *mut EC_KEY) -> c_long {
|
||||
SSL_ctrl(ssl, SSL_CTRL_SET_TMP_ECDH, 0, key as *mut c_void)
|
||||
}
|
||||
|
||||
pub unsafe fn SSL_CTX_add_extra_chain_cert(ctx: *mut SSL_CTX, x509: *mut X509) -> c_long {
|
||||
SSL_CTX_ctrl(ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0, x509 as *mut c_void)
|
||||
}
|
||||
|
||||
pub unsafe fn SSL_CTX_set_tlsext_servername_callback(ctx: *mut SSL_CTX,
|
||||
cb: Option<extern "C" fn()>)
|
||||
cb: Option<extern fn()>)
|
||||
-> c_long {
|
||||
SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, cb)
|
||||
}
|
||||
|
|
@ -1243,6 +1361,32 @@ pub unsafe fn SSL_set_tlsext_host_name(s: *mut SSL, name: *mut c_char) -> c_long
|
|||
name as *mut c_void)
|
||||
}
|
||||
|
||||
pub unsafe fn SSL_set_tlsext_status_type(s: *mut SSL, type_: c_int) -> c_long {
|
||||
SSL_ctrl(s, SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE, type_ as c_long, ptr::null_mut())
|
||||
}
|
||||
|
||||
pub unsafe fn SSL_CTX_set_tlsext_status_cb(ctx: *mut SSL_CTX,
|
||||
cb: Option<unsafe extern fn(*mut SSL, *mut c_void) -> c_int>)
|
||||
-> c_long {
|
||||
SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB, mem::transmute(cb))
|
||||
}
|
||||
|
||||
pub unsafe fn SSL_CTX_set_tlsext_status_arg(ctx: *mut SSL_CTX, arg: *mut c_void) -> c_long {
|
||||
SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG, 0, arg)
|
||||
}
|
||||
|
||||
pub unsafe fn SSL_CTX_get_extra_chain_certs(ctx: *mut SSL_CTX, chain: *mut *mut stack_st_X509) -> c_long {
|
||||
SSL_CTX_ctrl(ctx, SSL_CTRL_GET_EXTRA_CHAIN_CERTS, 0, chain as *mut c_void)
|
||||
}
|
||||
|
||||
pub unsafe fn SSL_get_tlsext_status_ocsp_resp(ssl: *mut SSL, resp: *mut *mut c_uchar) -> c_long {
|
||||
SSL_ctrl(ssl, SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP, 0, resp as *mut c_void)
|
||||
}
|
||||
|
||||
pub unsafe fn SSL_set_tlsext_status_ocsp_resp(ssl: *mut SSL, resp: *mut c_uchar, len: c_long) -> c_long {
|
||||
SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP, len, resp as *mut c_void)
|
||||
}
|
||||
|
||||
pub fn ERR_GET_LIB(l: c_ulong) -> c_int {
|
||||
((l >> 24) & 0x0FF) as c_int
|
||||
}
|
||||
|
|
@ -1256,11 +1400,19 @@ pub fn ERR_GET_REASON(l: c_ulong) -> c_int {
|
|||
}
|
||||
|
||||
extern {
|
||||
pub fn AES_set_encrypt_key(userKey: *const c_uchar, bits: c_int, key: *mut AES_KEY) -> c_int;
|
||||
pub fn AES_set_decrypt_key(userKey: *const c_uchar, bits: c_int, key: *mut AES_KEY) -> c_int;
|
||||
pub fn AES_ige_encrypt(in_: *const c_uchar, out: *mut c_uchar, length: size_t, key: *const AES_KEY, ivec: *mut c_uchar, enc: c_int);
|
||||
|
||||
pub fn ASN1_INTEGER_get(dest: *const ASN1_INTEGER) -> c_long;
|
||||
pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int;
|
||||
pub fn ASN1_GENERALIZEDTIME_free(tm: *mut ASN1_GENERALIZEDTIME);
|
||||
pub fn ASN1_GENERALIZEDTIME_print(b: *mut BIO, tm: *const ASN1_GENERALIZEDTIME) -> c_int;
|
||||
pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING;
|
||||
pub fn ASN1_TIME_free(tm: *mut ASN1_TIME);
|
||||
pub fn ASN1_TIME_print(b: *mut BIO, tm: *const ASN1_TIME) -> c_int;
|
||||
pub fn ASN1_INTEGER_free(x: *mut ASN1_INTEGER);
|
||||
pub fn ASN1_BIT_STRING_free(x: *mut ASN1_BIT_STRING);
|
||||
pub fn ASN1_OBJECT_free(x: *mut ASN1_OBJECT);
|
||||
|
||||
pub fn BIO_ctrl(b: *mut BIO, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long;
|
||||
pub fn BIO_free_all(b: *mut BIO);
|
||||
|
|
@ -1268,9 +1420,9 @@ extern {
|
|||
pub fn BIO_new_socket(sock: c_int, close_flag: c_int) -> *mut BIO;
|
||||
pub fn BIO_read(b: *mut BIO, buf: *mut c_void, len: c_int) -> c_int;
|
||||
pub fn BIO_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int;
|
||||
#[cfg(ossl101)]
|
||||
#[cfg(any(ossl101, libressl))]
|
||||
pub fn BIO_new_mem_buf(buf: *mut c_void, len: c_int) -> *mut BIO;
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub fn BIO_new_mem_buf(buf: *const c_void, len: c_int) -> *mut BIO;
|
||||
pub fn BIO_set_flags(b: *mut BIO, flags: c_int);
|
||||
pub fn BIO_clear_flags(b: *mut BIO, flags: c_int);
|
||||
|
|
@ -1339,20 +1491,54 @@ extern {
|
|||
|
||||
pub fn DH_new() -> *mut DH;
|
||||
pub fn DH_free(dh: *mut DH);
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub fn DH_get_1024_160() -> *mut DH;
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub fn DH_get_2048_224() -> *mut DH;
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub fn DH_get_2048_256() -> *mut DH;
|
||||
|
||||
pub fn EC_KEY_new() -> *mut EC_KEY;
|
||||
pub fn EC_KEY_new_by_curve_name(nid: c_int) -> *mut EC_KEY;
|
||||
pub fn EC_KEY_set_group(key: *mut EC_KEY, group: *const EC_GROUP) -> c_int;
|
||||
pub fn EC_KEY_get0_group(key: *const EC_KEY) -> *const EC_GROUP;
|
||||
pub fn EC_KEY_set_public_key(key: *mut EC_KEY, key: *const EC_POINT) -> c_int;
|
||||
pub fn EC_KEY_get0_public_key(key: *const EC_KEY) -> *const EC_POINT;
|
||||
pub fn EC_KEY_set_private_key(key: *mut EC_KEY, key: *const BIGNUM) -> c_int;
|
||||
pub fn EC_KEY_get0_private_key(key: *const EC_KEY) -> *const BIGNUM;
|
||||
pub fn EC_KEY_generate_key(key: *mut EC_KEY) -> c_int;
|
||||
pub fn EC_KEY_check_key(key: *const EC_KEY) -> c_int;
|
||||
pub fn EC_KEY_free(key: *mut EC_KEY);
|
||||
|
||||
pub fn EC_GF2m_simple_method() -> *const EC_METHOD;
|
||||
|
||||
pub fn EC_GROUP_new(meth: *const EC_METHOD) -> *mut EC_GROUP;
|
||||
pub fn EC_GROUP_new_curve_GFp(p: *const BIGNUM, a: *const BIGNUM, b: *const BIGNUM, ctx: *mut BN_CTX) -> *mut EC_GROUP;
|
||||
pub fn EC_GROUP_new_curve_GF2m(p: *const BIGNUM, a: *const BIGNUM, b: *const BIGNUM, ctx: *mut BN_CTX) -> *mut EC_GROUP;
|
||||
pub fn EC_GROUP_new_by_curve_name(nid: c_int) -> *mut EC_GROUP;
|
||||
pub fn EC_GROUP_get_curve_GFp(group: *const EC_GROUP, p: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int;
|
||||
pub fn EC_GROUP_get_curve_GF2m(group: *const EC_GROUP, p: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int;
|
||||
pub fn EC_GROUP_get_degree(group: *const EC_GROUP) -> c_int;
|
||||
pub fn EC_GROUP_get_order(group: *const EC_GROUP, order: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int;
|
||||
pub fn EC_GROUP_set_asn1_flag(key: *mut EC_GROUP, flag: c_int);
|
||||
|
||||
pub fn EC_GROUP_free(group: *mut EC_GROUP);
|
||||
|
||||
pub fn EC_POINT_new(group: *const EC_GROUP) -> *mut EC_POINT;
|
||||
pub fn EC_POINT_add(group: *const EC_GROUP, r: *mut EC_POINT, a: *const EC_POINT, b: *const EC_POINT, ctx: *mut BN_CTX) -> c_int;
|
||||
pub fn EC_POINT_mul(group: *const EC_GROUP, r: *mut EC_POINT, n: *const BIGNUM, q: *const EC_POINT, m: *const BIGNUM, ctx: *mut BN_CTX) -> c_int;
|
||||
pub fn EC_POINT_invert(group: *const EC_GROUP, r: *mut EC_POINT, ctx: *mut BN_CTX) -> c_int;
|
||||
pub fn EC_POINT_point2oct(group: *const EC_GROUP, p: *const EC_POINT, form: point_conversion_form_t, buf: *mut c_uchar, len: size_t, ctx: *mut BN_CTX) -> size_t;
|
||||
pub fn EC_POINT_oct2point(group: *const EC_GROUP, p: *mut EC_POINT, buf: *const c_uchar, len: size_t, ctx: *mut BN_CTX) -> c_int;
|
||||
pub fn EC_POINT_cmp(group: *const EC_GROUP, a: *const EC_POINT, b: *const EC_POINT, ctx: *mut BN_CTX) -> c_int;
|
||||
pub fn EC_POINT_free(point: *mut EC_POINT);
|
||||
|
||||
pub fn ERR_peek_last_error() -> c_ulong;
|
||||
pub fn ERR_get_error() -> c_ulong;
|
||||
pub fn ERR_lib_error_string(err: c_ulong) -> *const c_char;
|
||||
pub fn ERR_func_error_string(err: c_ulong) -> *const c_char;
|
||||
pub fn ERR_reason_error_string(err: c_ulong) -> *const c_char;
|
||||
pub fn ERR_clear_error();
|
||||
|
||||
pub fn EVP_md5() -> *const EVP_MD;
|
||||
pub fn EVP_ripemd160() -> *const EVP_MD;
|
||||
|
|
@ -1378,6 +1564,10 @@ extern {
|
|||
pub fn EVP_aes_256_cfb1() -> *const EVP_CIPHER;
|
||||
pub fn EVP_aes_256_cfb128() -> *const EVP_CIPHER;
|
||||
pub fn EVP_aes_256_cfb8() -> *const EVP_CIPHER;
|
||||
pub fn EVP_bf_cbc() -> *const EVP_CIPHER;
|
||||
pub fn EVP_bf_ecb() -> *const EVP_CIPHER;
|
||||
pub fn EVP_bf_cfb64() -> *const EVP_CIPHER;
|
||||
pub fn EVP_bf_ofb() -> *const EVP_CIPHER;
|
||||
pub fn EVP_rc4() -> *const EVP_CIPHER;
|
||||
|
||||
pub fn EVP_des_cbc() -> *const EVP_CIPHER;
|
||||
|
|
@ -1390,6 +1580,7 @@ extern {
|
|||
pub fn EVP_CIPHER_CTX_new() -> *mut EVP_CIPHER_CTX;
|
||||
pub fn EVP_CIPHER_CTX_set_padding(ctx: *mut EVP_CIPHER_CTX, padding: c_int) -> c_int;
|
||||
pub fn EVP_CIPHER_CTX_set_key_length(ctx: *mut EVP_CIPHER_CTX, keylen: c_int) -> c_int;
|
||||
pub fn EVP_CIPHER_CTX_ctrl(ctx: *mut EVP_CIPHER_CTX, type_: c_int, arg: c_int, ptr: *mut c_void) -> c_int;
|
||||
pub fn EVP_CIPHER_CTX_free(ctx: *mut EVP_CIPHER_CTX);
|
||||
|
||||
pub fn EVP_CipherInit(ctx: *mut EVP_CIPHER_CTX, evp: *const EVP_CIPHER,
|
||||
|
|
@ -1423,11 +1614,11 @@ extern {
|
|||
type_: *const EVP_MD,
|
||||
e: *mut ENGINE,
|
||||
pkey: *mut EVP_PKEY) -> c_int;
|
||||
#[cfg(ossl101)]
|
||||
#[cfg(any(ossl101, libressl))]
|
||||
pub fn EVP_DigestVerifyFinal(ctx: *mut EVP_MD_CTX,
|
||||
sigret: *mut c_uchar,
|
||||
siglen: size_t) -> c_int;
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub fn EVP_DigestVerifyFinal(ctx: *mut EVP_MD_CTX,
|
||||
sigret: *const c_uchar,
|
||||
siglen: size_t) -> c_int;
|
||||
|
|
@ -1440,14 +1631,47 @@ extern {
|
|||
pub fn EVP_PKEY_copy_parameters(to: *mut EVP_PKEY, from: *const EVP_PKEY) -> c_int;
|
||||
pub fn EVP_PKEY_get1_RSA(k: *mut EVP_PKEY) -> *mut RSA;
|
||||
pub fn EVP_PKEY_set1_RSA(k: *mut EVP_PKEY, r: *mut RSA) -> c_int;
|
||||
pub fn EVP_PKEY_get1_DSA(k: *mut EVP_PKEY) -> *mut DSA;
|
||||
pub fn EVP_PKEY_get1_DH(k: *mut EVP_PKEY) -> *mut DH;
|
||||
pub fn EVP_PKEY_get1_EC_KEY(k: *mut EVP_PKEY) -> *mut EC_KEY;
|
||||
pub fn EVP_PKEY_cmp(a: *const EVP_PKEY, b: *const EVP_PKEY) -> c_int;
|
||||
pub fn EVP_PKEY_new_mac_key(type_: c_int,
|
||||
e: *mut ENGINE,
|
||||
key: *const c_uchar,
|
||||
keylen: c_int) -> *mut EVP_PKEY;
|
||||
|
||||
|
||||
pub fn EVP_PKEY_CTX_ctrl(ctx: *mut EVP_PKEY_CTX, keytype: c_int, optype: c_int, cmd: c_int, p1: c_int, p2: *mut c_void) -> c_int;
|
||||
|
||||
pub fn HMAC_CTX_copy(dst: *mut HMAC_CTX, src: *mut HMAC_CTX) -> c_int;
|
||||
|
||||
pub fn OBJ_obj2nid(o: *const ASN1_OBJECT) -> c_int;
|
||||
pub fn OBJ_obj2txt(buf: *mut c_char, buf_len: c_int, a: *const ASN1_OBJECT, no_name: c_int) -> c_int;
|
||||
|
||||
pub fn OCSP_BASICRESP_new() -> *mut OCSP_BASICRESP;
|
||||
pub fn OCSP_BASICRESP_free(r: *mut OCSP_BASICRESP);
|
||||
pub fn OCSP_basic_verify(bs: *mut OCSP_BASICRESP, certs: *mut stack_st_X509, st: *mut X509_STORE, flags: c_ulong) -> c_int;
|
||||
pub fn OCSP_resp_find_status(bs: *mut OCSP_BASICRESP, id: *mut OCSP_CERTID, status: *mut c_int, reason: *mut c_int, revtime: *mut *mut ASN1_GENERALIZEDTIME, thisupd: *mut *mut ASN1_GENERALIZEDTIME, nextupd: *mut *mut ASN1_GENERALIZEDTIME) -> c_int;
|
||||
pub fn OCSP_check_validity(thisupd: *mut ASN1_GENERALIZEDTIME, nextupd: *mut ASN1_GENERALIZEDTIME, sec: c_long, maxsec: c_long) -> c_int;
|
||||
|
||||
pub fn OCSP_CERTID_free(id: *mut OCSP_CERTID);
|
||||
|
||||
pub fn OCSP_RESPONSE_new() -> *mut OCSP_RESPONSE;
|
||||
pub fn OCSP_RESPONSE_free(r: *mut OCSP_RESPONSE);
|
||||
pub fn i2d_OCSP_RESPONSE(a: *mut OCSP_RESPONSE, pp: *mut *mut c_uchar) -> c_int;
|
||||
pub fn d2i_OCSP_RESPONSE(a: *mut *mut OCSP_RESPONSE, pp: *mut *const c_uchar, length: c_long) -> *mut OCSP_RESPONSE;
|
||||
pub fn OCSP_response_create(status: c_int, bs: *mut OCSP_BASICRESP) -> *mut OCSP_RESPONSE;
|
||||
pub fn OCSP_response_status(resp: *mut OCSP_RESPONSE) -> c_int;
|
||||
pub fn OCSP_response_get1_basic(resp: *mut OCSP_RESPONSE) -> *mut OCSP_BASICRESP;
|
||||
|
||||
pub fn OCSP_REQUEST_new() -> *mut OCSP_REQUEST;
|
||||
pub fn OCSP_REQUEST_free(r: *mut OCSP_REQUEST);
|
||||
pub fn i2d_OCSP_REQUEST(a: *mut OCSP_REQUEST, pp: *mut *mut c_uchar) -> c_int;
|
||||
pub fn d2i_OCSP_REQUEST(a: *mut *mut OCSP_REQUEST, pp: *mut *const c_uchar, length: c_long) -> *mut OCSP_REQUEST;
|
||||
pub fn OCSP_request_add0_id(r: *mut OCSP_REQUEST, id: *mut OCSP_CERTID) -> *mut OCSP_ONEREQ;
|
||||
|
||||
pub fn OCSP_ONEREQ_free(r: *mut OCSP_ONEREQ);
|
||||
|
||||
pub fn PEM_read_bio_DHparams(bio: *mut BIO, out: *mut *mut DH, callback: Option<PasswordCallback>,
|
||||
user_data: *mut c_void) -> *mut DH;
|
||||
pub fn PEM_read_bio_X509(bio: *mut BIO, out: *mut *mut X509, callback: Option<PasswordCallback>,
|
||||
|
|
@ -1467,6 +1691,10 @@ extern {
|
|||
kstr: *mut c_uchar, klen: c_int,
|
||||
callback: Option<PasswordCallback>,
|
||||
user_data: *mut c_void) -> c_int;
|
||||
pub fn PEM_write_bio_PKCS8PrivateKey(bio: *mut BIO, pkey: *mut EVP_PKEY, cipher: *const EVP_CIPHER,
|
||||
kstr: *mut c_char, klen: c_int,
|
||||
callback: Option<PasswordCallback>,
|
||||
user_data: *mut c_void) -> c_int;
|
||||
pub fn PEM_write_bio_PUBKEY(bp: *mut BIO, x: *mut EVP_PKEY) -> c_int;
|
||||
pub fn PEM_write_bio_RSAPrivateKey(bp: *mut BIO, rsa: *mut RSA, cipher: *const EVP_CIPHER,
|
||||
kstr: *mut c_uchar, klen: c_int,
|
||||
|
|
@ -1484,11 +1712,19 @@ extern {
|
|||
user_data: *mut c_void) -> c_int;
|
||||
pub fn PEM_write_bio_DSA_PUBKEY(bp: *mut BIO, dsa: *mut DSA) -> c_int;
|
||||
|
||||
|
||||
|
||||
pub fn PEM_write_bio_X509(bio: *mut BIO, x509: *mut X509) -> c_int;
|
||||
pub fn PEM_write_bio_X509_REQ(bio: *mut BIO, x509: *mut X509_REQ) -> c_int;
|
||||
|
||||
pub fn PEM_write_bio_ECPrivateKey(bio: *mut BIO,
|
||||
key: *mut EC_KEY,
|
||||
cipher: *const EVP_CIPHER,
|
||||
kstr: *mut c_uchar,
|
||||
klen: c_int,
|
||||
callback: Option<PasswordCallback>,
|
||||
user_data: *mut c_void)
|
||||
-> c_int;
|
||||
pub fn PEM_read_bio_ECPrivateKey(bio: *mut BIO, key: *mut *mut EC_KEY, callback: Option<PasswordCallback>, user_data: *mut c_void) -> *mut EC_KEY;
|
||||
|
||||
pub fn PKCS5_PBKDF2_HMAC_SHA1(pass: *const c_char, passlen: c_int,
|
||||
salt: *const u8, saltlen: c_int,
|
||||
iter: c_int, keylen: c_int,
|
||||
|
|
@ -1547,8 +1783,10 @@ extern {
|
|||
pub fn SSL_get_ex_data_X509_STORE_CTX_idx() -> c_int;
|
||||
pub fn SSL_get_SSL_CTX(ssl: *const SSL) -> *mut SSL_CTX;
|
||||
pub fn SSL_set_SSL_CTX(ssl: *mut SSL, ctx: *mut SSL_CTX) -> *mut SSL_CTX;
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_COMP"))]
|
||||
#[cfg(not(any(osslconf = "OPENSSL_NO_COMP", libressl)))]
|
||||
pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const COMP_METHOD;
|
||||
#[cfg(libressl)]
|
||||
pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const libc::c_void;
|
||||
pub fn SSL_get_peer_certificate(ssl: *const SSL) -> *mut X509;
|
||||
pub fn SSL_get_ssl_method(ssl: *mut SSL) -> *const SSL_METHOD;
|
||||
pub fn SSL_get_version(ssl: *const SSL) -> *const c_char;
|
||||
|
|
@ -1561,19 +1799,26 @@ extern {
|
|||
pub fn SSL_get_ex_data(ssl: *const SSL, idx: c_int) -> *mut c_void;
|
||||
pub fn SSL_get_servername(ssl: *const SSL, name_type: c_int) -> *const c_char;
|
||||
pub fn SSL_get_current_cipher(ssl: *const SSL) -> *const SSL_CIPHER;
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub fn SSL_get0_param(ssl: *mut SSL) -> *mut X509_VERIFY_PARAM;
|
||||
pub fn SSL_get_verify_result(ssl: *const SSL) -> c_long;
|
||||
pub fn SSL_shutdown(ssl: *mut SSL) -> c_int;
|
||||
pub fn SSL_get_certificate(ssl: *const SSL) -> *mut X509;
|
||||
#[cfg(ossl101)]
|
||||
#[cfg(any(ossl101, libressl))]
|
||||
pub fn SSL_get_privatekey(ssl: *mut SSL) -> *mut EVP_PKEY;
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub fn SSL_get_privatekey(ssl: *const SSL) -> *mut EVP_PKEY;
|
||||
pub fn SSL_load_client_CA_file(file: *const c_char) -> *mut stack_st_X509_NAME;
|
||||
pub fn SSL_set_tmp_dh_callback(ctx: *mut SSL,
|
||||
dh: unsafe extern fn(ssl: *mut SSL,
|
||||
is_export: c_int,
|
||||
keylength: c_int)
|
||||
-> *mut DH);
|
||||
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_COMP"))]
|
||||
#[cfg(not(any(osslconf = "OPENSSL_NO_COMP", libressl)))]
|
||||
pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char;
|
||||
#[cfg(libressl)]
|
||||
pub fn SSL_COMP_get_name(comp: *const libc::c_void) -> *const c_char;
|
||||
|
||||
pub fn SSL_CIPHER_get_name(cipher: *const SSL_CIPHER) -> *const c_char;
|
||||
pub fn SSL_CIPHER_get_bits(cipher: *const SSL_CIPHER, alg_bits: *mut c_int) -> c_int;
|
||||
|
|
@ -1582,7 +1827,7 @@ extern {
|
|||
pub fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX;
|
||||
pub fn SSL_CTX_free(ctx: *mut SSL_CTX);
|
||||
pub fn SSL_CTX_ctrl(ctx: *mut SSL_CTX, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long;
|
||||
pub fn SSL_CTX_callback_ctrl(ctx: *mut SSL_CTX, cmd: c_int, fp: Option<extern "C" fn()>) -> c_long;
|
||||
pub fn SSL_CTX_callback_ctrl(ctx: *mut SSL_CTX, cmd: c_int, fp: Option<extern fn()>) -> c_long;
|
||||
pub fn SSL_CTX_set_verify(ctx: *mut SSL_CTX, mode: c_int,
|
||||
verify_callback: Option<extern fn(c_int, *mut X509_STORE_CTX) -> c_int>);
|
||||
pub fn SSL_CTX_set_verify_depth(ctx: *mut SSL_CTX, depth: c_int);
|
||||
|
|
@ -1602,10 +1847,16 @@ extern {
|
|||
pub fn SSL_CTX_use_PrivateKey(ctx: *mut SSL_CTX, key: *mut EVP_PKEY) -> c_int;
|
||||
pub fn SSL_CTX_check_private_key(ctx: *const SSL_CTX) -> c_int;
|
||||
pub fn SSL_CTX_set_client_CA_list(ctx: *mut SSL_CTX, list: *mut stack_st_X509_NAME);
|
||||
pub fn SSL_CTX_get_cert_store(ctx: *const SSL_CTX) -> *mut X509_STORE;
|
||||
pub fn SSL_CTX_set_tmp_dh_callback(ctx: *mut SSL_CTX,
|
||||
dh: unsafe extern fn(ssl: *mut SSL,
|
||||
is_export: c_int,
|
||||
keylength: c_int)
|
||||
-> *mut DH);
|
||||
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub fn SSL_CTX_get0_certificate(ctx: *const SSL_CTX) -> *mut X509;
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub fn SSL_CTX_get0_privatekey(ctx: *const SSL_CTX) -> *mut EVP_PKEY;
|
||||
|
||||
pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int;
|
||||
|
|
@ -1628,6 +1879,12 @@ extern {
|
|||
inbuf: *const c_uchar, inlen: c_uint,
|
||||
client: *const c_uchar, client_len: c_uint) -> c_int;
|
||||
pub fn SSL_get0_next_proto_negotiated(s: *const SSL, data: *mut *const c_uchar, len: *mut c_uint);
|
||||
pub fn SSL_get_session(s: *const SSL) -> *mut SSL_SESSION;
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub fn SSL_is_server(s: *mut SSL) -> c_int;
|
||||
|
||||
pub fn SSL_SESSION_free(s: *mut SSL_SESSION);
|
||||
pub fn SSL_SESSION_get_id(s: *const SSL_SESSION, len: *mut c_uint) -> *const c_uchar;
|
||||
|
||||
#[cfg(not(ossl101))]
|
||||
pub fn SSL_CTX_set_alpn_protos(s: *mut SSL_CTX, data: *const c_uchar, len: c_uint) -> c_int;
|
||||
|
|
@ -1663,6 +1920,10 @@ extern {
|
|||
pub fn X509_get_pubkey(x: *mut X509) -> *mut EVP_PKEY;
|
||||
pub fn X509_to_X509_REQ(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> *mut X509_REQ;
|
||||
pub fn X509_verify_cert_error_string(n: c_long) -> *const c_char;
|
||||
pub fn X509_get1_ocsp(x: *mut X509) -> *mut stack_st_OPENSSL_STRING;
|
||||
pub fn X509_check_issued(issuer: *mut X509, subject: *mut X509) -> c_int;
|
||||
|
||||
pub fn X509_ALGOR_free(x: *mut X509_ALGOR);
|
||||
|
||||
pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION);
|
||||
|
||||
|
|
@ -1676,6 +1937,13 @@ extern {
|
|||
pub fn ASN1_STRING_free(x: *mut ASN1_STRING);
|
||||
pub fn ASN1_STRING_length(x: *const ASN1_STRING) -> c_int;
|
||||
|
||||
pub fn ASN1_INTEGER_free(x: *mut ASN1_INTEGER);
|
||||
|
||||
pub fn X509_STORE_new() -> *mut X509_STORE;
|
||||
pub fn X509_STORE_free(store: *mut X509_STORE);
|
||||
pub fn X509_STORE_add_cert(store: *mut X509_STORE, x: *mut X509) -> c_int;
|
||||
pub fn X509_STORE_set_default_paths(store: *mut X509_STORE) -> c_int;
|
||||
|
||||
pub fn X509_STORE_CTX_free(ctx: *mut X509_STORE_CTX);
|
||||
pub fn X509_STORE_CTX_get_current_cert(ctx: *mut X509_STORE_CTX) -> *mut X509;
|
||||
pub fn X509_STORE_CTX_get_error(ctx: *mut X509_STORE_CTX) -> c_int;
|
||||
|
|
@ -1694,24 +1962,43 @@ extern {
|
|||
|
||||
#[cfg(not(ossl101))]
|
||||
pub fn X509_VERIFY_PARAM_free(param: *mut X509_VERIFY_PARAM);
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub fn X509_VERIFY_PARAM_set_hostflags(param: *mut X509_VERIFY_PARAM, flags: c_uint);
|
||||
#[cfg(not(ossl101))]
|
||||
#[cfg(not(any(ossl101, libressl)))]
|
||||
pub fn X509_VERIFY_PARAM_set1_host(param: *mut X509_VERIFY_PARAM,
|
||||
name: *const c_char,
|
||||
namelen: size_t) -> c_int;
|
||||
|
||||
pub fn d2i_DHparams(k: *mut *mut DH, pp: *mut *const c_uchar, length: c_long) -> *mut DH;
|
||||
pub fn i2d_DHparams(dh: *const DH, pp: *mut *mut c_uchar) -> c_int;
|
||||
|
||||
pub fn d2i_DSAPublicKey(a: *mut *mut DSA, pp: *mut *const c_uchar, length: c_long) -> *mut DSA;
|
||||
pub fn i2d_DSAPublicKey(a: *const DSA, pp: *mut *mut c_uchar) -> c_int;
|
||||
pub fn d2i_DSAPrivateKey(a: *mut *mut DSA, pp: *mut *const c_uchar, length: c_long) -> *mut DSA;
|
||||
pub fn i2d_DSAPrivateKey(a: *const DSA, pp: *mut *mut c_uchar) -> c_int;
|
||||
|
||||
pub fn d2i_ECPrivateKey(k: *mut *mut EC_KEY, pp: *mut *const c_uchar, length: c_long) -> *mut EC_KEY;
|
||||
pub fn i2d_ECPrivateKey(ec_key: *mut EC_KEY, pp: *mut *mut c_uchar) -> c_int;
|
||||
|
||||
pub fn d2i_X509(a: *mut *mut X509, pp: *mut *const c_uchar, length: c_long) -> *mut X509;
|
||||
pub fn d2i_X509_REQ(a: *mut *mut X509_REQ, pp: *mut *const c_uchar, length: c_long) -> *mut X509_REQ;
|
||||
pub fn i2d_X509_bio(b: *mut BIO, x: *mut X509) -> c_int;
|
||||
pub fn i2d_X509(x: *mut X509, buf: *mut *mut u8) -> c_int;
|
||||
pub fn i2d_X509_REQ_bio(b: *mut BIO, x: *mut X509_REQ) -> c_int;
|
||||
pub fn i2d_X509_REQ(x: *mut X509_REQ, buf: *mut *mut u8) -> c_int;
|
||||
|
||||
pub fn i2d_PUBKEY_bio(b: *mut BIO, x: *mut EVP_PKEY) -> c_int;
|
||||
pub fn i2d_PrivateKey_bio(b: *mut BIO, x: *mut EVP_PKEY) -> c_int;
|
||||
pub fn i2d_PUBKEY(k: *mut EVP_PKEY, buf: *mut *mut u8) -> c_int;
|
||||
pub fn i2d_PrivateKey(k: *mut EVP_PKEY, buf: *mut *mut u8) -> c_int;
|
||||
|
||||
pub fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *mut *mut u8) -> c_int;
|
||||
pub fn d2i_RSA_PUBKEY(k: *mut *mut RSA, buf: *mut *const u8, len: c_long) -> *mut RSA;
|
||||
pub fn i2d_RSAPrivateKey(k: *const RSA, buf: *mut *mut u8) -> c_int;
|
||||
pub fn d2i_RSAPrivateKey(k: *mut *mut RSA, buf: *mut *const u8, len: c_long) -> *mut RSA;
|
||||
|
||||
pub fn i2d_PKCS12_bio(b: *mut BIO, a: *mut PKCS12) -> c_int;
|
||||
pub fn i2d_PKCS12(a: *mut PKCS12, buf: *mut *mut u8) -> c_int;
|
||||
pub fn d2i_PKCS12(a: *mut *mut PKCS12, pp: *mut *const u8, length: c_long) -> *mut PKCS12;
|
||||
pub fn PKCS12_parse(p12: *mut PKCS12,
|
||||
pass: *const c_char,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,734 @@
|
|||
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};
|
||||
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_NAME {
|
||||
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_st_SSL_CIPHER {
|
||||
pub stack: _STACK,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct stack_st_OPENSSL_STRING {
|
||||
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 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,
|
||||
}
|
||||
|
||||
#[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,
|
||||
pub sig_alg: *mut ::X509_ALGOR,
|
||||
pub signature: *mut ::ASN1_BIT_STRING,
|
||||
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_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 X509_ALGOR {
|
||||
pub algorithm: *mut ::ASN1_OBJECT,
|
||||
parameter: *mut c_void,
|
||||
}
|
||||
|
||||
#[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 X509_REQ_INFO {
|
||||
pub enc: ASN1_ENCODING,
|
||||
pub version: *mut ::ASN1_INTEGER,
|
||||
pub subject: *mut ::X509_NAME,
|
||||
pubkey: *mut c_void,
|
||||
pub attributes: *mut stack_st_X509_ATTRIBUTE
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct X509_REQ {
|
||||
pub req_info: *mut X509_REQ_INFO,
|
||||
sig_alg: *mut c_void,
|
||||
signature: *mut c_void,
|
||||
references: c_int
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SSL {
|
||||
version: c_int,
|
||||
type_: c_int,
|
||||
method: *const ::SSL_METHOD,
|
||||
rbio: *mut c_void,
|
||||
wbio: *mut c_void,
|
||||
bbio: *mut c_void,
|
||||
rwstate: c_int,
|
||||
in_handshake: c_int,
|
||||
handshake_func: Option<unsafe extern fn(*mut SSL) -> c_int>,
|
||||
pub server: c_int,
|
||||
new_session: c_int,
|
||||
quiet_shutdown: c_int,
|
||||
shutdown: c_int,
|
||||
state: c_int,
|
||||
rstate: c_int,
|
||||
init_buf: *mut c_void,
|
||||
init_msg: *mut c_void,
|
||||
init_num: c_int,
|
||||
init_off: c_int,
|
||||
packet: *mut c_uchar,
|
||||
packet_length: c_uint,
|
||||
s3: *mut c_void,
|
||||
d1: *mut c_void,
|
||||
read_ahead: c_int,
|
||||
msg_callback: Option<unsafe extern fn(c_int, c_int, c_int, *const c_void, size_t, *mut SSL, *mut c_void)>,
|
||||
msg_callback_arg: *mut c_void,
|
||||
hit: c_int,
|
||||
param: *mut c_void,
|
||||
cipher_list: *mut stack_st_SSL_CIPHER,
|
||||
cipher_list_by_id: *mut stack_st_SSL_CIPHER,
|
||||
mac_flags: c_int,
|
||||
aead_read_ctx: *mut c_void,
|
||||
enc_read_ctx: *mut ::EVP_CIPHER_CTX,
|
||||
read_hash: *mut ::EVP_MD_CTX,
|
||||
aead_write_ctx: *mut c_void,
|
||||
enc_write_ctx: *mut ::EVP_CIPHER_CTX,
|
||||
write_hash: *mut ::EVP_MD_CTX,
|
||||
cert: *mut c_void,
|
||||
sid_ctx_length: c_uint,
|
||||
sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize],
|
||||
session: *mut ::SSL_SESSION,
|
||||
generate_session_id: ::GEN_SESSION_CB,
|
||||
verify_mode: c_int,
|
||||
verify_callback: Option<unsafe extern fn(c_int, *mut ::X509_STORE_CTX) -> c_int>,
|
||||
info_callback: Option<unsafe extern fn(*mut SSL, c_int, c_int)>,
|
||||
error: c_int,
|
||||
error_code: c_int,
|
||||
ctx: *mut ::SSL_CTX,
|
||||
debug: c_int,
|
||||
verify_result: c_long,
|
||||
ex_data: ::CRYPTO_EX_DATA,
|
||||
client_CA: *mut stack_st_X509_NAME,
|
||||
references: c_int,
|
||||
options: c_ulong,
|
||||
mode: c_ulong,
|
||||
max_cert_list: c_long,
|
||||
first_packet: c_int,
|
||||
client_version: c_int,
|
||||
max_send_fragment: c_uint,
|
||||
tlsext_debug_cb: Option<unsafe extern fn(*mut SSL, c_int, c_int, *mut c_uchar, c_int, *mut c_void)>,
|
||||
tlsext_debug_arg: *mut c_void,
|
||||
tlsext_hostname: *mut c_char,
|
||||
servername_done: c_int,
|
||||
tlsext_status_type: c_int,
|
||||
tlsext_status_expected: c_int,
|
||||
tlsext_ocsp_ids: *mut c_void,
|
||||
tlsext_ocsp_exts: *mut c_void,
|
||||
tlsext_ocsp_resp: *mut c_uchar,
|
||||
tlsext_ocsp_resplen: c_int,
|
||||
tlsext_ticket_expected: c_int,
|
||||
tlsext_ecpointformatlist_length: size_t,
|
||||
tlsext_ecpointformatlist: *mut c_uchar,
|
||||
tlsext_ellipticcurvelist_length: size_t,
|
||||
tlsext_ellipticcurvelist: *mut c_uchar,
|
||||
tlsext_session_ticket: *mut c_void,
|
||||
tlsext_session_ticket_ext_cb: ::tls_session_ticket_ext_cb_fn,
|
||||
tls_session_ticket_ext_cb_arg: *mut c_void,
|
||||
tls_session_secret_cb: ::tls_session_secret_cb_fn,
|
||||
tls_session_secret_cb_arg: *mut c_void,
|
||||
initial_ctx: *mut ::SSL_CTX,
|
||||
next_proto_negotiated: *mut c_uchar,
|
||||
next_proto_negotiated_len: c_uchar,
|
||||
srtp_profiles: *mut c_void,
|
||||
srtp_profile: *mut c_void,
|
||||
tlsext_heartbeat: c_uint,
|
||||
tlsext_hb_pending: c_uint,
|
||||
tlsext_hb_seq: c_uint,
|
||||
alpn_client_proto_list: *mut c_uchar,
|
||||
alpn_client_proto_list_len: c_uint,
|
||||
renegotiate: c_int,
|
||||
}
|
||||
|
||||
#[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,
|
||||
|
||||
tlsext_servername_callback: *mut c_void,
|
||||
tlsect_servername_arg: *mut c_void,
|
||||
tlsext_tick_key_name: [c_uchar; 16],
|
||||
tlsext_tick_hmac_key: [c_uchar; 16],
|
||||
tlsext_tick_aes_key: [c_uchar; 16],
|
||||
tlsext_ticket_key_cb: *mut c_void,
|
||||
tlsext_status_cb: *mut c_void,
|
||||
tlsext_status_arg: *mut c_void,
|
||||
tlsext_opaque_prf_input_callback: *mut c_void,
|
||||
tlsext_opaque_prf_input_callback_arg: *mut c_void,
|
||||
|
||||
next_protos_advertised_cb: *mut c_void,
|
||||
next_protos_advertised_cb_arg: *mut c_void,
|
||||
next_proto_select_cb: *mut c_void,
|
||||
next_proto_select_cb_arg: *mut c_void,
|
||||
|
||||
srtp_profiles: *mut c_void,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SSL_SESSION {
|
||||
ssl_version: c_int,
|
||||
pub master_key_length: c_int,
|
||||
pub master_key: [c_uchar; 48],
|
||||
session_id_length: c_uint,
|
||||
session_id: [c_uchar; SSL_MAX_SSL_SESSION_ID_LENGTH as usize],
|
||||
sid_ctx_length: c_uint,
|
||||
sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize],
|
||||
not_resumable: c_int,
|
||||
sess_cert: *mut c_void,
|
||||
peer: *mut X509,
|
||||
verify_result: c_long,
|
||||
timeout: c_long,
|
||||
time: time_t,
|
||||
references: c_int,
|
||||
cipher: *const c_void,
|
||||
cipher_id: c_ulong,
|
||||
ciphers: *mut c_void,
|
||||
ex_data: ::CRYPTO_EX_DATA,
|
||||
prev: *mut c_void,
|
||||
next: *mut c_void,
|
||||
tlsext_hostname: *mut c_char,
|
||||
tlsext_ecpointformatlist_length: size_t,
|
||||
tlsext_ecpointformatlist: *mut u8,
|
||||
tlsext_ellipticcurvelist_length: size_t,
|
||||
tlsext_ellipticcurvelist: *mut u16,
|
||||
tlsext_tick: *mut c_uchar,
|
||||
tlsext_ticklen: size_t,
|
||||
tlsext_tick_lifetime_hint: c_long,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
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,
|
||||
}
|
||||
|
||||
pub enum X509_VERIFY_PARAM_ID {}
|
||||
pub enum PKCS12 {}
|
||||
|
||||
pub const SSL_CTRL_OPTIONS: c_int = 32;
|
||||
pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77;
|
||||
pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94;
|
||||
|
||||
pub const SSL_OP_ALL: c_ulong = 0x80000014;
|
||||
pub const SSL_OP_CISCO_ANYCONNECT: c_ulong = 0x0;
|
||||
pub const SSL_OP_NO_COMPRESSION: c_ulong = 0x0;
|
||||
pub const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: c_ulong = 0x0;
|
||||
pub const SSL_OP_NO_SSLv3: c_ulong = 0x0;
|
||||
pub const SSL_OP_MICROSOFT_SESS_ID_BUG: c_ulong = 0x0;
|
||||
pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: c_ulong = 0x0;
|
||||
pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: c_ulong = 0x0;
|
||||
pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: c_ulong = 0x0;
|
||||
pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: c_ulong = 0x0;
|
||||
pub const SSL_OP_TLS_D5_BUG: c_ulong = 0x0;
|
||||
pub const SSL_OP_TLS_BLOCK_PADDING_BUG: c_ulong = 0x0;
|
||||
pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x00080000;
|
||||
pub const SSL_OP_SINGLE_DH_USE: c_ulong = 0x00100000;
|
||||
pub const SSL_OP_NO_SSLv2: c_ulong = 0x0;
|
||||
|
||||
pub const SSL_MAX_SSL_SESSION_ID_LENGTH: c_int = 32;
|
||||
pub const SSL_MAX_SID_CTX_LENGTH: c_int = 32;
|
||||
pub const SSL_MAX_MASTER_KEY_LENGTH: c_int = 48;
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
pub unsafe fn SSL_set_ecdh_auto(ssl: *mut ::SSL, onoff: c_int) -> c_int {
|
||||
::SSL_ctrl(ssl, 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 get_rfc2409_prime_768(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn get_rfc2409_prime_1024(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn get_rfc3526_prime_1536(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn get_rfc3526_prime_2048(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn get_rfc3526_prime_3072(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn get_rfc3526_prime_4096(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn get_rfc3526_prime_6144(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn get_rfc3526_prime_8192(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
|
||||
pub fn CRYPTO_malloc(num: c_int, file: *const c_char, line: c_int) -> *mut c_void;
|
||||
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 OCSP_cert_to_id(dgst: *const ::EVP_MD, subject: *mut ::X509, issuer: *mut ::X509) -> *mut ::OCSP_CERTID;
|
||||
|
||||
pub fn PKCS12_create(pass: *mut c_char,
|
||||
friendly_name: *mut c_char,
|
||||
pkey: *mut EVP_PKEY,
|
||||
cert: *mut X509,
|
||||
ca: *mut stack_st_X509,
|
||||
nid_key: c_int,
|
||||
nid_cert: c_int,
|
||||
iter: c_int,
|
||||
mac_iter: c_int,
|
||||
keytype: c_int) -> *mut PKCS12;
|
||||
|
||||
pub fn SSL_library_init() -> c_int;
|
||||
pub fn SSL_load_error_strings();
|
||||
pub fn OPENSSL_add_all_algorithms_noconf();
|
||||
pub fn HMAC_CTX_init(ctx: *mut ::HMAC_CTX);
|
||||
pub fn HMAC_CTX_cleanup(ctx: *mut ::HMAC_CTX);
|
||||
pub fn 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;
|
||||
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_set_tmp_ecdh_callback(ssl: *mut ::SSL,
|
||||
ecdh: unsafe extern fn(ssl: *mut ::SSL,
|
||||
is_export: c_int,
|
||||
keylength: c_int)
|
||||
-> *mut ::EC_KEY);
|
||||
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 SSL_CTX_set_tmp_ecdh_callback(ctx: *mut ::SSL_CTX,
|
||||
ecdh: unsafe extern fn(ssl: *mut ::SSL,
|
||||
is_export: c_int,
|
||||
keylength: c_int)
|
||||
-> *mut ::EC_KEY);
|
||||
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 EVP_PKEY_bits(key: *mut EVP_PKEY) -> c_int;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -41,6 +41,16 @@ pub struct stack_st_void {
|
|||
pub stack: _STACK,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct stack_st_SSL_CIPHER {
|
||||
pub stack: _STACK,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct stack_st_OPENSSL_STRING {
|
||||
pub stack: _STACK,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct _STACK {
|
||||
pub num: c_int,
|
||||
|
|
@ -240,8 +250,8 @@ pub struct DH {
|
|||
#[repr(C)]
|
||||
pub struct X509 {
|
||||
pub cert_info: *mut X509_CINF,
|
||||
sig_alg: *mut c_void,
|
||||
signature: *mut c_void,
|
||||
pub sig_alg: *mut ::X509_ALGOR,
|
||||
pub signature: *mut ::ASN1_BIT_STRING,
|
||||
pub valid: c_int,
|
||||
pub references: c_int,
|
||||
pub name: *mut c_char,
|
||||
|
|
@ -282,6 +292,12 @@ pub struct X509_CINF {
|
|||
enc: ASN1_ENCODING,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct X509_ALGOR {
|
||||
pub algorithm: *mut ::ASN1_OBJECT,
|
||||
parameter: *mut c_void,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ASN1_ENCODING {
|
||||
pub enc: *mut c_uchar,
|
||||
|
|
@ -295,6 +311,160 @@ pub struct X509_VAL {
|
|||
pub notAfter: *mut ::ASN1_TIME,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct X509_REQ_INFO {
|
||||
pub enc: ASN1_ENCODING,
|
||||
pub version: *mut ::ASN1_INTEGER,
|
||||
pub subject: *mut ::X509_NAME,
|
||||
pubkey: *mut c_void,
|
||||
pub attributes: *mut stack_st_X509_ATTRIBUTE
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct X509_REQ {
|
||||
pub req_info: *mut X509_REQ_INFO,
|
||||
sig_alg: *mut c_void,
|
||||
signature: *mut c_void,
|
||||
references: c_int
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SSL {
|
||||
version: c_int,
|
||||
type_: c_int,
|
||||
method: *const ::SSL_METHOD,
|
||||
rbio: *mut c_void,
|
||||
wbio: *mut c_void,
|
||||
bbio: *mut c_void,
|
||||
rwstate: c_int,
|
||||
in_handshake: c_int,
|
||||
handshake_func: Option<unsafe extern fn(*mut SSL) -> c_int>,
|
||||
pub server: c_int,
|
||||
new_session: c_int,
|
||||
quiet_session: c_int,
|
||||
shutdown: c_int,
|
||||
state: c_int,
|
||||
rstate: c_int,
|
||||
init_buf: *mut c_void,
|
||||
init_msg: *mut c_void,
|
||||
init_num: c_int,
|
||||
init_off: c_int,
|
||||
packet: *mut c_uchar,
|
||||
packet_length: c_uint,
|
||||
s2: *mut c_void,
|
||||
s3: *mut c_void,
|
||||
d1: *mut c_void,
|
||||
read_ahead: c_int,
|
||||
msg_callback: Option<unsafe extern fn(c_int, c_int, c_int, *const c_void, size_t, *mut SSL, *mut c_void)>,
|
||||
msg_callback_arg: *mut c_void,
|
||||
hit: c_int,
|
||||
param: *mut c_void,
|
||||
cipher_list: *mut stack_st_SSL_CIPHER,
|
||||
cipher_list_by_id: *mut stack_st_SSL_CIPHER,
|
||||
mac_flags: c_int,
|
||||
enc_read_ctx: *mut ::EVP_CIPHER_CTX,
|
||||
read_hash: *mut ::EVP_MD_CTX,
|
||||
expand: *mut c_void,
|
||||
enc_write_ctx: *mut ::EVP_CIPHER_CTX,
|
||||
write_hash: *mut ::EVP_MD_CTX,
|
||||
compress: *mut c_void,
|
||||
cert: *mut c_void,
|
||||
sid_ctx_length: c_uint,
|
||||
sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize],
|
||||
session: *mut ::SSL_SESSION,
|
||||
generate_session_id: ::GEN_SESSION_CB,
|
||||
verify_mode: c_int,
|
||||
verify_callback: Option<unsafe extern fn(c_int, *mut ::X509_STORE_CTX) -> c_int>,
|
||||
info_callback: Option<unsafe extern fn(*mut SSL, c_int, c_int)>,
|
||||
error: c_int,
|
||||
error_code: c_int,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_KRB5"))]
|
||||
kssl_ctx: *mut c_void,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
|
||||
psk_client_callback: Option<unsafe extern fn(*mut SSL, *const c_char, *mut c_char, c_uint, *mut c_uchar, c_uint) -> c_uint>,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
|
||||
psk_server_callback: Option<unsafe extern fn(*mut SSL, *const c_char, *mut c_uchar, c_uint) -> c_uint>,
|
||||
ctx: *mut ::SSL_CTX,
|
||||
debug: c_int,
|
||||
verify_result: c_long,
|
||||
ex_data: ::CRYPTO_EX_DATA,
|
||||
client_CA: *mut stack_st_X509_NAME,
|
||||
references: c_int,
|
||||
options: c_ulong,
|
||||
mode: c_ulong,
|
||||
max_cert_list: c_long,
|
||||
first_packet: c_int,
|
||||
client_version: c_int,
|
||||
max_send_fragment: c_uint,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_debug_cb: Option<unsafe extern fn(*mut SSL, c_int, c_int, *mut c_uchar, c_int, *mut c_void)>,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_debug_arg: *mut c_void,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_hostname: *mut c_char,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
servername_done: c_int,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_status_type: c_int,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_status_expected: c_int,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_ocsp_ids: *mut c_void,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_ocsp_exts: *mut c_void,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_ocsp_resp: *mut c_uchar,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_ocsp_resplen: c_int,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_ticket_expected: c_int,
|
||||
#[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))]
|
||||
tlsext_ecpointformatlist_length: size_t,
|
||||
#[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))]
|
||||
tlsext_ecpointformatlist: *mut c_uchar,
|
||||
#[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))]
|
||||
tlsext_ellipticcurvelist_length: size_t,
|
||||
#[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))]
|
||||
tlsext_ellipticcurvelist: *mut c_uchar,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_opaque_prf_input: *mut c_void,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_opaque_prf_input_len: size_t,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_session_ticket: *mut c_void,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_session_ticket_ext_cb: ::tls_session_ticket_ext_cb_fn,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tls_session_ticket_ext_cb_arg: *mut c_void,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tls_session_secret_cb: ::tls_session_secret_cb_fn,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tls_session_secret_cb_arg: *mut c_void,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
initial_ctx: *mut ::SSL_CTX,
|
||||
#[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))]
|
||||
next_proto_negotiated: *mut c_uchar,
|
||||
#[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))]
|
||||
next_proto_negotiated_len: c_uchar,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
srtp_profiles: *mut c_void,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
srtp_profile: *mut c_void,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_heartbeat: c_uint,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_hb_pending: c_uint,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_hb_seq: c_uint,
|
||||
renegotiate: c_int,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_SRP"))]
|
||||
srp_ctx: ::SRP_CTX,
|
||||
#[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))]
|
||||
alpn_client_proto_list: *mut c_uchar,
|
||||
#[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))]
|
||||
alpn_client_proto_list_len: c_uint,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SSL_CTX {
|
||||
method: *mut c_void,
|
||||
|
|
@ -417,6 +587,59 @@ pub struct SSL_CTX {
|
|||
tlsext_ellipticcurvelist: *mut c_uchar,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SSL_SESSION {
|
||||
ssl_version: c_int,
|
||||
key_arg_length: c_uint,
|
||||
key_arg: [c_uchar; SSL_MAX_KEY_ARG_LENGTH as usize],
|
||||
pub master_key_length: c_int,
|
||||
pub master_key: [c_uchar; 48],
|
||||
session_id_length: c_uint,
|
||||
session_id: [c_uchar; SSL_MAX_SSL_SESSION_ID_LENGTH as usize],
|
||||
sid_ctx_length: c_uint,
|
||||
sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize],
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_KRB5"))]
|
||||
krb5_client_princ_len: c_uint,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_KRB5"))]
|
||||
krb5_client_princ: [c_uchar; SSL_MAX_KRB5_PRINCIPAL_LENGTH as usize],
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
|
||||
psk_identity_hint: *mut c_char,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
|
||||
psk_identity: *mut c_char,
|
||||
not_resumable: c_int,
|
||||
sess_cert: *mut c_void,
|
||||
peer: *mut X509,
|
||||
verify_result: c_long,
|
||||
references: c_int,
|
||||
timeout: c_long,
|
||||
time: c_long,
|
||||
compress_meth: c_uint,
|
||||
cipher: *const c_void,
|
||||
cipher_id: c_ulong,
|
||||
ciphers: *mut c_void,
|
||||
ex_data: ::CRYPTO_EX_DATA,
|
||||
prev: *mut c_void,
|
||||
next: *mut c_void,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_hostname: *mut c_char,
|
||||
#[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))]
|
||||
tlsext_ecpointformatlist_length: size_t,
|
||||
#[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))]
|
||||
tlsext_ecpointformatlist: *mut c_uchar,
|
||||
#[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))]
|
||||
tlsext_ellipticcurvelist_length: size_t,
|
||||
#[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))]
|
||||
tlsext_ellipticcurvelist: *mut c_uchar,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_tick: *mut c_uchar,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_ticklen: size_t,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))]
|
||||
tlsext_tick_lifetime_hint: c_long,
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_SRP"))]
|
||||
srp_username: *mut c_char,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SRP_CTX {
|
||||
SRP_cb_arg: *mut c_void,
|
||||
|
|
@ -453,6 +676,7 @@ pub struct X509_VERIFY_PARAM {
|
|||
|
||||
#[cfg(not(ossl101))]
|
||||
pub enum X509_VERIFY_PARAM_ID {}
|
||||
pub enum PKCS12 {}
|
||||
|
||||
pub const SSL_CTRL_OPTIONS: c_int = 32;
|
||||
pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77;
|
||||
|
|
@ -470,6 +694,12 @@ 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 SSL_MAX_SSL_SESSION_ID_LENGTH: c_int = 32;
|
||||
pub const SSL_MAX_SID_CTX_LENGTH: c_int = 32;
|
||||
pub const SSL_MAX_KEY_ARG_LENGTH: c_int = 8;
|
||||
pub const SSL_MAX_MASTER_KEY_LENGTH: c_int = 48;
|
||||
pub const SSL_MAX_KRB5_PRINCIPAL_LENGTH: c_int = 256;
|
||||
|
||||
pub const SSLEAY_VERSION : c_int = 0;
|
||||
pub const SSLEAY_CFLAGS : c_int = 2;
|
||||
pub const SSLEAY_BUILT_ON : c_int = 3;
|
||||
|
|
@ -533,15 +763,32 @@ fn set_id_callback() {
|
|||
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
|
||||
}
|
||||
|
||||
#[cfg(ossl102)]
|
||||
pub unsafe fn SSL_set_ecdh_auto(ssl: *mut ::SSL, onoff: c_int) -> c_int {
|
||||
::SSL_ctrl(ssl, 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 get_rfc2409_prime_768(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn get_rfc2409_prime_1024(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn get_rfc3526_prime_1536(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn get_rfc3526_prime_2048(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn get_rfc3526_prime_3072(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn get_rfc3526_prime_4096(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn get_rfc3526_prime_6144(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn get_rfc3526_prime_8192(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
|
||||
pub fn CRYPTO_malloc(num: c_int, file: *const c_char, line: c_int) -> *mut c_void;
|
||||
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,
|
||||
|
|
@ -557,6 +804,19 @@ extern {
|
|||
cb: Option<extern fn(c_int, c_int, *mut c_void)>,
|
||||
cbarg: *mut c_void) -> *mut RSA;
|
||||
|
||||
pub fn OCSP_cert_to_id(dgst: *const ::EVP_MD, subject: *mut ::X509, issuer: *mut ::X509) -> *mut ::OCSP_CERTID;
|
||||
|
||||
pub fn PKCS12_create(pass: *mut c_char,
|
||||
friendly_name: *mut c_char,
|
||||
pkey: *mut EVP_PKEY,
|
||||
cert: *mut X509,
|
||||
ca: *mut stack_st_X509,
|
||||
nid_key: c_int,
|
||||
nid_cert: c_int,
|
||||
iter: c_int,
|
||||
mac_iter: c_int,
|
||||
keytype: c_int) -> *mut PKCS12;
|
||||
|
||||
pub fn SSL_library_init() -> c_int;
|
||||
pub fn SSL_load_error_strings();
|
||||
pub fn OPENSSL_add_all_algorithms_noconf();
|
||||
|
|
@ -576,17 +836,33 @@ extern {
|
|||
dup_func: Option<::CRYPTO_EX_dup>,
|
||||
free_func: Option<::CRYPTO_EX_free>)
|
||||
-> c_int;
|
||||
pub fn SSL_set_tmp_ecdh_callback(ssl: *mut ::SSL,
|
||||
ecdh: unsafe extern fn(ssl: *mut ::SSL,
|
||||
is_export: c_int,
|
||||
keylength: c_int)
|
||||
-> *mut ::EC_KEY);
|
||||
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 SSL_CTX_set_tmp_ecdh_callback(ctx: *mut ::SSL_CTX,
|
||||
ecdh: unsafe extern fn(ssl: *mut ::SSL,
|
||||
is_export: c_int,
|
||||
keylength: c_int)
|
||||
-> *mut ::EC_KEY);
|
||||
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_add_entry_by_NID(x: *mut ::X509_NAME, field: c_int, ty: c_int, bytes: *mut c_uchar, len: c_int, loc: c_int, set: c_int) -> c_int;
|
||||
#[cfg(not(ossl101))]
|
||||
pub fn X509_get0_signature(psig: *mut *mut ::ASN1_BIT_STRING, palg: *mut *mut ::X509_ALGOR, x: *const ::X509);
|
||||
#[cfg(not(ossl101))]
|
||||
pub fn X509_get_signature_nid(x: *const X509) -> c_int;
|
||||
#[cfg(not(ossl101))]
|
||||
pub fn X509_ALGOR_get0(paobj: *mut *mut ::ASN1_OBJECT, pptype: *mut c_int, ppval: *mut *mut c_void, alg: *mut ::X509_ALGOR);
|
||||
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;
|
||||
|
|
@ -601,6 +877,7 @@ extern {
|
|||
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 EVP_PKEY_bits(key: *mut EVP_PKEY) -> c_int;
|
||||
|
||||
pub fn sk_new_null() -> *mut _STACK;
|
||||
pub fn sk_num(st: *const _STACK) -> c_int;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use libc::{c_int, c_void, c_char, c_uchar, c_ulong, c_long, c_uint};
|
||||
use libc::{c_int, c_void, c_char, c_uchar, c_ulong, c_long, c_uint, size_t};
|
||||
|
||||
pub enum BIGNUM {}
|
||||
pub enum BIO {}
|
||||
|
|
@ -11,8 +11,11 @@ pub enum EVP_MD_CTX {}
|
|||
pub enum EVP_PKEY {}
|
||||
pub enum HMAC_CTX {}
|
||||
pub enum OPENSSL_STACK {}
|
||||
pub enum PKCS12 {}
|
||||
pub enum RSA {}
|
||||
pub enum SSL {}
|
||||
pub enum SSL_CTX {}
|
||||
pub enum SSL_SESSION {}
|
||||
pub enum stack_st_ASN1_OBJECT {}
|
||||
pub enum stack_st_GENERAL_NAME {}
|
||||
pub enum stack_st_OPENSSL_STRING {}
|
||||
|
|
@ -21,8 +24,11 @@ pub enum stack_st_X509 {}
|
|||
pub enum stack_st_X509_NAME {}
|
||||
pub enum stack_st_X509_ATTRIBUTE {}
|
||||
pub enum stack_st_X509_EXTENSION {}
|
||||
pub enum stack_st_SSL_CIPHER {}
|
||||
pub enum X509 {}
|
||||
pub enum X509_ALGOR {}
|
||||
pub enum X509_VERIFY_PARAM {}
|
||||
pub enum X509_REQ {}
|
||||
|
||||
pub const SSL_OP_MICROSOFT_SESS_ID_BUG: c_ulong = 0x00000000;
|
||||
pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: c_ulong = 0x00000000;
|
||||
|
|
@ -52,9 +58,27 @@ 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 BN_get_rfc2409_prime_768(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn BN_get_rfc2409_prime_1024(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn BN_get_rfc3526_prime_1536(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn BN_get_rfc3526_prime_2048(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn BN_get_rfc3526_prime_3072(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn BN_get_rfc3526_prime_4096(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn BN_get_rfc3526_prime_6144(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
pub fn BN_get_rfc3526_prime_8192(bn: *mut BIGNUM) -> *mut BIGNUM;
|
||||
|
||||
pub fn CRYPTO_malloc(num: size_t, file: *const c_char, line: c_int) -> *mut c_void;
|
||||
pub fn CRYPTO_free(buf: *mut c_void, file: *const c_char, line: c_int);
|
||||
|
||||
pub fn EVP_chacha20() -> *const ::EVP_CIPHER;
|
||||
pub fn EVP_chacha20_poly1305() -> *const ::EVP_CIPHER;
|
||||
|
||||
pub fn HMAC_CTX_new() -> *mut HMAC_CTX;
|
||||
pub fn HMAC_CTX_free(ctx: *mut HMAC_CTX);
|
||||
|
||||
pub fn OCSP_cert_to_id(dgst: *const ::EVP_MD, subject: *const ::X509, issuer: *const ::X509) -> *mut ::OCSP_CERTID;
|
||||
|
||||
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;
|
||||
|
|
@ -63,6 +87,8 @@ extern {
|
|||
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_add_entry_by_NID(x: *mut ::X509_NAME, field: c_int, ty: c_int, bytes: *const c_uchar, len: c_int, loc: c_int, set: c_int) -> c_int;
|
||||
pub fn X509_get_signature_nid(x: *const X509) -> c_int;
|
||||
pub fn X509_ALGOR_get0(paobj: *mut *const ::ASN1_OBJECT, pptype: *mut c_int, ppval: *mut *const c_void, alg: *const ::X509_ALGOR);
|
||||
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;
|
||||
|
|
@ -106,6 +132,7 @@ extern {
|
|||
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 X509_get0_signature(psig: *mut *const ::ASN1_BIT_STRING, palg: *mut *const ::X509_ALGOR, x: *const ::X509);
|
||||
pub fn DH_set0_pqg(dh: *mut ::DH,
|
||||
p: *mut ::BIGNUM,
|
||||
q: *mut ::BIGNUM,
|
||||
|
|
@ -144,10 +171,15 @@ extern {
|
|||
-> 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 SSL_SESSION_get_master_key(session: *const SSL_SESSION,
|
||||
out: *mut c_uchar,
|
||||
outlen: size_t)
|
||||
-> size_t;
|
||||
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 EVP_PKEY_bits(key: *const EVP_PKEY) -> c_int;
|
||||
|
||||
pub fn OpenSSL_version_num() -> c_ulong;
|
||||
pub fn OpenSSL_version(key: c_int) -> *const c_char;
|
||||
|
|
@ -156,4 +188,17 @@ extern {
|
|||
pub fn OPENSSL_sk_pop_free(st: *mut ::OPENSSL_STACK, free: Option<unsafe extern "C" fn (*mut c_void)>);
|
||||
pub fn OPENSSL_sk_push(st: *mut ::OPENSSL_STACK, data: *const c_void) -> c_int;
|
||||
pub fn OPENSSL_sk_pop(st: *mut ::OPENSSL_STACK) -> *mut c_void;
|
||||
|
||||
pub fn PKCS12_create(pass: *const c_char,
|
||||
friendly_name: *const c_char,
|
||||
pkey: *mut EVP_PKEY,
|
||||
cert: *mut X509,
|
||||
ca: *mut stack_st_X509,
|
||||
nid_key: c_int,
|
||||
nid_cert: c_int,
|
||||
iter: c_int,
|
||||
mac_iter: c_int,
|
||||
keytype: c_int) -> *mut PKCS12;
|
||||
pub fn X509_REQ_get_version(req: *const X509_REQ) -> c_long;
|
||||
pub fn X509_REQ_get_subject_name(req: *const X509_REQ) -> *mut ::X509_NAME;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
[package]
|
||||
name = "openssl"
|
||||
version = "0.9.0"
|
||||
version = "0.9.6"
|
||||
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.9.0/openssl"
|
||||
documentation = "https://docs.rs/openssl/0.9.6/openssl"
|
||||
readme = "../README.md"
|
||||
keywords = ["crypto", "tls", "ssl", "dtls"]
|
||||
categories = ["cryptography", "api-bindings"]
|
||||
build = "build.rs"
|
||||
exclude = ["test/*"]
|
||||
|
||||
|
|
@ -18,12 +19,13 @@ v110 = []
|
|||
|
||||
[dependencies]
|
||||
bitflags = "0.7"
|
||||
foreign-types = { git = "https://github.com/sfackler/foreign-types" }
|
||||
lazy_static = "0.2"
|
||||
libc = "0.2"
|
||||
openssl-sys = { version = "0.9", path = "../openssl-sys" }
|
||||
openssl-sys = { version = "0.9.6", path = "../openssl-sys" }
|
||||
|
||||
[dev-dependencies]
|
||||
rustc-serialize = "0.3"
|
||||
tempdir = "0.3"
|
||||
winapi = "0.2"
|
||||
ws2_32-sys = "0.2"
|
||||
hex = "0.2"
|
||||
|
|
@ -16,6 +16,10 @@ fn main() {
|
|||
_ => panic!("Unable to detect OpenSSL version"),
|
||||
}
|
||||
|
||||
if let Ok(_) = env::var("DEP_OPENSSL_LIBRESSL") {
|
||||
println!("cargo:rustc-cfg=libressl");
|
||||
}
|
||||
|
||||
if let Ok(vars) = env::var("DEP_OPENSSL_CONF") {
|
||||
for var in vars.split(",") {
|
||||
println!("cargo:rustc-cfg=osslconf=\"{}\"", var);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
//! Low level AES functionality
|
||||
//!
|
||||
//! The `symm` module should be used in preference to this module in most cases.
|
||||
use ffi;
|
||||
use std::mem;
|
||||
use libc::c_int;
|
||||
|
||||
use symm::Mode;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct KeyError(());
|
||||
|
||||
pub struct AesKey(ffi::AES_KEY);
|
||||
|
||||
impl AesKey {
|
||||
/// Prepares a key for encryption.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Returns an error if the key is not 128, 192, or 256 bits.
|
||||
pub fn new_encrypt(key: &[u8]) -> Result<AesKey, KeyError> {
|
||||
unsafe {
|
||||
assert!(key.len() <= c_int::max_value() as usize / 8);
|
||||
|
||||
let mut aes_key = mem::uninitialized();
|
||||
let r = ffi::AES_set_encrypt_key(key.as_ptr() as *const _,
|
||||
key.len() as c_int * 8,
|
||||
&mut aes_key);
|
||||
if r == 0 {
|
||||
Ok(AesKey(aes_key))
|
||||
} else {
|
||||
Err(KeyError(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepares a key for decryption.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Returns an error if the key is not 128, 192, or 256 bits.
|
||||
pub fn new_decrypt(key: &[u8]) -> Result<AesKey, KeyError> {
|
||||
unsafe {
|
||||
assert!(key.len() <= c_int::max_value() as usize / 8);
|
||||
|
||||
let mut aes_key = mem::uninitialized();
|
||||
let r = ffi::AES_set_decrypt_key(key.as_ptr() as *const _,
|
||||
key.len() as c_int * 8,
|
||||
&mut aes_key);
|
||||
|
||||
if r == 0 {
|
||||
Ok(AesKey(aes_key))
|
||||
} else {
|
||||
Err(KeyError(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs AES IGE encryption or decryption
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `in_` is not the same length as `out`, if that length is not a multiple of 16, or if
|
||||
/// `iv` is not at least 32 bytes.
|
||||
pub fn aes_ige(in_: &[u8], out: &mut [u8], key: &AesKey, iv: &mut [u8], mode: Mode) {
|
||||
unsafe {
|
||||
assert!(in_.len() == out.len());
|
||||
assert!(in_.len() % ffi::AES_BLOCK_SIZE as usize == 0);
|
||||
assert!(iv.len() >= ffi::AES_BLOCK_SIZE as usize * 2);
|
||||
|
||||
let mode = match mode {
|
||||
Mode::Encrypt => ffi::AES_ENCRYPT,
|
||||
Mode::Decrypt => ffi::AES_DECRYPT,
|
||||
};
|
||||
ffi::AES_ige_encrypt(in_.as_ptr() as *const _,
|
||||
out.as_mut_ptr() as *mut _,
|
||||
in_.len(),
|
||||
&key.0,
|
||||
iv.as_mut_ptr() as *mut _,
|
||||
mode);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use hex::FromHex;
|
||||
|
||||
use symm::Mode;
|
||||
use super::*;
|
||||
|
||||
// From https://www.mgp25.com/AESIGE/
|
||||
#[test]
|
||||
fn ige_vector_1() {
|
||||
let raw_key = "000102030405060708090A0B0C0D0E0F";
|
||||
let raw_iv = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F";
|
||||
let raw_pt = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
let raw_ct = "1A8519A6557BE652E9DA8E43DA4EF4453CF456B4CA488AA383C79C98B34797CB";
|
||||
|
||||
let key = AesKey::new_encrypt(&Vec::from_hex(raw_key).unwrap()).unwrap();
|
||||
let mut iv = Vec::from_hex(raw_iv).unwrap();
|
||||
let pt = Vec::from_hex(raw_pt).unwrap();
|
||||
let ct = Vec::from_hex(raw_ct).unwrap();
|
||||
|
||||
let mut ct_actual = vec![0; ct.len()];
|
||||
aes_ige(&pt, &mut ct_actual, &key, &mut iv, Mode::Encrypt);
|
||||
assert_eq!(ct_actual, ct);
|
||||
|
||||
let key = AesKey::new_decrypt(&Vec::from_hex(raw_key).unwrap()).unwrap();
|
||||
let mut iv = Vec::from_hex(raw_iv).unwrap();
|
||||
let mut pt_actual = vec![0; pt.len()];
|
||||
aes_ige(&ct, &mut pt_actual, &key, &mut iv, Mode::Decrypt);
|
||||
assert_eq!(pt_actual, pt);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
use ffi;
|
||||
use libc::c_long;
|
||||
use foreign_types::{ForeignType, ForeignTypeRef};
|
||||
use libc::{c_long, c_char, c_int};
|
||||
use std::fmt;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
|
|
@ -7,11 +8,35 @@ use std::str;
|
|||
|
||||
use {cvt, cvt_p};
|
||||
use bio::MemBio;
|
||||
use crypto::CryptoString;
|
||||
use error::ErrorStack;
|
||||
use types::{OpenSslType, OpenSslTypeRef};
|
||||
use nid::Nid;
|
||||
use string::OpensslString;
|
||||
|
||||
type_!(Asn1Time, Asn1TimeRef, ffi::ASN1_TIME, ffi::ASN1_TIME_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::ASN1_GENERALIZEDTIME;
|
||||
fn drop = ffi::ASN1_GENERALIZEDTIME_free;
|
||||
|
||||
pub struct Asn1GeneralizedTime;
|
||||
pub struct Asn1GeneralizedTimeRef;
|
||||
}
|
||||
|
||||
impl fmt::Display for Asn1GeneralizedTimeRef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
unsafe {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
try!(cvt(ffi::ASN1_GENERALIZEDTIME_print(mem_bio.as_ptr(), self.as_ptr())));
|
||||
write!(f, "{}", str::from_utf8_unchecked(mem_bio.get_buf()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = ffi::ASN1_TIME;
|
||||
fn drop = ffi::ASN1_TIME_free;
|
||||
|
||||
pub struct Asn1Time;
|
||||
pub struct Asn1TimeRef;
|
||||
}
|
||||
|
||||
impl fmt::Display for Asn1TimeRef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
|
@ -39,10 +64,16 @@ impl Asn1Time {
|
|||
}
|
||||
}
|
||||
|
||||
type_!(Asn1String, Asn1StringRef, ffi::ASN1_STRING, ffi::ASN1_STRING_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::ASN1_STRING;
|
||||
fn drop = ffi::ASN1_STRING_free;
|
||||
|
||||
pub struct Asn1String;
|
||||
pub struct Asn1StringRef;
|
||||
}
|
||||
|
||||
impl Asn1StringRef {
|
||||
pub fn as_utf8(&self) -> Result<CryptoString, ErrorStack> {
|
||||
pub fn as_utf8(&self) -> Result<OpensslString, ErrorStack> {
|
||||
unsafe {
|
||||
let mut ptr = ptr::null_mut();
|
||||
let len = ffi::ASN1_STRING_to_UTF8(&mut ptr, self.as_ptr());
|
||||
|
|
@ -50,7 +81,7 @@ impl Asn1StringRef {
|
|||
return Err(ErrorStack::get());
|
||||
}
|
||||
|
||||
Ok(CryptoString::from_raw_parts(ptr, len as usize))
|
||||
Ok(OpensslString::from_ptr(ptr as *mut c_char))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +94,77 @@ impl Asn1StringRef {
|
|||
}
|
||||
}
|
||||
|
||||
type_!(Asn1Integer, Asn1IntegerRef, ffi::ASN1_INTEGER, ffi::ASN1_INTEGER_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::ASN1_INTEGER;
|
||||
fn drop = ffi::ASN1_INTEGER_free;
|
||||
|
||||
pub struct Asn1Integer;
|
||||
pub struct Asn1IntegerRef;
|
||||
}
|
||||
|
||||
impl Asn1IntegerRef {
|
||||
pub fn get(&self) -> i64 {
|
||||
unsafe {
|
||||
::ffi::ASN1_INTEGER_get(self.as_ptr()) as i64
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(&mut self, value: i32) -> Result<(), ErrorStack>
|
||||
{
|
||||
unsafe {
|
||||
cvt(::ffi::ASN1_INTEGER_set(self.as_ptr(), value as c_long)).map(|_| ())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = ffi::ASN1_BIT_STRING;
|
||||
fn drop = ffi::ASN1_BIT_STRING_free;
|
||||
|
||||
pub struct Asn1BitString;
|
||||
pub struct Asn1BitStringRef;
|
||||
}
|
||||
|
||||
impl Asn1BitStringRef {
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
unsafe { slice::from_raw_parts(ASN1_STRING_data(self.as_ptr() as *mut _), self.len()) }
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
unsafe { ffi::ASN1_STRING_length(self.as_ptr() as *mut _) as usize }
|
||||
}
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = ffi::ASN1_OBJECT;
|
||||
fn drop = ffi::ASN1_OBJECT_free;
|
||||
|
||||
pub struct Asn1Object;
|
||||
pub struct Asn1ObjectRef;
|
||||
}
|
||||
|
||||
impl Asn1ObjectRef {
|
||||
/// Returns the NID associated with this OID.
|
||||
pub fn nid(&self) -> Nid {
|
||||
unsafe {
|
||||
Nid::from_raw(ffi::OBJ_obj2nid(self.as_ptr()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Asn1ObjectRef {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
unsafe {
|
||||
let mut buf = [0; 80];
|
||||
let len = ffi::OBJ_obj2txt(buf.as_mut_ptr() as *mut _,
|
||||
buf.len() as c_int,
|
||||
self.as_ptr(),
|
||||
0);
|
||||
let s = try!(str::from_utf8(&buf[..len as usize]).map_err(|_| fmt::Error));
|
||||
fmt.write_str(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(ossl101, ossl102))]
|
||||
use ffi::ASN1_STRING_data;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use ffi;
|
||||
use foreign_types::{ForeignType, ForeignTypeRef};
|
||||
use libc::c_int;
|
||||
use std::cmp::Ordering;
|
||||
use std::ffi::CString;
|
||||
|
|
@ -7,9 +8,23 @@ use std::ops::{Add, Div, Mul, Neg, Rem, Shl, Shr, Sub, Deref};
|
|||
|
||||
use {cvt, cvt_p, cvt_n};
|
||||
use asn1::Asn1Integer;
|
||||
use crypto::CryptoString;
|
||||
use error::ErrorStack;
|
||||
use types::{OpenSslType, OpenSslTypeRef};
|
||||
use string::OpensslString;
|
||||
|
||||
#[cfg(ossl10x)]
|
||||
use ffi::{get_rfc2409_prime_768 as BN_get_rfc2409_prime_768,
|
||||
get_rfc2409_prime_1024 as BN_get_rfc2409_prime_1024,
|
||||
get_rfc3526_prime_1536 as BN_get_rfc3526_prime_1536,
|
||||
get_rfc3526_prime_2048 as BN_get_rfc3526_prime_2048,
|
||||
get_rfc3526_prime_3072 as BN_get_rfc3526_prime_3072,
|
||||
get_rfc3526_prime_4096 as BN_get_rfc3526_prime_4096,
|
||||
get_rfc3526_prime_6144 as BN_get_rfc3526_prime_6144,
|
||||
get_rfc3526_prime_8192 as BN_get_rfc3526_prime_8192};
|
||||
|
||||
#[cfg(ossl110)]
|
||||
use ffi::{BN_get_rfc2409_prime_768, BN_get_rfc2409_prime_1024, BN_get_rfc3526_prime_1536,
|
||||
BN_get_rfc3526_prime_2048, BN_get_rfc3526_prime_3072, BN_get_rfc3526_prime_4096,
|
||||
BN_get_rfc3526_prime_6144, BN_get_rfc3526_prime_8192};
|
||||
|
||||
/// Options for the most significant bits of a randomly generated `BigNum`.
|
||||
pub struct MsbOption(c_int);
|
||||
|
|
@ -26,7 +41,13 @@ pub const MSB_ONE: MsbOption = MsbOption(0);
|
|||
/// of bits in the original numbers.
|
||||
pub const TWO_MSB_ONE: MsbOption = MsbOption(1);
|
||||
|
||||
type_!(BigNumContext, BigNumContextRef, ffi::BN_CTX, ffi::BN_CTX_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::BN_CTX;
|
||||
fn drop = ffi::BN_CTX_free;
|
||||
|
||||
pub struct BigNumContext;
|
||||
pub struct BigNumContextRef;
|
||||
}
|
||||
|
||||
impl BigNumContext {
|
||||
/// Returns a new `BigNumContext`.
|
||||
|
|
@ -470,12 +491,12 @@ impl BigNumRef {
|
|||
/// # use openssl::bn::BigNum;
|
||||
/// let s = -BigNum::from_u32(12345).unwrap();
|
||||
///
|
||||
/// assert_eq!(&*s.to_dec_str().unwrap(), "-12345");
|
||||
/// assert_eq!(&**s.to_dec_str().unwrap(), "-12345");
|
||||
/// ```
|
||||
pub fn to_dec_str(&self) -> Result<CryptoString, ErrorStack> {
|
||||
pub fn to_dec_str(&self) -> Result<OpensslString, ErrorStack> {
|
||||
unsafe {
|
||||
let buf = try!(cvt_p(ffi::BN_bn2dec(self.as_ptr())));
|
||||
Ok(CryptoString::from_null_terminated(buf))
|
||||
Ok(OpensslString::from_ptr(buf))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -485,12 +506,12 @@ impl BigNumRef {
|
|||
/// # use openssl::bn::BigNum;
|
||||
/// let s = -BigNum::from_u32(0x99ff).unwrap();
|
||||
///
|
||||
/// assert_eq!(&*s.to_hex_str().unwrap(), "-99FF");
|
||||
/// assert_eq!(&**s.to_hex_str().unwrap(), "-99FF");
|
||||
/// ```
|
||||
pub fn to_hex_str(&self) -> Result<CryptoString, ErrorStack> {
|
||||
pub fn to_hex_str(&self) -> Result<OpensslString, ErrorStack> {
|
||||
unsafe {
|
||||
let buf = try!(cvt_p(ffi::BN_bn2hex(self.as_ptr())));
|
||||
Ok(CryptoString::from_null_terminated(buf))
|
||||
Ok(OpensslString::from_ptr(buf))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -503,7 +524,13 @@ impl BigNumRef {
|
|||
}
|
||||
}
|
||||
|
||||
type_!(BigNum, BigNumRef, ffi::BIGNUM, ffi::BN_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::BIGNUM;
|
||||
fn drop = ffi::BN_free;
|
||||
|
||||
pub struct BigNum;
|
||||
pub struct BigNumRef;
|
||||
}
|
||||
|
||||
impl BigNum {
|
||||
/// Creates a new `BigNum` with the value 0.
|
||||
|
|
@ -525,6 +552,7 @@ impl BigNum {
|
|||
/// Creates a `BigNum` from a decimal string.
|
||||
pub fn from_dec_str(s: &str) -> Result<BigNum, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
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 _)));
|
||||
|
|
@ -535,6 +563,7 @@ impl BigNum {
|
|||
/// Creates a `BigNum` from a hexadecimal string.
|
||||
pub fn from_hex_str(s: &str) -> Result<BigNum, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
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 _)));
|
||||
|
|
@ -542,6 +571,62 @@ impl BigNum {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_rfc2409_prime_768() -> Result<BigNum, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
cvt_p(BN_get_rfc2409_prime_768(ptr::null_mut())).map(BigNum)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_rfc2409_prime_1024() -> Result<BigNum, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
cvt_p(BN_get_rfc2409_prime_1024(ptr::null_mut())).map(BigNum)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_rfc3526_prime_1536() -> Result<BigNum, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
cvt_p(BN_get_rfc3526_prime_1536(ptr::null_mut())).map(BigNum)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_rfc3526_prime_2048() -> Result<BigNum, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
cvt_p(BN_get_rfc3526_prime_2048(ptr::null_mut())).map(BigNum)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_rfc3526_prime_3072() -> Result<BigNum, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
cvt_p(BN_get_rfc3526_prime_3072(ptr::null_mut())).map(BigNum)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_rfc3526_prime_4096() -> Result<BigNum, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
cvt_p(BN_get_rfc3526_prime_4096(ptr::null_mut())).map(BigNum)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_rfc3526_prime_6144() -> Result<BigNum, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
cvt_p(BN_get_rfc3526_prime_6144(ptr::null_mut())).map(BigNum)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_rfc3526_prime_8192() -> Result<BigNum, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
cvt_p(BN_get_rfc3526_prime_8192(ptr::null_mut())).map(BigNum)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `BigNum` from an unsigned, big-endian encoded number of arbitrary length.
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -552,6 +637,7 @@ impl BigNum {
|
|||
/// ```
|
||||
pub fn from_slice(n: &[u8]) -> Result<BigNum, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
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))
|
||||
|
|
|
|||
|
|
@ -22,7 +22,13 @@ impl ConfMethod {
|
|||
}
|
||||
}
|
||||
|
||||
type_!(Conf, ConfRef, ffi::CONF, ffi::NCONF_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::CONF;
|
||||
fn drop = ffi::NCONF_free;
|
||||
|
||||
pub struct Conf;
|
||||
pub struct ConfRef;
|
||||
}
|
||||
|
||||
impl Conf {
|
||||
pub fn new(method: ConfMethod) -> Result<Conf, ErrorStack> {
|
||||
|
|
|
|||
|
|
@ -1,59 +1,4 @@
|
|||
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;
|
||||
use string::OpensslString;
|
||||
|
||||
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;
|
||||
#[deprecated(note = "renamed to OpensslString", since = "0.9.7")]
|
||||
pub type CryptoString = OpensslString;
|
||||
|
|
|
|||
|
|
@ -1,32 +1,30 @@
|
|||
use ffi;
|
||||
use error::ErrorStack;
|
||||
use bio::MemBioSlice;
|
||||
use std::ptr;
|
||||
use ffi;
|
||||
use foreign_types::ForeignTypeRef;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
|
||||
use {cvt, cvt_p};
|
||||
use bio::MemBio;
|
||||
use {cvt, cvt_p, init};
|
||||
use bn::BigNum;
|
||||
use types::OpenSslTypeRef;
|
||||
|
||||
type_!(Dh, DhRef, ffi::DH, ffi::DH_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::DH;
|
||||
fn drop = ffi::DH_free;
|
||||
|
||||
pub struct Dh;
|
||||
|
||||
pub struct DhRef;
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
to_pem!(ffi::PEM_write_bio_DHparams);
|
||||
to_der!(ffi::i2d_DHparams);
|
||||
}
|
||||
|
||||
impl Dh {
|
||||
pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result<Dh, ErrorStack> {
|
||||
unsafe {
|
||||
init();
|
||||
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));
|
||||
|
|
@ -34,16 +32,8 @@ impl 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)
|
||||
}
|
||||
}
|
||||
from_pem!(Dh, ffi::PEM_read_bio_DHparams);
|
||||
from_der!(Dh, ffi::d2i_DHparams);
|
||||
|
||||
/// 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)))]
|
||||
|
|
@ -139,7 +129,15 @@ mod tests {
|
|||
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");
|
||||
let dh = Dh::from_pem(params).unwrap();
|
||||
ctx.set_tmp_dh(&dh).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dh_from_der() {
|
||||
let params = include_bytes!("../test/dhparams.pem");
|
||||
let dh = Dh::from_pem(params).unwrap();
|
||||
let der = dh.to_der().unwrap();
|
||||
Dh::from_der(&der).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,41 +1,31 @@
|
|||
use error::ErrorStack;
|
||||
use ffi;
|
||||
use foreign_types::ForeignTypeRef;
|
||||
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};
|
||||
use bio::MemBioSlice;
|
||||
use bn::BigNumRef;
|
||||
use error::ErrorStack;
|
||||
use util::{CallbackState, invoke_passwd_cb_old};
|
||||
|
||||
type_!(Dsa, DsaRef, ffi::DSA, ffi::DSA_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::DSA;
|
||||
fn drop = ffi::DSA_free;
|
||||
|
||||
pub struct Dsa;
|
||||
pub struct DsaRef;
|
||||
}
|
||||
|
||||
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());
|
||||
private_key_to_pem!(ffi::PEM_write_bio_DSAPrivateKey);
|
||||
public_key_to_pem!(ffi::PEM_write_bio_DSA_PUBKEY);
|
||||
|
||||
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())
|
||||
}
|
||||
private_key_to_der!(ffi::i2d_DSAPrivateKey);
|
||||
public_key_to_der!(ffi::i2d_DSAPublicKey);
|
||||
|
||||
// FIXME should return u32
|
||||
pub fn size(&self) -> Option<u32> {
|
||||
if self.q().is_some() {
|
||||
unsafe { Some(ffi::DSA_size(self.as_ptr()) as u32) }
|
||||
|
|
@ -103,25 +93,12 @@ impl 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));
|
||||
private_key_from_pem!(Dsa, ffi::PEM_read_bio_DSAPrivateKey);
|
||||
private_key_from_der!(Dsa, ffi::d2i_DSAPrivateKey);
|
||||
public_key_from_pem!(Dsa, ffi::PEM_read_bio_DSA_PUBKEY);
|
||||
public_key_from_der!(Dsa, ffi::d2i_DSAPublicKey);
|
||||
|
||||
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.
|
||||
#[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")]
|
||||
pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<Dsa, ErrorStack>
|
||||
where F: FnOnce(&mut [c_char]) -> usize
|
||||
{
|
||||
|
|
@ -133,25 +110,11 @@ impl Dsa {
|
|||
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>),
|
||||
Some(invoke_passwd_cb_old::<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 {
|
||||
|
|
@ -193,7 +156,7 @@ mod compat {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use libc::c_char;
|
||||
use symm::Cipher;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -204,17 +167,26 @@ mod test {
|
|||
|
||||
#[test]
|
||||
pub fn test_password() {
|
||||
let key = include_bytes!("../test/dsa-encrypted.pem");
|
||||
Dsa::private_key_from_pem_passphrase(key, b"mypass").unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_password() {
|
||||
let key = Dsa::generate(2048).unwrap();
|
||||
let pem = key.private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar").unwrap();
|
||||
Dsa::private_key_from_pem_passphrase(&pem, b"foobar").unwrap();
|
||||
assert!(Dsa::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_password_callback() {
|
||||
let mut password_queried = false;
|
||||
let key = include_bytes!("../test/dsa-encrypted.pem");
|
||||
Dsa::private_key_from_pem_cb(key, |password| {
|
||||
Dsa::private_key_from_pem_callback(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
|
||||
password[..6].copy_from_slice(b"mypass");
|
||||
Ok(6)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,484 @@
|
|||
use ffi;
|
||||
use foreign_types::{ForeignType, ForeignTypeRef};
|
||||
use std::ptr;
|
||||
use std::mem;
|
||||
use libc::c_int;
|
||||
|
||||
use {cvt, cvt_n, cvt_p, init};
|
||||
use bn::{BigNumRef, BigNumContextRef};
|
||||
use error::ErrorStack;
|
||||
use nid::Nid;
|
||||
|
||||
pub const POINT_CONVERSION_COMPRESSED: PointConversionForm =
|
||||
PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED);
|
||||
|
||||
pub const POINT_CONVERSION_UNCOMPRESSED: PointConversionForm =
|
||||
PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED);
|
||||
|
||||
pub const POINT_CONVERSION_HYBRID: PointConversionForm =
|
||||
PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID);
|
||||
|
||||
// OPENSSL_EC_EXPLICIT_CURVE, but that was only added in 1.1.
|
||||
// Man page documents that 0 can be used in older versions.
|
||||
pub const EXPLICIT_CURVE: Asn1Flag = Asn1Flag(0);
|
||||
pub const NAMED_CURVE: Asn1Flag = Asn1Flag(ffi::OPENSSL_EC_NAMED_CURVE);
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PointConversionForm(ffi::point_conversion_form_t);
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Asn1Flag(c_int);
|
||||
|
||||
foreign_type! {
|
||||
type CType = ffi::EC_GROUP;
|
||||
fn drop = ffi::EC_GROUP_free;
|
||||
|
||||
pub struct EcGroup;
|
||||
pub struct EcGroupRef;
|
||||
}
|
||||
|
||||
impl EcGroup {
|
||||
/// Returns the group of a standard named curve.
|
||||
pub fn from_curve_name(nid: Nid) -> Result<EcGroup, ErrorStack> {
|
||||
unsafe {
|
||||
init();
|
||||
cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(EcGroup)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EcGroupRef {
|
||||
/// Places the components of a curve over a prime field in the provided `BigNum`s.
|
||||
pub fn components_gfp(&self,
|
||||
p: &mut BigNumRef,
|
||||
a: &mut BigNumRef,
|
||||
b: &mut BigNumRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::EC_GROUP_get_curve_GFp(self.as_ptr(),
|
||||
p.as_ptr(),
|
||||
a.as_ptr(),
|
||||
b.as_ptr(),
|
||||
ctx.as_ptr()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Places the components of a curve over a binary field in the provided `BigNum`s.
|
||||
pub fn components_gf2m(&self,
|
||||
p: &mut BigNumRef,
|
||||
a: &mut BigNumRef,
|
||||
b: &mut BigNumRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::EC_GROUP_get_curve_GF2m(self.as_ptr(),
|
||||
p.as_ptr(),
|
||||
a.as_ptr(),
|
||||
b.as_ptr(),
|
||||
ctx.as_ptr()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the degree of the curve.
|
||||
pub fn degree(&self) -> u32 {
|
||||
unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 }
|
||||
}
|
||||
|
||||
/// Places the order of the curve in the provided `BigNum`.
|
||||
pub fn order(&self,
|
||||
order: &mut BigNumRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::EC_GROUP_get_order(self.as_ptr(), order.as_ptr(), ctx.as_ptr())).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the flag determining if the group corresponds to a named curve or must be explicitly
|
||||
/// parameterized.
|
||||
///
|
||||
/// This defaults to `EXPLICIT_CURVE` in OpenSSL 1.0.1 and 1.0.2, but `NAMED_CURVE` in OpenSSL
|
||||
/// 1.1.0.
|
||||
pub fn set_asn1_flag(&mut self, flag: Asn1Flag) {
|
||||
unsafe {
|
||||
ffi::EC_GROUP_set_asn1_flag(self.as_ptr(), flag.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = ffi::EC_POINT;
|
||||
fn drop = ffi::EC_POINT_free;
|
||||
|
||||
pub struct EcPoint;
|
||||
pub struct EcPointRef;
|
||||
}
|
||||
|
||||
impl EcPointRef {
|
||||
/// Computes `a + b`, storing the result in `self`.
|
||||
pub fn add(&mut self,
|
||||
group: &EcGroupRef,
|
||||
a: &EcPointRef,
|
||||
b: &EcPointRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::EC_POINT_add(group.as_ptr(),
|
||||
self.as_ptr(),
|
||||
a.as_ptr(),
|
||||
b.as_ptr(),
|
||||
ctx.as_ptr()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes `q * m`, storing the result in `self`.
|
||||
pub fn mul(&mut self,
|
||||
group: &EcGroupRef,
|
||||
q: &EcPointRef,
|
||||
m: &BigNumRef,
|
||||
ctx: &BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::EC_POINT_mul(group.as_ptr(),
|
||||
self.as_ptr(),
|
||||
ptr::null(),
|
||||
q.as_ptr(),
|
||||
m.as_ptr(),
|
||||
ctx.as_ptr()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes `generator * n`, storing the result ing `self`.
|
||||
pub fn mul_generator(&mut self,
|
||||
group: &EcGroupRef,
|
||||
n: &BigNumRef,
|
||||
ctx: &BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::EC_POINT_mul(group.as_ptr(),
|
||||
self.as_ptr(),
|
||||
n.as_ptr(),
|
||||
ptr::null(),
|
||||
ptr::null(),
|
||||
ctx.as_ptr()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes `generator * n + q * m`, storing the result in `self`.
|
||||
pub fn mul_full(&mut self,
|
||||
group: &EcGroupRef,
|
||||
n: &BigNumRef,
|
||||
q: &EcPointRef,
|
||||
m: &BigNumRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::EC_POINT_mul(group.as_ptr(),
|
||||
self.as_ptr(),
|
||||
n.as_ptr(),
|
||||
q.as_ptr(),
|
||||
m.as_ptr(),
|
||||
ctx.as_ptr()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Inverts `self`.
|
||||
pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::EC_POINT_invert(group.as_ptr(), self.as_ptr(), ctx.as_ptr())).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Serializes the point to a binary representation.
|
||||
pub fn to_bytes(&self,
|
||||
group: &EcGroupRef,
|
||||
form: PointConversionForm,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<Vec<u8>, ErrorStack> {
|
||||
unsafe {
|
||||
let len = ffi::EC_POINT_point2oct(group.as_ptr(),
|
||||
self.as_ptr(),
|
||||
form.0,
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
ctx.as_ptr());
|
||||
if len == 0 {
|
||||
return Err(ErrorStack::get());
|
||||
}
|
||||
let mut buf = vec![0; len];
|
||||
let len = ffi::EC_POINT_point2oct(group.as_ptr(),
|
||||
self.as_ptr(),
|
||||
form.0,
|
||||
buf.as_mut_ptr(),
|
||||
len,
|
||||
ctx.as_ptr());
|
||||
if len == 0 {
|
||||
Err(ErrorStack::get())
|
||||
} else {
|
||||
Ok(buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines if this point is equal to another.
|
||||
pub fn eq(&self,
|
||||
group: &EcGroupRef,
|
||||
other: &EcPointRef,
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<bool, ErrorStack> {
|
||||
unsafe {
|
||||
let res = try!(cvt_n(ffi::EC_POINT_cmp(group.as_ptr(),
|
||||
self.as_ptr(),
|
||||
other.as_ptr(),
|
||||
ctx.as_ptr())));
|
||||
Ok(res == 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EcPoint {
|
||||
/// Creates a new point on the specified curve.
|
||||
pub fn new(group: &EcGroupRef) -> Result<EcPoint, ErrorStack> {
|
||||
unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) }
|
||||
}
|
||||
|
||||
pub fn from_bytes(group: &EcGroupRef,
|
||||
buf: &[u8],
|
||||
ctx: &mut BigNumContextRef)
|
||||
-> Result<EcPoint, ErrorStack> {
|
||||
let point = try!(EcPoint::new(group));
|
||||
unsafe {
|
||||
try!(cvt(ffi::EC_POINT_oct2point(group.as_ptr(),
|
||||
point.as_ptr(),
|
||||
buf.as_ptr(),
|
||||
buf.len(),
|
||||
ctx.as_ptr())));
|
||||
}
|
||||
Ok(point)
|
||||
}
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = ffi::EC_KEY;
|
||||
fn drop = ffi::EC_KEY_free;
|
||||
|
||||
pub struct EcKey;
|
||||
pub struct EcKeyRef;
|
||||
}
|
||||
|
||||
impl EcKeyRef {
|
||||
private_key_to_pem!(ffi::PEM_write_bio_ECPrivateKey);
|
||||
private_key_to_der!(ffi::i2d_ECPrivateKey);
|
||||
|
||||
pub fn group(&self) -> Option<&EcGroupRef> {
|
||||
unsafe {
|
||||
let ptr = ffi::EC_KEY_get0_group(self.as_ptr());
|
||||
if ptr.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(EcGroupRef::from_ptr(ptr as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn public_key(&self) -> Option<&EcPointRef> {
|
||||
unsafe {
|
||||
let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr());
|
||||
if ptr.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(EcPointRef::from_ptr(ptr as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn private_key(&self) -> Option<&BigNumRef> {
|
||||
unsafe {
|
||||
let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr());
|
||||
if ptr.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(ptr as *mut _))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks the key for validity.
|
||||
pub fn check_key(&self) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl EcKey {
|
||||
/// Constructs an `EcKey` corresponding to a known curve.
|
||||
///
|
||||
/// It will not have an associated public or private key. This kind of key is primarily useful
|
||||
/// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`.
|
||||
pub fn from_curve_name(nid: Nid) -> Result<EcKey, ErrorStack> {
|
||||
unsafe {
|
||||
init();
|
||||
cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(EcKey)
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs an `EcKey` from the specified group with the associated `EcPoint`, public_key.
|
||||
///
|
||||
/// This will only have the associated public_key.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use openssl::bn::BigNumContext;
|
||||
/// use openssl::ec::*;
|
||||
/// use openssl::nid;
|
||||
/// use openssl::pkey::PKey;
|
||||
///
|
||||
/// // get bytes from somewhere, i.e. this will not produce a valid key
|
||||
/// let public_key: Vec<u8> = vec![];
|
||||
///
|
||||
/// // create an EcKey from the binary form of a EcPoint
|
||||
/// let group = EcGroup::from_curve_name(nid::SECP256K1).unwrap();
|
||||
/// let mut ctx = BigNumContext::new().unwrap();
|
||||
/// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx).unwrap();
|
||||
/// let key = EcKey::from_public_key(&group, &point);
|
||||
/// ```
|
||||
pub fn from_public_key(group: &EcGroupRef, public_key: &EcPointRef) -> Result<EcKey, ErrorStack> {
|
||||
let mut builder = try!(EcKeyBuilder::new());
|
||||
try!(builder.set_group(group));
|
||||
try!(builder.set_public_key(public_key));
|
||||
Ok(builder.build())
|
||||
}
|
||||
|
||||
/// Generates a new public/private key pair on the specified curve.
|
||||
pub fn generate(group: &EcGroupRef) -> Result<EcKey, ErrorStack> {
|
||||
let mut builder = try!(EcKeyBuilder::new());
|
||||
try!(builder.set_group(group));
|
||||
try!(builder.generate_key());
|
||||
Ok(builder.build())
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.9.2", note = "use from_curve_name")]
|
||||
pub fn new_by_curve_name(nid: Nid) -> Result<EcKey, ErrorStack> {
|
||||
EcKey::from_curve_name(nid)
|
||||
}
|
||||
|
||||
private_key_from_pem!(EcKey, ffi::PEM_read_bio_ECPrivateKey);
|
||||
private_key_from_der!(EcKey, ffi::d2i_ECPrivateKey);
|
||||
}
|
||||
|
||||
|
||||
foreign_type! {
|
||||
type CType = ffi::EC_KEY;
|
||||
fn drop = ffi::EC_KEY_free;
|
||||
|
||||
pub struct EcKeyBuilder;
|
||||
pub struct EcKeyBuilderRef;
|
||||
}
|
||||
|
||||
impl EcKeyBuilder {
|
||||
pub fn new() -> Result<EcKeyBuilder, ErrorStack> {
|
||||
unsafe {
|
||||
init();
|
||||
cvt_p(ffi::EC_KEY_new()).map(EcKeyBuilder)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(self) -> EcKey {
|
||||
unsafe {
|
||||
let key = EcKey::from_ptr(self.as_ptr());
|
||||
mem::forget(self);
|
||||
key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EcKeyBuilderRef {
|
||||
pub fn set_group(&mut self, group: &EcGroupRef) -> Result<&mut EcKeyBuilderRef, ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::EC_KEY_set_group(self.as_ptr(), group.as_ptr())).map(|_| self)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_public_key(&mut self,
|
||||
public_key: &EcPointRef)
|
||||
-> Result<&mut EcKeyBuilderRef, ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::EC_KEY_set_public_key(self.as_ptr(), public_key.as_ptr())).map(|_| self)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_key(&mut self) -> Result<&mut EcKeyBuilderRef, ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::EC_KEY_generate_key(self.as_ptr())).map(|_| self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use bn::BigNumContext;
|
||||
use nid;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn key_new_by_curve_name() {
|
||||
EcKey::from_curve_name(nid::X9_62_PRIME256V1).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate() {
|
||||
let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap();
|
||||
let key = EcKey::generate(&group).unwrap();
|
||||
key.public_key().unwrap();
|
||||
key.private_key().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn point_new() {
|
||||
let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap();
|
||||
EcPoint::new(&group).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn point_bytes() {
|
||||
let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap();
|
||||
let key = EcKey::generate(&group).unwrap();
|
||||
let point = key.public_key().unwrap();
|
||||
let mut ctx = BigNumContext::new().unwrap();
|
||||
let bytes = point.to_bytes(&group, POINT_CONVERSION_COMPRESSED, &mut ctx).unwrap();
|
||||
let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
|
||||
assert!(point.eq(&group, &point2, &mut ctx).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mul_generator() {
|
||||
let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap();
|
||||
let key = EcKey::generate(&group).unwrap();
|
||||
let mut ctx = BigNumContext::new().unwrap();
|
||||
let mut public_key = EcPoint::new(&group).unwrap();
|
||||
public_key.mul_generator(&group, key.private_key().unwrap(), &mut ctx).unwrap();
|
||||
assert!(public_key.eq(&group, key.public_key().unwrap(), &mut ctx).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn key_from_public_key() {
|
||||
let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap();
|
||||
let key = EcKey::generate(&group).unwrap();
|
||||
let mut ctx = BigNumContext::new().unwrap();
|
||||
let bytes = key.public_key().unwrap().to_bytes(&group, POINT_CONVERSION_COMPRESSED, &mut ctx).unwrap();
|
||||
|
||||
drop(key);
|
||||
let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
|
||||
let ec_key = EcKey::from_public_key(&group, &public_key).unwrap();
|
||||
assert!(ec_key.check_key().is_ok());
|
||||
assert!(ec_key.public_key().is_some());
|
||||
assert!(ec_key.private_key().is_none());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +1,3 @@
|
|||
use ffi;
|
||||
#![deprecated(since = "0.9.2", note = "renamed to `ec`")]
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
pub use ec::{EcKey, EcKeyRef};
|
||||
|
|
|
|||
|
|
@ -32,11 +32,11 @@ impl fmt::Display for ErrorStack {
|
|||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut first = true;
|
||||
for err in &self.0 {
|
||||
if first {
|
||||
if !first {
|
||||
try!(fmt.write_str(", "));
|
||||
first = false;
|
||||
}
|
||||
try!(write!(fmt, "{}", err));
|
||||
first = false;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ use self::State::*;
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Calculate a hash in one go.
|
||||
/// Calculate a hash in one go:
|
||||
///
|
||||
/// ```
|
||||
/// use openssl::hash::{hash, MessageDigest};
|
||||
|
|
@ -71,7 +71,7 @@ use self::State::*;
|
|||
/// assert_eq!(res, spec);
|
||||
/// ```
|
||||
///
|
||||
/// Use the `Write` trait to supply the input in chunks.
|
||||
/// Supply the input in chunks:
|
||||
///
|
||||
/// ```
|
||||
/// use openssl::hash::{Hasher, MessageDigest};
|
||||
|
|
@ -208,17 +208,17 @@ pub fn hash(t: MessageDigest, data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serialize::hex::{FromHex, ToHex};
|
||||
use hex::{FromHex, ToHex};
|
||||
use super::{hash, Hasher, MessageDigest};
|
||||
use std::io::prelude::*;
|
||||
|
||||
fn hash_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
|
||||
let res = hash(hashtype, &*hashtest.0.from_hex().unwrap()).unwrap();
|
||||
let res = hash(hashtype, &Vec::from_hex(hashtest.0).unwrap()).unwrap();
|
||||
assert_eq!(res.to_hex(), hashtest.1);
|
||||
}
|
||||
|
||||
fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) {
|
||||
let _ = h.write_all(&*hashtest.0.from_hex().unwrap()).unwrap();
|
||||
let _ = h.write_all(&Vec::from_hex(hashtest.0).unwrap()).unwrap();
|
||||
let res = h.finish().unwrap();
|
||||
assert_eq!(res.to_hex(), hashtest.1);
|
||||
}
|
||||
|
|
@ -258,7 +258,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_finish_twice() {
|
||||
let mut h = Hasher::new(MessageDigest::md5()).unwrap();
|
||||
h.write_all(&*md5_tests[6].0.from_hex().unwrap()).unwrap();
|
||||
h.write_all(&Vec::from_hex(md5_tests[6].0).unwrap()).unwrap();
|
||||
h.finish().unwrap();
|
||||
let res = h.finish().unwrap();
|
||||
let null = hash(MessageDigest::md5(), &[]).unwrap();
|
||||
|
|
@ -268,7 +268,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_clone() {
|
||||
let i = 7;
|
||||
let inp = md5_tests[i].0.from_hex().unwrap();
|
||||
let inp = Vec::from_hex(md5_tests[i].0).unwrap();
|
||||
assert!(inp.len() > 2);
|
||||
let p = inp.len() / 2;
|
||||
let h0 = Hasher::new(MessageDigest::md5()).unwrap();
|
||||
|
|
@ -289,7 +289,7 @@ mod tests {
|
|||
|
||||
println!("Clone a finished hasher");
|
||||
let mut h3 = h1.clone();
|
||||
h3.write_all(&*md5_tests[i + 1].0.from_hex().unwrap()).unwrap();
|
||||
h3.write_all(&Vec::from_hex(md5_tests[i + 1].0).unwrap()).unwrap();
|
||||
let res = h3.finish().unwrap();
|
||||
assert_eq!(res.to_hex(), md5_tests[i + 1].1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.9.0")]
|
||||
#![doc(html_root_url="https://docs.rs/openssl/0.9.6")]
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
#[macro_use]
|
||||
extern crate foreign_types;
|
||||
extern crate libc;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate openssl_sys as ffi;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate rustc_serialize as serialize;
|
||||
|
||||
extern crate hex;
|
||||
#[cfg(test)]
|
||||
extern crate tempdir;
|
||||
|
||||
|
|
@ -20,76 +21,38 @@ use libc::c_int;
|
|||
|
||||
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)
|
||||
}
|
||||
|
||||
fn as_ptr(&self) -> *mut $c {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
mod bio;
|
||||
mod util;
|
||||
pub mod aes;
|
||||
pub mod asn1;
|
||||
pub mod bn;
|
||||
pub mod conf;
|
||||
pub mod crypto;
|
||||
pub mod dh;
|
||||
pub mod dsa;
|
||||
pub mod ec;
|
||||
pub mod ec_key;
|
||||
pub mod error;
|
||||
pub mod hash;
|
||||
pub mod memcmp;
|
||||
pub mod nid;
|
||||
pub mod ocsp;
|
||||
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 stack;
|
||||
pub mod string;
|
||||
pub mod symm;
|
||||
pub mod types;
|
||||
pub mod version;
|
||||
pub mod x509;
|
||||
pub mod stack;
|
||||
#[cfg(any(ossl102, ossl110))]
|
||||
mod verify;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,216 @@
|
|||
|
||||
macro_rules! private_key_from_pem {
|
||||
($t:ident, $f:path) => {
|
||||
from_pem_inner!(/// Deserializes a PEM-formatted private key.
|
||||
private_key_from_pem, $t, $f);
|
||||
|
||||
/// Deserializes a PEM-formatted private key, using the supplied password if the key is
|
||||
/// encrypted.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `passphrase` contains an embedded null.
|
||||
pub fn private_key_from_pem_passphrase(pem: &[u8],
|
||||
passphrase: &[u8])
|
||||
-> Result<$t, ::error::ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
let bio = try!(::bio::MemBioSlice::new(pem));
|
||||
let passphrase = ::std::ffi::CString::new(passphrase).unwrap();
|
||||
cvt_p($f(bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
passphrase.as_ptr() as *const _ as *mut _))
|
||||
.map($t)
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserializes a PEM-formatted private key, using a callback to retrieve a password if the
|
||||
/// key is encrypted.
|
||||
///
|
||||
/// The callback should copy the password into the provided buffer and return the number of
|
||||
/// bytes written.
|
||||
pub fn private_key_from_pem_callback<F>(pem: &[u8],
|
||||
callback: F)
|
||||
-> Result<$t, ::error::ErrorStack>
|
||||
where F: FnOnce(&mut [u8]) -> Result<usize, ::error::ErrorStack>
|
||||
{
|
||||
unsafe {
|
||||
ffi::init();
|
||||
let mut cb = ::util::CallbackState::new(callback);
|
||||
let bio = try!(::bio::MemBioSlice::new(pem));
|
||||
cvt_p($f(bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
Some(::util::invoke_passwd_cb::<F>),
|
||||
&mut cb as *mut _ as *mut _))
|
||||
.map($t)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! private_key_to_pem {
|
||||
($f:path) => {
|
||||
/// Serializes the private key to PEM.
|
||||
pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ::error::ErrorStack> {
|
||||
unsafe {
|
||||
let bio = try!(::bio::MemBio::new());
|
||||
try!(cvt($f(bio.as_ptr(),
|
||||
self.as_ptr(),
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
-1,
|
||||
None,
|
||||
ptr::null_mut())));
|
||||
Ok(bio.get_buf().to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
/// Serializes the private key to PEM, encrypting it with the specified symmetric cipher and
|
||||
/// passphrase.
|
||||
pub fn private_key_to_pem_passphrase(&self,
|
||||
cipher: ::symm::Cipher,
|
||||
passphrase: &[u8])
|
||||
-> Result<Vec<u8>, ::error::ErrorStack> {
|
||||
unsafe {
|
||||
let bio = try!(::bio::MemBio::new());
|
||||
assert!(passphrase.len() <= ::libc::c_int::max_value() as usize);
|
||||
try!(cvt($f(bio.as_ptr(),
|
||||
self.as_ptr(),
|
||||
cipher.as_ptr(),
|
||||
passphrase.as_ptr() as *const _ as *mut _,
|
||||
passphrase.len() as ::libc::c_int,
|
||||
None,
|
||||
ptr::null_mut())));
|
||||
Ok(bio.get_buf().to_owned())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! to_pem_inner {
|
||||
(#[$m:meta] $n:ident, $f:path) => {
|
||||
#[$m]
|
||||
pub fn $n(&self) -> Result<Vec<u8>, ::error::ErrorStack> {
|
||||
unsafe {
|
||||
let bio = try!(::bio::MemBio::new());
|
||||
try!(cvt($f(bio.as_ptr(), self.as_ptr())));
|
||||
Ok(bio.get_buf().to_owned())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! public_key_to_pem {
|
||||
($f:path) => {
|
||||
to_pem_inner!(/// Serializes a public key to PEM.
|
||||
public_key_to_pem, $f);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! to_pem {
|
||||
($f:path) => {
|
||||
to_pem_inner!(/// Serializes this value to PEM.
|
||||
to_pem, $f);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! to_der_inner {
|
||||
(#[$m:meta] $n:ident, $f:path) => {
|
||||
#[$m]
|
||||
pub fn $n(&self) -> Result<Vec<u8>, ::error::ErrorStack> {
|
||||
unsafe {
|
||||
let len = try!(::cvt($f(::foreign_types::ForeignTypeRef::as_ptr(self),
|
||||
ptr::null_mut())));
|
||||
let mut buf = vec![0; len as usize];
|
||||
try!(::cvt($f(::foreign_types::ForeignTypeRef::as_ptr(self),
|
||||
&mut buf.as_mut_ptr())));
|
||||
Ok(buf)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! to_der {
|
||||
($f:path) => {
|
||||
to_der_inner!(/// Serializes this value to DER.
|
||||
to_der, $f);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! private_key_to_der {
|
||||
($f:path) => {
|
||||
to_der_inner!(/// Serializes the private key to DER.
|
||||
private_key_to_der, $f);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! public_key_to_der {
|
||||
($f:path) => {
|
||||
to_der_inner!(/// Serializes the public key to DER.
|
||||
public_key_to_der, $f);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! from_der_inner {
|
||||
(#[$m:meta] $n:ident, $t:ident, $f:path) => {
|
||||
#[$m]
|
||||
pub fn $n(der: &[u8]) -> Result<$t, ::error::ErrorStack> {
|
||||
unsafe {
|
||||
::ffi::init();
|
||||
let len = ::std::cmp::min(der.len(), ::libc::c_long::max_value() as usize) as ::libc::c_long;
|
||||
::cvt_p($f(::std::ptr::null_mut(), &mut der.as_ptr(), len))
|
||||
.map($t)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! from_der {
|
||||
($t:ident, $f:path) => {
|
||||
from_der_inner!(/// Deserializes a value from DER-formatted data.
|
||||
from_der, $t, $f);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! private_key_from_der {
|
||||
($t:ident, $f:path) => {
|
||||
from_der_inner!(/// Deserializes a private key from DER-formatted data.
|
||||
private_key_from_der, $t, $f);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! public_key_from_der {
|
||||
($t:ident, $f:path) => {
|
||||
from_der_inner!(/// Deserializes a public key from DER-formatted data.
|
||||
public_key_from_der, $t, $f);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! from_pem_inner {
|
||||
(#[$m:meta] $n:ident, $t:ident, $f:path) => {
|
||||
#[$m]
|
||||
pub fn $n(pem: &[u8]) -> Result<$t, ::error::ErrorStack> {
|
||||
unsafe {
|
||||
::init();
|
||||
let bio = try!(::bio::MemBioSlice::new(pem));
|
||||
cvt_p($f(bio.as_ptr(), ::std::ptr::null_mut(), None, ::std::ptr::null_mut()))
|
||||
.map($t)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! public_key_from_pem {
|
||||
($t:ident, $f:path) => {
|
||||
from_pem_inner!(/// Deserializes a public key from PEM-formatted data.
|
||||
public_key_from_pem, $t, $f);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! from_pem {
|
||||
($t:ident, $f:path) => {
|
||||
from_pem_inner!(/// Deserializes a value from PEM-formatted data.
|
||||
from_pem, $t, $f);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,304 @@
|
|||
use ffi;
|
||||
use foreign_types::ForeignTypeRef;
|
||||
use libc::{c_int, c_long, c_ulong};
|
||||
use std::ptr;
|
||||
use std::mem;
|
||||
|
||||
use {cvt, cvt_p};
|
||||
use asn1::Asn1GeneralizedTimeRef;
|
||||
use error::ErrorStack;
|
||||
use hash::MessageDigest;
|
||||
use stack::StackRef;
|
||||
use x509::store::X509StoreRef;
|
||||
use x509::{X509, X509Ref};
|
||||
|
||||
bitflags! {
|
||||
pub flags Flag: c_ulong {
|
||||
const FLAG_NO_CERTS = ffi::OCSP_NOCERTS,
|
||||
const FLAG_NO_INTERN = ffi::OCSP_NOINTERN,
|
||||
const FLAG_NO_CHAIN = ffi::OCSP_NOCHAIN,
|
||||
const FLAG_NO_VERIFY = ffi::OCSP_NOVERIFY,
|
||||
const FLAG_NO_EXPLICIT = ffi::OCSP_NOEXPLICIT,
|
||||
const FLAG_NO_CA_SIGN = ffi::OCSP_NOCASIGN,
|
||||
const FLAG_NO_DELEGATED = ffi::OCSP_NODELEGATED,
|
||||
const FLAG_NO_CHECKS = ffi::OCSP_NOCHECKS,
|
||||
const FLAG_TRUST_OTHER = ffi::OCSP_TRUSTOTHER,
|
||||
const FLAG_RESPID_KEY = ffi::OCSP_RESPID_KEY,
|
||||
const FLAG_NO_TIME = ffi::OCSP_NOTIME,
|
||||
}
|
||||
}
|
||||
|
||||
pub const RESPONSE_STATUS_SUCCESSFUL: OcspResponseStatus =
|
||||
OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_SUCCESSFUL);
|
||||
pub const RESPONSE_STATUS_MALFORMED_REQUEST: OcspResponseStatus =
|
||||
OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_MALFORMEDREQUEST);
|
||||
pub const RESPONSE_STATUS_INTERNAL_ERROR: OcspResponseStatus =
|
||||
OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_INTERNALERROR);
|
||||
pub const RESPONSE_STATUS_TRY_LATER: OcspResponseStatus =
|
||||
OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_TRYLATER);
|
||||
pub const RESPONSE_STATUS_SIG_REQUIRED: OcspResponseStatus =
|
||||
OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_SIGREQUIRED);
|
||||
pub const RESPONSE_STATUS_UNAUTHORIZED: OcspResponseStatus =
|
||||
OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_UNAUTHORIZED);
|
||||
|
||||
pub const CERT_STATUS_GOOD: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_GOOD);
|
||||
pub const CERT_STATUS_REVOKED: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_REVOKED);
|
||||
pub const CERT_STATUS_UNKNOWN: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_UNKNOWN);
|
||||
|
||||
pub const REVOKED_STATUS_NO_STATUS: OcspRevokedStatus =
|
||||
OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_NOSTATUS);
|
||||
pub const REVOKED_STATUS_UNSPECIFIED: OcspRevokedStatus =
|
||||
OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_UNSPECIFIED);
|
||||
pub const REVOKED_STATUS_KEY_COMPROMISE: OcspRevokedStatus =
|
||||
OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_KEYCOMPROMISE);
|
||||
pub const REVOKED_STATUS_CA_COMPROMISE: OcspRevokedStatus =
|
||||
OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CACOMPROMISE);
|
||||
pub const REVOKED_STATUS_AFFILIATION_CHANGED: OcspRevokedStatus =
|
||||
OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_AFFILIATIONCHANGED);
|
||||
pub const REVOKED_STATUS_SUPERSEDED: OcspRevokedStatus =
|
||||
OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_SUPERSEDED);
|
||||
pub const REVOKED_STATUS_CESSATION_OF_OPERATION: OcspRevokedStatus =
|
||||
OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CESSATIONOFOPERATION);
|
||||
pub const REVOKED_STATUS_CERTIFICATE_HOLD: OcspRevokedStatus =
|
||||
OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CERTIFICATEHOLD);
|
||||
pub const REVOKED_STATUS_REMOVE_FROM_CRL: OcspRevokedStatus =
|
||||
OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_REMOVEFROMCRL);
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct OcspResponseStatus(c_int);
|
||||
|
||||
impl OcspResponseStatus {
|
||||
pub fn from_raw(raw: c_int) -> OcspResponseStatus {
|
||||
OcspResponseStatus(raw)
|
||||
}
|
||||
|
||||
pub fn as_raw(&self) -> c_int {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct OcspCertStatus(c_int);
|
||||
|
||||
impl OcspCertStatus {
|
||||
pub fn from_raw(raw: c_int) -> OcspCertStatus {
|
||||
OcspCertStatus(raw)
|
||||
}
|
||||
|
||||
pub fn as_raw(&self) -> c_int {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct OcspRevokedStatus(c_int);
|
||||
|
||||
impl OcspRevokedStatus {
|
||||
pub fn from_raw(raw: c_int) -> OcspRevokedStatus {
|
||||
OcspRevokedStatus(raw)
|
||||
}
|
||||
|
||||
pub fn as_raw(&self) -> c_int {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Status<'a> {
|
||||
/// The overall status of the response.
|
||||
pub status: OcspCertStatus,
|
||||
/// If `status` is `CERT_STATUS_REVOKED`, the reason for the revocation.
|
||||
pub reason: OcspRevokedStatus,
|
||||
/// If `status` is `CERT_STATUS_REVOKED`, the time at which the certificate was revoked.
|
||||
pub revocation_time: Option<&'a Asn1GeneralizedTimeRef>,
|
||||
/// The time that this revocation check was performed.
|
||||
pub this_update: &'a Asn1GeneralizedTimeRef,
|
||||
/// The time at which this revocation check expires.
|
||||
pub next_update: &'a Asn1GeneralizedTimeRef,
|
||||
}
|
||||
|
||||
impl<'a> Status<'a> {
|
||||
/// Checks validity of the `this_update` and `next_update` fields.
|
||||
///
|
||||
/// The `nsec` parameter specifies an amount of slack time that will be used when comparing
|
||||
/// those times with the current time to account for delays and clock skew.
|
||||
///
|
||||
/// The `maxsec` parameter limits the maximum age of the `this_update` parameter to prohibit
|
||||
/// very old responses.
|
||||
pub fn check_validity(&self, nsec: u32, maxsec: Option<u32>) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::OCSP_check_validity(self.this_update.as_ptr(),
|
||||
self.next_update.as_ptr(),
|
||||
nsec as c_long,
|
||||
maxsec.map(|n| n as c_long).unwrap_or(-1)))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = ffi::OCSP_BASICRESP;
|
||||
fn drop = ffi::OCSP_BASICRESP_free;
|
||||
|
||||
pub struct OcspBasicResponse;
|
||||
pub struct OcspBasicResponseRef;
|
||||
}
|
||||
|
||||
impl OcspBasicResponseRef {
|
||||
/// Verifies the validity of the response.
|
||||
///
|
||||
/// The `certs` parameter contains a set of certificates that will be searched when locating the
|
||||
/// OCSP response signing certificate. Some responders do not include this in the response.
|
||||
pub fn verify(&self,
|
||||
certs: &StackRef<X509>,
|
||||
store: &X509StoreRef,
|
||||
flags: Flag)
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::OCSP_basic_verify(self.as_ptr(), certs.as_ptr(), store.as_ptr(), flags.bits()))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Looks up the status for the specified certificate ID.
|
||||
pub fn find_status<'a>(&'a self, id: &OcspCertIdRef) -> Option<Status<'a>> {
|
||||
unsafe {
|
||||
let mut status = ffi::V_OCSP_CERTSTATUS_UNKNOWN;
|
||||
let mut reason = ffi::OCSP_REVOKED_STATUS_NOSTATUS;
|
||||
let mut revocation_time = ptr::null_mut();
|
||||
let mut this_update = ptr::null_mut();
|
||||
let mut next_update = ptr::null_mut();
|
||||
|
||||
let r = ffi::OCSP_resp_find_status(self.as_ptr(),
|
||||
id.as_ptr(),
|
||||
&mut status,
|
||||
&mut reason,
|
||||
&mut revocation_time,
|
||||
&mut this_update,
|
||||
&mut next_update);
|
||||
if r == 1 {
|
||||
let revocation_time = if revocation_time.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(Asn1GeneralizedTimeRef::from_ptr(revocation_time))
|
||||
};
|
||||
Some(Status {
|
||||
status: OcspCertStatus(status),
|
||||
reason: OcspRevokedStatus(status),
|
||||
revocation_time: revocation_time,
|
||||
this_update: Asn1GeneralizedTimeRef::from_ptr(this_update),
|
||||
next_update: Asn1GeneralizedTimeRef::from_ptr(next_update),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = ffi::OCSP_CERTID;
|
||||
fn drop = ffi::OCSP_CERTID_free;
|
||||
|
||||
pub struct OcspCertId;
|
||||
pub struct OcspCertIdRef;
|
||||
}
|
||||
|
||||
impl OcspCertId {
|
||||
/// Constructs a certificate ID for certificate `subject`.
|
||||
pub fn from_cert(digest: MessageDigest,
|
||||
subject: &X509Ref,
|
||||
issuer: &X509Ref)
|
||||
-> Result<OcspCertId, ErrorStack> {
|
||||
unsafe {
|
||||
cvt_p(ffi::OCSP_cert_to_id(digest.as_ptr(), subject.as_ptr(), issuer.as_ptr()))
|
||||
.map(OcspCertId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = ffi::OCSP_RESPONSE;
|
||||
fn drop = ffi::OCSP_RESPONSE_free;
|
||||
|
||||
pub struct OcspResponse;
|
||||
pub struct OcspResponseRef;
|
||||
}
|
||||
|
||||
impl OcspResponse {
|
||||
/// Creates an OCSP response from the status and optional body.
|
||||
///
|
||||
/// A body should only be provided if `status` is `RESPONSE_STATUS_SUCCESSFUL`.
|
||||
pub fn create(status: OcspResponseStatus,
|
||||
body: Option<&OcspBasicResponseRef>)
|
||||
-> Result<OcspResponse, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
|
||||
cvt_p(ffi::OCSP_response_create(status.as_raw(),
|
||||
body.map(|r| r.as_ptr()).unwrap_or(ptr::null_mut())))
|
||||
.map(OcspResponse)
|
||||
}
|
||||
}
|
||||
|
||||
from_der!(OcspResponse, ffi::d2i_OCSP_RESPONSE);
|
||||
}
|
||||
|
||||
impl OcspResponseRef {
|
||||
to_der!(ffi::i2d_OCSP_RESPONSE);
|
||||
|
||||
/// Returns the status of the response.
|
||||
pub fn status(&self) -> OcspResponseStatus {
|
||||
unsafe {
|
||||
OcspResponseStatus(ffi::OCSP_response_status(self.as_ptr()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the basic response.
|
||||
///
|
||||
/// This will only succeed if `status()` returns `RESPONSE_STATUS_SUCCESSFUL`.
|
||||
pub fn basic(&self) -> Result<OcspBasicResponse, ErrorStack> {
|
||||
unsafe {
|
||||
cvt_p(ffi::OCSP_response_get1_basic(self.as_ptr())).map(OcspBasicResponse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = ffi::OCSP_REQUEST;
|
||||
fn drop = ffi::OCSP_REQUEST_free;
|
||||
|
||||
pub struct OcspRequest;
|
||||
pub struct OcspRequestRef;
|
||||
}
|
||||
|
||||
impl OcspRequest {
|
||||
pub fn new() -> Result<OcspRequest, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
|
||||
cvt_p(ffi::OCSP_REQUEST_new()).map(OcspRequest)
|
||||
}
|
||||
}
|
||||
|
||||
from_der!(OcspRequest, ffi::d2i_OCSP_REQUEST);
|
||||
}
|
||||
|
||||
impl OcspRequestRef {
|
||||
to_der!(ffi::i2d_OCSP_REQUEST);
|
||||
|
||||
pub fn add_id(&mut self, id: OcspCertId) -> Result<&mut OcspOneReqRef, ErrorStack> {
|
||||
unsafe {
|
||||
let ptr = try!(cvt_p(ffi::OCSP_request_add0_id(self.as_ptr(), id.as_ptr())));
|
||||
mem::forget(id);
|
||||
Ok(OcspOneReqRef::from_ptr_mut(ptr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = ffi::OCSP_ONEREQ;
|
||||
fn drop = ffi::OCSP_ONEREQ_free;
|
||||
|
||||
pub struct OcspOneReq;
|
||||
pub struct OcspOneReqRef;
|
||||
}
|
||||
|
|
@ -1,35 +1,31 @@
|
|||
//! PKCS #12 archives.
|
||||
|
||||
use ffi;
|
||||
use libc::{c_long, c_uchar};
|
||||
use std::cmp;
|
||||
use foreign_types::{ForeignType, ForeignTypeRef};
|
||||
use libc::c_int;
|
||||
use std::ptr;
|
||||
use std::ffi::CString;
|
||||
|
||||
use {cvt, cvt_p};
|
||||
use pkey::PKey;
|
||||
use pkey::{PKey, PKeyRef};
|
||||
use error::ErrorStack;
|
||||
use x509::X509;
|
||||
use types::{OpenSslType, OpenSslTypeRef};
|
||||
use stack::Stack;
|
||||
use nid;
|
||||
|
||||
type_!(Pkcs12, Pkcs12Ref, ffi::PKCS12, ffi::PKCS12_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::PKCS12;
|
||||
fn drop = ffi::PKCS12_free;
|
||||
|
||||
impl Pkcs12 {
|
||||
/// Deserializes a `Pkcs12` structure from DER-encoded data.
|
||||
pub fn from_der(der: &[u8]) -> Result<Pkcs12, ErrorStack> {
|
||||
unsafe {
|
||||
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!(cvt_p(ffi::d2i_PKCS12(ptr::null_mut(), &mut ptr, length)));
|
||||
Ok(Pkcs12(p12))
|
||||
}
|
||||
}
|
||||
pub struct Pkcs12;
|
||||
pub struct Pkcs12Ref;
|
||||
}
|
||||
|
||||
impl Pkcs12Ref {
|
||||
to_der!(ffi::i2d_PKCS12);
|
||||
|
||||
/// Extracts the contents of the `Pkcs12`.
|
||||
// FIXME should take an &[u8]
|
||||
pub fn parse(&self, pass: &str) -> Result<ParsedPkcs12, ErrorStack> {
|
||||
unsafe {
|
||||
let pass = CString::new(pass).unwrap();
|
||||
|
|
@ -57,16 +53,132 @@ impl Pkcs12Ref {
|
|||
}
|
||||
}
|
||||
|
||||
impl Pkcs12 {
|
||||
from_der!(Pkcs12, ffi::d2i_PKCS12);
|
||||
|
||||
/// Creates a new builder for a protected pkcs12 certificate.
|
||||
///
|
||||
/// This uses the defaults from the OpenSSL library:
|
||||
///
|
||||
/// * `nid_key` - `nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC`
|
||||
/// * `nid_cert` - `nid::PBE_WITHSHA1AND40BITRC2_CBC`
|
||||
/// * `iter` - `2048`
|
||||
/// * `mac_iter` - `2048`
|
||||
pub fn builder() -> Pkcs12Builder {
|
||||
ffi::init();
|
||||
|
||||
Pkcs12Builder {
|
||||
nid_key: nid::UNDEF, //nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC,
|
||||
nid_cert: nid::UNDEF, //nid::PBE_WITHSHA1AND40BITRC2_CBC,
|
||||
iter: ffi::PKCS12_DEFAULT_ITER,
|
||||
mac_iter: ffi::PKCS12_DEFAULT_ITER,
|
||||
ca: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ParsedPkcs12 {
|
||||
pub pkey: PKey,
|
||||
pub cert: X509,
|
||||
pub chain: Stack<X509>,
|
||||
}
|
||||
|
||||
pub struct Pkcs12Builder {
|
||||
nid_key: nid::Nid,
|
||||
nid_cert: nid::Nid,
|
||||
iter: c_int,
|
||||
mac_iter: c_int,
|
||||
ca: Option<Stack<X509>>,
|
||||
}
|
||||
|
||||
impl Pkcs12Builder {
|
||||
/// The encryption algorithm that should be used for the key
|
||||
pub fn key_algorithm(&mut self, nid: nid::Nid) -> &mut Self {
|
||||
self.nid_key = nid;
|
||||
self
|
||||
}
|
||||
|
||||
/// The encryption algorithm that should be used for the cert
|
||||
pub fn cert_algorithm(&mut self, nid: nid::Nid) -> &mut Self {
|
||||
self.nid_cert = nid;
|
||||
self
|
||||
}
|
||||
|
||||
/// Key iteration count, default is 2048 as of this writing
|
||||
pub fn key_iter(&mut self, iter: u32) -> &mut Self {
|
||||
self.iter = iter as c_int;
|
||||
self
|
||||
}
|
||||
|
||||
/// MAC iteration count, default is the same as key_iter.
|
||||
///
|
||||
/// Old implementations don't understand MAC iterations greater than 1, (pre 1.0.1?), if such
|
||||
/// compatibility is required this should be set to 1.
|
||||
pub fn mac_iter(&mut self, mac_iter: u32) -> &mut Self {
|
||||
self.mac_iter = mac_iter as c_int;
|
||||
self
|
||||
}
|
||||
|
||||
/// An additional set of certificates to include in the archive beyond the one provided to
|
||||
/// `build`.
|
||||
pub fn ca(&mut self, ca: Stack<X509>) -> &mut Self {
|
||||
self.ca = Some(ca);
|
||||
self
|
||||
}
|
||||
|
||||
/// Builds the PKCS #12 object
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `password` - the password used to encrypt the key and certificate
|
||||
/// * `friendly_name` - user defined name for the certificate
|
||||
/// * `pkey` - key to store
|
||||
/// * `cert` - certificate to store
|
||||
pub fn build(self,
|
||||
password: &str,
|
||||
friendly_name: &str,
|
||||
pkey: &PKeyRef,
|
||||
cert: &X509) -> Result<Pkcs12, ErrorStack> {
|
||||
unsafe {
|
||||
let pass = CString::new(password).unwrap();
|
||||
let friendly_name = CString::new(friendly_name).unwrap();
|
||||
let pkey = pkey.as_ptr();
|
||||
let cert = cert.as_ptr();
|
||||
let ca = self.ca.as_ref().map(|ca| ca.as_ptr()).unwrap_or(ptr::null_mut());
|
||||
let nid_key = self.nid_key.as_raw();
|
||||
let nid_cert = self.nid_cert.as_raw();
|
||||
|
||||
// According to the OpenSSL docs, keytype is a non-standard extension for MSIE,
|
||||
// It's values are KEY_SIG or KEY_EX, see the OpenSSL docs for more information:
|
||||
// https://www.openssl.org/docs/man1.0.2/crypto/PKCS12_create.html
|
||||
let keytype = 0;
|
||||
|
||||
cvt_p(ffi::PKCS12_create(pass.as_ptr() as *const _ as *mut _,
|
||||
friendly_name.as_ptr() as *const _ as *mut _,
|
||||
pkey,
|
||||
cert,
|
||||
ca,
|
||||
nid_key,
|
||||
nid_cert,
|
||||
self.iter,
|
||||
self.mac_iter,
|
||||
keytype))
|
||||
.map(Pkcs12)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use hash::MessageDigest;
|
||||
use serialize::hex::ToHex;
|
||||
use hex::ToHex;
|
||||
|
||||
use asn1::Asn1Time;
|
||||
use rsa::Rsa;
|
||||
use pkey::PKey;
|
||||
use nid;
|
||||
use x509::{X509, X509Name};
|
||||
use x509::extension::KeyUsage;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -83,4 +195,38 @@ mod test {
|
|||
assert_eq!(parsed.chain[0].fingerprint(MessageDigest::sha1()).unwrap().to_hex(),
|
||||
"c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create() {
|
||||
let subject_name = "ns.example.com";
|
||||
let rsa = Rsa::generate(2048).unwrap();
|
||||
let pkey = PKey::from_rsa(rsa).unwrap();
|
||||
|
||||
let mut name = X509Name::builder().unwrap();
|
||||
name.append_entry_by_nid(nid::COMMONNAME, subject_name).unwrap();
|
||||
let name = name.build();
|
||||
|
||||
let key_usage = KeyUsage::new().digital_signature().build().unwrap();;
|
||||
|
||||
let mut builder = X509::builder().unwrap();
|
||||
builder.set_version(2).unwrap();
|
||||
builder.set_not_before(&Asn1Time::days_from_now(0).unwrap()).unwrap();
|
||||
builder.set_not_after(&Asn1Time::days_from_now(365).unwrap()).unwrap();
|
||||
builder.set_subject_name(&name).unwrap();
|
||||
builder.set_issuer_name(&name).unwrap();
|
||||
builder.append_extension(key_usage).unwrap();
|
||||
builder.set_pubkey(&pkey).unwrap();
|
||||
builder.sign(&pkey, MessageDigest::sha256()).unwrap();
|
||||
let cert = builder.build();
|
||||
|
||||
let pkcs12_builder = Pkcs12::builder();
|
||||
let pkcs12 = pkcs12_builder.build("mypass", subject_name, &pkey, &cert).unwrap();
|
||||
let der = pkcs12.to_der().unwrap();
|
||||
|
||||
let pkcs12 = Pkcs12::from_der(&der).unwrap();
|
||||
let parsed = pkcs12.parse("mypass").unwrap();
|
||||
|
||||
assert_eq!(parsed.cert.fingerprint(MessageDigest::sha1()).unwrap(), cert.fingerprint(MessageDigest::sha1()).unwrap());
|
||||
assert!(parsed.pkey.public_eq(&pkey));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ pub struct KeyIvPair {
|
|||
/// 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.
|
||||
/// `pbkdf2_hmac` or another more modern key derivation algorithm.
|
||||
pub fn bytes_to_key(cipher: Cipher,
|
||||
digest: MessageDigest,
|
||||
data: &[u8],
|
||||
|
|
|
|||
|
|
@ -2,62 +2,73 @@ use libc::{c_void, c_char, c_int};
|
|||
use std::ptr;
|
||||
use std::mem;
|
||||
use ffi;
|
||||
use foreign_types::{Opaque, ForeignType, ForeignTypeRef};
|
||||
|
||||
use {cvt, cvt_p};
|
||||
use bio::{MemBio, MemBioSlice};
|
||||
use bio::MemBioSlice;
|
||||
use dh::Dh;
|
||||
use dsa::Dsa;
|
||||
use rsa::Rsa;
|
||||
use ec::EcKey;
|
||||
use rsa::{Rsa, Padding};
|
||||
use error::ErrorStack;
|
||||
use util::{CallbackState, invoke_passwd_cb};
|
||||
use types::{OpenSslType, OpenSslTypeRef};
|
||||
use util::{CallbackState, invoke_passwd_cb_old};
|
||||
|
||||
type_!(PKey, PKeyRef, ffi::EVP_PKEY, ffi::EVP_PKEY_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::EVP_PKEY;
|
||||
fn drop = ffi::EVP_PKEY_free;
|
||||
|
||||
pub struct PKey;
|
||||
pub struct PKeyRef;
|
||||
}
|
||||
|
||||
impl PKeyRef {
|
||||
/// Get a reference to the interal RSA key for direct access to the key components
|
||||
/// Returns a copy of the internal RSA key.
|
||||
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());
|
||||
/// Returns a copy of the internal DSA key.
|
||||
pub fn dsa(&self) -> Result<Dsa, ErrorStack> {
|
||||
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())));
|
||||
|
||||
let dsa = try!(cvt_p(ffi::EVP_PKEY_get1_DSA(self.as_ptr())));
|
||||
Ok(Dsa::from_ptr(dsa))
|
||||
}
|
||||
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());
|
||||
/// Returns a copy of the internal DH key.
|
||||
pub fn dh(&self) -> Result<Dh, ErrorStack> {
|
||||
unsafe {
|
||||
try!(cvt(ffi::PEM_write_bio_PUBKEY(mem_bio.as_ptr(), self.as_ptr())));
|
||||
let dh = try!(cvt_p(ffi::EVP_PKEY_get1_DH(self.as_ptr())));
|
||||
Ok(Dh::from_ptr(dh))
|
||||
}
|
||||
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());
|
||||
/// Returns a copy of the internal elliptic curve key.
|
||||
pub fn ec_key(&self) -> Result<EcKey, ErrorStack> {
|
||||
unsafe {
|
||||
try!(cvt(ffi::i2d_PUBKEY_bio(mem_bio.as_ptr(), self.as_ptr())));
|
||||
let ec_key = try!(cvt_p(ffi::EVP_PKEY_get1_EC_KEY(self.as_ptr())));
|
||||
Ok(EcKey::from_ptr(ec_key))
|
||||
}
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
public_key_to_pem!(ffi::PEM_write_bio_PUBKEY);
|
||||
private_key_to_pem!(ffi::PEM_write_bio_PKCS8PrivateKey);
|
||||
|
||||
private_key_to_der!(ffi::i2d_PrivateKey);
|
||||
public_key_to_der!(ffi::i2d_PUBKEY);
|
||||
|
||||
/// Returns the size of the key.
|
||||
///
|
||||
/// This corresponds to the bit length of the modulus of an RSA key, and the bit length of the
|
||||
/// group order for an elliptic curve key, for example.
|
||||
pub fn bits(&self) -> u32 {
|
||||
unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as u32 }
|
||||
}
|
||||
|
||||
/// Compares the public component of this key with another.
|
||||
pub fn public_eq(&self, other: &PKeyRef) -> bool {
|
||||
unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 }
|
||||
}
|
||||
|
|
@ -67,7 +78,7 @@ unsafe impl Send for PKey {}
|
|||
unsafe impl Sync for PKey {}
|
||||
|
||||
impl PKey {
|
||||
/// Create a new `PKey` containing an RSA key.
|
||||
/// Creates 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()));
|
||||
|
|
@ -78,7 +89,7 @@ impl PKey {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create a new `PKey` containing a DSA key.
|
||||
/// Creates 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()));
|
||||
|
|
@ -89,7 +100,32 @@ impl PKey {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create a new `PKey` containing an HMAC key.
|
||||
/// Creates a new `PKey` containing a Diffie-Hellman key.
|
||||
pub fn from_dh(dh: Dh) -> 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_DH, dh.as_ptr() as *mut _)));
|
||||
mem::forget(dh);
|
||||
Ok(pkey)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `PKey` containing an elliptic curve key.
|
||||
pub fn from_ec_key(ec_key: EcKey) -> 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_EC, ec_key.as_ptr() as *mut _)));
|
||||
mem::forget(ec_key);
|
||||
Ok(pkey)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `PKey` containing an HMAC key.
|
||||
///
|
||||
/// # Note
|
||||
/// To compute HMAC values, use the `sign` module.
|
||||
pub fn hmac(key: &[u8]) -> Result<PKey, ErrorStack> {
|
||||
unsafe {
|
||||
assert!(key.len() <= c_int::max_value() as usize);
|
||||
|
|
@ -101,24 +137,10 @@ impl PKey {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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))
|
||||
}
|
||||
}
|
||||
private_key_from_pem!(PKey, ffi::PEM_read_bio_PrivateKey);
|
||||
public_key_from_pem!(PKey, ffi::PEM_read_bio_PUBKEY);
|
||||
|
||||
/// 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.
|
||||
#[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")]
|
||||
pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<PKey, ErrorStack>
|
||||
where F: FnOnce(&mut [c_char]) -> usize
|
||||
{
|
||||
|
|
@ -128,44 +150,72 @@ impl PKey {
|
|||
unsafe {
|
||||
let evp = try!(cvt_p(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
Some(invoke_passwd_cb::<F>),
|
||||
Some(invoke_passwd_cb_old::<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));
|
||||
pub struct PKeyCtxRef(Opaque);
|
||||
|
||||
impl PKeyCtxRef {
|
||||
pub fn set_rsa_padding(&mut self, pad: Padding) -> Result<(), ErrorStack> {
|
||||
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))
|
||||
try!(cvt(ffi::EVP_PKEY_CTX_set_rsa_padding(self.as_ptr(), pad.as_raw())));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn rsa_padding(&self) -> Result<Padding, ErrorStack> {
|
||||
let mut pad: c_int = 0;
|
||||
unsafe {
|
||||
try!(cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.as_ptr(), &mut pad)));
|
||||
};
|
||||
Ok(Padding::from_raw(pad))
|
||||
}
|
||||
}
|
||||
|
||||
impl ForeignTypeRef for PKeyCtxRef {
|
||||
type CType = ffi::EVP_PKEY_CTX;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use symm::Cipher;
|
||||
use dh::Dh;
|
||||
use dsa::Dsa;
|
||||
use ec::EcKey;
|
||||
use rsa::Rsa;
|
||||
use nid;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_password() {
|
||||
let rsa = Rsa::generate(2048).unwrap();
|
||||
let pkey = PKey::from_rsa(rsa).unwrap();
|
||||
let pem = pkey.private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar").unwrap();
|
||||
PKey::private_key_from_pem_passphrase(&pem, b"foobar").unwrap();
|
||||
assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_private_key_from_pem() {
|
||||
let key = include_bytes!("../test/key.pem");
|
||||
super::PKey::private_key_from_pem(key).unwrap();
|
||||
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();
|
||||
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 key = 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();
|
||||
|
|
@ -175,4 +225,37 @@ mod tests {
|
|||
assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY"));
|
||||
assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rsa_accessor() {
|
||||
let rsa = Rsa::generate(2048).unwrap();
|
||||
let pkey = PKey::from_rsa(rsa).unwrap();
|
||||
pkey.rsa().unwrap();
|
||||
assert!(pkey.dsa().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dsa_accessor() {
|
||||
let dsa = Dsa::generate(2048).unwrap();
|
||||
let pkey = PKey::from_dsa(dsa).unwrap();
|
||||
pkey.dsa().unwrap();
|
||||
assert!(pkey.rsa().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dh_accessor() {
|
||||
let dh = include_bytes!("../test/dhparams.pem");
|
||||
let dh = Dh::from_pem(dh).unwrap();
|
||||
let pkey = PKey::from_dh(dh).unwrap();
|
||||
pkey.dh().unwrap();
|
||||
assert!(pkey.rsa().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ec_key_accessor() {
|
||||
let ec_key = EcKey::from_curve_name(nid::X9_62_PRIME256V1).unwrap();
|
||||
let pkey = PKey::from_ec_key(ec_key).unwrap();
|
||||
pkey.ec_key().unwrap();
|
||||
assert!(pkey.rsa().is_err());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,52 +3,48 @@ use std::fmt;
|
|||
use std::ptr;
|
||||
use std::mem;
|
||||
use libc::{c_int, c_void, c_char};
|
||||
use foreign_types::ForeignTypeRef;
|
||||
|
||||
use {cvt, cvt_p, cvt_n};
|
||||
use bn::{BigNum, BigNumRef};
|
||||
use bio::{MemBio, MemBioSlice};
|
||||
use bio::MemBioSlice;
|
||||
use error::ErrorStack;
|
||||
use util::{CallbackState, invoke_passwd_cb};
|
||||
use types::OpenSslTypeRef;
|
||||
use util::{CallbackState, invoke_passwd_cb_old};
|
||||
|
||||
/// Type of encryption padding to use.
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct Padding(c_int);
|
||||
|
||||
impl Padding {
|
||||
pub fn from_raw(value: c_int) -> Padding {
|
||||
Padding(value)
|
||||
}
|
||||
|
||||
pub fn as_raw(&self) -> c_int {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
foreign_type! {
|
||||
type CType = ffi::RSA;
|
||||
fn drop = ffi::RSA_free;
|
||||
|
||||
pub struct Rsa;
|
||||
pub struct RsaRef;
|
||||
}
|
||||
|
||||
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());
|
||||
private_key_to_pem!(ffi::PEM_write_bio_RSAPrivateKey);
|
||||
public_key_to_pem!(ffi::PEM_write_bio_RSA_PUBKEY);
|
||||
|
||||
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())
|
||||
}
|
||||
private_key_to_der!(ffi::i2d_RSAPrivateKey);
|
||||
public_key_to_der!(ffi::i2d_RSA_PUBKEY);
|
||||
|
||||
// FIXME should return u32
|
||||
pub fn size(&self) -> usize {
|
||||
unsafe {
|
||||
assert!(self.n().is_some());
|
||||
|
|
@ -250,6 +246,7 @@ impl Rsa {
|
|||
///
|
||||
/// The public exponent will be 65537.
|
||||
pub fn generate(bits: u32) -> Result<Rsa, ErrorStack> {
|
||||
ffi::init();
|
||||
unsafe {
|
||||
let rsa = Rsa(try!(cvt_p(ffi::RSA_new())));
|
||||
let e = try!(BigNum::from_u32(ffi::RSA_F4 as u32));
|
||||
|
|
@ -258,22 +255,16 @@ impl 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))
|
||||
}
|
||||
}
|
||||
private_key_from_pem!(Rsa, ffi::PEM_read_bio_RSAPrivateKey);
|
||||
private_key_from_der!(Rsa, ffi::d2i_RSAPrivateKey);
|
||||
public_key_from_pem!(Rsa, ffi::PEM_read_bio_RSA_PUBKEY);
|
||||
public_key_from_der!(Rsa, ffi::d2i_RSA_PUBKEY);
|
||||
|
||||
/// Reads an RSA private key from PEM formatted data and supplies a password callback.
|
||||
#[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")]
|
||||
pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<Rsa, ErrorStack>
|
||||
where F: FnOnce(&mut [c_char]) -> usize
|
||||
{
|
||||
ffi::init();
|
||||
let mut cb = CallbackState::new(pass_cb);
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
|
||||
|
|
@ -281,23 +272,11 @@ impl Rsa {
|
|||
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>),
|
||||
Some(invoke_passwd_cb_old::<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 {
|
||||
|
|
@ -380,26 +359,26 @@ mod compat {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use libc::c_char;
|
||||
use symm::Cipher;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
pub fn test_password() {
|
||||
fn test_from_password() {
|
||||
let key = include_bytes!("../test/rsa-encrypted.pem");
|
||||
Rsa::private_key_from_pem_passphrase(key, b"mypass").unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_password_callback() {
|
||||
let mut password_queried = false;
|
||||
let key = include_bytes!("../test/rsa-encrypted.pem");
|
||||
Rsa::private_key_from_pem_cb(key, |password| {
|
||||
Rsa::private_key_from_pem_callback(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
|
||||
password[..6].copy_from_slice(b"mypass");
|
||||
Ok(6)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
|
|
@ -407,7 +386,15 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_public_encrypt_private_decrypt_with_padding() {
|
||||
fn test_to_password() {
|
||||
let key = Rsa::generate(2048).unwrap();
|
||||
let pem = key.private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar").unwrap();
|
||||
Rsa::private_key_from_pem_passphrase(&pem, b"foobar").unwrap();
|
||||
assert!(Rsa::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
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();
|
||||
|
||||
|
|
|
|||
|
|
@ -35,12 +35,13 @@
|
|||
//! assert!(verifier.finish(&signature).unwrap());
|
||||
//! ```
|
||||
//!
|
||||
//! Compute an HMAC (note that `Verifier` cannot be used with HMACs):
|
||||
//! Compute an HMAC:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use openssl::sign::Signer;
|
||||
//! use openssl::pkey::PKey;
|
||||
//! use openssl::hash::MessageDigest;
|
||||
//! use openssl::memcmp;
|
||||
//! use openssl::pkey::PKey;
|
||||
//! use openssl::sign::Signer;
|
||||
//!
|
||||
//! // Create a PKey
|
||||
//! let key = PKey::hmac(b"my secret").unwrap();
|
||||
|
|
@ -53,29 +54,40 @@
|
|||
//! signer.update(data).unwrap();
|
||||
//! signer.update(data2).unwrap();
|
||||
//! let hmac = signer.finish().unwrap();
|
||||
//!
|
||||
//! // `Verifier` cannot be used with HMACs; use the `memcmp::eq` function instead
|
||||
//! //
|
||||
//! // Do not simply check for equality with `==`!
|
||||
//! # let target = hmac.clone();
|
||||
//! assert!(memcmp::eq(&hmac, &target));
|
||||
//! ```
|
||||
use ffi;
|
||||
use foreign_types::ForeignTypeRef;
|
||||
use std::io::{self, Write};
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr;
|
||||
|
||||
use {cvt, cvt_p};
|
||||
use hash::MessageDigest;
|
||||
use pkey::PKeyRef;
|
||||
use pkey::{PKeyRef, PKeyCtxRef};
|
||||
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>);
|
||||
pub struct Signer<'a> {
|
||||
md_ctx: *mut ffi::EVP_MD_CTX,
|
||||
pkey_ctx: *mut ffi::EVP_PKEY_CTX,
|
||||
pkey_pd: PhantomData<&'a PKeyRef>,
|
||||
}
|
||||
|
||||
impl<'a> Drop for Signer<'a> {
|
||||
fn drop(&mut self) {
|
||||
// pkey_ctx is owned by the md_ctx, so no need to explicitly free it.
|
||||
unsafe {
|
||||
EVP_MD_CTX_free(self.0);
|
||||
EVP_MD_CTX_free(self.md_ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -86,8 +98,9 @@ impl<'a> Signer<'a> {
|
|||
ffi::init();
|
||||
|
||||
let ctx = try!(cvt_p(EVP_MD_CTX_new()));
|
||||
let mut pctx: *mut ffi::EVP_PKEY_CTX = ptr::null_mut();
|
||||
let r = ffi::EVP_DigestSignInit(ctx,
|
||||
ptr::null_mut(),
|
||||
&mut pctx,
|
||||
type_.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
pkey.as_ptr());
|
||||
|
|
@ -95,22 +108,37 @@ impl<'a> Signer<'a> {
|
|||
EVP_MD_CTX_free(ctx);
|
||||
return Err(ErrorStack::get());
|
||||
}
|
||||
Ok(Signer(ctx, PhantomData))
|
||||
|
||||
assert!(!pctx.is_null());
|
||||
|
||||
Ok(Signer {
|
||||
md_ctx: ctx,
|
||||
pkey_ctx: pctx,
|
||||
pkey_pd: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pkey_ctx(&self) -> &PKeyCtxRef {
|
||||
unsafe { PKeyCtxRef::from_ptr(self.pkey_ctx) }
|
||||
}
|
||||
|
||||
pub fn pkey_ctx_mut(&mut self) -> &mut PKeyCtxRef {
|
||||
unsafe { PKeyCtxRef::from_ptr_mut(self.pkey_ctx) }
|
||||
}
|
||||
|
||||
pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::EVP_DigestUpdate(self.0, buf.as_ptr() as *const _, buf.len())).map(|_| ())
|
||||
cvt(ffi::EVP_DigestUpdate(self.md_ctx, 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)));
|
||||
try!(cvt(ffi::EVP_DigestSignFinal(self.md_ctx, 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)));
|
||||
try!(cvt(ffi::EVP_DigestSignFinal(self.md_ctx, 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)
|
||||
|
|
@ -129,12 +157,17 @@ impl<'a> Write for Signer<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Verifier<'a>(*mut ffi::EVP_MD_CTX, PhantomData<&'a PKeyRef>);
|
||||
pub struct Verifier<'a> {
|
||||
md_ctx: *mut ffi::EVP_MD_CTX,
|
||||
pkey_ctx: *mut ffi::EVP_PKEY_CTX,
|
||||
pkey_pd: PhantomData<&'a PKeyRef>,
|
||||
}
|
||||
|
||||
impl<'a> Drop for Verifier<'a> {
|
||||
fn drop(&mut self) {
|
||||
// pkey_ctx is owned by the md_ctx, so no need to explicitly free it.
|
||||
unsafe {
|
||||
EVP_MD_CTX_free(self.0);
|
||||
EVP_MD_CTX_free(self.md_ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -145,8 +178,9 @@ impl<'a> Verifier<'a> {
|
|||
ffi::init();
|
||||
|
||||
let ctx = try!(cvt_p(EVP_MD_CTX_new()));
|
||||
let mut pctx: *mut ffi::EVP_PKEY_CTX = ptr::null_mut();
|
||||
let r = ffi::EVP_DigestVerifyInit(ctx,
|
||||
ptr::null_mut(),
|
||||
&mut pctx,
|
||||
type_.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
pkey.as_ptr());
|
||||
|
|
@ -155,19 +189,33 @@ impl<'a> Verifier<'a> {
|
|||
return Err(ErrorStack::get());
|
||||
}
|
||||
|
||||
Ok(Verifier(ctx, PhantomData))
|
||||
assert!(!pctx.is_null());
|
||||
|
||||
Ok(Verifier {
|
||||
md_ctx: ctx,
|
||||
pkey_ctx: pctx,
|
||||
pkey_pd: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pkey_ctx(&self) -> &PKeyCtxRef {
|
||||
unsafe { PKeyCtxRef::from_ptr(self.pkey_ctx) }
|
||||
}
|
||||
|
||||
pub fn pkey_ctx_mut(&mut self) -> &mut PKeyCtxRef {
|
||||
unsafe { PKeyCtxRef::from_ptr_mut(self.pkey_ctx) }
|
||||
}
|
||||
|
||||
pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::EVP_DigestUpdate(self.0, buf.as_ptr() as *const _, buf.len())).map(|_| ())
|
||||
cvt(ffi::EVP_DigestUpdate(self.md_ctx, 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());
|
||||
let r = EVP_DigestVerifyFinal(self.md_ctx, signature.as_ptr() as *const _, signature.len());
|
||||
match r {
|
||||
1 => Ok(true),
|
||||
0 => {
|
||||
|
|
@ -205,12 +253,14 @@ unsafe fn EVP_DigestVerifyFinal(ctx: *mut ffi::EVP_MD_CTX,
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use serialize::hex::FromHex;
|
||||
use hex::FromHex;
|
||||
use std::iter;
|
||||
|
||||
use hash::MessageDigest;
|
||||
use sign::{Signer, Verifier};
|
||||
use rsa::Rsa;
|
||||
use ec::{EcGroup, EcKey};
|
||||
use nid;
|
||||
use rsa::{Rsa, PKCS1_PADDING};
|
||||
use dsa::Dsa;
|
||||
use pkey::PKey;
|
||||
|
||||
|
|
@ -245,6 +295,8 @@ mod test {
|
|||
let pkey = PKey::from_rsa(private_key).unwrap();
|
||||
|
||||
let mut signer = Signer::new(MessageDigest::sha256(), &pkey).unwrap();
|
||||
assert_eq!(signer.pkey_ctx_mut().rsa_padding().unwrap(), PKCS1_PADDING);
|
||||
signer.pkey_ctx_mut().set_rsa_padding(PKCS1_PADDING).unwrap();
|
||||
signer.update(INPUT).unwrap();
|
||||
let result = signer.finish().unwrap();
|
||||
|
||||
|
|
@ -258,6 +310,7 @@ mod test {
|
|||
let pkey = PKey::from_rsa(private_key).unwrap();
|
||||
|
||||
let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap();
|
||||
assert_eq!(verifier.pkey_ctx_mut().rsa_padding().unwrap(), PKCS1_PADDING);
|
||||
verifier.update(INPUT).unwrap();
|
||||
assert!(verifier.finish(SIGNATURE).unwrap());
|
||||
}
|
||||
|
|
@ -339,27 +392,27 @@ mod test {
|
|||
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()),
|
||||
Vec::from_hex("9294727a3638bb1c13f48ef8158bfc9d").unwrap()),
|
||||
(b"Jefe".to_vec(),
|
||||
b"what do ya want for nothing?".to_vec(),
|
||||
"750c783e6ab0b503eaa86e310a5db738".from_hex().unwrap()),
|
||||
Vec::from_hex("750c783e6ab0b503eaa86e310a5db738").unwrap()),
|
||||
(iter::repeat(0xaa_u8).take(16).collect(),
|
||||
iter::repeat(0xdd_u8).take(50).collect(),
|
||||
"56be34521d144c88dbb8c733f0e8b3f6".from_hex().unwrap()),
|
||||
("0102030405060708090a0b0c0d0e0f10111213141516171819".from_hex().unwrap(),
|
||||
Vec::from_hex("56be34521d144c88dbb8c733f0e8b3f6").unwrap()),
|
||||
(Vec::from_hex("0102030405060708090a0b0c0d0e0f10111213141516171819").unwrap(),
|
||||
iter::repeat(0xcd_u8).take(50).collect(),
|
||||
"697eaf0aca3a3aea3a75164746ffaa79".from_hex().unwrap()),
|
||||
Vec::from_hex("697eaf0aca3a3aea3a75164746ffaa79").unwrap()),
|
||||
(iter::repeat(0x0c_u8).take(16).collect(),
|
||||
b"Test With Truncation".to_vec(),
|
||||
"56461ef2342edc00f9bab995690efd4c".from_hex().unwrap()),
|
||||
Vec::from_hex("56461ef2342edc00f9bab995690efd4c").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()),
|
||||
Vec::from_hex("6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd").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())];
|
||||
Vec::from_hex("6f630fad67cda0ee1fb1f562db3aa53e").unwrap())];
|
||||
|
||||
test_hmac(MessageDigest::md5(), &tests);
|
||||
}
|
||||
|
|
@ -370,28 +423,43 @@ mod test {
|
|||
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()),
|
||||
Vec::from_hex("b617318655057264e28bc0b6fb378c8ef146be00").unwrap()),
|
||||
(b"Jefe".to_vec(),
|
||||
b"what do ya want for nothing?".to_vec(),
|
||||
"effcdf6ae5eb2fa2d27416d5f184df9c259a7c79".from_hex().unwrap()),
|
||||
Vec::from_hex("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79").unwrap()),
|
||||
(iter::repeat(0xaa_u8).take(20).collect(),
|
||||
iter::repeat(0xdd_u8).take(50).collect(),
|
||||
"125d7342b9ac11cd91a39af48aa17b4f63f175d3".from_hex().unwrap()),
|
||||
("0102030405060708090a0b0c0d0e0f10111213141516171819".from_hex().unwrap(),
|
||||
Vec::from_hex("125d7342b9ac11cd91a39af48aa17b4f63f175d3").unwrap()),
|
||||
(Vec::from_hex("0102030405060708090a0b0c0d0e0f10111213141516171819").unwrap(),
|
||||
iter::repeat(0xcd_u8).take(50).collect(),
|
||||
"4c9007f4026250c6bc8414f9bf50c86c2d7235da".from_hex().unwrap()),
|
||||
Vec::from_hex("4c9007f4026250c6bc8414f9bf50c86c2d7235da").unwrap()),
|
||||
(iter::repeat(0x0c_u8).take(20).collect(),
|
||||
b"Test With Truncation".to_vec(),
|
||||
"4c1a03424b55e07fe7f27be1d58bb9324a9a5a04".from_hex().unwrap()),
|
||||
Vec::from_hex("4c1a03424b55e07fe7f27be1d58bb9324a9a5a04").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()),
|
||||
Vec::from_hex("aa4ae5e15272d00e95705637ce8a3b55ed402112").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())];
|
||||
Vec::from_hex("e8e99d0f45237d786d6bbaa7965c7808bbff1a91").unwrap())];
|
||||
|
||||
test_hmac(MessageDigest::sha1(), &tests);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ec() {
|
||||
let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap();
|
||||
let key = EcKey::generate(&group).unwrap();
|
||||
let key = PKey::from_ec_key(key).unwrap();
|
||||
|
||||
let mut signer = Signer::new(MessageDigest::sha256(), &key).unwrap();
|
||||
signer.update(b"hello world").unwrap();
|
||||
let signature = signer.finish().unwrap();
|
||||
|
||||
let mut verifier = Verifier::new(MessageDigest::sha256(), &key).unwrap();
|
||||
verifier.update(b"hello world").unwrap();
|
||||
assert!(verifier.finish(&signature).unwrap());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use std::any::Any;
|
|||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::mem;
|
||||
use std::panic::{AssertUnwindSafe, catch_unwind};
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
|
||||
|
|
@ -67,22 +68,16 @@ pub unsafe fn get_mut<'a, S: 'a>(bio: *mut BIO) -> &'a mut S {
|
|||
}
|
||||
|
||||
unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState<S> {
|
||||
mem::transmute(compat::BIO_get_data(bio))
|
||||
&mut *(compat::BIO_get_data(bio) as *mut _)
|
||||
}
|
||||
|
||||
fn catch_unwind<F, T>(f: F) -> Result<T, Box<Any + Send>>
|
||||
where F: FnOnce() -> T
|
||||
{
|
||||
::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(f))
|
||||
}
|
||||
|
||||
unsafe extern "C" fn bwrite<S: Write>(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int {
|
||||
unsafe extern fn bwrite<S: Write>(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int {
|
||||
BIO_clear_retry_flags(bio);
|
||||
|
||||
let state = state::<S>(bio);
|
||||
let buf = slice::from_raw_parts(buf as *const _, len as usize);
|
||||
|
||||
match catch_unwind(|| state.stream.write(buf)) {
|
||||
match catch_unwind(AssertUnwindSafe(|| state.stream.write(buf))) {
|
||||
Ok(Ok(len)) => len as c_int,
|
||||
Ok(Err(err)) => {
|
||||
if retriable_error(&err) {
|
||||
|
|
@ -98,13 +93,13 @@ unsafe extern "C" fn bwrite<S: Write>(bio: *mut BIO, buf: *const c_char, len: c_
|
|||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn bread<S: Read>(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int {
|
||||
unsafe extern fn bread<S: Read>(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int {
|
||||
BIO_clear_retry_flags(bio);
|
||||
|
||||
let state = state::<S>(bio);
|
||||
let buf = slice::from_raw_parts_mut(buf as *mut _, len as usize);
|
||||
|
||||
match catch_unwind(|| state.stream.read(buf)) {
|
||||
match catch_unwind(AssertUnwindSafe(|| state.stream.read(buf))) {
|
||||
Ok(Ok(len)) => len as c_int,
|
||||
Ok(Err(err)) => {
|
||||
if retriable_error(&err) {
|
||||
|
|
@ -128,11 +123,11 @@ fn retriable_error(err: &io::Error) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn bputs<S: Write>(bio: *mut BIO, s: *const c_char) -> c_int {
|
||||
unsafe extern fn bputs<S: Write>(bio: *mut BIO, s: *const c_char) -> c_int {
|
||||
bwrite::<S>(bio, s, strlen(s) as c_int)
|
||||
}
|
||||
|
||||
unsafe extern "C" fn ctrl<S: Write>(bio: *mut BIO,
|
||||
unsafe extern fn ctrl<S: Write>(bio: *mut BIO,
|
||||
cmd: c_int,
|
||||
_num: c_long,
|
||||
_ptr: *mut c_void)
|
||||
|
|
@ -140,7 +135,7 @@ unsafe extern "C" fn ctrl<S: Write>(bio: *mut BIO,
|
|||
if cmd == BIO_CTRL_FLUSH {
|
||||
let state = state::<S>(bio);
|
||||
|
||||
match catch_unwind(|| state.stream.flush()) {
|
||||
match catch_unwind(AssertUnwindSafe(|| state.stream.flush())) {
|
||||
Ok(Ok(())) => 1,
|
||||
Ok(Err(err)) => {
|
||||
state.error = Some(err);
|
||||
|
|
@ -156,7 +151,7 @@ unsafe extern "C" fn ctrl<S: Write>(bio: *mut BIO,
|
|||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn create(bio: *mut BIO) -> c_int {
|
||||
unsafe extern fn create(bio: *mut BIO) -> c_int {
|
||||
compat::BIO_set_init(bio, 0);
|
||||
compat::BIO_set_num(bio, 0);
|
||||
compat::BIO_set_data(bio, ptr::null_mut());
|
||||
|
|
@ -164,7 +159,7 @@ unsafe extern "C" fn create(bio: *mut BIO) -> c_int {
|
|||
1
|
||||
}
|
||||
|
||||
unsafe extern "C" fn destroy<S>(bio: *mut BIO) -> c_int {
|
||||
unsafe extern fn destroy<S>(bio: *mut BIO) -> c_int {
|
||||
if bio.is_null() {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,32 +7,26 @@ use ssl::{self, SslMethod, SslContextBuilder, SslContext, Ssl, SSL_VERIFY_PEER,
|
|||
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#"
|
||||
// ffdhe2048 from https://wiki.mozilla.org/Security/Server_Side_TLS#ffdhe2048
|
||||
const DHPARAM_PEM: &'static str = "
|
||||
-----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
|
||||
MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
|
||||
+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
|
||||
87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
|
||||
YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
|
||||
7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
|
||||
ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
|
||||
-----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_TICKET;
|
||||
opts |= ssl::SSL_OP_NO_COMPRESSION;
|
||||
opts |= ssl::SSL_OP_NO_SSLV2;
|
||||
opts |= ssl::SSL_OP_NO_SSLV3;
|
||||
opts |= ssl::SSL_OP_SINGLE_DH_USE;
|
||||
|
|
@ -61,6 +55,7 @@ impl SslConnectorBuilder {
|
|||
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"));
|
||||
ctx.set_verify(SSL_VERIFY_PEER);
|
||||
|
||||
Ok(SslConnectorBuilder(ctx))
|
||||
}
|
||||
|
|
@ -88,6 +83,7 @@ impl SslConnectorBuilder {
|
|||
///
|
||||
/// 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.
|
||||
#[derive(Clone)]
|
||||
pub struct SslConnector(SslContext);
|
||||
|
||||
impl SslConnector {
|
||||
|
|
@ -103,6 +99,22 @@ impl SslConnector {
|
|||
|
||||
ssl.connect(stream)
|
||||
}
|
||||
|
||||
/// Initiates a client-side TLS session on a stream without performing hostname verification.
|
||||
///
|
||||
/// The verification configuration of the connector's `SslContext` is not overridden.
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// You should think very carefully before you use this method. If hostname verification is not
|
||||
/// used, *any* valid certificate for *any* site will be trusted for use from any other. This
|
||||
/// introduces a significant vulnerability to man-in-the-middle attacks.
|
||||
pub fn danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication<S>(
|
||||
&self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
|
||||
where S: Read + Write
|
||||
{
|
||||
try!(Ssl::new(&self.0)).connect(stream)
|
||||
}
|
||||
}
|
||||
|
||||
/// A builder for `SslAcceptor`s.
|
||||
|
|
@ -124,25 +136,8 @@ impl SslAcceptorBuilder {
|
|||
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)
|
||||
let builder = try!(SslAcceptorBuilder::mozilla_intermediate_raw(method));
|
||||
builder.finish_setup(private_key, certificate, chain)
|
||||
}
|
||||
|
||||
/// Creates a new builder configured to connect to modern clients.
|
||||
|
|
@ -159,6 +154,35 @@ impl SslAcceptorBuilder {
|
|||
where I: IntoIterator,
|
||||
I::Item: AsRef<X509Ref>
|
||||
{
|
||||
let builder = try!(SslAcceptorBuilder::mozilla_modern_raw(method));
|
||||
builder.finish_setup(private_key, certificate, chain)
|
||||
}
|
||||
|
||||
/// Like `mozilla_intermediate`, but does not load the certificate chain and private key.
|
||||
pub fn mozilla_intermediate_raw(method: SslMethod) -> Result<SslAcceptorBuilder, ErrorStack> {
|
||||
let mut ctx = try!(ctx(method));
|
||||
let dh = try!(Dh::from_pem(DHPARAM_PEM.as_bytes()));
|
||||
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"));
|
||||
Ok(SslAcceptorBuilder(ctx))
|
||||
}
|
||||
|
||||
/// Like `mozilla_modern`, but does not load the certificate chain and private key.
|
||||
pub fn mozilla_modern_raw(method: SslMethod) -> Result<SslAcceptorBuilder, ErrorStack> {
|
||||
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:\
|
||||
|
|
@ -166,10 +190,10 @@ impl SslAcceptorBuilder {
|
|||
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)
|
||||
Ok(SslAcceptorBuilder(ctx))
|
||||
}
|
||||
|
||||
fn finish_setup<I>(mut ctx: SslContextBuilder,
|
||||
fn finish_setup<I>(mut self,
|
||||
private_key: &PKeyRef,
|
||||
certificate: &X509Ref,
|
||||
chain: I)
|
||||
|
|
@ -177,13 +201,13 @@ impl SslAcceptorBuilder {
|
|||
where I: IntoIterator,
|
||||
I::Item: AsRef<X509Ref>
|
||||
{
|
||||
try!(ctx.set_private_key(private_key));
|
||||
try!(ctx.set_certificate(certificate));
|
||||
try!(ctx.check_private_key());
|
||||
try!(self.0.set_private_key(private_key));
|
||||
try!(self.0.set_certificate(certificate));
|
||||
try!(self.0.check_private_key());
|
||||
for cert in chain {
|
||||
try!(ctx.add_extra_chain_cert(cert.as_ref().to_owned()));
|
||||
try!(self.0.add_extra_chain_cert(cert.as_ref().to_owned()));
|
||||
}
|
||||
Ok(SslAcceptorBuilder(ctx))
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Returns a shared reference to the inner `SslContextBuilder`.
|
||||
|
|
@ -202,28 +226,12 @@ impl SslAcceptorBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
#[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 ec::EcKey;
|
||||
use nid;
|
||||
|
||||
let curve = try!(EcKey::new_by_curve_name(nid::X9_62_PRIME256V1));
|
||||
let curve = try!(EcKey::from_curve_name(nid::X9_62_PRIME256V1));
|
||||
ctx.set_tmp_ecdh(&curve)
|
||||
}
|
||||
|
||||
|
|
@ -241,6 +249,7 @@ fn setup_curves(_: &mut SslContextBuilder) -> Result<(), ErrorStack> {
|
|||
///
|
||||
/// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL
|
||||
/// structures, configuring cipher suites, session options, and more.
|
||||
#[derive(Clone)]
|
||||
pub struct SslAcceptor(SslContext);
|
||||
|
||||
impl SslAcceptor {
|
||||
|
|
@ -255,7 +264,9 @@ impl SslAcceptor {
|
|||
|
||||
#[cfg(any(ossl102, ossl110))]
|
||||
fn setup_verify(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> {
|
||||
ssl.set_verify(SSL_VERIFY_PEER);
|
||||
// pass a noop closure in here to ensure that we consistently override any callback on the
|
||||
// context
|
||||
ssl.set_verify_callback(SSL_VERIFY_PEER, |p, _| p);
|
||||
let param = ssl._param_mut();
|
||||
param.set_hostflags(::verify::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
|
||||
param.set_host(domain)
|
||||
|
|
@ -380,7 +391,7 @@ mod verify {
|
|||
// 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
|
||||
// potentially be used here, but it's both huge and updated frequently
|
||||
// enough that management would be a PITA.
|
||||
if dot_idxs.next().is_none() {
|
||||
return None;
|
||||
|
|
@ -437,15 +448,3 @@ mod verify {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@
|
|||
//! }
|
||||
//! ```
|
||||
use ffi;
|
||||
use foreign_types::{ForeignType, ForeignTypeRef};
|
||||
use libc::{c_int, c_void, c_long, c_ulong};
|
||||
use libc::{c_uchar, c_uint};
|
||||
use std::any::Any;
|
||||
|
|
@ -84,6 +85,7 @@ use std::io::prelude::*;
|
|||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::panic::resume_unwind;
|
||||
use std::path::Path;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
|
|
@ -91,16 +93,18 @@ use std::str;
|
|||
use std::sync::Mutex;
|
||||
|
||||
use {init, cvt, cvt_p};
|
||||
use dh::DhRef;
|
||||
use ec_key::EcKeyRef;
|
||||
use dh::{Dh, DhRef};
|
||||
use ec::EcKeyRef;
|
||||
#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))]
|
||||
use ec::EcKey;
|
||||
use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError, X509Name};
|
||||
use x509::store::{X509StoreBuilderRef, X509StoreRef};
|
||||
#[cfg(any(ossl102, ossl110))]
|
||||
use verify::X509VerifyParamRef;
|
||||
use pkey::PKeyRef;
|
||||
use error::ErrorStack;
|
||||
use types::{OpenSslType, OpenSslTypeRef};
|
||||
use util::Opaque;
|
||||
use stack::Stack;
|
||||
use stack::{Stack, StackRef};
|
||||
|
||||
mod error;
|
||||
mod connector;
|
||||
|
|
@ -162,8 +166,11 @@ bitflags! {
|
|||
const SSL_MODE_AUTO_RETRY = ffi::SSL_MODE_AUTO_RETRY,
|
||||
const SSL_MODE_NO_AUTO_CHAIN = ffi::SSL_MODE_NO_AUTO_CHAIN,
|
||||
const SSL_MODE_RELEASE_BUFFERS = ffi::SSL_MODE_RELEASE_BUFFERS,
|
||||
#[cfg(not(libressl))]
|
||||
const SSL_MODE_SEND_CLIENTHELLO_TIME = ffi::SSL_MODE_SEND_CLIENTHELLO_TIME,
|
||||
#[cfg(not(libressl))]
|
||||
const SSL_MODE_SEND_SERVERHELLO_TIME = ffi::SSL_MODE_SEND_SERVERHELLO_TIME,
|
||||
#[cfg(not(libressl))]
|
||||
const SSL_MODE_SEND_FALLBACK_SCSV = ffi::SSL_MODE_SEND_FALLBACK_SCSV,
|
||||
}
|
||||
}
|
||||
|
|
@ -210,6 +217,22 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct StatusType(c_int);
|
||||
|
||||
impl StatusType {
|
||||
pub fn from_raw(raw: c_int) -> StatusType {
|
||||
StatusType(raw)
|
||||
}
|
||||
|
||||
pub fn as_raw(&self) -> c_int {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// An OSCP status.
|
||||
pub const STATUS_TYPE_OCSP: StatusType = StatusType(ffi::TLSEXT_STATUSTYPE_ocsp);
|
||||
|
||||
lazy_static! {
|
||||
static ref INDEXES: Mutex<HashMap<TypeId, c_int>> = Mutex::new(HashMap::new());
|
||||
static ref SSL_INDEXES: Mutex<HashMap<TypeId, c_int>> = Mutex::new(HashMap::new());
|
||||
|
|
@ -218,11 +241,11 @@ lazy_static! {
|
|||
// Creates a static index for user data of type T
|
||||
// Registers a destructor for the data which will be called
|
||||
// when context is freed
|
||||
fn get_verify_data_idx<T: Any + 'static>() -> c_int {
|
||||
fn get_callback_idx<T: Any + 'static>() -> c_int {
|
||||
*INDEXES.lock().unwrap().entry(TypeId::of::<T>()).or_insert_with(|| get_new_idx::<T>())
|
||||
}
|
||||
|
||||
fn get_ssl_verify_data_idx<T: Any + 'static>() -> c_int {
|
||||
fn get_ssl_callback_idx<T: Any + 'static>() -> c_int {
|
||||
*SSL_INDEXES.lock().unwrap().entry(TypeId::of::<T>()).or_insert_with(|| get_new_ssl_idx::<T>())
|
||||
}
|
||||
|
||||
|
|
@ -271,7 +294,7 @@ extern "C" fn raw_verify<F>(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_
|
|||
let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx();
|
||||
let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx);
|
||||
let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl as *const _);
|
||||
let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::<F>());
|
||||
let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::<F>());
|
||||
let verify: &F = &*(verify as *mut F);
|
||||
|
||||
let ctx = X509StoreContextRef::from_ptr(x509_ctx);
|
||||
|
|
@ -286,7 +309,7 @@ extern "C" fn ssl_raw_verify<F>(preverify_ok: c_int, x509_ctx: *mut ffi::X509_ST
|
|||
unsafe {
|
||||
let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx();
|
||||
let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx);
|
||||
let verify = ffi::SSL_get_ex_data(ssl as *const _, get_ssl_verify_data_idx::<F>());
|
||||
let verify = ffi::SSL_get_ex_data(ssl as *const _, get_ssl_callback_idx::<F>());
|
||||
let verify: &F = &*(verify as *mut F);
|
||||
|
||||
let ctx = X509StoreContextRef::from_ptr(x509_ctx);
|
||||
|
|
@ -300,7 +323,7 @@ extern "C" fn raw_sni<F>(ssl: *mut ffi::SSL, al: *mut c_int, _arg: *mut c_void)
|
|||
{
|
||||
unsafe {
|
||||
let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
|
||||
let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::<F>());
|
||||
let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::<F>());
|
||||
let callback: &F = &*(callback as *mut F);
|
||||
let ssl = SslRef::from_ptr_mut(ssl);
|
||||
|
||||
|
|
@ -372,6 +395,133 @@ extern "C" fn raw_alpn_select_cb(ssl: *mut ffi::SSL,
|
|||
unsafe { select_proto_using(ssl, out as *mut _, outlen, inbuf, inlen, *ALPN_PROTOS_IDX) }
|
||||
}
|
||||
|
||||
unsafe extern fn raw_tmp_dh<F>(ssl: *mut ffi::SSL,
|
||||
is_export: c_int,
|
||||
keylength: c_int)
|
||||
-> *mut ffi::DH
|
||||
where F: Fn(&mut SslRef, bool, u32) -> Result<Dh, ErrorStack> + Any + 'static + Sync + Send
|
||||
{
|
||||
let ctx = ffi::SSL_get_SSL_CTX(ssl);
|
||||
let callback = ffi::SSL_CTX_get_ex_data(ctx, get_callback_idx::<F>());
|
||||
let callback = &*(callback as *mut F);
|
||||
|
||||
let ssl = SslRef::from_ptr_mut(ssl);
|
||||
match callback(ssl, is_export != 0, keylength as u32) {
|
||||
Ok(dh) => {
|
||||
let ptr = dh.as_ptr();
|
||||
mem::forget(dh);
|
||||
ptr
|
||||
}
|
||||
Err(_) => {
|
||||
// FIXME reset error stack
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))]
|
||||
unsafe extern fn raw_tmp_ecdh<F>(ssl: *mut ffi::SSL,
|
||||
is_export: c_int,
|
||||
keylength: c_int)
|
||||
-> *mut ffi::EC_KEY
|
||||
where F: Fn(&mut SslRef, bool, u32) -> Result<EcKey, ErrorStack> + Any + 'static + Sync + Send
|
||||
{
|
||||
let ctx = ffi::SSL_get_SSL_CTX(ssl);
|
||||
let callback = ffi::SSL_CTX_get_ex_data(ctx, get_callback_idx::<F>());
|
||||
let callback = &*(callback as *mut F);
|
||||
|
||||
let ssl = SslRef::from_ptr_mut(ssl);
|
||||
match callback(ssl, is_export != 0, keylength as u32) {
|
||||
Ok(ec_key) => {
|
||||
let ptr = ec_key.as_ptr();
|
||||
mem::forget(ec_key);
|
||||
ptr
|
||||
}
|
||||
Err(_) => {
|
||||
// FIXME reset error stack
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern fn raw_tmp_dh_ssl<F>(ssl: *mut ffi::SSL,
|
||||
is_export: c_int,
|
||||
keylength: c_int)
|
||||
-> *mut ffi::DH
|
||||
where F: Fn(&mut SslRef, bool, u32) -> Result<Dh, ErrorStack> + Any + 'static + Sync + Send
|
||||
{
|
||||
let callback = ffi::SSL_get_ex_data(ssl, get_ssl_callback_idx::<F>());
|
||||
let callback = &*(callback as *mut F);
|
||||
|
||||
let ssl = SslRef::from_ptr_mut(ssl);
|
||||
match callback(ssl, is_export != 0, keylength as u32) {
|
||||
Ok(dh) => {
|
||||
let ptr = dh.as_ptr();
|
||||
mem::forget(dh);
|
||||
ptr
|
||||
}
|
||||
Err(_) => {
|
||||
// FIXME reset error stack
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))]
|
||||
unsafe extern fn raw_tmp_ecdh_ssl<F>(ssl: *mut ffi::SSL,
|
||||
is_export: c_int,
|
||||
keylength: c_int)
|
||||
-> *mut ffi::EC_KEY
|
||||
where F: Fn(&mut SslRef, bool, u32) -> Result<EcKey, ErrorStack> + Any + 'static + Sync + Send
|
||||
{
|
||||
let callback = ffi::SSL_get_ex_data(ssl, get_ssl_callback_idx::<F>());
|
||||
let callback = &*(callback as *mut F);
|
||||
|
||||
let ssl = SslRef::from_ptr_mut(ssl);
|
||||
match callback(ssl, is_export != 0, keylength as u32) {
|
||||
Ok(ec_key) => {
|
||||
let ptr = ec_key.as_ptr();
|
||||
mem::forget(ec_key);
|
||||
ptr
|
||||
}
|
||||
Err(_) => {
|
||||
// FIXME reset error stack
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern fn raw_tlsext_status<F>(ssl: *mut ffi::SSL, _: *mut c_void) -> c_int
|
||||
where F: Fn(&mut SslRef) -> Result<bool, ErrorStack> + Any + 'static + Sync + Send
|
||||
{
|
||||
let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl as *const _);
|
||||
let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::<F>());
|
||||
let callback = &*(callback as *mut F);
|
||||
|
||||
let ssl = SslRef::from_ptr_mut(ssl);
|
||||
let ret = callback(ssl);
|
||||
|
||||
if ssl.is_server() {
|
||||
match ret {
|
||||
Ok(true) => ffi::SSL_TLSEXT_ERR_OK,
|
||||
Ok(false) => ffi::SSL_TLSEXT_ERR_NOACK,
|
||||
Err(_) => {
|
||||
// FIXME reset error stack
|
||||
ffi::SSL_TLSEXT_ERR_ALERT_FATAL
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match ret {
|
||||
Ok(true) => 1,
|
||||
Ok(false) => 0,
|
||||
Err(_) => {
|
||||
// FIXME reset error stack
|
||||
-1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The function is given as the callback to `SSL_CTX_set_next_protos_advertised_cb`.
|
||||
///
|
||||
/// It causes the parameter `out` to point at a `*const c_uchar` instance that
|
||||
|
|
@ -471,7 +621,7 @@ impl SslContextBuilder {
|
|||
unsafe {
|
||||
let verify = Box::new(verify);
|
||||
ffi::SSL_CTX_set_ex_data(self.as_ptr(),
|
||||
get_verify_data_idx::<F>(),
|
||||
get_callback_idx::<F>(),
|
||||
mem::transmute(verify));
|
||||
ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, Some(raw_verify::<F>));
|
||||
}
|
||||
|
|
@ -487,7 +637,7 @@ impl SslContextBuilder {
|
|||
unsafe {
|
||||
let callback = Box::new(callback);
|
||||
ffi::SSL_CTX_set_ex_data(self.as_ptr(),
|
||||
get_verify_data_idx::<F>(),
|
||||
get_callback_idx::<F>(),
|
||||
mem::transmute(callback));
|
||||
let f: extern "C" fn(_, _, _) -> _ = raw_sni::<F>;
|
||||
let f: extern "C" fn() = mem::transmute(f);
|
||||
|
|
@ -519,10 +669,38 @@ impl SslContextBuilder {
|
|||
unsafe { cvt(ffi::SSL_CTX_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) }
|
||||
}
|
||||
|
||||
pub fn set_tmp_dh_callback<F>(&mut self, callback: F)
|
||||
where F: Fn(&mut SslRef, bool, u32) -> Result<Dh, ErrorStack> + Any + 'static + Sync + Send
|
||||
{
|
||||
unsafe {
|
||||
let callback = Box::new(callback);
|
||||
ffi::SSL_CTX_set_ex_data(self.as_ptr(),
|
||||
get_callback_idx::<F>(),
|
||||
Box::into_raw(callback) as *mut c_void);
|
||||
let f: unsafe extern fn (_, _, _) -> _ = raw_tmp_dh::<F>;
|
||||
ffi::SSL_CTX_set_tmp_dh_callback(self.as_ptr(), f);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::SSL_CTX_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Requires the `v101` feature and OpenSSL 1.0.1, or the `v102` feature and OpenSSL 1.0.2.
|
||||
#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))]
|
||||
pub fn set_tmp_ecdh_callback<F>(&mut self, callback: F)
|
||||
where F: Fn(&mut SslRef, bool, u32) -> Result<EcKey, ErrorStack> + Any + 'static + Sync + Send
|
||||
{
|
||||
unsafe {
|
||||
let callback = Box::new(callback);
|
||||
ffi::SSL_CTX_set_ex_data(self.as_ptr(),
|
||||
get_callback_idx::<F>(),
|
||||
Box::into_raw(callback) as *mut c_void);
|
||||
let f: unsafe extern fn(_, _, _) -> _ = raw_tmp_ecdh::<F>;
|
||||
ffi::SSL_CTX_set_tmp_ecdh_callback(self.as_ptr(), f);
|
||||
}
|
||||
}
|
||||
|
||||
/// Use the default locations of trusted certificates for verification.
|
||||
///
|
||||
/// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR`
|
||||
|
|
@ -571,7 +749,7 @@ impl SslContextBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/// Specifies the file that contains certificate
|
||||
/// Loads a certificate from a file.
|
||||
pub fn set_certificate_file<P: AsRef<Path>>(&mut self,
|
||||
file: P,
|
||||
file_type: X509FileType)
|
||||
|
|
@ -585,7 +763,11 @@ impl SslContextBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/// Specifies the file that contains certificate chain
|
||||
/// Loads a certificate chain from a file.
|
||||
///
|
||||
/// The file should contain a sequence of PEM-formatted certificates, the first being the leaf
|
||||
/// certificate, and the remainder forming the chain of certificates up to and including the
|
||||
/// trusted root certificate.
|
||||
pub fn set_certificate_chain_file<P: AsRef<Path>>(&mut self,
|
||||
file: P)
|
||||
-> Result<(), ErrorStack> {
|
||||
|
|
@ -596,13 +778,15 @@ impl SslContextBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/// Specifies the certificate
|
||||
/// Sets the certificate.
|
||||
pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::SSL_CTX_use_certificate(self.as_ptr(), cert.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Adds a certificate to the certificate chain presented together with the
|
||||
/// certificate specified using set_certificate()
|
||||
/// Appends a certificate to the certificate chain.
|
||||
///
|
||||
/// This chain should contain all certificates necessary to go from the certificate specified by
|
||||
/// `set_certificate` to a trusted root.
|
||||
pub fn add_extra_chain_cert(&mut self, cert: X509) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
try!(cvt(ffi::SSL_CTX_add_extra_chain_cert(self.as_ptr(), cert.as_ptr()) as c_int));
|
||||
|
|
@ -611,7 +795,7 @@ impl SslContextBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/// Specifies the file that contains private key
|
||||
/// Loads the private key from a file.
|
||||
pub fn set_private_key_file<P: AsRef<Path>>(&mut self,
|
||||
file: P,
|
||||
file_type: X509FileType)
|
||||
|
|
@ -625,11 +809,14 @@ impl SslContextBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/// Specifies the private key
|
||||
/// Sets the private key.
|
||||
pub fn set_private_key(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Sets the cipher configuration.
|
||||
///
|
||||
/// See `man 1 ciphers` for details on the format.
|
||||
pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> {
|
||||
let cipher_list = CString::new(cipher_list).unwrap();
|
||||
unsafe {
|
||||
|
|
@ -638,17 +825,15 @@ impl SslContextBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/// If `onoff` is set to `true`, enable ECDHE for key exchange with
|
||||
/// compatible clients, and automatically select an appropriate elliptic
|
||||
/// curve.
|
||||
/// Enables ECDHE key exchange with an automatically chosen curve list.
|
||||
///
|
||||
/// Requires the `v102` feature and OpenSSL 1.0.2.
|
||||
#[cfg(all(feature = "v102", ossl102))]
|
||||
#[cfg(all(feature = "v102", any(ossl102, libressl)))]
|
||||
pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
|
||||
self._set_ecdh_auto(onoff)
|
||||
}
|
||||
|
||||
#[cfg(ossl102)]
|
||||
#[cfg(any(ossl102,libressl))]
|
||||
fn _set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::SSL_CTX_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) }
|
||||
}
|
||||
|
|
@ -739,6 +924,41 @@ impl SslContextBuilder {
|
|||
unsafe { cvt(ffi::SSL_CTX_check_private_key(self.as_ptr())).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Returns a shared reference to the context's certificate store.
|
||||
pub fn cert_store(&self) -> &X509StoreBuilderRef {
|
||||
unsafe { X509StoreBuilderRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) }
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the context's certificate store.
|
||||
pub fn cert_store_mut(&mut self) -> &mut X509StoreBuilderRef {
|
||||
unsafe { X509StoreBuilderRef::from_ptr_mut(ffi::SSL_CTX_get_cert_store(self.as_ptr())) }
|
||||
}
|
||||
|
||||
/// Sets the callback dealing with OCSP stapling.
|
||||
///
|
||||
/// On the client side, this callback is responsible for validating the OCSP status response
|
||||
/// returned by the server. The status may be retrieved with the `SslRef::ocsp_status` method.
|
||||
/// A response of `Ok(true)` indicates that the OCSP status is valid, and a response of
|
||||
/// `Ok(false)` indicates that the OCSP status is invalid and the handshake should be
|
||||
/// terminated.
|
||||
///
|
||||
/// On the server side, this callback is resopnsible for setting the OCSP status response to be
|
||||
/// returned to clients. The status may be set with the `SslRef::set_ocsp_status` method. A
|
||||
/// response of `Ok(true)` indicates that the OCSP status should be returned to the client, and
|
||||
/// `Ok(false)` indicates that the status should not be returned to the client.
|
||||
pub fn set_status_callback<F>(&mut self, callback: F) -> Result<(), ErrorStack>
|
||||
where F: Fn(&mut SslRef) -> Result<bool, ErrorStack> + Any + 'static + Sync + Send
|
||||
{
|
||||
unsafe {
|
||||
let callback = Box::new(callback);
|
||||
ffi::SSL_CTX_set_ex_data(self.as_ptr(),
|
||||
get_callback_idx::<F>(),
|
||||
Box::into_raw(callback) as *mut c_void);
|
||||
let f: unsafe extern fn (_, _) -> _ = raw_tlsext_status::<F>;
|
||||
cvt(ffi::SSL_CTX_set_tlsext_status_cb(self.as_ptr(), Some(f)) as c_int).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(self) -> SslContext {
|
||||
let ctx = SslContext(self.0);
|
||||
mem::forget(self);
|
||||
|
|
@ -746,7 +966,13 @@ impl SslContextBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
type_!(SslContext, SslContextRef, ffi::SSL_CTX, ffi::SSL_CTX_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::SSL_CTX;
|
||||
fn drop = ffi::SSL_CTX_free;
|
||||
|
||||
pub struct SslContext;
|
||||
pub struct SslContextRef;
|
||||
}
|
||||
|
||||
unsafe impl Send for SslContext {}
|
||||
unsafe impl Sync for SslContext {}
|
||||
|
|
@ -803,6 +1029,22 @@ impl SslContextRef {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the certificate store used for verification.
|
||||
pub fn cert_store(&self) -> &X509StoreRef {
|
||||
unsafe {
|
||||
X509StoreRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extra_chain_certs(&self) -> &StackRef<X509> {
|
||||
unsafe {
|
||||
let mut chain = ptr::null_mut();
|
||||
ffi::SSL_CTX_get_extra_chain_certs(self.as_ptr(), &mut chain);
|
||||
assert!(!chain.is_null());
|
||||
StackRef::from_ptr(chain)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CipherBits {
|
||||
|
|
@ -815,14 +1057,16 @@ pub struct CipherBits {
|
|||
|
||||
pub struct SslCipher(*mut ffi::SSL_CIPHER);
|
||||
|
||||
impl OpenSslType for SslCipher {
|
||||
impl ForeignType for SslCipher {
|
||||
type CType = ffi::SSL_CIPHER;
|
||||
type Ref = SslCipherRef;
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_ptr(ptr: *mut ffi::SSL_CIPHER) -> SslCipher {
|
||||
SslCipher(ptr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_ptr(&self) -> *mut ffi::SSL_CIPHER {
|
||||
self.0
|
||||
}
|
||||
|
|
@ -844,7 +1088,7 @@ impl DerefMut for SslCipher {
|
|||
|
||||
pub struct SslCipherRef(Opaque);
|
||||
|
||||
impl OpenSslTypeRef for SslCipherRef {
|
||||
impl ForeignTypeRef for SslCipherRef {
|
||||
type CType = ffi::SSL_CIPHER;
|
||||
}
|
||||
|
||||
|
|
@ -892,7 +1136,44 @@ impl SslCipherRef {
|
|||
}
|
||||
}
|
||||
|
||||
type_!(Ssl, SslRef, ffi::SSL, ffi::SSL_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::SSL_SESSION;
|
||||
fn drop = ffi::SSL_SESSION_free;
|
||||
|
||||
pub struct SslSession;
|
||||
pub struct SslSessionRef;
|
||||
}
|
||||
|
||||
impl SslSessionRef {
|
||||
/// Returns the SSL session ID.
|
||||
pub fn id(&self) -> &[u8] {
|
||||
unsafe {
|
||||
let mut len = 0;
|
||||
let p = ffi::SSL_SESSION_get_id(self.as_ptr(), &mut len);
|
||||
slice::from_raw_parts(p as *const u8, len as usize)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the length of the master key.
|
||||
pub fn master_key_len(&self) -> usize {
|
||||
unsafe { compat::SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) }
|
||||
}
|
||||
|
||||
/// Copies the master key into the provided buffer.
|
||||
///
|
||||
/// Returns the number of bytes written.
|
||||
pub fn master_key(&self, buf: &mut [u8]) -> usize {
|
||||
unsafe { compat::SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) }
|
||||
}
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = ffi::SSL;
|
||||
fn drop = ffi::SSL_free;
|
||||
|
||||
pub struct Ssl;
|
||||
pub struct SslRef;
|
||||
}
|
||||
|
||||
impl fmt::Debug for SslRef {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
|
@ -944,12 +1225,58 @@ impl SslRef {
|
|||
unsafe {
|
||||
let verify = Box::new(verify);
|
||||
ffi::SSL_set_ex_data(self.as_ptr(),
|
||||
get_ssl_verify_data_idx::<F>(),
|
||||
get_ssl_callback_idx::<F>(),
|
||||
mem::transmute(verify));
|
||||
ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, Some(ssl_raw_verify::<F>));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_tmp_dh(&mut self, dh: &DhRef) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::SSL_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) }
|
||||
}
|
||||
|
||||
pub fn set_tmp_dh_callback<F>(&mut self, callback: F)
|
||||
where F: Fn(&mut SslRef, bool, u32) -> Result<Dh, ErrorStack> + Any + 'static + Sync + Send
|
||||
{
|
||||
unsafe {
|
||||
let callback = Box::new(callback);
|
||||
ffi::SSL_set_ex_data(self.as_ptr(),
|
||||
get_ssl_callback_idx::<F>(),
|
||||
Box::into_raw(callback) as *mut c_void);
|
||||
let f: unsafe extern fn (_, _, _) -> _ = raw_tmp_dh_ssl::<F>;
|
||||
ffi::SSL_set_tmp_dh_callback(self.as_ptr(), f);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::SSL_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) }
|
||||
}
|
||||
|
||||
/// Requires the `v101` feature and OpenSSL 1.0.1, or the `v102` feature and OpenSSL 1.0.2.
|
||||
#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))]
|
||||
pub fn set_tmp_ecdh_callback<F>(&mut self, callback: F)
|
||||
where F: Fn(&mut SslRef, bool, u32) -> Result<EcKey, ErrorStack> + Any + 'static + Sync + Send
|
||||
{
|
||||
unsafe {
|
||||
let callback = Box::new(callback);
|
||||
ffi::SSL_set_ex_data(self.as_ptr(),
|
||||
get_ssl_callback_idx::<F>(),
|
||||
Box::into_raw(callback) as *mut c_void);
|
||||
let f: unsafe extern fn(_, _, _) -> _ = raw_tmp_ecdh_ssl::<F>;
|
||||
ffi::SSL_set_tmp_ecdh_callback(self.as_ptr(), f);
|
||||
}
|
||||
}
|
||||
|
||||
/// If `onoff` is set to `true`, enable ECDHE for key exchange with
|
||||
/// compatible clients, and automatically select an appropriate elliptic
|
||||
/// curve.
|
||||
///
|
||||
/// Requires the `v102` feature and OpenSSL 1.0.2.
|
||||
#[cfg(all(feature = "v102", ossl102))]
|
||||
pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
|
||||
unsafe { cvt(ffi::SSL_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) }
|
||||
}
|
||||
|
||||
pub fn current_cipher(&self) -> Option<&SslCipherRef> {
|
||||
unsafe {
|
||||
let ptr = ffi::SSL_get_current_cipher(self.as_ptr());
|
||||
|
|
@ -1151,6 +1478,61 @@ impl SslRef {
|
|||
pub fn verify_result(&self) -> Option<X509VerifyError> {
|
||||
unsafe { X509VerifyError::from_raw(ffi::SSL_get_verify_result(self.as_ptr())) }
|
||||
}
|
||||
|
||||
/// Returns the SSL session.
|
||||
pub fn session(&self) -> Option<&SslSessionRef> {
|
||||
unsafe {
|
||||
let p = ffi::SSL_get_session(self.as_ptr());
|
||||
if p.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(SslSessionRef::from_ptr(p))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the status response a client wishes the server to reply with.
|
||||
pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::SSL_set_tlsext_status_type(self.as_ptr(), type_.as_raw()) as c_int).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the server's OCSP response, if present.
|
||||
pub fn ocsp_status(&self) -> Option<&[u8]> {
|
||||
unsafe {
|
||||
let mut p = ptr::null_mut();
|
||||
let len = ffi::SSL_get_tlsext_status_ocsp_resp(self.as_ptr(), &mut p);
|
||||
|
||||
if len < 0 {
|
||||
None
|
||||
} else {
|
||||
Some(slice::from_raw_parts(p as *const u8, len as usize))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the OCSP response to be returned to the client.
|
||||
pub fn set_ocsp_status(&mut self, response: &[u8]) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
assert!(response.len() <= c_int::max_value() as usize);
|
||||
let p = try!(cvt_p(ffi::CRYPTO_malloc(response.len() as _,
|
||||
concat!(file!(), "\0").as_ptr() as *const _,
|
||||
line!() as c_int)));
|
||||
ptr::copy_nonoverlapping(response.as_ptr(), p as *mut u8, response.len());
|
||||
cvt(ffi::SSL_set_tlsext_status_ocsp_resp(self.as_ptr(),
|
||||
p as *mut c_uchar,
|
||||
response.len() as c_long) as c_int)
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines if this `Ssl` is configured for server-side or client-side use.
|
||||
pub fn is_server(&self) -> bool {
|
||||
unsafe {
|
||||
compat::SSL_is_server(self.as_ptr()) != 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for Ssl {}
|
||||
|
|
@ -1326,11 +1708,24 @@ impl<S: Read + Write> SslStream<S> {
|
|||
/// This is particularly useful with a nonblocking socket, where the error
|
||||
/// value will identify if OpenSSL is waiting on read or write readiness.
|
||||
pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
// The intepretation of the return code here is a little odd with a
|
||||
// zero-length write. OpenSSL will likely correctly report back to us
|
||||
// that it read zero bytes, but zero is also the sentinel for "error".
|
||||
// To avoid that confusion short-circuit that logic and return quickly
|
||||
// if `buf` has a length of zero.
|
||||
if buf.len() == 0 {
|
||||
return Ok(0)
|
||||
}
|
||||
|
||||
let ret = self.ssl.read(buf);
|
||||
if ret >= 0 {
|
||||
if ret > 0 {
|
||||
Ok(ret as usize)
|
||||
} else {
|
||||
Err(self.make_error(ret))
|
||||
match self.make_error(ret) {
|
||||
// Don't treat unexpected EOFs as errors when reading
|
||||
Error::Stream(ref e) if e.kind() == io::ErrorKind::ConnectionAborted => Ok(0),
|
||||
e => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1339,8 +1734,13 @@ impl<S: Read + Write> SslStream<S> {
|
|||
/// This is particularly useful with a nonblocking socket, where the error
|
||||
/// value will identify if OpenSSL is waiting on read or write readiness.
|
||||
pub fn ssl_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
|
||||
// See above for why we short-circuit on zero-length buffers
|
||||
if buf.len() == 0 {
|
||||
return Ok(0)
|
||||
}
|
||||
|
||||
let ret = self.ssl.write(buf);
|
||||
if ret >= 0 {
|
||||
if ret > 0 {
|
||||
Ok(ret as usize)
|
||||
} else {
|
||||
Err(self.make_error(ret))
|
||||
|
|
@ -1377,19 +1777,38 @@ impl<S> SslStream<S> {
|
|||
ffi::SSL_ERROR_SYSCALL => {
|
||||
let errs = ErrorStack::get();
|
||||
if errs.errors().is_empty() {
|
||||
if ret == 0 {
|
||||
match self.get_bio_error() {
|
||||
Some(err) => Error::Stream(err),
|
||||
None => {
|
||||
Error::Stream(io::Error::new(io::ErrorKind::ConnectionAborted,
|
||||
"unexpected EOF observed"))
|
||||
} else {
|
||||
Error::Stream(self.get_bio_error())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Error::Ssl(errs)
|
||||
}
|
||||
}
|
||||
ffi::SSL_ERROR_ZERO_RETURN => Error::ZeroReturn,
|
||||
ffi::SSL_ERROR_WANT_WRITE => Error::WantWrite(self.get_bio_error()),
|
||||
ffi::SSL_ERROR_WANT_READ => Error::WantRead(self.get_bio_error()),
|
||||
ffi::SSL_ERROR_WANT_WRITE => {
|
||||
let err = match self.get_bio_error() {
|
||||
Some(err) => err,
|
||||
None => {
|
||||
io::Error::new(io::ErrorKind::Other,
|
||||
"BUG: got an SSL_ERROR_WANT_WRITE with no error in the BIO")
|
||||
}
|
||||
};
|
||||
Error::WantWrite(err)
|
||||
},
|
||||
ffi::SSL_ERROR_WANT_READ => {
|
||||
let err = match self.get_bio_error() {
|
||||
Some(err) => err,
|
||||
None => {
|
||||
io::Error::new(io::ErrorKind::Other,
|
||||
"BUG: got an SSL_ERROR_WANT_WRITE with no error in the BIO")
|
||||
}
|
||||
};
|
||||
Error::WantRead(err)
|
||||
},
|
||||
err => {
|
||||
Error::Stream(io::Error::new(io::ErrorKind::InvalidData,
|
||||
format!("unexpected error {}", err)))
|
||||
|
|
@ -1399,19 +1818,12 @@ impl<S> SslStream<S> {
|
|||
|
||||
fn check_panic(&mut self) {
|
||||
if let Some(err) = unsafe { bio::take_panic::<S>(self.ssl.get_raw_rbio()) } {
|
||||
::std::panic::resume_unwind(err)
|
||||
resume_unwind(err)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_bio_error(&mut self) -> io::Error {
|
||||
let error = unsafe { bio::take_error::<S>(self.ssl.get_raw_rbio()) };
|
||||
match error {
|
||||
Some(error) => error,
|
||||
None => {
|
||||
io::Error::new(io::ErrorKind::Other,
|
||||
"BUG: got an ErrorSyscall without an error in the BIO?")
|
||||
}
|
||||
}
|
||||
fn get_bio_error(&mut self) -> Option<io::Error> {
|
||||
unsafe { bio::take_error::<S>(self.ssl.get_raw_rbio()) }
|
||||
}
|
||||
|
||||
/// Returns a reference to the underlying stream.
|
||||
|
|
@ -1488,8 +1900,8 @@ mod compat {
|
|||
use ffi;
|
||||
use libc::c_int;
|
||||
|
||||
pub use ffi::{SSL_CTX_get_options, SSL_CTX_set_options};
|
||||
pub use ffi::{SSL_CTX_clear_options, SSL_CTX_up_ref};
|
||||
pub use ffi::{SSL_CTX_get_options, SSL_CTX_set_options, SSL_CTX_clear_options, SSL_CTX_up_ref,
|
||||
SSL_SESSION_get_master_key, SSL_is_server};
|
||||
|
||||
pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
|
||||
ffi::CRYPTO_get_ex_new_index(ffi::CRYPTO_EX_INDEX_SSL_CTX,
|
||||
|
|
@ -1524,7 +1936,7 @@ mod compat {
|
|||
use std::ptr;
|
||||
|
||||
use ffi;
|
||||
use libc::{self, c_long, c_ulong, c_int};
|
||||
use libc::{self, c_long, c_ulong, c_int, size_t, c_uchar};
|
||||
|
||||
pub unsafe fn SSL_CTX_get_options(ctx: *const ffi::SSL_CTX) -> c_ulong {
|
||||
ffi::SSL_CTX_ctrl(ctx as *mut _, ffi::SSL_CTRL_OPTIONS, 0, ptr::null_mut()) as c_ulong
|
||||
|
|
@ -1561,6 +1973,19 @@ mod compat {
|
|||
0
|
||||
}
|
||||
|
||||
pub unsafe fn SSL_SESSION_get_master_key(session: *const ffi::SSL_SESSION,
|
||||
out: *mut c_uchar,
|
||||
mut outlen: size_t) -> size_t {
|
||||
if outlen == 0 {
|
||||
return (*session).master_key_length as size_t;
|
||||
}
|
||||
if outlen > (*session).master_key_length as size_t {
|
||||
outlen = (*session).master_key_length as size_t;
|
||||
}
|
||||
ptr::copy_nonoverlapping((*session).master_key.as_ptr(), out, outlen);
|
||||
outlen
|
||||
}
|
||||
|
||||
pub fn tls_method() -> *const ffi::SSL_METHOD {
|
||||
unsafe { ffi::SSLv23_method() }
|
||||
}
|
||||
|
|
@ -1568,4 +1993,8 @@ mod compat {
|
|||
pub fn dtls_method() -> *const ffi::SSL_METHOD {
|
||||
unsafe { ffi::DTLSv1_method() }
|
||||
}
|
||||
|
||||
pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int {
|
||||
(*s).server
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,17 +9,18 @@ use std::mem;
|
|||
use std::net::{TcpStream, TcpListener, SocketAddr};
|
||||
use std::path::Path;
|
||||
use std::process::{Command, Child, Stdio, ChildStdin};
|
||||
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use tempdir::TempDir;
|
||||
|
||||
use dh::Dh;
|
||||
use hash::MessageDigest;
|
||||
use ocsp::{OcspResponse, RESPONSE_STATUS_UNAUTHORIZED};
|
||||
use ssl;
|
||||
use ssl::SSL_VERIFY_PEER;
|
||||
use ssl::{SslMethod, HandshakeError};
|
||||
use ssl::{SslContext, SslStream, Ssl, ShutdownResult, SslConnectorBuilder, SslAcceptorBuilder,
|
||||
Error};
|
||||
use ssl::{SslMethod, HandshakeError, SslContext, SslStream, Ssl, ShutdownResult,
|
||||
SslConnectorBuilder, SslAcceptorBuilder, Error, SSL_VERIFY_PEER, SSL_VERIFY_NONE,
|
||||
STATUS_TYPE_OCSP};
|
||||
use x509::{X509StoreContext, X509, X509Name, X509_FILETYPE_PEM};
|
||||
#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
|
||||
use x509::verify::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS;
|
||||
|
|
@ -29,6 +30,7 @@ use std::net::UdpSocket;
|
|||
|
||||
mod select;
|
||||
|
||||
static ROOT_CERT: &'static [u8] = include_bytes!("../../../test/root-ca.pem");
|
||||
static CERT: &'static [u8] = include_bytes!("../../../test/cert.pem");
|
||||
static KEY: &'static [u8] = include_bytes!("../../../test/key.pem");
|
||||
|
||||
|
|
@ -98,6 +100,7 @@ impl Server {
|
|||
Server::new_tcp(&["-www"])
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn new_alpn() -> (Server, TcpStream) {
|
||||
Server::new_tcp(&["-www",
|
||||
"-nextprotoneg",
|
||||
|
|
@ -170,8 +173,8 @@ macro_rules! run_test(
|
|||
use ssl::SSL_VERIFY_PEER;
|
||||
use hash::MessageDigest;
|
||||
use x509::X509StoreContext;
|
||||
use serialize::hex::FromHex;
|
||||
use types::OpenSslTypeRef;
|
||||
use hex::FromHex;
|
||||
use foreign_types::ForeignTypeRef;
|
||||
use super::Server;
|
||||
|
||||
#[test]
|
||||
|
|
@ -181,7 +184,7 @@ macro_rules! run_test(
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(any(windows, target_arch = "arm"), ignore)] // FIXME(#467)
|
||||
#[cfg_attr(any(libressl, windows, target_arch = "arm"), ignore)] // FIXME(#467)
|
||||
fn dtlsv1() {
|
||||
let (_s, stream) = Server::new_dtlsv1(Some("hello"));
|
||||
$blk(SslMethod::dtls(), stream);
|
||||
|
|
@ -302,7 +305,7 @@ run_test!(verify_callback_data, |method, stream| {
|
|||
// Command: openssl x509 -in test/cert.pem -outform DER | openssl dgst -sha256
|
||||
// Please update if "test/cert.pem" will ever change
|
||||
let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584";
|
||||
let node_id = node_hash_str.from_hex().unwrap();
|
||||
let node_id = Vec::from_hex(node_hash_str).unwrap();
|
||||
ctx.set_verify_callback(SSL_VERIFY_PEER, move |_preverify_ok, x509_ctx| {
|
||||
let cert = x509_ctx.current_cert();
|
||||
match cert {
|
||||
|
|
@ -330,7 +333,7 @@ run_test!(ssl_verify_callback, |method, stream| {
|
|||
let mut ssl = Ssl::new(&ctx.build()).unwrap();
|
||||
|
||||
let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584";
|
||||
let node_id = node_hash_str.from_hex().unwrap();
|
||||
let node_id = Vec::from_hex(node_hash_str).unwrap();
|
||||
ssl.set_verify_callback(SSL_VERIFY_PEER, move |_, x509| {
|
||||
CHECKED.store(1, Ordering::SeqCst);
|
||||
match x509.current_cert() {
|
||||
|
|
@ -421,18 +424,28 @@ fn test_write() {
|
|||
stream.flush().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_length_buffers() {
|
||||
let (_s, stream) = Server::new();
|
||||
let ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
||||
let mut stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap();
|
||||
|
||||
assert_eq!(stream.write(b"").unwrap(), 0);
|
||||
assert_eq!(stream.read(&mut []).unwrap(), 0);
|
||||
}
|
||||
|
||||
run_test!(get_peer_certificate, |method, stream| {
|
||||
let ctx = SslContext::builder(method).unwrap();
|
||||
let stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap();
|
||||
let cert = stream.ssl().peer_certificate().unwrap();
|
||||
let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap();
|
||||
let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584";
|
||||
let node_id = node_hash_str.from_hex().unwrap();
|
||||
let node_id = Vec::from_hex(node_hash_str).unwrap();
|
||||
assert_eq!(node_id, fingerprint)
|
||||
});
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(any(windows, target_arch = "arm"), ignore)] // FIXME(#467)
|
||||
#[cfg_attr(any(libressl, windows, target_arch = "arm"), ignore)] // FIXME(#467)
|
||||
fn test_write_dtlsv1() {
|
||||
let (_s, stream) = Server::new_dtlsv1(iter::repeat("y\n"));
|
||||
let ctx = SslContext::builder(SslMethod::dtls()).unwrap();
|
||||
|
|
@ -771,7 +784,7 @@ fn test_alpn_server_select_none() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(any(windows, target_arch = "arm"), ignore)] // FIXME(#467)
|
||||
#[cfg_attr(any(libressl, windows, target_arch = "arm"), ignore)] // FIXME(#467)
|
||||
fn test_read_dtlsv1() {
|
||||
let (_s, stream) = Server::new_dtlsv1(Some("hello"));
|
||||
|
||||
|
|
@ -849,7 +862,7 @@ fn test_write_nonblocking() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(any(windows, target_arch = "arm"), ignore)] // FIXME(#467)
|
||||
#[cfg_attr(any(libressl, windows, target_arch = "arm"), ignore)] // FIXME(#467)
|
||||
fn test_read_nonblocking() {
|
||||
let (_s, stream) = Server::new();
|
||||
stream.set_nonblocking(true).unwrap();
|
||||
|
|
@ -1088,6 +1101,36 @@ fn connector_invalid_hostname() {
|
|||
assert!(connector.connect("foobar.com", s).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connector_invalid_no_hostname_verification() {
|
||||
let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build();
|
||||
|
||||
let s = TcpStream::connect("google.com:443").unwrap();
|
||||
connector.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(s)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connector_no_hostname_still_verifies() {
|
||||
let (_s, tcp) = Server::new();
|
||||
|
||||
let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build();
|
||||
|
||||
assert!(connector.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(tcp)
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connector_no_hostname_can_disable_verify() {
|
||||
let (_s, tcp) = Server::new();
|
||||
|
||||
let mut connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
|
||||
connector.builder_mut().set_verify(SSL_VERIFY_NONE);
|
||||
let connector = connector.build();
|
||||
|
||||
connector.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(tcp).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connector_client_server_mozilla_intermediate() {
|
||||
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
|
|
@ -1193,6 +1236,210 @@ fn client_ca_list() {
|
|||
ctx.set_client_ca_list(names);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cert_store() {
|
||||
let (_s, tcp) = Server::new();
|
||||
|
||||
let cert = X509::from_pem(ROOT_CERT).unwrap();
|
||||
|
||||
let mut ctx = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
|
||||
ctx.builder_mut().cert_store_mut().add_cert(cert).unwrap();
|
||||
let ctx = ctx.build();
|
||||
|
||||
ctx.connect("foobar.com", tcp).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tmp_dh_callback() {
|
||||
static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT;
|
||||
|
||||
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let port = listener.local_addr().unwrap().port();
|
||||
|
||||
thread::spawn(move ||{
|
||||
let stream = listener.accept().unwrap().0;
|
||||
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
||||
ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM).unwrap();
|
||||
ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM).unwrap();
|
||||
ctx.set_tmp_dh_callback(|_, _, _| {
|
||||
CALLED_BACK.store(true, Ordering::SeqCst);
|
||||
let dh = include_bytes!("../../../test/dhparams.pem");
|
||||
Dh::from_pem(dh)
|
||||
});
|
||||
let ssl = Ssl::new(&ctx.build()).unwrap();
|
||||
ssl.accept(stream).unwrap();
|
||||
});
|
||||
|
||||
let stream = TcpStream::connect(("127.0.0.1", port)).unwrap();
|
||||
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
||||
ctx.set_cipher_list("EDH").unwrap();
|
||||
let ssl = Ssl::new(&ctx.build()).unwrap();
|
||||
ssl.connect(stream).unwrap();
|
||||
|
||||
assert!(CALLED_BACK.load(Ordering::SeqCst));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))]
|
||||
fn tmp_ecdh_callback() {
|
||||
use ec::EcKey;
|
||||
use nid;
|
||||
|
||||
static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT;
|
||||
|
||||
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let port = listener.local_addr().unwrap().port();
|
||||
|
||||
thread::spawn(move ||{
|
||||
let stream = listener.accept().unwrap().0;
|
||||
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
||||
ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM).unwrap();
|
||||
ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM).unwrap();
|
||||
ctx.set_tmp_ecdh_callback(|_, _, _| {
|
||||
CALLED_BACK.store(true, Ordering::SeqCst);
|
||||
EcKey::new_by_curve_name(nid::X9_62_PRIME256V1)
|
||||
});
|
||||
let ssl = Ssl::new(&ctx.build()).unwrap();
|
||||
ssl.accept(stream).unwrap();
|
||||
});
|
||||
|
||||
let stream = TcpStream::connect(("127.0.0.1", port)).unwrap();
|
||||
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
||||
ctx.set_cipher_list("ECDH").unwrap();
|
||||
let ssl = Ssl::new(&ctx.build()).unwrap();
|
||||
ssl.connect(stream).unwrap();
|
||||
|
||||
assert!(CALLED_BACK.load(Ordering::SeqCst));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tmp_dh_callback_ssl() {
|
||||
static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT;
|
||||
|
||||
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let port = listener.local_addr().unwrap().port();
|
||||
|
||||
thread::spawn(move ||{
|
||||
let stream = listener.accept().unwrap().0;
|
||||
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
||||
ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM).unwrap();
|
||||
ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM).unwrap();
|
||||
let mut ssl = Ssl::new(&ctx.build()).unwrap();
|
||||
ssl.set_tmp_dh_callback(|_, _, _| {
|
||||
CALLED_BACK.store(true, Ordering::SeqCst);
|
||||
let dh = include_bytes!("../../../test/dhparams.pem");
|
||||
Dh::from_pem(dh)
|
||||
});
|
||||
ssl.accept(stream).unwrap();
|
||||
});
|
||||
|
||||
let stream = TcpStream::connect(("127.0.0.1", port)).unwrap();
|
||||
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
||||
ctx.set_cipher_list("EDH").unwrap();
|
||||
let ssl = Ssl::new(&ctx.build()).unwrap();
|
||||
ssl.connect(stream).unwrap();
|
||||
|
||||
assert!(CALLED_BACK.load(Ordering::SeqCst));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))]
|
||||
fn tmp_ecdh_callback_ssl() {
|
||||
use ec::EcKey;
|
||||
use nid;
|
||||
|
||||
static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT;
|
||||
|
||||
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let port = listener.local_addr().unwrap().port();
|
||||
|
||||
thread::spawn(move ||{
|
||||
let stream = listener.accept().unwrap().0;
|
||||
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
||||
ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM).unwrap();
|
||||
ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM).unwrap();
|
||||
let mut ssl = Ssl::new(&ctx.build()).unwrap();
|
||||
ssl.set_tmp_ecdh_callback(|_, _, _| {
|
||||
CALLED_BACK.store(true, Ordering::SeqCst);
|
||||
EcKey::new_by_curve_name(nid::X9_62_PRIME256V1)
|
||||
});
|
||||
ssl.accept(stream).unwrap();
|
||||
});
|
||||
|
||||
let stream = TcpStream::connect(("127.0.0.1", port)).unwrap();
|
||||
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
||||
ctx.set_cipher_list("ECDH").unwrap();
|
||||
let ssl = Ssl::new(&ctx.build()).unwrap();
|
||||
ssl.connect(stream).unwrap();
|
||||
|
||||
assert!(CALLED_BACK.load(Ordering::SeqCst));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn idle_session() {
|
||||
let ctx = SslContext::builder(SslMethod::tls()).unwrap().build();
|
||||
let ssl = Ssl::new(&ctx).unwrap();
|
||||
assert!(ssl.session().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn active_session() {
|
||||
let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build();
|
||||
|
||||
let s = TcpStream::connect("google.com:443").unwrap();
|
||||
let socket = connector.connect("google.com", s).unwrap();
|
||||
let session = socket.ssl().session().unwrap();
|
||||
let len = session.master_key_len();
|
||||
let mut buf = vec![0; len - 1];
|
||||
let copied = session.master_key(&mut buf);
|
||||
assert_eq!(copied, buf.len());
|
||||
let mut buf = vec![0; len + 1];
|
||||
let copied = session.master_key(&mut buf);
|
||||
assert_eq!(copied, len);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn status_callbacks() {
|
||||
static CALLED_BACK_SERVER: AtomicBool = ATOMIC_BOOL_INIT;
|
||||
static CALLED_BACK_CLIENT: AtomicBool = ATOMIC_BOOL_INIT;
|
||||
|
||||
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let port = listener.local_addr().unwrap().port();
|
||||
|
||||
let guard = thread::spawn(move || {
|
||||
let stream = listener.accept().unwrap().0;
|
||||
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
||||
ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM).unwrap();
|
||||
ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM).unwrap();
|
||||
ctx.set_status_callback(|ssl| {
|
||||
CALLED_BACK_SERVER.store(true, Ordering::SeqCst);
|
||||
let response = OcspResponse::create(RESPONSE_STATUS_UNAUTHORIZED, None).unwrap();
|
||||
let response = response.to_der().unwrap();
|
||||
ssl.set_ocsp_status(&response).unwrap();
|
||||
Ok(true)
|
||||
}).unwrap();
|
||||
let ssl = Ssl::new(&ctx.build()).unwrap();
|
||||
ssl.accept(stream).unwrap();
|
||||
});
|
||||
|
||||
let stream = TcpStream::connect(("127.0.0.1", port)).unwrap();
|
||||
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
|
||||
ctx.set_status_callback(|ssl| {
|
||||
CALLED_BACK_CLIENT.store(true, Ordering::SeqCst);
|
||||
let response = OcspResponse::from_der(ssl.ocsp_status().unwrap()).unwrap();
|
||||
assert_eq!(response.status(), RESPONSE_STATUS_UNAUTHORIZED);
|
||||
Ok(true)
|
||||
}).unwrap();
|
||||
let mut ssl = Ssl::new(&ctx.build()).unwrap();
|
||||
ssl.set_status_type(STATUS_TYPE_OCSP).unwrap();
|
||||
ssl.connect(stream).unwrap();
|
||||
|
||||
assert!(CALLED_BACK_SERVER.load(Ordering::SeqCst));
|
||||
assert!(CALLED_BACK_CLIENT.load(Ordering::SeqCst));
|
||||
|
||||
guard.join().unwrap();
|
||||
}
|
||||
|
||||
fn _check_kinds() {
|
||||
fn is_send<T: Send>() {}
|
||||
fn is_sync<T: Sync>() {}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
use std::ops::{Deref, DerefMut, Index, IndexMut};
|
||||
use std::iter;
|
||||
use foreign_types::{ForeignTypeRef, ForeignType};
|
||||
use libc::c_int;
|
||||
use std::borrow::Borrow;
|
||||
use std::convert::AsRef;
|
||||
use std::iter;
|
||||
use std::marker::PhantomData;
|
||||
use libc::c_int;
|
||||
use std::mem;
|
||||
use ffi;
|
||||
|
||||
use {cvt, cvt_p};
|
||||
use error::ErrorStack;
|
||||
use types::{OpenSslType, OpenSslTypeRef};
|
||||
use std::ops::{Deref, DerefMut, Index, IndexMut};
|
||||
|
||||
use util::Opaque;
|
||||
|
||||
#[cfg(ossl10x)]
|
||||
|
|
@ -22,9 +23,8 @@ use ffi::{OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value, OPE
|
|||
|
||||
/// 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 {
|
||||
/// It should not be implemented for any type outside of this crate.
|
||||
pub trait Stackable: ForeignType {
|
||||
/// The C stack type for this element.
|
||||
///
|
||||
/// Generally called `stack_st_{ELEMENT_TYPE}`, normally hidden by the
|
||||
|
|
@ -80,14 +80,16 @@ impl<T: Stackable> Borrow<StackRef<T>> for Stack<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Stackable> OpenSslType for Stack<T> {
|
||||
impl<T: Stackable> ForeignType for Stack<T> {
|
||||
type CType = T::StackType;
|
||||
type Ref = StackRef<T>;
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_ptr(ptr: *mut T::StackType) -> Stack<T> {
|
||||
Stack(ptr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_ptr(&self) -> *mut T::StackType {
|
||||
self.0
|
||||
}
|
||||
|
|
@ -152,7 +154,7 @@ impl<T: Stackable> ExactSizeIterator for IntoIter<T> {}
|
|||
|
||||
pub struct StackRef<T: Stackable>(Opaque, PhantomData<T>);
|
||||
|
||||
impl<T: Stackable> OpenSslTypeRef for StackRef<T> {
|
||||
impl<T: Stackable> ForeignTypeRef for StackRef<T> {
|
||||
type CType = T::StackType;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
use ffi;
|
||||
use foreign_types::{ForeignType, ForeignTypeRef};
|
||||
use libc::{c_char, c_void};
|
||||
use std::fmt;
|
||||
use std::ffi::CStr;
|
||||
use std::ops::Deref;
|
||||
use std::str;
|
||||
|
||||
use stack::Stackable;
|
||||
|
||||
foreign_type! {
|
||||
type CType = c_char;
|
||||
fn drop = free;
|
||||
|
||||
pub struct OpensslString;
|
||||
pub struct OpensslStringRef;
|
||||
}
|
||||
|
||||
impl OpensslString {
|
||||
#[deprecated(note = "use from_ptr", since = "0.9.7")]
|
||||
pub unsafe fn from_raw_parts(buf: *mut u8, _: usize) -> OpensslString {
|
||||
OpensslString::from_ptr(buf as *mut c_char)
|
||||
}
|
||||
|
||||
#[deprecated(note = "use from_ptr", since = "0.9.7")]
|
||||
pub unsafe fn from_null_terminated(buf: *mut c_char) -> OpensslString {
|
||||
OpensslString::from_ptr(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for OpensslString {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for OpensslString {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Stackable for OpensslString {
|
||||
type StackType = ffi::stack_st_OPENSSL_STRING;
|
||||
}
|
||||
|
||||
impl Deref for OpensslStringRef {
|
||||
type Target = str;
|
||||
|
||||
fn deref(&self) -> &str {
|
||||
unsafe {
|
||||
let slice = CStr::from_ptr(self.as_ptr()).to_bytes();
|
||||
str::from_utf8_unchecked(slice)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for OpensslStringRef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for OpensslStringRef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(ossl110))]
|
||||
unsafe fn free(buf: *mut c_char) {
|
||||
::ffi::CRYPTO_free(buf as *mut c_void);
|
||||
}
|
||||
|
||||
#[cfg(ossl110)]
|
||||
unsafe fn free(buf: *mut c_char) {
|
||||
::ffi::CRYPTO_free(buf as *mut c_void,
|
||||
concat!(file!(), "\0").as_ptr() as *const c_char,
|
||||
line!() as ::libc::c_int);
|
||||
}
|
||||
|
|
@ -80,6 +80,22 @@ impl Cipher {
|
|||
unsafe { Cipher(ffi::EVP_aes_256_gcm()) }
|
||||
}
|
||||
|
||||
pub fn bf_cbc() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_bf_cbc()) }
|
||||
}
|
||||
|
||||
pub fn bf_ecb() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_bf_ecb()) }
|
||||
}
|
||||
|
||||
pub fn bf_cfb64() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_bf_cfb64()) }
|
||||
}
|
||||
|
||||
pub fn bf_ofb() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_bf_ofb()) }
|
||||
}
|
||||
|
||||
pub fn des_cbc() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_des_cbc()) }
|
||||
}
|
||||
|
|
@ -92,6 +108,18 @@ impl Cipher {
|
|||
unsafe { Cipher(ffi::EVP_rc4()) }
|
||||
}
|
||||
|
||||
/// Requires the `v110` feature and OpenSSL 1.1.0.
|
||||
#[cfg(all(ossl110, feature = "v110"))]
|
||||
pub fn chacha20() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_chacha20()) }
|
||||
}
|
||||
|
||||
/// Requires the `v110` feature and OpenSSL 1.1.0.
|
||||
#[cfg(all(ossl110, feature = "v110"))]
|
||||
pub fn chacha20_poly1305() -> Cipher {
|
||||
unsafe { Cipher(ffi::EVP_chacha20_poly1305()) }
|
||||
}
|
||||
|
||||
pub unsafe fn from_ptr(ptr: *const ffi::EVP_CIPHER) -> Cipher {
|
||||
Cipher(ptr)
|
||||
}
|
||||
|
|
@ -135,8 +163,7 @@ 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 `Cipher::iv_len`).
|
||||
/// Panics if an IV is required by the cipher but not provided.
|
||||
pub fn new(t: Cipher,
|
||||
mode: Mode,
|
||||
key: &[u8],
|
||||
|
|
@ -169,7 +196,13 @@ impl Crypter {
|
|||
let key = key.as_ptr() as *mut _;
|
||||
let iv = match (iv, t.iv_len()) {
|
||||
(Some(iv), Some(len)) => {
|
||||
assert!(iv.len() == len);
|
||||
if iv.len() != len {
|
||||
assert!(iv.len() <= c_int::max_value() as usize);
|
||||
try!(cvt(ffi::EVP_CIPHER_CTX_ctrl(crypter.ctx,
|
||||
ffi::EVP_CTRL_GCM_SET_IVLEN,
|
||||
iv.len() as c_int,
|
||||
ptr::null_mut())));
|
||||
}
|
||||
iv.as_ptr() as *mut _
|
||||
}
|
||||
(Some(_), None) | (None, None) => ptr::null_mut(),
|
||||
|
|
@ -196,6 +229,39 @@ impl Crypter {
|
|||
}
|
||||
}
|
||||
|
||||
/// Sets the tag used to authenticate ciphertext in AEAD ciphers such as AES GCM.
|
||||
///
|
||||
/// When decrypting cipher text using an AEAD cipher, this must be called before `finalize`.
|
||||
pub fn set_tag(&mut self, tag: &[u8]) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
assert!(tag.len() <= c_int::max_value() as usize);
|
||||
// NB: this constant is actually more general than just GCM.
|
||||
cvt(ffi::EVP_CIPHER_CTX_ctrl(self.ctx,
|
||||
ffi::EVP_CTRL_GCM_SET_TAG,
|
||||
tag.len() as c_int,
|
||||
tag.as_ptr() as *mut _))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Feeds Additional Authenticated Data (AAD) through the cipher.
|
||||
///
|
||||
/// This can only be used with AEAD ciphers such as AES GCM. Data fed in is not encrypted, but
|
||||
/// is factored into the authentication tag. It must be called before the first call to
|
||||
/// `update`.
|
||||
pub fn aad_update(&mut self, input: &[u8]) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
assert!(input.len() <= c_int::max_value() as usize);
|
||||
let mut len = 0;
|
||||
cvt(ffi::EVP_CipherUpdate(self.ctx,
|
||||
ptr::null_mut(),
|
||||
&mut len,
|
||||
input.as_ptr(),
|
||||
input.len() as c_int))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Feeds data from `input` through the cipher, writing encrypted/decrypted
|
||||
/// bytes into `output`.
|
||||
///
|
||||
|
|
@ -244,6 +310,25 @@ impl Crypter {
|
|||
Ok(outl as usize)
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves the authentication tag used to authenticate ciphertext in AEAD ciphers such
|
||||
/// as AES GCM.
|
||||
///
|
||||
/// When encrypting data with an AEAD cipher, this must be called after `finalize`.
|
||||
///
|
||||
/// The size of the buffer indicates the required size of the tag. While some ciphers support a
|
||||
/// range of tag sizes, it is recommended to pick the maximum size. For AES GCM, this is 16
|
||||
/// bytes, for example.
|
||||
pub fn get_tag(&self, tag: &mut [u8]) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
assert!(tag.len() <= c_int::max_value() as usize);
|
||||
cvt(ffi::EVP_CIPHER_CTX_ctrl(self.ctx,
|
||||
ffi::EVP_CTRL_GCM_GET_TAG,
|
||||
tag.len() as c_int,
|
||||
tag.as_mut_ptr() as *mut _))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Crypter {
|
||||
|
|
@ -292,6 +377,52 @@ fn cipher(t: Cipher,
|
|||
Ok(out)
|
||||
}
|
||||
|
||||
/// Like `encrypt`, but for AEAD ciphers such as AES GCM.
|
||||
///
|
||||
/// Additional Authenticated Data can be provided in the `aad` field, and the authentication tag
|
||||
/// will be copied into the `tag` field.
|
||||
///
|
||||
/// The size of the `tag` buffer indicates the required size of the tag. While some ciphers support
|
||||
/// a range of tag sizes, it is recommended to pick the maximum size. For AES GCM, this is 16 bytes,
|
||||
/// for example.
|
||||
pub fn encrypt_aead(t: Cipher,
|
||||
key: &[u8],
|
||||
iv: Option<&[u8]>,
|
||||
aad: &[u8],
|
||||
data: &[u8],
|
||||
tag: &mut [u8])
|
||||
-> Result<Vec<u8>, ErrorStack> {
|
||||
let mut c = try!(Crypter::new(t, Mode::Encrypt, key, iv));
|
||||
let mut out = vec![0; data.len() + t.block_size()];
|
||||
try!(c.aad_update(aad));
|
||||
let count = try!(c.update(data, &mut out));
|
||||
let rest = try!(c.finalize(&mut out[count..]));
|
||||
try!(c.get_tag(tag));
|
||||
out.truncate(count + rest);
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// Like `decrypt`, but for AEAD ciphers such as AES GCM.
|
||||
///
|
||||
/// Additional Authenticated Data can be provided in the `aad` field, and the authentication tag
|
||||
/// should be provided in the `tag` field.
|
||||
pub fn decrypt_aead(t: Cipher,
|
||||
key: &[u8],
|
||||
iv: Option<&[u8]>,
|
||||
aad: &[u8],
|
||||
data: &[u8],
|
||||
tag: &[u8])
|
||||
-> Result<Vec<u8>, ErrorStack> {
|
||||
let mut c = try!(Crypter::new(t, Mode::Decrypt, key, iv));
|
||||
let mut out = vec![0; data.len() + t.block_size()];
|
||||
try!(c.aad_update(aad));
|
||||
let count = try!(c.update(data, &mut out));
|
||||
try!(c.set_tag(tag));
|
||||
let rest = try!(c.finalize(&mut out[count..]));
|
||||
out.truncate(count + rest);
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
#[cfg(ossl110)]
|
||||
use ffi::{EVP_CIPHER_iv_length, EVP_CIPHER_block_size, EVP_CIPHER_key_length};
|
||||
|
||||
|
|
@ -318,7 +449,8 @@ use self::compat::*;
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serialize::hex::{FromHex, ToHex};
|
||||
use hex::{FromHex, ToHex};
|
||||
use super::*;
|
||||
|
||||
// Test vectors from FIPS-197:
|
||||
// http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
|
||||
|
|
@ -385,12 +517,10 @@ mod tests {
|
|||
}
|
||||
|
||||
fn cipher_test(ciphertype: super::Cipher, pt: &str, ct: &str, key: &str, iv: &str) {
|
||||
use serialize::hex::ToHex;
|
||||
|
||||
let pt = pt.from_hex().unwrap();
|
||||
let ct = ct.from_hex().unwrap();
|
||||
let key = key.from_hex().unwrap();
|
||||
let iv = iv.from_hex().unwrap();
|
||||
let pt = Vec::from_hex(pt).unwrap();
|
||||
let ct = Vec::from_hex(ct).unwrap();
|
||||
let key = Vec::from_hex(key).unwrap();
|
||||
let iv = Vec::from_hex(iv).unwrap();
|
||||
|
||||
let computed = super::decrypt(ciphertype, &key, Some(&iv), &ct).unwrap();
|
||||
let expected = pt;
|
||||
|
|
@ -407,6 +537,35 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
fn cipher_test_nopad(ciphertype: super::Cipher, pt: &str, ct: &str, key: &str, iv: &str) {
|
||||
let pt = Vec::from_hex(pt).unwrap();
|
||||
let ct = Vec::from_hex(ct).unwrap();
|
||||
let key = Vec::from_hex(key).unwrap();
|
||||
let iv = Vec::from_hex(iv).unwrap();
|
||||
|
||||
let computed = {
|
||||
let mut c = Crypter::new(ciphertype, Mode::Decrypt, &key, Some(&iv)).unwrap();
|
||||
c.pad(false);
|
||||
let mut out = vec![0; ct.len() + ciphertype.block_size()];
|
||||
let count = c.update(&ct, &mut out).unwrap();
|
||||
let rest = c.finalize(&mut out[count..]).unwrap();
|
||||
out.truncate(count + rest);
|
||||
out
|
||||
};
|
||||
let expected = pt;
|
||||
|
||||
if computed != expected {
|
||||
println!("Computed: {}", computed.to_hex());
|
||||
println!("Expected: {}", expected.to_hex());
|
||||
if computed.len() != expected.len() {
|
||||
println!("Lengths differ: {} in computed vs {} expected",
|
||||
computed.len(),
|
||||
expected.len());
|
||||
}
|
||||
panic!("test failure");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rc4() {
|
||||
|
||||
|
|
@ -513,6 +672,51 @@ mod tests {
|
|||
cipher_test(super::Cipher::aes_256_cfb8(), pt, ct, key, iv);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bf_cbc() {
|
||||
// https://www.schneier.com/code/vectors.txt
|
||||
|
||||
let pt = "37363534333231204E6F77206973207468652074696D6520666F722000000000";
|
||||
let ct = "6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC";
|
||||
let key = "0123456789ABCDEFF0E1D2C3B4A59687";
|
||||
let iv = "FEDCBA9876543210";
|
||||
|
||||
cipher_test_nopad(super::Cipher::bf_cbc(), pt, ct, key, iv);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bf_ecb() {
|
||||
|
||||
let pt = "5CD54CA83DEF57DA";
|
||||
let ct = "B1B8CC0B250F09A0";
|
||||
let key = "0131D9619DC1376E";
|
||||
let iv = "0000000000000000";
|
||||
|
||||
cipher_test_nopad(super::Cipher::bf_ecb(), pt, ct, key, iv);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bf_cfb64() {
|
||||
|
||||
let pt = "37363534333231204E6F77206973207468652074696D6520666F722000";
|
||||
let ct = "E73214A2822139CAF26ECF6D2EB9E76E3DA3DE04D1517200519D57A6C3";
|
||||
let key = "0123456789ABCDEFF0E1D2C3B4A59687";
|
||||
let iv = "FEDCBA9876543210";
|
||||
|
||||
cipher_test_nopad(super::Cipher::bf_cfb64(), pt, ct, key, iv);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bf_ofb() {
|
||||
|
||||
let pt = "37363534333231204E6F77206973207468652074696D6520666F722000";
|
||||
let ct = "E73214A2822139CA62B343CC5B65587310DD908D0C241B2263C2CF80DA";
|
||||
let key = "0123456789ABCDEFF0E1D2C3B4A59687";
|
||||
let iv = "FEDCBA9876543210";
|
||||
|
||||
cipher_test_nopad(super::Cipher::bf_ofb(), pt, ct, key, iv);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_des_cbc() {
|
||||
|
||||
|
|
@ -534,4 +738,93 @@ mod tests {
|
|||
|
||||
cipher_test(super::Cipher::des_ecb(), pt, ct, key, iv);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_aes128_gcm() {
|
||||
let key = "0e00c76561d2bd9b40c3c15427e2b08f";
|
||||
let iv =
|
||||
"492cadaccd3ca3fbc9cf9f06eb3325c4e159850b0dbe98199b89b7af528806610b6f63998e1eae80c348e7\
|
||||
4cbb921d8326631631fc6a5d304f39166daf7ea15fa1977f101819adb510b50fe9932e12c5a85aa3fd1e73\
|
||||
d8d760af218be829903a77c63359d75edd91b4f6ed5465a72662f5055999e059e7654a8edc921aa0d496";
|
||||
let pt =
|
||||
"fef03c2d7fb15bf0d2df18007d99f967c878ad59359034f7bb2c19af120685d78e32f6b8b83b032019956c\
|
||||
a9c0195721476b85";
|
||||
let aad =
|
||||
"d8f1163d8c840292a2b2dacf4ac7c36aff8733f18fabb4fa5594544125e03d1e6e5d6d0fd61656c8d8f327\
|
||||
c92839ae5539bb469c9257f109ebff85aad7bd220fdaa95c022dbd0c7bb2d878ad504122c943045d3c5eba\
|
||||
8f1f56c0";
|
||||
let ct =
|
||||
"4f6cf471be7cbd2575cd5a1747aea8fe9dea83e51936beac3e68f66206922060c697ffa7af80ad6bb68f2c\
|
||||
f4fc97416ee52abe";
|
||||
let tag = "e20b6655";
|
||||
|
||||
// this tag is smaller than you'd normally want, but I pulled this test from the part of
|
||||
// the NIST test vectors that cover 4 byte tags.
|
||||
let mut actual_tag = [0; 4];
|
||||
let out = encrypt_aead(Cipher::aes_128_gcm(),
|
||||
&Vec::from_hex(key).unwrap(),
|
||||
Some(&Vec::from_hex(iv).unwrap()),
|
||||
&Vec::from_hex(aad).unwrap(),
|
||||
&Vec::from_hex(pt).unwrap(),
|
||||
&mut actual_tag)
|
||||
.unwrap();
|
||||
assert_eq!(ct, out.to_hex());
|
||||
assert_eq!(tag, actual_tag.to_hex());
|
||||
|
||||
let out = decrypt_aead(Cipher::aes_128_gcm(),
|
||||
&Vec::from_hex(key).unwrap(),
|
||||
Some(&Vec::from_hex(iv).unwrap()),
|
||||
&Vec::from_hex(aad).unwrap(),
|
||||
&Vec::from_hex(ct).unwrap(),
|
||||
&Vec::from_hex(tag).unwrap()).unwrap();
|
||||
assert_eq!(pt, out.to_hex());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(ossl110, feature = "v110"))]
|
||||
fn test_chacha20() {
|
||||
let key = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
let iv = "00000000000000000000000000000000";
|
||||
let pt = "000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||
00000000000000000000000000000000000000000000000";
|
||||
let ct = "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7\
|
||||
724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586";
|
||||
|
||||
cipher_test(Cipher::chacha20(), pt, ct, key, iv);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(ossl110, feature = "v110"))]
|
||||
fn test_chacha20_poly1305() {
|
||||
let key = "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f";
|
||||
let iv = "070000004041424344454647";
|
||||
let aad = "50515253c0c1c2c3c4c5c6c7";
|
||||
let pt = "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393\
|
||||
a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f722074\
|
||||
6865206675747572652c2073756e73637265656e20776f756c642062652069742e";
|
||||
let ct = "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca967128\
|
||||
2fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fa\
|
||||
b324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116";
|
||||
let tag = "1ae10b594f09e26a7e902ecbd0600691";
|
||||
|
||||
let mut actual_tag = [0; 16];
|
||||
let out = encrypt_aead(Cipher::chacha20_poly1305(),
|
||||
&Vec::from_hex(key).unwrap(),
|
||||
Some(&Vec::from_hex(iv).unwrap()),
|
||||
&Vec::from_hex(aad).unwrap(),
|
||||
&Vec::from_hex(pt).unwrap(),
|
||||
&mut actual_tag)
|
||||
.unwrap();
|
||||
assert_eq!(ct, out.to_hex());
|
||||
assert_eq!(tag, actual_tag.to_hex());
|
||||
|
||||
let out = decrypt_aead(Cipher::chacha20_poly1305(),
|
||||
&Vec::from_hex(key).unwrap(),
|
||||
Some(&Vec::from_hex(iv).unwrap()),
|
||||
&Vec::from_hex(aad).unwrap(),
|
||||
&Vec::from_hex(ct).unwrap(),
|
||||
&Vec::from_hex(tag).unwrap())
|
||||
.unwrap();
|
||||
assert_eq!(pt, out.to_hex());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,5 @@
|
|||
//! Items used by other types.
|
||||
#[deprecated(note = "use foreign_types instead", since = "0.9.7")]
|
||||
pub use foreign_types::ForeignType as OpenSslType;
|
||||
|
||||
/// 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;
|
||||
|
||||
/// Returns a raw pointer to the wrapped value.
|
||||
fn as_ptr(&self) -> *mut Self::CType;
|
||||
}
|
||||
|
||||
/// 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 _
|
||||
}
|
||||
}
|
||||
#[deprecated(note = "use foreign_types instead", since = "0.9.7")]
|
||||
pub use foreign_types::ForeignTypeRef as OpenSslTypeRef;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ use std::cell::UnsafeCell;
|
|||
use std::panic::{self, AssertUnwindSafe};
|
||||
use std::slice;
|
||||
|
||||
use error::ErrorStack;
|
||||
|
||||
/// Wraps a user-supplied callback and a slot for panics thrown inside the callback (while FFI
|
||||
/// frames are on the stack).
|
||||
///
|
||||
|
|
@ -33,10 +35,7 @@ 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 unsafe extern "C" fn invoke_passwd_cb<F>(buf: *mut c_char,
|
||||
pub unsafe extern fn invoke_passwd_cb_old<F>(buf: *mut c_char,
|
||||
size: c_int,
|
||||
_rwflag: c_int,
|
||||
cb_state: *mut c_void)
|
||||
|
|
@ -46,9 +45,7 @@ pub unsafe extern "C" fn invoke_passwd_cb<F>(buf: *mut c_char,
|
|||
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 = slice::from_raw_parts_mut(buf, size as usize);
|
||||
|
||||
callback.cb.take().unwrap()(pass_slice)
|
||||
}));
|
||||
|
||||
|
|
@ -61,6 +58,36 @@ pub unsafe extern "C" fn invoke_passwd_cb<F>(buf: *mut c_char,
|
|||
}
|
||||
}
|
||||
|
||||
/// Password callback function, passed to private key loading functions.
|
||||
///
|
||||
/// `cb_state` is expected to be a pointer to a `CallbackState`.
|
||||
pub unsafe extern 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 [u8]) -> Result<usize, ErrorStack>
|
||||
{
|
||||
let callback = &mut *(cb_state as *mut CallbackState<F>);
|
||||
|
||||
let result = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||
let pass_slice = slice::from_raw_parts_mut(buf as *mut u8, size as usize);
|
||||
callback.cb.take().unwrap()(pass_slice)
|
||||
}));
|
||||
|
||||
match result {
|
||||
Ok(Ok(len)) => len as c_int,
|
||||
Ok(Err(_)) => {
|
||||
// FIXME restore error stack
|
||||
0
|
||||
}
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use libc::c_uint;
|
||||
use ffi;
|
||||
use foreign_types::ForeignTypeRef;
|
||||
|
||||
use cvt;
|
||||
use error::ErrorStack;
|
||||
use types::OpenSslTypeRef;
|
||||
|
||||
bitflags! {
|
||||
pub flags X509CheckFlags: c_uint {
|
||||
|
|
@ -19,7 +19,13 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
type_!(X509VerifyParam, X509VerifyParamRef, ffi::X509_VERIFY_PARAM, ffi::X509_VERIFY_PARAM_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::X509_VERIFY_PARAM;
|
||||
fn drop = ffi::X509_VERIFY_PARAM_free;
|
||||
|
||||
pub struct X509VerifyParam;
|
||||
pub struct X509VerifyParamRef;
|
||||
}
|
||||
|
||||
impl X509VerifyParamRef {
|
||||
pub fn set_hostflags(&mut self, hostflags: X509CheckFlags) {
|
||||
|
|
|
|||
|
|
@ -20,11 +20,8 @@ use ffi::{SSLEAY_VERSION as OPENSSL_VERSION, SSLEAY_CFLAGS as OPENSSL_CFLAGS,
|
|||
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};
|
||||
use ffi::{OPENSSL_VERSION, OPENSSL_CFLAGS, OPENSSL_BUILT_ON, OPENSSL_PLATFORM, OPENSSL_DIR,
|
||||
OpenSSL_version_num, OpenSSL_version};
|
||||
|
||||
/// OPENSSL_VERSION_NUMBER is a numeric release version identifier:
|
||||
///
|
||||
|
|
@ -92,8 +89,13 @@ fn test_versions() {
|
|||
println!("Platform: '{}'", platform());
|
||||
println!("Dir: '{}'", dir());
|
||||
|
||||
#[cfg(not(libressl))]
|
||||
fn expected_name() -> &'static str { "OpenSSL" }
|
||||
#[cfg(libressl)]
|
||||
fn expected_name() -> &'static str { "LibreSSL" }
|
||||
|
||||
assert!(number() > 0);
|
||||
assert!(version().starts_with("OpenSSL"));
|
||||
assert!(version().starts_with(expected_name()));
|
||||
assert!(c_flags().starts_with("compiler:"));
|
||||
assert!(built_on().starts_with("built on:"));
|
||||
assert!(dir().starts_with("OPENSSLDIR:"));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
#![allow(deprecated)]
|
||||
use libc::{c_int, c_long};
|
||||
use ffi;
|
||||
use foreign_types::{ForeignType, ForeignTypeRef};
|
||||
use std::borrow::Borrow;
|
||||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::ffi::{CStr, CString};
|
||||
|
|
@ -14,17 +15,16 @@ use std::slice;
|
|||
use std::str;
|
||||
|
||||
use {cvt, cvt_p};
|
||||
use asn1::{Asn1StringRef, Asn1Time, Asn1TimeRef, Asn1IntegerRef};
|
||||
use asn1::{Asn1StringRef, Asn1Time, Asn1TimeRef, Asn1BitStringRef, Asn1IntegerRef, Asn1ObjectRef};
|
||||
use bio::MemBioSlice;
|
||||
use bn::{BigNum, MSB_MAYBE_ZERO};
|
||||
use bio::{MemBio, MemBioSlice};
|
||||
use conf::ConfRef;
|
||||
use hash::MessageDigest;
|
||||
use pkey::{PKey, PKeyRef};
|
||||
use error::ErrorStack;
|
||||
use ffi;
|
||||
use hash::MessageDigest;
|
||||
use nid::{self, Nid};
|
||||
use types::{OpenSslType, OpenSslTypeRef};
|
||||
use pkey::{PKey, PKeyRef};
|
||||
use stack::{Stack, StackRef, Stackable};
|
||||
use string::OpensslString;
|
||||
|
||||
#[cfg(ossl10x)]
|
||||
use ffi::{X509_set_notBefore, X509_set_notAfter, ASN1_STRING_data, X509_STORE_CTX_get_chain};
|
||||
|
|
@ -39,6 +39,7 @@ pub mod verify;
|
|||
use x509::extension::{ExtensionType, Extension};
|
||||
|
||||
pub mod extension;
|
||||
pub mod store;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
@ -55,7 +56,13 @@ pub const X509_FILETYPE_PEM: X509FileType = X509FileType(ffi::X509_FILETYPE_PEM)
|
|||
pub const X509_FILETYPE_ASN1: X509FileType = X509FileType(ffi::X509_FILETYPE_ASN1);
|
||||
pub const X509_FILETYPE_DEFAULT: X509FileType = X509FileType(ffi::X509_FILETYPE_DEFAULT);
|
||||
|
||||
type_!(X509StoreContext, X509StoreContextRef, ffi::X509_STORE_CTX, ffi::X509_STORE_CTX_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::X509_STORE_CTX;
|
||||
fn drop = ffi::X509_STORE_CTX_free;
|
||||
|
||||
pub struct X509StoreContext;
|
||||
pub struct X509StoreContextRef;
|
||||
}
|
||||
|
||||
impl X509StoreContextRef {
|
||||
pub fn error(&self) -> Option<X509VerifyError> {
|
||||
|
|
@ -376,7 +383,13 @@ impl X509Builder {
|
|||
}
|
||||
}
|
||||
|
||||
type_!(X509, X509Ref, ffi::X509, ffi::X509_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::X509;
|
||||
fn drop = ffi::X509_free;
|
||||
|
||||
pub struct X509;
|
||||
pub struct X509Ref;
|
||||
}
|
||||
|
||||
impl X509Ref {
|
||||
pub fn subject_name(&self) -> &X509NameRef {
|
||||
|
|
@ -420,8 +433,8 @@ impl X509Ref {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns certificate Not After validity period.
|
||||
pub fn not_after<'a>(&'a self) -> &'a Asn1TimeRef {
|
||||
/// Returns the certificate's Not After validity period.
|
||||
pub fn not_after(&self) -> &Asn1TimeRef {
|
||||
unsafe {
|
||||
let date = compat::X509_get_notAfter(self.as_ptr());
|
||||
assert!(!date.is_null());
|
||||
|
|
@ -429,8 +442,8 @@ impl X509Ref {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns certificate Not Before validity period.
|
||||
pub fn not_before<'a>(&'a self) -> &'a Asn1TimeRef {
|
||||
/// Returns the certificate's Not Before validity period.
|
||||
pub fn not_before(&self) -> &Asn1TimeRef {
|
||||
unsafe {
|
||||
let date = compat::X509_get_notBefore(self.as_ptr());
|
||||
assert!(!date.is_null());
|
||||
|
|
@ -438,23 +451,47 @@ impl X509Ref {
|
|||
}
|
||||
}
|
||||
|
||||
/// Writes certificate as PEM
|
||||
pub fn to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
/// Returns the certificate's signature
|
||||
pub fn signature(&self) -> &Asn1BitStringRef {
|
||||
unsafe {
|
||||
try!(cvt(ffi::PEM_write_bio_X509(mem_bio.as_ptr(), self.as_ptr())));
|
||||
let mut signature = ptr::null();
|
||||
compat::X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr());
|
||||
assert!(!signature.is_null());
|
||||
Asn1BitStringRef::from_ptr(signature as *mut _)
|
||||
}
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
/// Returns a DER serialized form of the certificate
|
||||
pub fn to_der(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
/// Returns the certificate's signature algorithm.
|
||||
pub fn signature_algorithm(&self) -> &X509AlgorithmRef {
|
||||
unsafe {
|
||||
ffi::i2d_X509_bio(mem_bio.as_ptr(), self.as_ptr());
|
||||
let mut algor = ptr::null();
|
||||
compat::X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr());
|
||||
assert!(!algor.is_null());
|
||||
X509AlgorithmRef::from_ptr(algor as *mut _)
|
||||
}
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
/// Returns the list of OCSP responder URLs specified in the certificate's Authority Information
|
||||
/// Access field.
|
||||
pub fn ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack> {
|
||||
unsafe {
|
||||
cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p))
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that this certificate issued `subject`.
|
||||
pub fn issued(&self, subject: &X509Ref) -> Result<(), X509VerifyError> {
|
||||
unsafe {
|
||||
let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr());
|
||||
match X509VerifyError::from_raw(r as c_long) {
|
||||
Some(e) => Err(e),
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
to_pem!(ffi::PEM_write_bio_X509);
|
||||
to_der!(ffi::i2d_X509);
|
||||
}
|
||||
|
||||
impl ToOwned for X509Ref {
|
||||
|
|
@ -474,25 +511,36 @@ impl X509 {
|
|||
X509Builder::new()
|
||||
}
|
||||
|
||||
/// Reads a certificate from DER.
|
||||
pub fn from_der(buf: &[u8]) -> Result<X509, ErrorStack> {
|
||||
from_pem!(X509, ffi::PEM_read_bio_X509);
|
||||
from_der!(X509, ffi::d2i_X509);
|
||||
|
||||
/// Deserializes a list of PEM-formatted certificates.
|
||||
pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> {
|
||||
unsafe {
|
||||
let mut ptr = buf.as_ptr();
|
||||
let len = cmp::min(buf.len(), c_long::max_value() as usize) as c_long;
|
||||
let x509 = try!(cvt_p(ffi::d2i_X509(ptr::null_mut(), &mut ptr, len)));
|
||||
Ok(X509::from_ptr(x509))
|
||||
ffi::init();
|
||||
let bio = try!(MemBioSlice::new(pem));
|
||||
|
||||
let mut certs = vec![];
|
||||
loop {
|
||||
let r = ffi::PEM_read_bio_X509(bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut());
|
||||
if r.is_null() {
|
||||
let err = ffi::ERR_peek_last_error();
|
||||
if ffi::ERR_GET_LIB(err) == ffi::ERR_LIB_PEM
|
||||
&& ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE {
|
||||
ffi::ERR_clear_error();
|
||||
break;
|
||||
}
|
||||
|
||||
return Err(ErrorStack::get());
|
||||
} else {
|
||||
certs.push(X509(r));
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a certificate from PEM.
|
||||
pub fn from_pem(buf: &[u8]) -> Result<X509, ErrorStack> {
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let handle = try!(cvt_p(ffi::PEM_read_bio_X509(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut())));
|
||||
Ok(X509::from_ptr(handle))
|
||||
Ok(certs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -534,7 +582,13 @@ impl<'a> X509v3Context<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
type_!(X509Extension, X509ExtensionRef, ffi::X509_EXTENSION, ffi::X509_EXTENSION_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::X509_EXTENSION;
|
||||
fn drop = ffi::X509_EXTENSION_free;
|
||||
|
||||
pub struct X509Extension;
|
||||
pub struct X509ExtensionRef;
|
||||
}
|
||||
|
||||
impl Stackable for X509Extension {
|
||||
type StackType = ffi::stack_st_X509_EXTENSION;
|
||||
|
|
@ -635,7 +689,13 @@ impl X509NameBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
type_!(X509Name, X509NameRef, ffi::X509_NAME, ffi::X509_NAME_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::X509_NAME;
|
||||
fn drop = ffi::X509_NAME_free;
|
||||
|
||||
pub struct X509Name;
|
||||
pub struct X509NameRef;
|
||||
}
|
||||
|
||||
impl X509Name {
|
||||
/// Returns a new builder.
|
||||
|
|
@ -694,7 +754,13 @@ impl<'a> Iterator for X509NameEntries<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
type_!(X509NameEntry, X509NameEntryRef, ffi::X509_NAME_ENTRY, ffi::X509_NAME_ENTRY_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::X509_NAME_ENTRY;
|
||||
fn drop = ffi::X509_NAME_ENTRY_free;
|
||||
|
||||
pub struct X509NameEntry;
|
||||
pub struct X509NameEntryRef;
|
||||
}
|
||||
|
||||
impl X509NameEntryRef {
|
||||
pub fn data(&self) -> &Asn1StringRef {
|
||||
|
|
@ -769,7 +835,13 @@ impl X509ReqBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
type_!(X509Req, X509ReqRef, ffi::X509_REQ, ffi::X509_REQ_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::X509_REQ;
|
||||
fn drop = ffi::X509_REQ_free;
|
||||
|
||||
pub struct X509Req;
|
||||
pub struct X509ReqRef;
|
||||
}
|
||||
|
||||
impl X509Req {
|
||||
pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
|
||||
|
|
@ -787,25 +859,40 @@ impl X509Req {
|
|||
Ok(X509Req::from_ptr(handle))
|
||||
}
|
||||
}
|
||||
|
||||
from_der!(X509Req, ffi::d2i_X509_REQ);
|
||||
}
|
||||
|
||||
impl X509ReqRef {
|
||||
/// Writes CSR as PEM
|
||||
pub fn to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
if unsafe { ffi::PEM_write_bio_X509_REQ(mem_bio.as_ptr(), self.as_ptr()) } != 1 {
|
||||
return Err(ErrorStack::get());
|
||||
to_pem!(ffi::PEM_write_bio_X509_REQ);
|
||||
to_der!(ffi::i2d_X509_REQ);
|
||||
|
||||
pub fn version(&self) -> i32
|
||||
{
|
||||
unsafe {
|
||||
compat::X509_REQ_get_version(self.as_ptr()) as i32
|
||||
}
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
/// Returns a DER serialized form of the CSR
|
||||
pub fn to_der(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
pub fn set_version(&mut self, value: i32) -> Result<(), ErrorStack>
|
||||
{
|
||||
unsafe {
|
||||
ffi::i2d_X509_REQ_bio(mem_bio.as_ptr(), self.as_ptr());
|
||||
cvt(ffi::X509_REQ_set_version(self.as_ptr(), value as c_long)).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn subject_name(&self) -> &X509NameRef {
|
||||
unsafe {
|
||||
let name = compat::X509_REQ_get_subject_name(self.as_ptr());
|
||||
assert!(!name.is_null());
|
||||
X509NameRef::from_ptr(name)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_subject_name(&mut self, value: &X509NameRef) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::X509_REQ_set_subject_name(self.as_ptr(), value.as_ptr())).map(|_| ())
|
||||
}
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -932,7 +1019,13 @@ impl X509VerifyError {
|
|||
}
|
||||
}
|
||||
|
||||
type_!(GeneralName, GeneralNameRef, ffi::GENERAL_NAME, ffi::GENERAL_NAME_free);
|
||||
foreign_type! {
|
||||
type CType = ffi::GENERAL_NAME;
|
||||
fn drop = ffi::GENERAL_NAME_free;
|
||||
|
||||
pub struct GeneralName;
|
||||
pub struct GeneralNameRef;
|
||||
}
|
||||
|
||||
impl GeneralNameRef {
|
||||
/// Returns the contents of this `GeneralName` if it is a `dNSName`.
|
||||
|
|
@ -972,18 +1065,42 @@ impl Stackable for GeneralName {
|
|||
type StackType = ffi::stack_st_GENERAL_NAME;
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = ffi::X509_ALGOR;
|
||||
fn drop = ffi::X509_ALGOR_free;
|
||||
|
||||
pub struct X509Algorithm;
|
||||
pub struct X509AlgorithmRef;
|
||||
}
|
||||
|
||||
impl X509AlgorithmRef {
|
||||
/// Returns the ASN.1 OID of this algorithm.
|
||||
pub fn object(&self) -> &Asn1ObjectRef {
|
||||
unsafe {
|
||||
let mut oid = ptr::null();
|
||||
compat::X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr());
|
||||
assert!(!oid.is_null());
|
||||
Asn1ObjectRef::from_ptr(oid as *mut _)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(ossl110)]
|
||||
mod compat {
|
||||
pub use ffi::X509_getm_notAfter as X509_get_notAfter;
|
||||
pub use ffi::X509_getm_notBefore as X509_get_notBefore;
|
||||
pub use ffi::X509_up_ref;
|
||||
pub use ffi::X509_get0_extensions;
|
||||
pub use ffi::X509_REQ_get_version;
|
||||
pub use ffi::X509_REQ_get_subject_name;
|
||||
pub use ffi::X509_get0_signature;
|
||||
pub use ffi::X509_ALGOR_get0;
|
||||
}
|
||||
|
||||
#[cfg(ossl10x)]
|
||||
#[allow(bad_style)]
|
||||
mod compat {
|
||||
use libc::c_int;
|
||||
use libc::{c_int, c_void};
|
||||
use ffi;
|
||||
|
||||
pub unsafe fn X509_get_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
|
||||
|
|
@ -1011,4 +1128,36 @@ mod compat {
|
|||
(*info).extensions
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long
|
||||
{
|
||||
::ffi::ASN1_INTEGER_get((*(*x).req_info).version)
|
||||
}
|
||||
|
||||
pub unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME
|
||||
{
|
||||
(*(*x).req_info).subject
|
||||
}
|
||||
|
||||
pub unsafe fn X509_get0_signature(psig: *mut *const ffi::ASN1_BIT_STRING,
|
||||
palg: *mut *const ffi::X509_ALGOR,
|
||||
x: *const ffi::X509) {
|
||||
if !psig.is_null() {
|
||||
*psig = (*x).signature;
|
||||
}
|
||||
if !palg.is_null() {
|
||||
*palg = (*x).sig_alg;
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn X509_ALGOR_get0(paobj: *mut *const ffi::ASN1_OBJECT,
|
||||
pptype: *mut c_int,
|
||||
pval: *mut *mut c_void,
|
||||
alg: *const ffi::X509_ALGOR) {
|
||||
if !paobj.is_null() {
|
||||
*paobj = (*alg).algorithm;
|
||||
}
|
||||
assert!(pptype.is_null());
|
||||
assert!(pval.is_null());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
use ffi;
|
||||
use foreign_types::ForeignTypeRef;
|
||||
use std::mem;
|
||||
|
||||
use {cvt, cvt_p};
|
||||
use error::ErrorStack;
|
||||
use x509::X509;
|
||||
|
||||
foreign_type! {
|
||||
type CType = ffi::X509_STORE;
|
||||
fn drop = ffi::X509_STORE_free;
|
||||
|
||||
pub struct X509StoreBuilder;
|
||||
pub struct X509StoreBuilderRef;
|
||||
}
|
||||
|
||||
impl X509StoreBuilder {
|
||||
/// Returns a builder for a certificate store.
|
||||
///
|
||||
/// The store is initially empty.
|
||||
pub fn new() -> Result<X509StoreBuilder, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
|
||||
cvt_p(ffi::X509_STORE_new()).map(X509StoreBuilder)
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs the `X509Store`.
|
||||
pub fn build(self) -> X509Store {
|
||||
let store = X509Store(self.0);
|
||||
mem::forget(self);
|
||||
store
|
||||
}
|
||||
}
|
||||
|
||||
impl X509StoreBuilderRef {
|
||||
/// Adds a certificate to the certificate store.
|
||||
pub fn add_cert(&mut self, cert: X509) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
let ptr = cert.as_ptr();
|
||||
mem::forget(cert); // the cert will be freed inside of X509_STORE_add_cert on error
|
||||
cvt(ffi::X509_STORE_add_cert(self.as_ptr(), ptr)).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Load certificates from their default locations.
|
||||
///
|
||||
/// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR`
|
||||
/// environment variables if present, or defaults specified at OpenSSL
|
||||
/// build time otherwise.
|
||||
pub fn set_default_paths(&mut self) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
cvt(ffi::X509_STORE_set_default_paths(self.as_ptr())).map(|_| ())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = ffi::X509_STORE;
|
||||
fn drop = ffi::X509_STORE_free;
|
||||
|
||||
pub struct X509Store;
|
||||
pub struct X509StoreRef;
|
||||
}
|
||||
|
|
@ -1,14 +1,17 @@
|
|||
use serialize::hex::FromHex;
|
||||
use hex::{FromHex, ToHex};
|
||||
|
||||
use asn1::Asn1Time;
|
||||
use bn::{BigNum, MSB_MAYBE_ZERO};
|
||||
use ec::{NAMED_CURVE, EcGroup, EcKey};
|
||||
use hash::MessageDigest;
|
||||
use nid::X9_62_PRIME256V1;
|
||||
use pkey::PKey;
|
||||
use rsa::Rsa;
|
||||
use stack::Stack;
|
||||
use x509::{X509, X509Generator, X509Name, X509Req};
|
||||
use x509::extension::{Extension, BasicConstraints, KeyUsage, ExtendedKeyUsage,
|
||||
SubjectKeyIdentifier, AuthorityKeyIdentifier, SubjectAlternativeName};
|
||||
use ssl::{SslMethod, SslContextBuilder};
|
||||
use x509::extension::AltNameOption as SAN;
|
||||
use x509::extension::KeyUsageOption::{DigitalSignature, KeyEncipherment};
|
||||
use x509::extension::ExtKeyUsageOption::{self, ClientAuth, ServerAuth};
|
||||
|
|
@ -76,7 +79,12 @@ fn test_req_gen() {
|
|||
let pkey = pkey();
|
||||
|
||||
let req = get_generator().request(&pkey).unwrap();
|
||||
req.to_pem().unwrap();
|
||||
let reqpem = req.to_pem().unwrap();
|
||||
|
||||
let req = X509Req::from_pem(&reqpem).ok().expect("Failed to load PEM");
|
||||
let cn = (*req).subject_name().entries_by_nid(nid::COMMONNAME).next().unwrap();
|
||||
assert_eq!(0, (*req).version());
|
||||
assert_eq!(cn.data().as_slice(), b"test_me");
|
||||
|
||||
// FIXME: check data in result to be correct, needs implementation
|
||||
// of X509_REQ getters
|
||||
|
|
@ -89,7 +97,7 @@ fn test_cert_loading() {
|
|||
let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap();
|
||||
|
||||
let hash_str = "59172d9313e84459bcff27f967e79e6e9217e584";
|
||||
let hash_vec = hash_str.from_hex().unwrap();
|
||||
let hash_vec = Vec::from_hex(hash_str).unwrap();
|
||||
|
||||
assert_eq!(fingerprint, hash_vec);
|
||||
}
|
||||
|
|
@ -136,7 +144,7 @@ fn test_nid_values() {
|
|||
assert_eq!(email.data().as_slice(), b"test@example.com");
|
||||
|
||||
let friendly = subject.entries_by_nid(nid::FRIENDLYNAME).next().unwrap();
|
||||
assert_eq!(&*friendly.data().as_utf8().unwrap(), "Example");
|
||||
assert_eq!(&**friendly.data().as_utf8().unwrap(), "Example");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -260,3 +268,64 @@ fn x509_req_builder() {
|
|||
|
||||
builder.sign(&pkey, MessageDigest::sha256()).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stack_from_pem() {
|
||||
let certs = include_bytes!("../../test/certs.pem");
|
||||
let certs = X509::stack_from_pem(certs).unwrap();
|
||||
|
||||
assert_eq!(certs.len(), 2);
|
||||
assert_eq!(certs[0].fingerprint(MessageDigest::sha1()).unwrap().to_hex(),
|
||||
"59172d9313e84459bcff27f967e79e6e9217e584");
|
||||
assert_eq!(certs[1].fingerprint(MessageDigest::sha1()).unwrap().to_hex(),
|
||||
"c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issued() {
|
||||
let cert = include_bytes!("../../test/cert.pem");
|
||||
let cert = X509::from_pem(cert).unwrap();
|
||||
let ca = include_bytes!("../../test/root-ca.pem");
|
||||
let ca = X509::from_pem(ca).unwrap();
|
||||
|
||||
ca.issued(&cert).unwrap();
|
||||
cert.issued(&cert).err().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ecdsa_cert() {
|
||||
let mut group = EcGroup::from_curve_name(X9_62_PRIME256V1).unwrap();
|
||||
group.set_asn1_flag(NAMED_CURVE);
|
||||
let key = EcKey::generate(&group).unwrap();
|
||||
let key = PKey::from_ec_key(key).unwrap();
|
||||
|
||||
let cert = X509Generator::new()
|
||||
.set_valid_period(365)
|
||||
.add_name("CN".to_owned(), "TestServer".to_owned())
|
||||
.set_sign_hash(MessageDigest::sha256())
|
||||
.sign(&key)
|
||||
.unwrap();
|
||||
|
||||
let mut ctx = SslContextBuilder::new(SslMethod::tls()).unwrap();
|
||||
ctx.set_certificate(&cert).unwrap();
|
||||
ctx.set_private_key(&key).unwrap();
|
||||
ctx.check_private_key().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signature() {
|
||||
let cert = include_bytes!("../../test/cert.pem");
|
||||
let cert = X509::from_pem(cert).unwrap();
|
||||
let signature = cert.signature();
|
||||
assert_eq!(signature.as_slice().to_hex(),
|
||||
"4af607b889790b43470442cfa551cdb8b6d0b0340d2958f76b9e3ef6ad4992230cead6842587f0ecad5\
|
||||
78e6e11a221521e940187e3d6652de14e84e82f6671f097cc47932e022add3c0cb54a26bf27fa84c107\
|
||||
4971caa6bee2e42d34a5b066c427f2d452038082b8073993399548088429de034fdd589dcfb0dd33be7\
|
||||
ebdfdf698a28d628a89568881d658151276bde333600969502c4e62e1d3470a683364dfb241f78d310a\
|
||||
89c119297df093eb36b7fd7540224f488806780305d1e79ffc938fe2275441726522ab36d88348e6c51\
|
||||
f13dcc46b5e1cdac23c974fd5ef86aa41e91c9311655090a52333bc79687c748d833595d4c5f987508f\
|
||||
e121997410d37c");
|
||||
let algorithm = cert.signature_algorithm();
|
||||
assert_eq!(algorithm.object().nid(), nid::SHA256WITHRSAENCRYPTION);
|
||||
assert_eq!(algorithm.object().to_string(), "sha256WithRSAEncryption");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,21 +3,29 @@
|
|||
set -ex
|
||||
|
||||
MAX_REDIRECTS=5
|
||||
OPENSSL=openssl-$BUILD_OPENSSL_VERSION.tar.gz
|
||||
OUT=/tmp/$OPENSSL
|
||||
|
||||
me=$0
|
||||
myname=`basename $me`
|
||||
|
||||
cmp --silent $me $HOME/openssl/$myname && exit 0 || echo "cache is busted"
|
||||
|
||||
rm -rf $HOME/openssl
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||
if [ -n "${BUILD_LIBRESSL_VERSION}" ]; then
|
||||
NAME=libressl
|
||||
URL1="http://ftp3.usa.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${BUILD_LIBRESSL_VERSION}.tar.gz"
|
||||
URL2="http://ftp.eu.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${BUILD_LIBRESSL_VERSION}.tar.gz"
|
||||
OUT="/tmp/libressl-${BUILD_OPENSSL_VERSION}.tar.gz"
|
||||
elif [ -n "${BUILD_OPENSSL_VERSION}" ]; then
|
||||
NAME=openssl
|
||||
URL1="https://openssl.org/source/openssl-${BUILD_OPENSSL_VERSION}.tar.gz"
|
||||
URL2="http://mirrors.ibiblio.org/openssl/source/openssl-${BUILD_OPENSSL_VERSION}.tar.gz"
|
||||
OUT="/tmp/openssl-${BUILD_OPENSSL_VERSION}.tar.gz"
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$BUILD_OPENSSL_VERSION" == "" ]; then
|
||||
me=$0
|
||||
myname=`basename ${me}`
|
||||
|
||||
cmp --silent ${me} ${HOME}/${NAME}/${myname} && exit 0 || echo "cache is busted"
|
||||
|
||||
rm -rf "${HOME}/${NAME}"
|
||||
|
||||
if [ "${TRAVIS_OS_NAME}" == "osx" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
|
@ -32,17 +40,21 @@ else
|
|||
OS_COMPILER=linux-x86_64
|
||||
fi
|
||||
|
||||
mkdir -p /tmp/openssl
|
||||
cp $me /tmp/openssl/$myname
|
||||
cd /tmp/openssl
|
||||
mkdir -p /tmp/build
|
||||
cp ${me} /tmp/build/${myname}
|
||||
cd /tmp/build
|
||||
|
||||
curl -o $OUT -L --max-redirs $MAX_REDIRECTS https://openssl.org/source/$OPENSSL \
|
||||
|| curl -o $OUT -L --max-redirs ${MAX_REDIRECTS} http://mirrors.ibiblio.org/openssl/source/$OPENSSL
|
||||
curl -o ${OUT} -L --max-redirs ${MAX_REDIRECTS} ${URL1} \
|
||||
|| curl -o ${OUT} -L --max-redirs ${MAX_REDIRECTS} ${URL2}
|
||||
|
||||
tar --strip-components=1 -xzf $OUT
|
||||
tar --strip-components=1 -xzf ${OUT}
|
||||
|
||||
./Configure --prefix=$HOME/openssl $OS_COMPILER -fPIC $OS_FLAGS
|
||||
if [ -n "${BUILD_LIBRESSL_VERSION}" ]; then
|
||||
./configure --prefix=${HOME}/libressl
|
||||
else
|
||||
./Configure --prefix=${HOME}/openssl ${OS_COMPILER} -fPIC ${OS_FLAGS}
|
||||
fi
|
||||
|
||||
make -j$(nproc)
|
||||
make install
|
||||
cp $myname $HOME/openssl/$myname
|
||||
cp ${myname} ${HOME}/${NAME}/${myname}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDGzCCAgMCCQCHcfe97pgvpTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB
|
||||
VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
|
||||
cyBQdHkgTHRkMB4XDTE2MDgxNDE3MDAwM1oXDTI2MDgxMjE3MDAwM1owWjELMAkG
|
||||
A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
|
||||
IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKZm9vYmFyLmNvbTCCASIwDQYJKoZI
|
||||
hvcNAQEBBQADggEPADCCAQoCggEBAKj0JYxEsxejUIX+I5GH0Hg2G0kX/y1H0+Ub
|
||||
3mw2/Ja5BD/yN96/7zMSumXF8uS3SkmpyiJkbyD01TSRTqjlP7/VCBlyUIChlpLQ
|
||||
mrGaijZiT/VCyPXqmcwFzXS5IOTpX1olJfW8rA41U1LCIcDUyFf6LtZ/v8rSeKr6
|
||||
TuE6SGV4WRaBm1SrjWBeHVV866CRrtSS1ieT2asFsAyOZqWhk2fakwwBDFWDhOGI
|
||||
ubfO+5aq9cBJbNRlzsgB3UZs3gC0O6GzbnZ6oT0TiJMeTsXXjABLUlaq/rrqFF4Y
|
||||
euZkkbHTFBMz288PUc3m3ZTcpN+E7+ZOUBRZXKD20K07NugqCzUCAwEAATANBgkq
|
||||
hkiG9w0BAQsFAAOCAQEASvYHuIl5C0NHBELPpVHNuLbQsDQNKVj3a54+9q1JkiMM
|
||||
6taEJYfw7K1Xjm4RoiFSHpQBh+PWZS3hToToL2Zx8JfMR5MuAirdPAy1Sia/J/qE
|
||||
wQdJccqmvuLkLTSlsGbEJ/LUUgOAgrgHOZM5lUgIhCneA0/dWJ3PsN0zvn69/faY
|
||||
oo1iiolWiIHWWBUSdr3jM2AJaVAsTmLh00cKaDNk37JB940xConBGSl98JPrNrf9
|
||||
dUAiT0iIBngDBdHnn/yTj+InVEFyZSKrNtiDSObFHxPcxGteHNrCPJdP1e+GqkHp
|
||||
HJMRZVCQpSMzvHlofHSNgzWV1MX5h1CP4SGZdBDTfA==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDXTCCAkWgAwIBAgIJAOIvDiVb18eVMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
|
||||
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
|
||||
aWRnaXRzIFB0eSBMdGQwHhcNMTYwODE0MTY1NjExWhcNMjYwODEyMTY1NjExWjBF
|
||||
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
|
||||
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
|
||||
CgKCAQEArVHWFn52Lbl1l59exduZntVSZyDYpzDND+S2LUcO6fRBWhV/1Kzox+2G
|
||||
ZptbuMGmfI3iAnb0CFT4uC3kBkQQlXonGATSVyaFTFR+jq/lc0SP+9Bd7SBXieIV
|
||||
eIXlY1TvlwIvj3Ntw9zX+scTA4SXxH6M0rKv9gTOub2vCMSHeF16X8DQr4XsZuQr
|
||||
7Cp7j1I4aqOJyap5JTl5ijmG8cnu0n+8UcRlBzy99dLWJG0AfI3VRJdWpGTNVZ92
|
||||
aFff3RpK3F/WI2gp3qV1ynRAKuvmncGC3LDvYfcc2dgsc1N6Ffq8GIrkgRob6eBc
|
||||
klDHp1d023Lwre+VaVDSo1//Y72UFwIDAQABo1AwTjAdBgNVHQ4EFgQUbNOlA6sN
|
||||
XyzJjYqciKeId7g3/ZowHwYDVR0jBBgwFoAUbNOlA6sNXyzJjYqciKeId7g3/Zow
|
||||
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAVVaR5QWLZIRR4Dw6TSBn
|
||||
BQiLpBSXN6oAxdDw6n4PtwW6CzydaA+creiK6LfwEsiifUfQe9f+T+TBSpdIYtMv
|
||||
Z2H2tjlFX8VrjUFvPrvn5c28CuLI0foBgY8XGSkR2YMYzWw2jPEq3Th/KM5Catn3
|
||||
AFm3bGKWMtGPR4v+90chEN0jzaAmJYRrVUh9vea27bOCn31Nse6XXQPmSI6Gyncy
|
||||
OAPUsvPClF3IjeL1tmBotWqSGn1cYxLo+Lwjk22A9h6vjcNQRyZF2VLVvtwYrNU3
|
||||
mwJ6GCLsLHpwW/yjyvn8iEltnJvByM/eeRnfXV6WDObyiZsE/n6DxIRJodQzFqy9
|
||||
GA==
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -12,15 +12,21 @@ esac
|
|||
|
||||
echo Using features: $FEATURES
|
||||
|
||||
if [ -d "$HOME/openssl/lib" ]; then
|
||||
export OPENSSL_DIR=$HOME/openssl
|
||||
export PATH=$HOME/openssl/bin:$PATH
|
||||
if [ -n "${BUILD_LIBRESSL_VERSION}" -a -d "$HOME/libressl/lib" ]; then
|
||||
echo "Testing build libressl-${BUILD_LIBRESSL_VERSION}"
|
||||
export OPENSSL_DIR=${HOME}/libressl
|
||||
export PATH="${HOME}/libressl/bin:${PATH}"
|
||||
|
||||
elif [ -n "${BUILD_OPENSSL_VERSION}" -a -d "$HOME/openssl/lib" ]; then
|
||||
echo "Testing build openssl-${BUILD_LIBRESSL_VERSION}"
|
||||
export OPENSSL_DIR="${HOME}/openssl"
|
||||
export PATH="${HOME}/openssl/bin:${PATH}"
|
||||
fi
|
||||
|
||||
if [ "$TARGET" == "arm-unknown-linux-gnueabihf" ]; then
|
||||
FLAGS="--no-run"
|
||||
fi
|
||||
|
||||
cargo run --manifest-path systest/Cargo.toml --target $TARGET
|
||||
cargo run --manifest-path systest/Cargo.toml --target $TARGET -v
|
||||
exec cargo test --manifest-path openssl/Cargo.toml --target $TARGET \
|
||||
--features "$FEATURES" $FLAGS
|
||||
--features "$FEATURES" -v $FLAGS
|
||||
|
|
|
|||
|
|
@ -22,7 +22,11 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
cfg.cfg(&format!("ossl{}", env::var("DEP_OPENSSL_VERSION").unwrap()), None);
|
||||
if let Ok(_) = env::var("DEP_OPENSSL_LIBRESSL") {
|
||||
cfg.cfg("libressl", None);
|
||||
} else if let Ok(version) = env::var("DEP_OPENSSL_VERSION") {
|
||||
cfg.cfg(&format!("ossl{}", version), None);
|
||||
}
|
||||
if let Ok(vars) = env::var("DEP_OPENSSL_CONF") {
|
||||
for var in vars.split(",") {
|
||||
cfg.cfg("osslconf", Some(var));
|
||||
|
|
@ -42,7 +46,9 @@ fn main() {
|
|||
.header("openssl/err.h")
|
||||
.header("openssl/rand.h")
|
||||
.header("openssl/pkcs12.h")
|
||||
.header("openssl/bn.h");
|
||||
.header("openssl/bn.h")
|
||||
.header("openssl/aes.h")
|
||||
.header("openssl/ocsp.h");
|
||||
cfg.type_name(|s, is_struct| {
|
||||
// Add some `*` on some callback parameters to get function pointer to
|
||||
// typecheck in C, especially on MSVC.
|
||||
|
|
@ -52,7 +58,8 @@ fn main() {
|
|||
format!("bio_info_cb*")
|
||||
} else if s == "_STACK" {
|
||||
format!("struct stack_st")
|
||||
} else if is_struct && s.chars().next().unwrap().is_lowercase() {
|
||||
// This logic should really be cleaned up
|
||||
} else if is_struct && s != "point_conversion_form_t" && s.chars().next().unwrap().is_lowercase() {
|
||||
format!("struct {}", s)
|
||||
} else {
|
||||
format!("{}", s)
|
||||
|
|
@ -85,6 +92,8 @@ fn main() {
|
|||
});
|
||||
cfg.skip_signededness(|s| {
|
||||
s.ends_with("_cb") ||
|
||||
s.ends_with("_CB") ||
|
||||
s.ends_with("_cb_fn") ||
|
||||
s.starts_with("CRYPTO_") ||
|
||||
s == "PasswordCallback"
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue