Merge remote-tracking branch 'origin/master' into x509-builder

This commit is contained in:
Steven Fackler 2017-02-11 10:13:00 -08:00
commit f2c69ae7e9
48 changed files with 5219 additions and 981 deletions

View File

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

View File

@ -2,18 +2,18 @@
[![Build Status](https://travis-ci.org/sfackler/rust-openssl.svg?branch=master)](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.

View File

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

View File

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

View File

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

View File

@ -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,

734
openssl-sys/src/libressl.rs Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

115
openssl/src/aes.rs Normal file
View File

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

View File

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

View File

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

View File

@ -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> {

View File

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

View File

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

View File

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

484
openssl/src/ec.rs Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

216
openssl/src/macros.rs Normal file
View File

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

304
openssl/src/ocsp.rs Normal file
View File

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

View File

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

View File

@ -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],

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

80
openssl/src/string.rs Normal file
View File

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

View File

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

View File

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

View File

@ -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.

View File

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

View File

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

View File

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

65
openssl/src/x509/store.rs Normal file
View File

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

View File

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

View File

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

40
openssl/test/certs.pem Normal file
View File

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

View File

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

View File

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