Merge branch 'release-v0.7.15-sys-v0.8.0' into release

This commit is contained in:
Steven Fackler 2016-08-11 21:01:27 -07:00
commit 652326003c
46 changed files with 3100 additions and 3762 deletions

View File

@ -6,7 +6,7 @@ addons:
- gcc-arm-linux-gnueabihf - gcc-arm-linux-gnueabihf
rust: rust:
- nightly - nightly
- 1.8.0 - 1.9.0
os: os:
- osx - osx
- linux - linux

2
Cargo.toml Normal file
View File

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

View File

@ -2,7 +2,7 @@
[![Build Status](https://travis-ci.org/sfackler/rust-openssl.svg?branch=master)](https://travis-ci.org/sfackler/rust-openssl) [![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.7.14/openssl). [Documentation](https://sfackler.github.io/rust-openssl/doc/v0.8.0/openssl).
## Building ## Building

View File

@ -10,8 +10,8 @@ environment:
install: install:
- ps: Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-1_0_2h.exe" - ps: Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-1_0_2h.exe"
- Win%BITS%OpenSSL-1_0_2h.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL" - Win%BITS%OpenSSL-1_0_2h.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL"
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.8.0-${env:TARGET}.exe" - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.9.0-${env:TARGET}.exe"
- rust-1.8.0-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" - rust-1.9.0-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
- SET PATH=%PATH%;C:\MinGW\bin - SET PATH=%PATH%;C:\MinGW\bin
- rustc -V - rustc -V

View File

@ -1,19 +0,0 @@
[package]
name = "openssl-sys-extras"
version = "0.7.14"
authors = ["Steven Fackler <sfackler@gmail.com>"]
license = "MIT"
description = "Extra FFI bindings to OpenSSL that require a C shim"
repository = "https://github.com/sfackler/rust-openssl"
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.14/openssl_sys_extras"
build = "build.rs"
[features]
ecdh_auto = []
[dependencies]
libc = "0.2"
openssl-sys = { version = "0.7.14", path = "../openssl-sys" }
[build-dependencies]
gcc = "0.3"

View File

@ -1,77 +0,0 @@
extern crate gcc;
use std::env;
use std::path::PathBuf;
use std::fs::File;
use std::io::Write as IoWrite;
use std::fmt::Write;
fn main() {
let options_shim_file = generate_options_shim();
let mut config = gcc::Config::new();
if let Some(paths) = env::var_os("DEP_OPENSSL_INCLUDE") {
for path in env::split_paths(&paths) {
config.include(PathBuf::from(path));
}
}
config.file("src/openssl_shim.c")
.file(options_shim_file)
.compile("libopenssl_shim.a");
}
macro_rules! import_options {
( $( $name:ident $val:expr )* ) => {
&[ $( (stringify!($name),$val), )* ]
};
}
fn generate_options_shim() -> PathBuf {
let options: &[(&'static str,u64)]=include!("src/ssl_options.rs");
let mut shim = String::new();
writeln!(shim,"#include <stdint.h>").unwrap();
writeln!(shim,"#include <openssl/ssl.h>").unwrap();
for &(name,value) in options {
writeln!(shim,"#define RUST_{} UINT64_C({})",name,value).unwrap();
writeln!(shim,"#ifndef {}",name).unwrap();
writeln!(shim,"# define {} 0",name).unwrap();
writeln!(shim,"#endif").unwrap();
}
writeln!(shim,"#define COPY_MASK ( \\").unwrap();
let mut it=options.iter().peekable();
while let Some(&(name,_))=it.next() {
let eol=match it.peek() {
Some(_) => " | \\",
None => " )"
};
writeln!(shim," ((RUST_{0}==(uint64_t)(uint32_t){0})?RUST_{0}:UINT64_C(0)){1}",name,eol).unwrap();
}
writeln!(shim,"long rust_openssl_ssl_ctx_options_rust_to_c(uint64_t rustval) {{").unwrap();
writeln!(shim," long cval=rustval&COPY_MASK;").unwrap();
for &(name,_) in options {
writeln!(shim," if (rustval&RUST_{0}) cval|={0};",name).unwrap();
}
writeln!(shim," return cval;").unwrap();
writeln!(shim,"}}").unwrap();
writeln!(shim,"uint64_t rust_openssl_ssl_ctx_options_c_to_rust(long cval) {{").unwrap();
writeln!(shim," uint64_t rustval=cval&COPY_MASK;").unwrap();
for &(name,_) in options {
writeln!(shim," if (cval&{0}) rustval|=RUST_{0};",name).unwrap();
}
writeln!(shim," return rustval;").unwrap();
writeln!(shim,"}}").unwrap();
let out_dir = env::var("OUT_DIR").unwrap();
let dest_file = PathBuf::from(&out_dir).join("ssl_ctx_options_shim.c");
let mut f = File::create(&dest_file).unwrap();
f.write_all(shim.as_bytes()).unwrap();
dest_file
}

View File

@ -1,82 +0,0 @@
#![allow(non_upper_case_globals, non_snake_case)]
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.14")]
extern crate openssl_sys;
extern crate libc;
use libc::{c_int, c_uint, c_long, c_char, c_void};
use openssl_sys::{HMAC_CTX, EVP_MD, ENGINE, SSL_CTX, BIO, X509, stack_st_X509_EXTENSION, SSL, DH};
macro_rules! import_options {
( $( $name:ident $val:expr )* ) => {
$( pub const $name: u64 = $val; )*
};
}
include!("ssl_options.rs");
pub unsafe fn SSL_CTX_set_options(ssl: *mut SSL_CTX, op: u64) -> u64 {
rust_openssl_ssl_ctx_options_c_to_rust(SSL_CTX_set_options_shim(ssl, rust_openssl_ssl_ctx_options_rust_to_c(op)))
}
pub unsafe fn SSL_CTX_get_options(ssl: *mut SSL_CTX) -> u64 {
rust_openssl_ssl_ctx_options_c_to_rust(SSL_CTX_get_options_shim(ssl))
}
pub unsafe fn SSL_CTX_clear_options(ssl: *mut SSL_CTX, op: u64) -> u64 {
rust_openssl_ssl_ctx_options_c_to_rust(SSL_CTX_clear_options_shim(ssl, rust_openssl_ssl_ctx_options_rust_to_c(op)))
}
extern {
fn rust_openssl_ssl_ctx_options_rust_to_c(rustval: u64) -> c_long;
fn rust_openssl_ssl_ctx_options_c_to_rust(cval: c_long) -> u64;
// Pre-1.0 versions of these didn't return anything, so the shims bridge that gap
#[cfg_attr(not(target_os = "nacl"), link_name = "HMAC_Init_ex_shim")]
pub fn HMAC_Init_ex(ctx: *mut HMAC_CTX, key: *const u8, keylen: c_int, md: *const EVP_MD, imple: *const ENGINE) -> c_int;
#[cfg_attr(not(target_os = "nacl"), link_name = "HMAC_Final_shim")]
pub fn HMAC_Final(ctx: *mut HMAC_CTX, output: *mut u8, len: *mut c_uint) -> c_int;
#[cfg_attr(not(target_os = "nacl"), link_name = "HMAC_Update_shim")]
pub fn HMAC_Update(ctx: *mut HMAC_CTX, input: *const u8, len: c_uint) -> c_int;
// This isn't defined in < 1.0 so we copy the implementation there
pub fn HMAC_CTX_copy(dst: *mut HMAC_CTX, src: *const HMAC_CTX) -> c_int;
// These functions are defined in OpenSSL as macros, so we shim them
#[link_name = "BIO_eof_shim"]
pub fn BIO_eof(b: *mut BIO) -> c_int;
#[link_name = "BIO_set_nbio_shim"]
pub fn BIO_set_nbio(b: *mut BIO, enabled: c_long) -> c_long;
#[link_name = "BIO_set_mem_eof_return_shim"]
pub fn BIO_set_mem_eof_return(b: *mut BIO, v: c_int);
#[link_name = "BIO_clear_retry_flags_shim"]
pub fn BIO_clear_retry_flags(b: *mut BIO);
#[link_name = "BIO_set_retry_read_shim"]
pub fn BIO_set_retry_read(b: *mut BIO);
#[link_name = "BIO_set_retry_write_shim"]
pub fn BIO_set_retry_write(b: *mut BIO);
#[link_name = "BIO_flush"]
pub fn BIO_flush(b: *mut BIO) -> c_long;
pub fn SSL_CTX_set_options_shim(ctx: *mut SSL_CTX, options: c_long) -> c_long;
pub fn SSL_CTX_get_options_shim(ctx: *mut SSL_CTX) -> c_long;
pub fn SSL_CTX_clear_options_shim(ctx: *mut SSL_CTX, options: c_long) -> c_long;
#[link_name = "SSL_CTX_set_mode_shim"]
pub fn SSL_CTX_set_mode(ctx: *mut SSL_CTX, options: c_long) -> c_long;
#[link_name = "SSL_CTX_add_extra_chain_cert_shim"]
pub fn SSL_CTX_add_extra_chain_cert(ctx: *mut SSL_CTX, x509: *mut X509) -> c_long;
#[link_name = "SSL_CTX_set_read_ahead_shim"]
pub fn SSL_CTX_set_read_ahead(ctx: *mut SSL_CTX, m: c_long) -> c_long;
#[cfg(feature = "ecdh_auto")]
#[link_name = "SSL_CTX_set_ecdh_auto_shim"]
pub fn SSL_CTX_set_ecdh_auto(ssl: *mut SSL_CTX, onoff: c_int) -> c_int;
#[link_name = "SSL_set_tlsext_host_name_shim"]
pub fn SSL_set_tlsext_host_name(s: *mut SSL, name: *const c_char) -> c_long;
#[link_name = "SSL_CTX_set_tmp_dh_shim"]
pub fn SSL_CTX_set_tmp_dh(s: *mut SSL, dh: *const DH) -> c_long;
#[link_name = "X509_get_extensions_shim"]
pub fn X509_get_extensions(x: *mut X509) -> *mut stack_st_X509_EXTENSION;
#[link_name = "SSL_CTX_set_tlsext_servername_callback_shim"]
pub fn SSL_CTX_set_tlsext_servername_callback(ssl: *mut SSL_CTX, callback: Option<extern fn()>);
#[link_name = "SSL_CTX_set_tlsext_servername_arg_shim"]
pub fn SSL_CTX_set_tlsext_servername_arg(ssl: *mut SSL_CTX, arg: *const c_void);
}

View File

@ -1,144 +0,0 @@
#include <openssl/hmac.h>
#include <openssl/ssl.h>
#include <openssl/dh.h>
#include <openssl/bn.h>
#if OPENSSL_VERSION_NUMBER < 0x10000000L
// Copied from openssl crypto/hmac/hmac.c
int HMAC_CTX_copy(HMAC_CTX *dctx, HMAC_CTX *sctx)
{
if (!EVP_MD_CTX_copy(&dctx->i_ctx, &sctx->i_ctx))
goto err;
if (!EVP_MD_CTX_copy(&dctx->o_ctx, &sctx->o_ctx))
goto err;
if (!EVP_MD_CTX_copy(&dctx->md_ctx, &sctx->md_ctx))
goto err;
memcpy(dctx->key, sctx->key, HMAC_MAX_MD_CBLOCK);
dctx->key_length = sctx->key_length;
dctx->md = sctx->md;
return 1;
err:
return 0;
}
int HMAC_Init_ex_shim(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md, ENGINE *impl) {
HMAC_Init_ex(ctx, key, key_len, md, impl);
return 1;
}
int HMAC_Update_shim(HMAC_CTX *ctx, const unsigned char *data, int len) {
HMAC_Update(ctx, data, len);
return 1;
}
int HMAC_Final_shim(HMAC_CTX *ctx, unsigned char *md, unsigned int *len) {
HMAC_Final(ctx, md, len);
return 1;
}
#else
int HMAC_Init_ex_shim(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md, ENGINE *impl) {
return HMAC_Init_ex(ctx, key, key_len, md, impl);
}
int HMAC_Update_shim(HMAC_CTX *ctx, const unsigned char *data, int len) {
return HMAC_Update(ctx, data, len);
}
int HMAC_Final_shim(HMAC_CTX *ctx, unsigned char *md, unsigned int *len) {
return HMAC_Final(ctx, md, len);
}
#endif
// shims for OpenSSL macros
int BIO_eof_shim(BIO *b) {
return BIO_eof(b);
}
long BIO_set_nbio_shim(BIO *b, long enabled) {
return BIO_set_nbio(b, enabled);
}
void BIO_set_mem_eof_return_shim(BIO *b, int v) {
BIO_set_mem_eof_return(b, v);
}
void BIO_clear_retry_flags_shim(BIO *b) {
BIO_clear_retry_flags(b);
}
void BIO_set_retry_read_shim(BIO *b) {
BIO_set_retry_read(b);
}
void BIO_set_retry_write_shim(BIO *b) {
BIO_set_retry_write(b);
}
long BIO_flush_shim(BIO *b) {
return BIO_flush(b);
}
long SSL_CTX_set_options_shim(SSL_CTX *ctx, long options) {
return SSL_CTX_set_options(ctx, options);
}
long SSL_CTX_get_options_shim(SSL_CTX *ctx) {
return SSL_CTX_get_options(ctx);
}
long SSL_CTX_clear_options_shim(SSL_CTX *ctx, long options) {
return SSL_CTX_clear_options(ctx, options);
}
long SSL_CTX_set_mode_shim(SSL_CTX *ctx, long options) {
return SSL_CTX_set_mode(ctx, options);
}
long SSL_CTX_add_extra_chain_cert_shim(SSL_CTX *ctx, X509 *x509) {
return SSL_CTX_add_extra_chain_cert(ctx, x509);
}
long SSL_CTX_set_read_ahead_shim(SSL_CTX *ctx, long m) {
return SSL_CTX_set_read_ahead(ctx, m);
}
long SSL_CTX_set_tmp_dh_shim(SSL_CTX *ctx, DH *dh) {
return SSL_CTX_set_tmp_dh(ctx, dh);
}
long SSL_CTX_set_tlsext_servername_callback_shim(SSL_CTX *ctx, int (*callback)(SSL_CTX *, int *, void*)) {
return SSL_CTX_set_tlsext_servername_callback(ctx, callback);
}
long SSL_CTX_set_tlsext_servername_arg_shim(SSL_CTX *ctx, void* arg) {
return SSL_CTX_set_tlsext_servername_arg(ctx, arg);
}
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
int SSL_CTX_set_ecdh_auto_shim(SSL_CTX *ctx, int onoff) {
return SSL_CTX_set_ecdh_auto(ctx, onoff);
}
#endif
DH *DH_new_from_params(BIGNUM *p, BIGNUM *g, BIGNUM *q) {
DH *dh;
if ((dh = DH_new()) == NULL) {
return NULL;
}
dh->p = p;
dh->g = g;
dh->q = q;
return dh;
}
long SSL_set_tlsext_host_name_shim(SSL *s, char *name) {
return SSL_set_tlsext_host_name(s, name);
}
STACK_OF(X509_EXTENSION) *X509_get_extensions_shim(X509 *x) {
return x->cert_info ? x->cert_info->extensions : NULL;
}

View File

@ -1,46 +0,0 @@
import_options!{
// The following values are directly from recent OpenSSL
SSL_OP_MICROSOFT_SESS_ID_BUG 0x00000001
SSL_OP_NETSCAPE_CHALLENGE_BUG 0x00000002
SSL_OP_LEGACY_SERVER_CONNECT 0x00000004
SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 0x00000008
SSL_OP_TLSEXT_PADDING 0x00000010
SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER 0x00000020
SSL_OP_SAFARI_ECDHE_ECDSA_BUG 0x00000040
SSL_OP_SSLEAY_080_CLIENT_DH_BUG 0x00000080
SSL_OP_TLS_D5_BUG 0x00000100
SSL_OP_TLS_BLOCK_PADDING_BUG 0x00000200
// unused: 0x00000400
SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0x00000800
SSL_OP_NO_QUERY_MTU 0x00001000
SSL_OP_COOKIE_EXCHANGE 0x00002000
SSL_OP_NO_TICKET 0x00004000
SSL_OP_CISCO_ANYCONNECT 0x00008000
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0x00010000
SSL_OP_NO_COMPRESSION 0x00020000
SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000
SSL_OP_SINGLE_ECDH_USE 0x00080000
SSL_OP_SINGLE_DH_USE 0x00100000
// unused: 0x00200000
SSL_OP_CIPHER_SERVER_PREFERENCE 0x00400000
SSL_OP_TLS_ROLLBACK_BUG 0x00800000
SSL_OP_NO_SSLv2 0x01000000
SSL_OP_NO_SSLv3 0x02000000
SSL_OP_NO_DTLSv1 0x04000000
SSL_OP_NO_TLSv1 0x04000000
SSL_OP_NO_DTLSv1_2 0x08000000
SSL_OP_NO_TLSv1_2 0x08000000
SSL_OP_NO_TLSv1_1 0x10000000
SSL_OP_NETSCAPE_CA_DN_BUG 0x20000000
SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG 0x40000000
SSL_OP_CRYPTOPRO_TLSEXT_BUG 0x80000000
// The following values were in 32-bit range in old OpenSSL
SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG 0x100000000
SSL_OP_MSIE_SSLV2_RSA_PADDING 0x200000000
SSL_OP_PKCS1_CHECK_1 0x400000000
SSL_OP_PKCS1_CHECK_2 0x800000000
// The following values were redefined to 0 for security reasons
SSL_OP_EPHEMERAL_RSA 0x0
}

View File

@ -1,12 +1,12 @@
[package] [package]
name = "openssl-sys" name = "openssl-sys"
version = "0.7.14" version = "0.7.15"
authors = ["Alex Crichton <alex@alexcrichton.com>", authors = ["Alex Crichton <alex@alexcrichton.com>",
"Steven Fackler <sfackler@gmail.com>"] "Steven Fackler <sfackler@gmail.com>"]
license = "MIT" license = "MIT"
description = "FFI bindings to OpenSSL" description = "FFI bindings to OpenSSL"
repository = "https://github.com/sfackler/rust-openssl" repository = "https://github.com/sfackler/rust-openssl"
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.14/openssl_sys" documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.15/openssl_sys"
links = "openssl" links = "openssl"
build = "build.rs" build = "build.rs"
@ -23,6 +23,8 @@ npn = []
alpn = [] alpn = []
rfc5114 = [] rfc5114 = []
pkcs5_pbkdf2_hmac = [] pkcs5_pbkdf2_hmac = []
ecdh_auto = []
hmac_clone = []
[dependencies] [dependencies]
libc = "0.2" libc = "0.2"
@ -40,15 +42,6 @@ libressl-pnacl-sys = "2.1.0"
libressl-pnacl-sys = "2.1.0" libressl-pnacl-sys = "2.1.0"
# Only here to make sure we link to these in a static build on Windows # Only here to make sure we link to these in a static build on Windows
[target.i686-pc-windows-gnu.dependencies] [target.'cfg(windows)'.dependencies]
user32-sys = "0.2"
gdi32-sys = "0.2"
[target.x86_64-pc-windows-gnu.dependencies]
user32-sys = "0.2"
gdi32-sys = "0.2"
[target.i686-pc-windows-msvc.dependencies]
user32-sys = "0.2"
gdi32-sys = "0.2"
[target.x86_64-pc-windows-msvc.dependencies]
user32-sys = "0.2" user32-sys = "0.2"
gdi32-sys = "0.2" gdi32-sys = "0.2"

View File

@ -1,6 +1,6 @@
#![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] #![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)]
#![allow(dead_code)] #![allow(dead_code)]
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.14")] #![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.15")]
extern crate libc; extern crate libc;
@ -9,17 +9,19 @@ extern crate libressl_pnacl_sys;
use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t}; use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t};
use std::mem; use std::mem;
use std::ptr;
use std::sync::{Mutex, MutexGuard}; use std::sync::{Mutex, MutexGuard};
use std::sync::{Once, ONCE_INIT}; use std::sync::{Once, ONCE_INIT};
pub type ASN1_INTEGER = c_void; pub type ASN1_INTEGER = c_void;
pub type ASN1_STRING = c_void; pub type ASN1_STRING = c_void;
pub type ASN1_TIME = c_void; pub type ASN1_TIME = c_void;
pub type ASN1_TYPE = c_void;
pub type BN_CTX = c_void; pub type BN_CTX = c_void;
pub type BN_GENCB = c_void;
pub type COMP_METHOD = c_void; pub type COMP_METHOD = c_void;
pub type DH = c_void; pub type DH = c_void;
pub type ENGINE = c_void; pub type ENGINE = c_void;
pub type EVP_CIPHER = c_void;
pub type EVP_CIPHER_CTX = c_void; pub type EVP_CIPHER_CTX = c_void;
pub type EVP_MD = c_void; pub type EVP_MD = c_void;
pub type EVP_PKEY_CTX = c_void; pub type EVP_PKEY_CTX = c_void;
@ -114,6 +116,28 @@ pub struct RSA {
pub mt_blinding: *mut c_void, pub mt_blinding: *mut c_void,
} }
#[repr(C)]
pub struct DSA {
pub pad: c_int,
pub version: c_long,
pub write_params: c_int,
pub p: *mut BIGNUM,
pub q: *mut BIGNUM,
pub g: *mut BIGNUM,
pub pub_key: *mut BIGNUM,
pub priv_key: *mut BIGNUM,
pub kinv: *mut BIGNUM,
pub r: *mut BIGNUM,
pub flags: c_int,
pub _method_mont_p: *mut c_void,
pub references: c_int,
pub ex_data: *mut c_void,
pub meth: *const c_void,
pub engine: *const c_void,
}
#[repr(C)] #[repr(C)]
pub struct EVP_PKEY { pub struct EVP_PKEY {
pub type_: c_int, pub type_: c_int,
@ -172,6 +196,39 @@ impl Clone for EVP_MD_CTX {
fn clone(&self) -> EVP_MD_CTX { *self } fn clone(&self) -> EVP_MD_CTX { *self }
} }
#[repr(C)]
pub struct EVP_CIPHER {
pub nid: c_int,
pub block_size: c_int,
pub key_len: c_int,
pub iv_len: c_int,
pub flags: c_ulong,
pub init: Option<unsafe extern "C" fn(*mut EVP_CIPHER_CTX,
*mut c_uchar,
*const c_uchar,
size_t) -> c_int>,
pub do_cipher: Option<unsafe extern "C" fn(*mut EVP_CIPHER_CTX,
*mut c_uchar,
*const c_uchar,
size_t) -> c_int>,
pub cleanup: Option<unsafe extern "C" fn(*mut EVP_CIPHER_CTX) -> c_int>,
pub ctx_size: c_int,
pub set_asn1_parameters: Option<unsafe extern "C" fn(*mut EVP_CIPHER_CTX,
*mut ASN1_TYPE) -> c_int>,
pub get_asn1_parameters: Option<unsafe extern "C" fn(*mut EVP_CIPHER_CTX,
*mut ASN1_TYPE) -> c_int>,
pub ctrl: Option<unsafe extern "C" fn(*mut EVP_CIPHER_CTX,
c_int,
c_int,
*mut c_void) -> c_int>,
pub app_data: *mut c_void,
}
impl Copy for EVP_CIPHER {}
impl Clone for EVP_CIPHER {
fn clone(&self) -> EVP_CIPHER { *self }
}
#[repr(C)] #[repr(C)]
pub struct HMAC_CTX { pub struct HMAC_CTX {
md: *mut EVP_MD, md: *mut EVP_MD,
@ -247,31 +304,48 @@ pub type PasswordCallback = extern "C" fn(buf: *mut c_char, size: c_int,
pub const BIO_TYPE_NONE: c_int = 0; pub const BIO_TYPE_NONE: c_int = 0;
pub const BIO_CTRL_EOF: c_int = 2; pub const BIO_CTRL_EOF: c_int = 2;
pub const BIO_CTRL_INFO: c_int = 3;
pub const BIO_CTRL_FLUSH: c_int = 11; pub const BIO_CTRL_FLUSH: c_int = 11;
pub const BIO_C_SET_BUF_MEM_EOF_RETURN: c_int = 130; pub const BIO_C_SET_BUF_MEM_EOF_RETURN: c_int = 130;
pub const BIO_FLAGS_READ: c_int = 0x01;
pub const BIO_FLAGS_WRITE: c_int = 0x02;
pub const BIO_FLAGS_IO_SPECIAL: c_int = 0x04;
pub const BIO_FLAGS_RWS: c_int = BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL;
pub const BIO_FLAGS_SHOULD_RETRY: c_int = 0x08;
pub const CRYPTO_LOCK: c_int = 1; pub const CRYPTO_LOCK: c_int = 1;
pub const EVP_MAX_MD_SIZE: c_uint = 64;
pub const EVP_PKEY_RSA: c_int = NID_rsaEncryption;
pub const MBSTRING_ASC: c_int = MBSTRING_FLAG | 1; pub const MBSTRING_ASC: c_int = MBSTRING_FLAG | 1;
pub const MBSTRING_BMP: c_int = MBSTRING_FLAG | 2; pub const MBSTRING_BMP: c_int = MBSTRING_FLAG | 2;
pub const MBSTRING_FLAG: c_int = 0x1000; pub const MBSTRING_FLAG: c_int = 0x1000;
pub const MBSTRING_UNIV: c_int = MBSTRING_FLAG | 4; pub const MBSTRING_UNIV: c_int = MBSTRING_FLAG | 4;
pub const MBSTRING_UTF8: c_int = MBSTRING_FLAG; pub const MBSTRING_UTF8: c_int = MBSTRING_FLAG;
pub const NID_rsaEncryption: c_int = 6;
pub const NID_ext_key_usage: c_int = 126; pub const NID_ext_key_usage: c_int = 126;
pub const NID_key_usage: c_int = 83; pub const NID_key_usage: c_int = 83;
pub const PKCS5_SALT_LEN: c_int = 8; pub const PKCS5_SALT_LEN: c_int = 8;
pub const SSL_CTRL_OPTIONS: c_int = 32; pub const RSA_F4: c_long = 0x10001;
pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77;
pub const SSL_CTRL_SET_TMP_DH: c_int = 3;
pub const SSL_CTRL_EXTRA_CHAIN_CERT: c_int = 14;
pub const SSL_CTRL_OPTIONS: c_int = 32;
pub const SSL_CTRL_MODE: c_int = 33;
pub const SSL_CTRL_SET_READ_AHEAD: c_int = 41;
pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_CB: c_int = 53; pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_CB: c_int = 53;
pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG: c_int = 54; 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_HOSTNAME: c_int = 55;
pub const SSL_CTRL_EXTRA_CHAIN_CERT: c_int = 14; pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77;
pub const SSL_CTRL_SET_READ_AHEAD: c_int = 41; #[cfg(feature = "ecdh_auto")]
pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94;
pub const SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER: c_long = 2;
pub const SSL_MODE_AUTO_RETRY: c_long = 4; pub const SSL_MODE_AUTO_RETRY: c_long = 4;
pub const SSL_ERROR_NONE: c_int = 0; pub const SSL_ERROR_NONE: c_int = 0;
@ -287,6 +361,42 @@ pub const SSL_VERIFY_NONE: c_int = 0;
pub const SSL_VERIFY_PEER: c_int = 1; pub const SSL_VERIFY_PEER: c_int = 1;
pub const SSL_VERIFY_FAIL_IF_NO_PEER_CERT: c_int = 2; pub const SSL_VERIFY_FAIL_IF_NO_PEER_CERT: c_int = 2;
pub const SSL_OP_MICROSOFT_SESS_ID_BUG: c_long = 0x00000001;
pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: c_long = 0x00000002;
pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: c_long = 0x00000008;
pub const SSL_OP_TLSEXT_PADDING: c_long = 0x00000010;
pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: c_long = 0x00000020;
pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: c_long = 0x00000080;
pub const SSL_OP_TLS_D5_BUG: c_long = 0x00000100;
pub const SSL_OP_TLS_BLOCK_PADDING_BUG: c_long = 0x00000200;
pub const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: c_long = 0x00000800;
pub const SSL_OP_ALL: c_long = 0x80000BFF;
pub const SSL_OP_NO_QUERY_MTU: c_long = 0x00001000;
pub const SSL_OP_COOKIE_EXCHANGE: c_long = 0x00002000;
pub const SSL_OP_NO_TICKET: c_long = 0x00004000;
pub const SSL_OP_CISCO_ANYCONNECT: c_long = 0x00008000;
pub const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION: c_long = 0x00010000;
pub const SSL_OP_NO_COMPRESSION: c_long = 0x00020000;
pub const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: c_long = 0x00040000;
pub const SSL_OP_SINGLE_ECDH_USE: c_long = 0x00080000;
pub const SSL_OP_SINGLE_DH_USE: c_long = 0x00100000;
pub const SSL_OP_CIPHER_SERVER_PREFERENCE: c_long = 0x00400000;
pub const SSL_OP_TLS_ROLLBACK_BUG: c_long = 0x00800000;
pub const SSL_OP_NO_SSLv2: c_long = 0x01000000;
pub const SSL_OP_NO_SSLv3: c_long = 0x02000000;
pub const SSL_OP_NO_TLSv1: c_long = 0x04000000;
// Intentionally not bound since they conflict with SSL_OP_PKCS1_CHECK_1 and
// SSL_OP_PKCS1_CHECK_2 on 0.9.8 :(
/*
pub const SSL_OP_NO_TLSv1_2: c_long = 0x08000000;
pub const SSL_OP_NO_TLSv1_1: c_long = 0x10000000;
pub const SSL_OP_NO_DTLSv1: c_long = 0x04000000;
pub const SSL_OP_NO_DTLSv1_2: c_long = 0x08000000;
pub const SSL_OP_NO_SSL_MASK: c_long = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
*/
pub const TLSEXT_NAMETYPE_host_name: c_long = 0; pub const TLSEXT_NAMETYPE_host_name: c_long = 0;
pub const SSL_TLSEXT_ERR_OK: c_int = 0; pub const SSL_TLSEXT_ERR_OK: c_int = 0;
@ -430,6 +540,78 @@ fn set_id_callback() {
#[cfg(not(unix))] #[cfg(not(unix))]
fn set_id_callback() {} fn set_id_callback() {}
// macros
pub unsafe fn BIO_get_mem_data(b: *mut BIO, pp: *mut *mut c_char) -> c_long {
BIO_ctrl(b, BIO_CTRL_INFO, 0, pp as *mut c_void)
}
pub unsafe fn BIO_clear_retry_flags(b: *mut BIO) {
BIO_clear_flags(b, BIO_FLAGS_RWS | BIO_FLAGS_SHOULD_RETRY)
}
pub unsafe fn BIO_set_retry_read(b: *mut BIO) {
BIO_set_flags(b, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY)
}
pub unsafe fn BIO_set_retry_write(b: *mut BIO) {
BIO_set_flags(b, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY)
}
pub unsafe fn SSL_CTX_set_mode(ctx: *mut SSL_CTX, op: c_long) -> c_long {
SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, op, ptr::null_mut())
}
pub unsafe fn SSL_CTX_set_options(ctx: *mut SSL_CTX, op: c_long) -> c_long {
SSL_CTX_ctrl(ctx, SSL_CTRL_OPTIONS, op, ptr::null_mut())
}
pub unsafe fn SSL_CTX_clear_options(ctx: *mut SSL_CTX, op: c_long) -> c_long {
SSL_CTX_ctrl(ctx, SSL_CTRL_CLEAR_OPTIONS, op, ptr::null_mut())
}
pub unsafe fn SSL_CTX_get_options(ctx: *mut SSL_CTX) -> c_long {
SSL_CTX_ctrl(ctx, SSL_CTRL_OPTIONS, 0, ptr::null_mut())
}
pub unsafe fn SSL_CTX_set_read_ahead(ctx: *mut SSL_CTX, m: c_long) -> c_long {
SSL_CTX_ctrl(ctx, SSL_CTRL_SET_READ_AHEAD, m, ptr::null_mut())
}
pub unsafe fn SSL_CTX_set_tmp_dh(ctx: *mut SSL_CTX, dh: *mut DH) -> c_long {
SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TMP_DH, 0, dh 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)
}
#[cfg(feature = "ecdh_auto")]
pub unsafe fn SSL_CTX_set_ecdh_auto(ctx: *mut SSL_CTX, onoff: c_long) -> c_long {
SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, ptr::null_mut())
}
pub unsafe fn SSL_CTX_set_tlsext_servername_callback(ctx: *mut SSL_CTX,
cb: Option<extern "C" fn()>)
-> c_long {
SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, cb)
}
pub unsafe fn SSL_set_tlsext_host_name(s: *mut SSL, name: *mut c_char) -> c_long {
SSL_ctrl(s, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, name as *mut c_void)
}
pub unsafe fn EVP_CIPHER_block_size(e: *const EVP_CIPHER) -> c_int {
(*e).block_size
}
pub unsafe fn EVP_CIPHER_key_length(e: *const EVP_CIPHER) -> c_int {
(*e).key_len
}
pub unsafe fn EVP_CIPHER_iv_length(e: *const EVP_CIPHER) -> c_int {
(*e).iv_len
}
// True functions // True functions
extern "C" { extern "C" {
pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int;
@ -443,6 +625,9 @@ extern "C" {
pub fn BIO_read(b: *mut BIO, buf: *mut c_void, len: c_int) -> c_int; pub fn BIO_read(b: *mut BIO, buf: *mut c_void, len: c_int) -> c_int;
pub fn BIO_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int; pub fn BIO_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int;
pub fn BIO_s_mem() -> *const BIO_METHOD; pub fn BIO_s_mem() -> *const BIO_METHOD;
pub fn BIO_new_mem_buf(buf: *const c_void, len: c_int) -> *mut BIO;
pub fn BIO_set_flags(b: *mut BIO, flags: c_int);
pub fn BIO_clear_flags(b: *mut BIO, flags: c_int);
pub fn BN_new() -> *mut BIGNUM; pub fn BN_new() -> *mut BIGNUM;
pub fn BN_dup(n: *mut BIGNUM) -> *mut BIGNUM; pub fn BN_dup(n: *mut BIGNUM) -> *mut BIGNUM;
@ -532,6 +717,7 @@ extern "C" {
#[cfg(feature = "rfc5114")] #[cfg(feature = "rfc5114")]
pub fn DH_get_2048_256() -> *mut DH; pub fn DH_get_2048_256() -> *mut DH;
// FIXME delete on next version bump
pub fn DH_new_from_params(p: *mut BIGNUM, g: *mut BIGNUM, q: *mut BIGNUM) -> *mut DH; pub fn DH_new_from_params(p: *mut BIGNUM, g: *mut BIGNUM, q: *mut BIGNUM) -> *mut DH;
pub fn ERR_get_error() -> c_ulong; pub fn ERR_get_error() -> c_ulong;
@ -581,10 +767,17 @@ extern "C" {
pub fn EVP_CIPHER_CTX_new() -> *mut EVP_CIPHER_CTX; 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_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_free(ctx: *mut EVP_CIPHER_CTX); pub fn EVP_CIPHER_CTX_free(ctx: *mut EVP_CIPHER_CTX);
pub fn EVP_CipherInit(ctx: *mut EVP_CIPHER_CTX, evp: *const EVP_CIPHER, pub fn EVP_CipherInit(ctx: *mut EVP_CIPHER_CTX, evp: *const EVP_CIPHER,
key: *const u8, iv: *const u8, mode: c_int) -> c_int; key: *const u8, iv: *const u8, mode: c_int) -> c_int;
pub fn EVP_CipherInit_ex(ctx: *mut EVP_CIPHER_CTX,
type_: *const EVP_CIPHER,
impl_: *mut ENGINE,
key: *mut c_uchar,
iv: *mut c_uchar,
enc: c_int) -> c_int;
pub fn EVP_CipherUpdate(ctx: *mut EVP_CIPHER_CTX, outbuf: *mut u8, pub fn EVP_CipherUpdate(ctx: *mut EVP_CIPHER_CTX, outbuf: *mut u8,
outlen: &mut c_int, inbuf: *const u8, inlen: c_int) -> c_int; outlen: &mut c_int, inbuf: *const u8, inlen: c_int) -> c_int;
pub fn EVP_CipherFinal(ctx: *mut EVP_CIPHER_CTX, res: *mut u8, len: &mut c_int) -> c_int; pub fn EVP_CipherFinal(ctx: *mut EVP_CIPHER_CTX, res: *mut u8, len: &mut c_int) -> c_int;
@ -609,6 +802,8 @@ extern "C" {
pub fn HMAC_CTX_init(ctx: *mut HMAC_CTX); pub fn HMAC_CTX_init(ctx: *mut HMAC_CTX);
pub fn HMAC_CTX_cleanup(ctx: *mut HMAC_CTX); pub fn HMAC_CTX_cleanup(ctx: *mut HMAC_CTX);
#[cfg(feature = "hmac_clone")]
pub fn HMAC_CTX_copy(dst: *mut HMAC_CTX, src: *const HMAC_CTX) -> c_int;
pub fn PEM_read_bio_DHparams(bio: *mut BIO, out: *mut *mut DH, callback: Option<PasswordCallback>, pub fn PEM_read_bio_DHparams(bio: *mut BIO, out: *mut *mut DH, callback: Option<PasswordCallback>,
user_data: *mut c_void) -> *mut DH; user_data: *mut c_void) -> *mut DH;
@ -617,24 +812,36 @@ extern "C" {
pub fn PEM_read_bio_X509_REQ(bio: *mut BIO, out: *mut *mut X509_REQ, callback: Option<PasswordCallback>, pub fn PEM_read_bio_X509_REQ(bio: *mut BIO, out: *mut *mut X509_REQ, callback: Option<PasswordCallback>,
user_data: *mut c_void) -> *mut X509_REQ; user_data: *mut c_void) -> *mut X509_REQ;
pub fn PEM_read_bio_PrivateKey(bio: *mut BIO, out: *mut *mut EVP_PKEY, callback: Option<PasswordCallback>, pub fn PEM_read_bio_PrivateKey(bio: *mut BIO, out: *mut *mut EVP_PKEY, callback: Option<PasswordCallback>,
user_data: *mut c_void) -> *mut X509; user_data: *mut c_void) -> *mut EVP_PKEY;
pub fn PEM_read_bio_PUBKEY(bio: *mut BIO, out: *mut *mut EVP_PKEY, callback: Option<PasswordCallback>, pub fn PEM_read_bio_PUBKEY(bio: *mut BIO, out: *mut *mut EVP_PKEY, callback: Option<PasswordCallback>,
user_data: *mut c_void) -> *mut X509; user_data: *mut c_void) -> *mut EVP_PKEY;
pub fn PEM_read_bio_RSAPrivateKey(bio: *mut BIO, rsa: *mut *mut RSA, callback: Option<PasswordCallback>, user_data: *mut c_void) -> *mut RSA; pub fn PEM_read_bio_RSAPrivateKey(bio: *mut BIO, rsa: *mut *mut RSA, callback: Option<PasswordCallback>, user_data: *mut c_void) -> *mut RSA;
pub fn PEM_read_bio_RSA_PUBKEY(bio: *mut BIO, rsa: *mut *mut RSA, callback: Option<PasswordCallback>, user_data: *mut c_void) -> *mut RSA; pub fn PEM_read_bio_RSA_PUBKEY(bio: *mut BIO, rsa: *mut *mut RSA, callback: Option<PasswordCallback>, user_data: *mut c_void) -> *mut RSA;
pub fn PEM_write_bio_PrivateKey(bio: *mut BIO, pkey: *mut EVP_PKEY, cipher: *const EVP_CIPHER, pub fn PEM_write_bio_PrivateKey(bio: *mut BIO, pkey: *mut EVP_PKEY, cipher: *const EVP_CIPHER,
kstr: *mut c_char, klen: c_int, kstr: *mut c_uchar, klen: c_int,
callback: Option<PasswordCallback>, callback: Option<PasswordCallback>,
user_data: *mut c_void) -> c_int; 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_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, pub fn PEM_write_bio_RSAPrivateKey(bp: *mut BIO, rsa: *mut RSA, cipher: *const EVP_CIPHER,
kstr: *mut c_char, klen: c_int, kstr: *mut c_uchar, klen: c_int,
callback: Option<PasswordCallback>, callback: Option<PasswordCallback>,
user_data: *mut c_void) -> c_int; user_data: *mut c_void) -> c_int;
pub fn PEM_write_bio_RSAPublicKey(bp: *mut BIO, rsa: *mut RSA) -> c_int; pub fn PEM_write_bio_RSAPublicKey(bp: *mut BIO, rsa: *mut RSA) -> c_int;
pub fn PEM_write_bio_RSA_PUBKEY(bp: *mut BIO, rsa: *mut RSA) -> c_int; pub fn PEM_write_bio_RSA_PUBKEY(bp: *mut BIO, rsa: *mut RSA) -> c_int;
pub fn PEM_read_bio_DSAPrivateKey(bp: *mut BIO, dsa: *mut *mut DSA, callback: Option<PasswordCallback>,
user_data: *mut c_void) -> *mut DSA;
pub fn PEM_read_bio_DSA_PUBKEY(bp: *mut BIO, dsa: *mut *mut DSA, callback: Option<PasswordCallback>,
user_data: *mut c_void) -> *mut DSA;
pub fn PEM_write_bio_DSAPrivateKey(bp: *mut BIO, dsa: *mut DSA, cipher: *const EVP_CIPHER,
kstr: *mut c_uchar, klen: c_int, callback: Option<PasswordCallback>,
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(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_X509_REQ(bio: *mut BIO, x509: *mut X509_REQ) -> c_int;
@ -653,7 +860,7 @@ extern "C" {
pub fn RSA_new() -> *mut RSA; pub fn RSA_new() -> *mut RSA;
pub fn RSA_free(rsa: *mut RSA); pub fn RSA_free(rsa: *mut RSA);
pub fn RSA_generate_key(modsz: c_int, e: c_ulong, cb: *const c_void, cbarg: *const c_void) -> *mut RSA; pub fn RSA_generate_key(modsz: c_int, e: c_ulong, cb: *const c_void, cbarg: *const c_void) -> *mut RSA;
pub fn RSA_generate_key_ex(rsa: *mut RSA, bits: c_int, e: *mut BIGNUM, cb: *const c_void) -> c_int; pub fn RSA_generate_key_ex(rsa: *mut RSA, bits: c_int, e: *mut BIGNUM, cb: *mut BN_GENCB) -> c_int;
pub fn RSA_private_decrypt(flen: c_int, from: *const u8, to: *mut u8, k: *mut RSA, pub fn RSA_private_decrypt(flen: c_int, from: *const u8, to: *mut u8, k: *mut RSA,
pad: c_int) -> c_int; pad: c_int) -> c_int;
pub fn RSA_public_decrypt(flen: c_int, from: *const u8, to: *mut u8, k: *mut RSA, pub fn RSA_public_decrypt(flen: c_int, from: *const u8, to: *mut u8, k: *mut RSA,
@ -668,6 +875,18 @@ extern "C" {
pub fn RSA_verify(t: c_int, m: *const u8, mlen: c_uint, sig: *const u8, siglen: c_uint, pub fn RSA_verify(t: c_int, m: *const u8, mlen: c_uint, sig: *const u8, siglen: c_uint,
k: *mut RSA) -> c_int; k: *mut RSA) -> c_int;
pub fn DSA_new() -> *mut DSA;
pub fn DSA_free(dsa: *mut DSA);
pub fn DSA_size(dsa: *const DSA) -> c_int;
pub fn DSA_generate_parameters_ex(dsa: *mut DSA, bits: c_int, seed: *const c_uchar, seed_len: c_int,
counter_ref: *mut c_int, h_ret: *mut c_ulong,
cb: *const c_void) -> c_int;
pub fn DSA_generate_key(dsa: *mut DSA) -> c_int;
pub fn DSA_sign(dummy: c_int, dgst: *const c_uchar, len: c_int, sigret: *mut c_uchar,
siglen: *mut c_uint, dsa: *mut DSA) -> c_int;
pub fn DSA_verify(dummy: c_int, dgst: *const c_uchar, len: c_int, sigbuf: *const c_uchar,
siglen: c_int, dsa: *mut DSA) -> c_int;
pub fn SSL_library_init() -> c_int; pub fn SSL_library_init() -> c_int;
pub fn SSL_load_error_strings(); pub fn SSL_load_error_strings();
@ -694,6 +913,7 @@ extern "C" {
pub fn SSL_get_wbio(ssl: *mut SSL) -> *mut BIO; pub fn SSL_get_wbio(ssl: *mut SSL) -> *mut BIO;
pub fn SSL_accept(ssl: *mut SSL) -> c_int; pub fn SSL_accept(ssl: *mut SSL) -> c_int;
pub fn SSL_connect(ssl: *mut SSL) -> c_int; pub fn SSL_connect(ssl: *mut SSL) -> c_int;
pub fn SSL_do_handshake(ssl: *mut SSL) -> c_int;
pub fn SSL_ctrl(ssl: *mut SSL, cmd: c_int, larg: c_long, pub fn SSL_ctrl(ssl: *mut SSL, cmd: c_int, larg: c_long,
parg: *mut c_void) -> c_long; parg: *mut c_void) -> c_long;
pub fn SSL_get_error(ssl: *mut SSL, ret: c_int) -> c_int; pub fn SSL_get_error(ssl: *mut SSL, ret: c_int) -> c_int;
@ -732,6 +952,8 @@ extern "C" {
pub fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX; 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_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_set_verify(ctx: *mut SSL_CTX, mode: c_int, 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>); 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); pub fn SSL_CTX_set_verify_depth(ctx: *mut SSL_CTX, depth: c_int);
@ -840,6 +1062,9 @@ extern "C" {
pub fn X509_REQ_add_extensions(req: *mut X509_REQ, exts: *mut stack_st_X509_EXTENSION) -> c_int; pub fn X509_REQ_add_extensions(req: *mut X509_REQ, exts: *mut stack_st_X509_EXTENSION) -> c_int;
pub fn X509_REQ_sign(x: *mut X509_REQ, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; pub fn X509_REQ_sign(x: *mut X509_REQ, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int;
pub fn i2d_X509_bio(b: *mut BIO, x: *mut X509) -> c_int;
pub fn i2d_X509_REQ_bio(b: *mut BIO, x: *mut X509_REQ) -> c_int;
pub fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *const *mut u8) -> c_int; pub fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *const *mut u8) -> c_int;
pub fn d2i_RSA_PUBKEY(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA; pub fn d2i_RSA_PUBKEY(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA;
pub fn i2d_RSAPrivateKey(k: *mut RSA, buf: *const *mut u8) -> c_int; pub fn i2d_RSAPrivateKey(k: *mut RSA, buf: *const *mut u8) -> c_int;

View File

@ -1,11 +1,11 @@
[package] [package]
name = "openssl" name = "openssl"
version = "0.7.14" version = "0.8.0"
authors = ["Steven Fackler <sfackler@gmail.com>"] authors = ["Steven Fackler <sfackler@gmail.com>"]
license = "Apache-2.0" license = "Apache-2.0"
description = "OpenSSL bindings" description = "OpenSSL bindings"
repository = "https://github.com/sfackler/rust-openssl" repository = "https://github.com/sfackler/rust-openssl"
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.14/openssl" documentation = "https://sfackler.github.io/rust-openssl/doc/v0.8.0/openssl"
readme = "../README.md" readme = "../README.md"
keywords = ["crypto", "tls", "ssl", "dtls"] keywords = ["crypto", "tls", "ssl", "dtls"]
build = "build.rs" build = "build.rs"
@ -23,20 +23,25 @@ aes_ctr = ["openssl-sys/aes_ctr"]
npn = ["openssl-sys/npn"] npn = ["openssl-sys/npn"]
alpn = ["openssl-sys/alpn"] alpn = ["openssl-sys/alpn"]
rfc5114 = ["openssl-sys/rfc5114"] rfc5114 = ["openssl-sys/rfc5114"]
ecdh_auto = ["openssl-sys-extras/ecdh_auto"] ecdh_auto = ["openssl-sys/ecdh_auto"]
pkcs5_pbkdf2_hmac = ["openssl-sys/pkcs5_pbkdf2_hmac"] pkcs5_pbkdf2_hmac = ["openssl-sys/pkcs5_pbkdf2_hmac"]
hmac_clone = ["openssl-sys/hmac_clone"]
nightly = [] c_helpers = ["gcc"]
x509_clone = ["c_helpers"]
x509_generator_request = ["c_helpers"]
ssl_context_clone = ["c_helpers"]
hmac = ["c_helpers"]
dh_from_params = ["c_helpers"]
[dependencies] [dependencies]
bitflags = ">= 0.5.0, < 0.8.0" bitflags = "0.7"
lazy_static = "0.2" lazy_static = "0.2"
libc = "0.2" libc = "0.2"
openssl-sys = { version = "0.7.14", path = "../openssl-sys" } openssl-sys = { version = "0.7.15", path = "../openssl-sys" }
openssl-sys-extras = { version = "0.7.14", path = "../openssl-sys-extras" }
[build-dependencies] [build-dependencies]
gcc = "0.3" gcc = { version = "0.3", optional = true }
[dev-dependencies] [dev-dependencies]
rustc-serialize = "0.3" rustc-serialize = "0.3"

View File

@ -1,9 +1,11 @@
#[cfg(feature = "c_helpers")]
mod imp {
extern crate gcc; extern crate gcc;
use std::env; use std::env;
use std::path::PathBuf; use std::path::PathBuf;
fn main() { pub fn main() {
let mut config = gcc::Config::new(); let mut config = gcc::Config::new();
if let Some(paths) = env::var_os("DEP_OPENSSL_INCLUDE") { if let Some(paths) = env::var_os("DEP_OPENSSL_INCLUDE") {
@ -14,3 +16,13 @@ fn main() {
config.file("src/c_helpers.c").compile("libc_helpers.a"); config.file("src/c_helpers.c").compile("libc_helpers.a");
} }
}
#[cfg(not(feature = "c_helpers"))]
mod imp {
pub fn main() {}
}
fn main() {
imp::main()
}

View File

@ -2,47 +2,38 @@ use libc::c_long;
use std::ptr; use std::ptr;
use ffi; use ffi;
use ssl::error::SslError; use error::ErrorStack;
pub struct Asn1Time(*mut ffi::ASN1_TIME);
pub struct Asn1Time {
handle: *mut ffi::ASN1_TIME,
owned: bool,
}
impl Asn1Time { impl Asn1Time {
/// Wraps existing ASN1_TIME and takes ownership /// Wraps existing ASN1_TIME and takes ownership
pub fn new(handle: *mut ffi::ASN1_TIME) -> Asn1Time { pub unsafe fn from_ptr(handle: *mut ffi::ASN1_TIME) -> Asn1Time {
Asn1Time { Asn1Time(handle)
handle: handle,
owned: true,
}
} }
fn new_with_period(period: u64) -> Result<Asn1Time, SslError> { fn from_period(period: c_long) -> Result<Asn1Time, ErrorStack> {
ffi::init(); ffi::init();
let handle = unsafe { unsafe {
try_ssl_null!(ffi::X509_gmtime_adj(ptr::null_mut(), period as c_long)) let handle = try_ssl_null!(ffi::X509_gmtime_adj(ptr::null_mut(), period));
}; Ok(Asn1Time::from_ptr(handle))
Ok(Asn1Time::new(handle)) }
} }
/// Creates a new time on specified interval in days from now /// Creates a new time on specified interval in days from now
pub fn days_from_now(days: u32) -> Result<Asn1Time, SslError> { pub fn days_from_now(days: u32) -> Result<Asn1Time, ErrorStack> {
Asn1Time::new_with_period(days as u64 * 60 * 60 * 24) Asn1Time::from_period(days as c_long * 60 * 60 * 24)
} }
/// Returns raw handle /// Returns the raw handle
pub unsafe fn get_handle(&self) -> *mut ffi::ASN1_TIME { pub fn as_ptr(&self) -> *mut ffi::ASN1_TIME {
return self.handle; self.0
} }
} }
impl Drop for Asn1Time { impl Drop for Asn1Time {
fn drop(&mut self) { fn drop(&mut self) {
if self.owned { unsafe { ffi::ASN1_TIME_free(self.0) };
unsafe { ffi::ASN1_TIME_free(self.handle) };
}
} }
} }

67
openssl/src/bio.rs Normal file
View File

@ -0,0 +1,67 @@
use std::marker::PhantomData;
use std::ptr;
use std::slice;
use libc::c_int;
use ffi;
use error::ErrorStack;
pub struct MemBioSlice<'a>(*mut ffi::BIO, PhantomData<&'a [u8]>);
impl<'a> Drop for MemBioSlice<'a> {
fn drop(&mut self) {
unsafe {
ffi::BIO_free_all(self.0);
}
}
}
impl<'a> MemBioSlice<'a> {
pub fn new(buf: &'a [u8]) -> Result<MemBioSlice<'a>, ErrorStack> {
ffi::init();
assert!(buf.len() <= c_int::max_value() as usize);
let bio = unsafe {
try_ssl_null!(ffi::BIO_new_mem_buf(buf.as_ptr() as *const _, buf.len() as c_int))
};
Ok(MemBioSlice(bio, PhantomData))
}
pub fn as_ptr(&self) -> *mut ffi::BIO {
self.0
}
}
pub struct MemBio(*mut ffi::BIO);
impl Drop for MemBio {
fn drop(&mut self) {
unsafe {
ffi::BIO_free_all(self.0);
}
}
}
impl MemBio {
pub fn new() -> Result<MemBio, ErrorStack> {
ffi::init();
let bio = unsafe {
try_ssl_null!(ffi::BIO_new(ffi::BIO_s_mem()))
};
Ok(MemBio(bio))
}
pub fn as_ptr(&self) -> *mut ffi::BIO {
self.0
}
pub fn get_buf(&self) -> &[u8] {
unsafe {
let mut ptr = ptr::null_mut();
let len = ffi::BIO_get_mem_data(self.0, &mut ptr);
slice::from_raw_parts(ptr as *const _ as *const _, len as usize)
}
}
}

View File

@ -1,107 +0,0 @@
use libc::{c_void, c_int};
use std::io;
use std::io::prelude::*;
use std::ptr;
use std::cmp;
use ffi;
use ffi_extras;
use ssl::error::SslError;
pub struct MemBio {
bio: *mut ffi::BIO,
owned: bool,
}
impl Drop for MemBio {
fn drop(&mut self) {
if self.owned {
unsafe {
ffi::BIO_free_all(self.bio);
}
}
}
}
impl MemBio {
/// Creates a new owned memory based BIO
pub fn new() -> Result<MemBio, SslError> {
ffi::init();
let bio = unsafe { ffi::BIO_new(ffi::BIO_s_mem()) };
try_ssl_null!(bio);
Ok(MemBio {
bio: bio,
owned: true,
})
}
/// Returns a "borrow", i.e. it has no ownership
pub fn borrowed(bio: *mut ffi::BIO) -> MemBio {
MemBio {
bio: bio,
owned: false,
}
}
/// Consumes current bio and returns wrapped value
/// Note that data ownership is lost and
/// should be managed manually
pub unsafe fn unwrap(mut self) -> *mut ffi::BIO {
self.owned = false;
self.bio
}
/// Temporarily gets wrapped value
pub unsafe fn get_handle(&self) -> *mut ffi::BIO {
self.bio
}
/// Sets the BIO's EOF state.
pub fn set_eof(&self, eof: bool) {
let v = if eof {
0
} else {
-1
};
unsafe {
ffi_extras::BIO_set_mem_eof_return(self.bio, v);
}
}
}
impl Read for MemBio {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
let ret = unsafe { ffi::BIO_read(self.bio, buf.as_ptr() as *mut c_void, len) };
if ret <= 0 {
let is_eof = unsafe { ffi_extras::BIO_eof(self.bio) };
if is_eof != 0 {
Ok(0)
} else {
Err(io::Error::new(io::ErrorKind::Other, SslError::get()))
}
} else {
Ok(ret as usize)
}
}
}
impl Write for MemBio {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
let ret = unsafe { ffi::BIO_write(self.bio, buf.as_ptr() as *const c_void, len) };
if ret < 0 {
Err(io::Error::new(io::ErrorKind::Other, SslError::get()))
} else {
Ok(ret as usize)
}
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,7 @@
#include <openssl/hmac.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/dh.h>
void rust_SSL_clone(SSL *ssl) { #include <openssl/bn.h>
CRYPTO_add(&ssl->references, 1, CRYPTO_LOCK_SSL);
}
void rust_SSL_CTX_clone(SSL_CTX *ctx) { void rust_SSL_CTX_clone(SSL_CTX *ctx) {
CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX); CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
@ -11,3 +10,50 @@ void rust_SSL_CTX_clone(SSL_CTX *ctx) {
void rust_X509_clone(X509 *x509) { void rust_X509_clone(X509 *x509) {
CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509); CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509);
} }
STACK_OF(X509_EXTENSION) *rust_X509_get_extensions(X509 *x) {
return x->cert_info ? x->cert_info->extensions : NULL;
}
DH *rust_DH_new_from_params(BIGNUM *p, BIGNUM *g, BIGNUM *q) {
DH *dh;
if ((dh = DH_new()) == NULL) {
return NULL;
}
dh->p = p;
dh->g = g;
dh->q = q;
return dh;
}
#if OPENSSL_VERSION_NUMBER < 0x10000000L
int rust_HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md, ENGINE *impl) {
HMAC_Init_ex(ctx, key, key_len, md, impl);
return 1;
}
int rust_HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, int len) {
HMAC_Update(ctx, data, len);
return 1;
}
int rust_HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len) {
HMAC_Final(ctx, md, len);
return 1;
}
#else
int rust_HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md, ENGINE *impl) {
return HMAC_Init_ex(ctx, key, key_len, md, impl);
}
int rust_HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, int len) {
return HMAC_Update(ctx, data, len);
}
int rust_HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len) {
return HMAC_Final(ctx, md, len);
}
#endif

14
openssl/src/c_helpers.rs Normal file
View File

@ -0,0 +1,14 @@
use ffi;
use libc::{c_int, c_void, c_uint, c_uchar};
#[allow(dead_code)]
extern "C" {
pub fn rust_SSL_CTX_clone(cxt: *mut ffi::SSL_CTX);
pub fn rust_X509_clone(x509: *mut ffi::X509);
pub fn rust_X509_get_extensions(x: *mut ffi::X509) -> *mut ffi::stack_st_X509_EXTENSION;
pub fn rust_HMAC_Init_ex(ctx: *mut ffi::HMAC_CTX, key: *const c_void, keylen: c_int, md: *const ffi::EVP_MD, impl_: *mut ffi::ENGINE) -> c_int;
pub fn rust_HMAC_Final(ctx: *mut ffi::HMAC_CTX, output: *mut c_uchar, len: *mut c_uint) -> c_int;
pub fn rust_HMAC_Update(ctx: *mut ffi::HMAC_CTX, input: *const c_uchar, len: c_uint) -> c_int;
pub fn rust_DH_new_from_params(p: *mut ffi::BIGNUM, g: *mut ffi::BIGNUM, q: *mut ffi::BIGNUM) -> *mut ffi::DH;
}

338
openssl/src/crypto/dsa.rs Normal file
View File

@ -0,0 +1,338 @@
use ffi;
use std::fmt;
use error::ErrorStack;
use std::ptr;
use libc::{c_uint, c_int, c_char, c_void};
use bn::BigNumRef;
use bio::{MemBio, MemBioSlice};
use crypto::hash;
use HashTypeInternals;
use crypto::util::{CallbackState, invoke_passwd_cb};
/// Builder for upfront DSA parameter generateration
pub struct DSAParams(*mut ffi::DSA);
impl DSAParams {
pub fn with_size(size: u32) -> Result<DSAParams, ErrorStack> {
unsafe {
// Wrap it so that if we panic we'll call the dtor
let dsa = DSAParams(try_ssl_null!(ffi::DSA_new()));
try_ssl!(ffi::DSA_generate_parameters_ex(dsa.0, size as c_int, ptr::null(), 0,
ptr::null_mut(), ptr::null_mut(), ptr::null()));
Ok(dsa)
}
}
/// Generate a key pair from the initialized parameters
pub fn generate(self) -> Result<DSA, ErrorStack> {
unsafe {
try_ssl!(ffi::DSA_generate_key(self.0));
let dsa = DSA(self.0);
::std::mem::forget(self);
Ok(dsa)
}
}
}
impl Drop for DSAParams {
fn drop(&mut self) {
unsafe {
ffi::DSA_free(self.0);
}
}
}
pub struct DSA(*mut ffi::DSA);
impl Drop for DSA {
fn drop(&mut self) {
unsafe {
ffi::DSA_free(self.0);
}
}
}
impl DSA {
pub unsafe fn from_ptr(dsa: *mut ffi::DSA) -> DSA {
DSA(dsa)
}
/// Generate a DSA key pair
/// For more complicated key generation scenarios see the `DSAParams` type
pub fn generate(size: u32) -> Result<DSA, ErrorStack> {
let params = try!(DSAParams::with_size(size));
params.generate()
}
/// Reads a DSA private key from PEM formatted data.
pub fn private_key_from_pem(buf: &[u8]) -> Result<DSA, ErrorStack> {
ffi::init();
let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let dsa = try_ssl_null!(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(),
ptr::null_mut(),
None,
ptr::null_mut()));
let dsa = DSA(dsa);
assert!(dsa.has_private_key());
Ok(dsa)
}
}
/// Read a private key from PEM supplying a password callback to be invoked if the private key
/// is encrypted.
///
/// The callback will be passed the password buffer and should return the number of characters
/// placed into the buffer.
pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<DSA, ErrorStack>
where F: FnOnce(&mut [c_char]) -> usize
{
ffi::init();
let mut cb = CallbackState::new(pass_cb);
let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let cb_ptr = &mut cb as *mut _ as *mut c_void;
let dsa = try_ssl_null!(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(),
ptr::null_mut(),
Some(invoke_passwd_cb::<F>),
cb_ptr));
let dsa = DSA(dsa);
assert!(dsa.has_private_key());
Ok(dsa)
}
}
/// Writes an DSA private key as unencrypted PEM formatted data
pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack>
{
assert!(self.has_private_key());
let mem_bio = try!(MemBio::new());
unsafe {
try_ssl!(ffi::PEM_write_bio_DSAPrivateKey(mem_bio.as_ptr(), self.0,
ptr::null(), ptr::null_mut(), 0,
None, ptr::null_mut()))
};
Ok(mem_bio.get_buf().to_owned())
}
/// Reads an DSA public key from PEM formatted data.
pub fn public_key_from_pem(buf: &[u8]) -> Result<DSA, ErrorStack>
{
ffi::init();
let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let dsa = try_ssl_null!(ffi::PEM_read_bio_DSA_PUBKEY(mem_bio.as_ptr(),
ptr::null_mut(),
None,
ptr::null_mut()));
Ok(DSA(dsa))
}
}
/// Writes an DSA public key as PEM formatted data
pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
let mem_bio = try!(MemBio::new());
unsafe { try_ssl!(ffi::PEM_write_bio_DSA_PUBKEY(mem_bio.as_ptr(), self.0)) };
Ok(mem_bio.get_buf().to_owned())
}
pub fn size(&self) -> Option<u32> {
if self.q().is_some() {
unsafe { Some(ffi::DSA_size(self.0) as u32) }
} else {
None
}
}
pub fn sign(&self, hash: hash::Type, message: &[u8]) -> Result<Vec<u8>, ErrorStack> {
let k_len = self.size().expect("DSA missing a q") as c_uint;
let mut sig = vec![0; k_len as usize];
let mut sig_len = k_len;
assert!(self.has_private_key());
unsafe {
try_ssl!(ffi::DSA_sign(hash.as_nid() as c_int,
message.as_ptr(),
message.len() as c_int,
sig.as_mut_ptr(),
&mut sig_len,
self.0));
sig.set_len(sig_len as usize);
sig.shrink_to_fit();
Ok(sig)
}
}
pub fn verify(&self, hash: hash::Type, message: &[u8], sig: &[u8]) -> Result<bool, ErrorStack> {
unsafe {
let result = ffi::DSA_verify(hash.as_nid() as c_int,
message.as_ptr(),
message.len() as c_int,
sig.as_ptr(),
sig.len() as c_int,
self.0);
try_ssl_if!(result == -1);
Ok(result == 1)
}
}
pub fn as_ptr(&self) -> *mut ffi::DSA {
self.0
}
pub fn p<'a>(&'a self) -> Option<BigNumRef<'a>> {
unsafe {
let p = (*self.0).p;
if p.is_null() {
None
} else {
Some(BigNumRef::from_ptr((*self.0).p))
}
}
}
pub fn q<'a>(&'a self) -> Option<BigNumRef<'a>> {
unsafe {
let q = (*self.0).q;
if q.is_null() {
None
} else {
Some(BigNumRef::from_ptr((*self.0).q))
}
}
}
pub fn g<'a>(&'a self) -> Option<BigNumRef<'a>> {
unsafe {
let g = (*self.0).g;
if g.is_null() {
None
} else {
Some(BigNumRef::from_ptr((*self.0).g))
}
}
}
pub fn has_public_key(&self) -> bool {
unsafe { !(*self.0).pub_key.is_null() }
}
pub fn has_private_key(&self) -> bool {
unsafe { !(*self.0).priv_key.is_null() }
}
}
impl fmt::Debug for DSA {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "DSA")
}
}
#[cfg(test)]
mod test {
use std::io::Write;
use libc::c_char;
use super::*;
use crypto::hash::*;
#[test]
pub fn test_generate() {
let key = DSA::generate(1024).unwrap();
key.public_key_to_pem().unwrap();
key.private_key_to_pem().unwrap();
let input: Vec<u8> = (0..25).cycle().take(1024).collect();
let digest = {
let mut sha = Hasher::new(Type::SHA1).unwrap();
sha.write_all(&input).unwrap();
sha.finish().unwrap()
};
let sig = key.sign(Type::SHA1, &digest).unwrap();
let verified = key.verify(Type::SHA1, &digest, &sig).unwrap();
assert!(verified);
}
#[test]
pub fn test_sign_verify() {
let input: Vec<u8> = (0..25).cycle().take(1024).collect();
let private_key = {
let key = include_bytes!("../../test/dsa.pem");
DSA::private_key_from_pem(key).unwrap()
};
let public_key = {
let key = include_bytes!("../../test/dsa.pem.pub");
DSA::public_key_from_pem(key).unwrap()
};
let digest = {
let mut sha = Hasher::new(Type::SHA1).unwrap();
sha.write_all(&input).unwrap();
sha.finish().unwrap()
};
let sig = private_key.sign(Type::SHA1, &digest).unwrap();
let verified = public_key.verify(Type::SHA1, &digest, &sig).unwrap();
assert!(verified);
}
#[test]
pub fn test_sign_verify_fail() {
let input: Vec<u8> = (0..25).cycle().take(128).collect();
let private_key = {
let key = include_bytes!("../../test/dsa.pem");
DSA::private_key_from_pem(key).unwrap()
};
let public_key = {
let key = include_bytes!("../../test/dsa.pem.pub");
DSA::public_key_from_pem(key).unwrap()
};
let digest = {
let mut sha = Hasher::new(Type::SHA1).unwrap();
sha.write_all(&input).unwrap();
sha.finish().unwrap()
};
let mut sig = private_key.sign(Type::SHA1, &digest).unwrap();
// tamper with the sig this should cause a failure
let len = sig.len();
sig[len / 2] = 0;
sig[len - 1] = 0;
if let Ok(true) = public_key.verify(Type::SHA1, &digest, &sig) {
panic!("Tampered with signatures should not verify!");
}
}
#[test]
pub fn test_password() {
let mut password_queried = false;
let key = include_bytes!("../../test/dsa-encrypted.pem");
DSA::private_key_from_pem_cb(key, |password| {
password_queried = true;
password[0] = b'm' as c_char;
password[1] = b'y' as c_char;
password[2] = b'p' as c_char;
password[3] = b'a' as c_char;
password[4] = b's' as c_char;
password[5] = b's' as c_char;
6
}).unwrap();
assert!(password_queried);
}
}

View File

@ -1,10 +1,12 @@
use libc::c_uint; use libc::c_uint;
use std::iter::repeat;
use std::io::prelude::*; use std::io::prelude::*;
use std::io; use std::io;
use std::ptr;
use std::cmp;
use ffi; use ffi;
use crypto::HashTypeInternals; use HashTypeInternals;
use error::ErrorStack;
use nid::Nid; use nid::Nid;
/// Message digest (hash) type. /// Message digest (hash) type.
@ -31,26 +33,8 @@ impl HashTypeInternals for Type {
Type::RIPEMD160 => Nid::RIPEMD160, Type::RIPEMD160 => Nid::RIPEMD160,
} }
} }
}
impl Type { fn evp_md(&self) -> *const ffi::EVP_MD {
/// Returns the length of the message digest.
#[inline]
pub fn md_len(&self) -> usize {
match *self {
Type::MD5 => 16,
Type::SHA1 => 20,
Type::SHA224 => 28,
Type::SHA256 => 32,
Type::SHA384 => 48,
Type::SHA512 => 64,
Type::RIPEMD160 => 20,
}
}
/// Internal interface subject to removal.
#[inline]
pub fn evp_md(&self) -> *const ffi::EVP_MD {
unsafe { unsafe {
match *self { match *self {
Type::MD5 => ffi::EVP_md5(), Type::MD5 => ffi::EVP_md5(),
@ -84,21 +68,20 @@ use self::State::*;
/// use openssl::crypto::hash::{hash, Type}; /// use openssl::crypto::hash::{hash, Type};
/// let data = b"\x42\xF4\x97\xE0"; /// let data = b"\x42\xF4\x97\xE0";
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2"; /// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
/// let res = hash(Type::MD5, data); /// let res = hash(Type::MD5, data).unwrap();
/// assert_eq!(res, spec); /// assert_eq!(res, spec);
/// ``` /// ```
/// ///
/// Use the `Write` trait to supply the input in chunks. /// Use the `Write` trait to supply the input in chunks.
/// ///
/// ``` /// ```
/// use std::io::prelude::*;
/// use openssl::crypto::hash::{Hasher, Type}; /// use openssl::crypto::hash::{Hasher, Type};
/// let data = [b"\x42\xF4", b"\x97\xE0"]; /// let data = [b"\x42\xF4", b"\x97\xE0"];
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2"; /// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
/// let mut h = Hasher::new(Type::MD5); /// let mut h = Hasher::new(Type::MD5).unwrap();
/// h.write_all(data[0]); /// h.update(data[0]).unwrap();
/// h.write_all(data[1]); /// h.update(data[1]).unwrap();
/// let res = h.finish(); /// let res = h.finish().unwrap();
/// assert_eq!(res, spec); /// assert_eq!(res, spec);
/// ``` /// ```
/// ///
@ -116,14 +99,10 @@ pub struct Hasher {
impl Hasher { impl Hasher {
/// Creates a new `Hasher` with the specified hash type. /// Creates a new `Hasher` with the specified hash type.
pub fn new(ty: Type) -> Hasher { pub fn new(ty: Type) -> Result<Hasher, ErrorStack> {
ffi::init(); ffi::init();
let ctx = unsafe { let ctx = unsafe { try_ssl_null!(ffi::EVP_MD_CTX_create()) };
let r = ffi::EVP_MD_CTX_create();
assert!(!r.is_null());
r
};
let md = ty.evp_md(); let md = ty.evp_md();
let mut h = Hasher { let mut h = Hasher {
@ -132,67 +111,60 @@ impl Hasher {
type_: ty, type_: ty,
state: Finalized, state: Finalized,
}; };
h.init(); try!(h.init());
h Ok(h)
} }
#[inline] fn init(&mut self) -> Result<(), ErrorStack> {
fn init(&mut self) {
match self.state { match self.state {
Reset => return, Reset => return Ok(()),
Updated => { Updated => {
self.finalize(); try!(self.finish());
} }
Finalized => (), Finalized => (),
} }
unsafe { unsafe { try_ssl!(ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *const _)); }
let r = ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *const _);
assert_eq!(r, 1);
}
self.state = Reset; self.state = Reset;
Ok(())
} }
#[inline] /// Feeds data into the hasher.
fn update(&mut self, data: &[u8]) { pub fn update(&mut self, mut data: &[u8]) -> Result<(), ErrorStack> {
if self.state == Finalized { if self.state == Finalized {
self.init(); try!(self.init());
} }
while !data.is_empty() {
let len = cmp::min(data.len(), c_uint::max_value() as usize);
unsafe { unsafe {
let r = ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), data.len() as c_uint); try_ssl!(ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), len as c_uint));
assert_eq!(r, 1); }
data = &data[len..];
} }
self.state = Updated; self.state = Updated;
} Ok(())
#[inline]
fn finalize(&mut self) -> Vec<u8> {
if self.state == Finalized {
self.init();
}
let md_len = self.type_.md_len();
let mut res: Vec<u8> = repeat(0).take(md_len).collect();
unsafe {
let mut len = 0;
let r = ffi::EVP_DigestFinal_ex(self.ctx, res.as_mut_ptr(), &mut len);
self.state = Finalized;
assert_eq!(len as usize, md_len);
assert_eq!(r, 1);
}
res
} }
/// Returns the hash of the data written since creation or /// Returns the hash of the data written since creation or
/// the last `finish` and resets the hasher. /// the last `finish` and resets the hasher.
#[inline] pub fn finish(&mut self) -> Result<Vec<u8>, ErrorStack> {
pub fn finish(&mut self) -> Vec<u8> { if self.state == Finalized {
self.finalize() try!(self.init());
}
unsafe {
let mut len = ffi::EVP_MAX_MD_SIZE;
let mut res = vec![0; len as usize];
try_ssl!(ffi::EVP_DigestFinal_ex(self.ctx, res.as_mut_ptr(), &mut len));
res.truncate(len as usize);
self.state = Finalized;
Ok(res)
}
} }
} }
impl Write for Hasher { impl Write for Hasher {
#[inline] #[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.update(buf); try!(self.update(buf));
Ok(buf.len()) Ok(buf.len())
} }
@ -223,9 +195,7 @@ impl Drop for Hasher {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
if self.state != Finalized { if self.state != Finalized {
let mut buf: Vec<u8> = repeat(0).take(self.type_.md_len()).collect(); drop(self.finish());
let mut len = 0;
ffi::EVP_DigestFinal_ex(self.ctx, buf.as_mut_ptr(), &mut len);
} }
ffi::EVP_MD_CTX_destroy(self.ctx); ffi::EVP_MD_CTX_destroy(self.ctx);
} }
@ -233,9 +203,9 @@ impl Drop for Hasher {
} }
/// Computes the hash of the `data` with the hash `t`. /// Computes the hash of the `data` with the hash `t`.
pub fn hash(t: Type, data: &[u8]) -> Vec<u8> { pub fn hash(t: Type, data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
let mut h = Hasher::new(t); let mut h = try!(Hasher::new(t));
let _ = h.write_all(data); try!(h.update(data));
h.finish() h.finish()
} }
@ -246,13 +216,13 @@ mod tests {
use std::io::prelude::*; use std::io::prelude::*;
fn hash_test(hashtype: Type, hashtest: &(&str, &str)) { fn hash_test(hashtype: Type, hashtest: &(&str, &str)) {
let res = hash(hashtype, &*hashtest.0.from_hex().unwrap()); let res = hash(hashtype, &*hashtest.0.from_hex().unwrap()).unwrap();
assert_eq!(res.to_hex(), hashtest.1); assert_eq!(res.to_hex(), hashtest.1);
} }
fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) { fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) {
let _ = h.write_all(&*hashtest.0.from_hex().unwrap()); let _ = h.write_all(&*hashtest.0.from_hex().unwrap()).unwrap();
let res = h.finish(); let res = h.finish().unwrap();
assert_eq!(res.to_hex(), hashtest.1); assert_eq!(res.to_hex(), hashtest.1);
} }
@ -294,7 +264,7 @@ mod tests {
#[test] #[test]
fn test_md5_recycle() { fn test_md5_recycle() {
let mut h = Hasher::new(Type::MD5); let mut h = Hasher::new(Type::MD5).unwrap();
for test in md5_tests.iter() { for test in md5_tests.iter() {
hash_recycle_test(&mut h, test); hash_recycle_test(&mut h, test);
} }
@ -302,11 +272,11 @@ mod tests {
#[test] #[test]
fn test_finish_twice() { fn test_finish_twice() {
let mut h = Hasher::new(Type::MD5); let mut h = Hasher::new(Type::MD5).unwrap();
let _ = h.write_all(&*md5_tests[6].0.from_hex().unwrap()); h.write_all(&*md5_tests[6].0.from_hex().unwrap()).unwrap();
let _ = h.finish(); h.finish().unwrap();
let res = h.finish(); let res = h.finish().unwrap();
let null = hash(Type::MD5, &[]); let null = hash(Type::MD5, &[]).unwrap();
assert_eq!(res, null); assert_eq!(res, null);
} }
@ -316,26 +286,26 @@ mod tests {
let inp = md5_tests[i].0.from_hex().unwrap(); let inp = md5_tests[i].0.from_hex().unwrap();
assert!(inp.len() > 2); assert!(inp.len() > 2);
let p = inp.len() / 2; let p = inp.len() / 2;
let h0 = Hasher::new(Type::MD5); let h0 = Hasher::new(Type::MD5).unwrap();
println!("Clone a new hasher"); println!("Clone a new hasher");
let mut h1 = h0.clone(); let mut h1 = h0.clone();
let _ = h1.write_all(&inp[..p]); h1.write_all(&inp[..p]).unwrap();
{ {
println!("Clone an updated hasher"); println!("Clone an updated hasher");
let mut h2 = h1.clone(); let mut h2 = h1.clone();
let _ = h2.write_all(&inp[p..]); h2.write_all(&inp[p..]).unwrap();
let res = h2.finish(); let res = h2.finish().unwrap();
assert_eq!(res.to_hex(), md5_tests[i].1); assert_eq!(res.to_hex(), md5_tests[i].1);
} }
let _ = h1.write_all(&inp[p..]); h1.write_all(&inp[p..]).unwrap();
let res = h1.finish(); let res = h1.finish().unwrap();
assert_eq!(res.to_hex(), md5_tests[i].1); assert_eq!(res.to_hex(), md5_tests[i].1);
println!("Clone a finished hasher"); println!("Clone a finished hasher");
let mut h3 = h1.clone(); let mut h3 = h1.clone();
let _ = h3.write_all(&*md5_tests[i + 1].0.from_hex().unwrap()); h3.write_all(&*md5_tests[i + 1].0.from_hex().unwrap()).unwrap();
let res = h3.finish(); let res = h3.finish().unwrap();
assert_eq!(res.to_hex(), md5_tests[i + 1].1); assert_eq!(res.to_hex(), md5_tests[i + 1].1);
} }

View File

@ -14,13 +14,15 @@
// //
use libc::{c_int, c_uint}; use libc::{c_int, c_uint};
use std::iter::repeat;
use std::io; use std::io;
use std::io::prelude::*; use std::io::prelude::*;
use std::cmp;
use crypto::hash::Type;
use ffi; use ffi;
use ffi_extras;
use HashTypeInternals;
use crypto::hash::Type;
use error::ErrorStack;
use c_helpers;
#[derive(PartialEq, Copy, Clone)] #[derive(PartialEq, Copy, Clone)]
enum State { enum State {
@ -33,6 +35,8 @@ use self::State::*;
/// Provides HMAC computation. /// Provides HMAC computation.
/// ///
/// Requires the `hmac` feature.
///
/// # Examples /// # Examples
/// ///
/// Calculate a HMAC in one go. /// Calculate a HMAC in one go.
@ -43,34 +47,32 @@ use self::State::*;
/// let key = b"Jefe"; /// let key = b"Jefe";
/// let data = b"what do ya want for nothing?"; /// let data = b"what do ya want for nothing?";
/// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38"; /// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38";
/// let res = hmac(Type::MD5, key, data); /// let res = hmac(Type::MD5, key, data).unwrap();
/// assert_eq!(res, spec); /// assert_eq!(res, spec);
/// ``` /// ```
/// ///
/// Use the `Write` trait to supply the input in chunks. /// Use the `Write` trait to supply the input in chunks.
/// ///
/// ``` /// ```
/// use std::io::prelude::*;
/// use openssl::crypto::hash::Type; /// use openssl::crypto::hash::Type;
/// use openssl::crypto::hmac::HMAC; /// use openssl::crypto::hmac::HMAC;
/// let key = b"Jefe"; /// let key = b"Jefe";
/// let data: &[&[u8]] = &[b"what do ya ", b"want for nothing?"]; /// let data: &[&[u8]] = &[b"what do ya ", b"want for nothing?"];
/// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38"; /// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38";
/// let mut h = HMAC::new(Type::MD5, &*key); /// let mut h = HMAC::new(Type::MD5, &*key).unwrap();
/// h.write_all(data[0]); /// h.update(data[0]).unwrap();
/// h.write_all(data[1]); /// h.update(data[1]).unwrap();
/// let res = h.finish(); /// let res = h.finish().unwrap();
/// assert_eq!(res, spec); /// assert_eq!(res, spec);
/// ``` /// ```
pub struct HMAC { pub struct HMAC {
ctx: ffi::HMAC_CTX, ctx: ffi::HMAC_CTX,
type_: Type,
state: State, state: State,
} }
impl HMAC { impl HMAC {
/// Creates a new `HMAC` with the specified hash type using the `key`. /// Creates a new `HMAC` with the specified hash type using the `key`.
pub fn new(ty: Type, key: &[u8]) -> HMAC { pub fn new(ty: Type, key: &[u8]) -> Result<HMAC, ErrorStack> {
ffi::init(); ffi::init();
let ctx = unsafe { let ctx = unsafe {
@ -82,89 +84,81 @@ impl HMAC {
let mut h = HMAC { let mut h = HMAC {
ctx: ctx, ctx: ctx,
type_: ty,
state: Finalized, state: Finalized,
}; };
h.init_once(md, key); try!(h.init_once(md, key));
h Ok(h)
} }
#[inline] fn init_once(&mut self, md: *const ffi::EVP_MD, key: &[u8]) -> Result<(), ErrorStack> {
fn init_once(&mut self, md: *const ffi::EVP_MD, key: &[u8]) {
unsafe { unsafe {
let r = ffi_extras::HMAC_Init_ex(&mut self.ctx, try_ssl!(c_helpers::rust_HMAC_Init_ex(&mut self.ctx,
key.as_ptr(), key.as_ptr() as *const _,
key.len() as c_int, key.len() as c_int,
md, md,
0 as *const _); 0 as *mut _));
assert_eq!(r, 1);
} }
self.state = Reset; self.state = Reset;
Ok(())
} }
#[inline] fn init(&mut self) -> Result<(), ErrorStack> {
fn init(&mut self) {
match self.state { match self.state {
Reset => return, Reset => return Ok(()),
Updated => { Updated => {
self.finalize(); try!(self.finish());
} }
Finalized => (), Finalized => (),
} }
// If the key and/or md is not supplied it's reused from the last time // If the key and/or md is not supplied it's reused from the last time
// avoiding redundant initializations // avoiding redundant initializations
unsafe { unsafe {
let r = ffi_extras::HMAC_Init_ex(&mut self.ctx, try_ssl!(c_helpers::rust_HMAC_Init_ex(&mut self.ctx,
0 as *const _, 0 as *const _,
0, 0,
0 as *const _, 0 as *const _,
0 as *const _); 0 as *mut _));
assert_eq!(r, 1);
} }
self.state = Reset; self.state = Reset;
Ok(())
} }
#[inline] pub fn update(&mut self, mut data: &[u8]) -> Result<(), ErrorStack> {
fn update(&mut self, data: &[u8]) {
if self.state == Finalized { if self.state == Finalized {
self.init(); try!(self.init());
} }
while !data.is_empty() {
let len = cmp::min(data.len(), c_uint::max_value() as usize);
unsafe { unsafe {
let r = ffi_extras::HMAC_Update(&mut self.ctx, data.as_ptr(), data.len() as c_uint); try_ssl!(c_helpers::rust_HMAC_Update(&mut self.ctx, data.as_ptr(), len as c_uint));
assert_eq!(r, 1); }
data = &data[len..];
} }
self.state = Updated; self.state = Updated;
} Ok(())
#[inline]
fn finalize(&mut self) -> Vec<u8> {
if self.state == Finalized {
self.init();
}
let md_len = self.type_.md_len();
let mut res: Vec<u8> = repeat(0).take(md_len).collect();
unsafe {
let mut len = 0;
let r = ffi_extras::HMAC_Final(&mut self.ctx, res.as_mut_ptr(), &mut len);
self.state = Finalized;
assert_eq!(len as usize, md_len);
assert_eq!(r, 1);
}
res
} }
/// Returns the hash of the data written since creation or /// Returns the hash of the data written since creation or
/// the last `finish` and resets the hasher. /// the last `finish` and resets the hasher.
#[inline] pub fn finish(&mut self) -> Result<Vec<u8>, ErrorStack> {
pub fn finish(&mut self) -> Vec<u8> { if self.state == Finalized {
self.finalize() try!(self.init());
}
unsafe {
let mut len = ffi::EVP_MAX_MD_SIZE;
let mut res = vec![0; len as usize];
try_ssl!(c_helpers::rust_HMAC_Final(&mut self.ctx, res.as_mut_ptr(), &mut len));
res.truncate(len as usize);
self.state = Finalized;
Ok(res)
}
} }
} }
impl Write for HMAC { impl Write for HMAC {
#[inline] #[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.update(buf); try!(self.update(buf));
Ok(buf.len()) Ok(buf.len())
} }
@ -173,17 +167,18 @@ impl Write for HMAC {
} }
} }
#[cfg(feature = "hmac_clone")]
impl Clone for HMAC { impl Clone for HMAC {
/// Requires the `hmac_clone` feature.
fn clone(&self) -> HMAC { fn clone(&self) -> HMAC {
let mut ctx: ffi::HMAC_CTX; let mut ctx: ffi::HMAC_CTX;
unsafe { unsafe {
ctx = ::std::mem::uninitialized(); ctx = ::std::mem::uninitialized();
let r = ffi_extras::HMAC_CTX_copy(&mut ctx, &self.ctx); let r = ffi::HMAC_CTX_copy(&mut ctx, &self.ctx);
assert_eq!(r, 1); assert_eq!(r, 1);
} }
HMAC { HMAC {
ctx: ctx, ctx: ctx,
type_: self.type_,
state: self.state, state: self.state,
} }
} }
@ -193,9 +188,7 @@ impl Drop for HMAC {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
if self.state != Finalized { if self.state != Finalized {
let mut buf: Vec<u8> = repeat(0).take(self.type_.md_len()).collect(); drop(self.finish());
let mut len = 0;
ffi_extras::HMAC_Final(&mut self.ctx, buf.as_mut_ptr(), &mut len);
} }
ffi::HMAC_CTX_cleanup(&mut self.ctx); ffi::HMAC_CTX_cleanup(&mut self.ctx);
} }
@ -203,9 +196,9 @@ impl Drop for HMAC {
} }
/// Computes the HMAC of the `data` with the hash `t` and `key`. /// Computes the HMAC of the `data` with the hash `t` and `key`.
pub fn hmac(t: Type, key: &[u8], data: &[u8]) -> Vec<u8> { pub fn hmac(t: Type, key: &[u8], data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
let mut h = HMAC::new(t, key); let mut h = try!(HMAC::new(t, key));
let _ = h.write_all(data); try!(h.update(data));
h.finish() h.finish()
} }
@ -220,14 +213,14 @@ mod tests {
fn test_hmac(ty: Type, tests: &[(Vec<u8>, Vec<u8>, Vec<u8>)]) { fn test_hmac(ty: Type, tests: &[(Vec<u8>, Vec<u8>, Vec<u8>)]) {
for &(ref key, ref data, ref res) in tests.iter() { for &(ref key, ref data, ref res) in tests.iter() {
assert_eq!(hmac(ty, &**key, &**data), *res); assert_eq!(hmac(ty, &**key, &**data).unwrap(), *res);
} }
} }
fn test_hmac_recycle(h: &mut HMAC, test: &(Vec<u8>, Vec<u8>, Vec<u8>)) { fn test_hmac_recycle(h: &mut HMAC, test: &(Vec<u8>, Vec<u8>, Vec<u8>)) {
let &(_, ref data, ref res) = test; let &(_, ref data, ref res) = test;
let _ = h.write_all(&**data); h.write_all(&**data).unwrap();
assert_eq!(h.finish(), *res); assert_eq!(h.finish().unwrap(), *res);
} }
#[test] #[test]
@ -273,7 +266,7 @@ mod tests {
.to_vec(), .to_vec(),
"6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())]; "6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())];
let mut h = HMAC::new(MD5, &*tests[0].0); let mut h = HMAC::new(MD5, &*tests[0].0).unwrap();
for i in 0..100usize { for i in 0..100usize {
let test = &tests[i % 2]; let test = &tests[i % 2];
test_hmac_recycle(&mut h, test); test_hmac_recycle(&mut h, test);
@ -287,15 +280,16 @@ mod tests {
b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(), b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
"6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap()); "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap());
let mut h = HMAC::new(Type::MD5, &*test.0); let mut h = HMAC::new(Type::MD5, &*test.0).unwrap();
let _ = h.write_all(&*test.1); h.write_all(&*test.1).unwrap();
let _ = h.finish(); h.finish().unwrap();
let res = h.finish(); let res = h.finish().unwrap();
let null = hmac(Type::MD5, &*test.0, &[]); let null = hmac(Type::MD5, &*test.0, &[]).unwrap();
assert_eq!(res, null); assert_eq!(res, null);
} }
#[test] #[test]
#[cfg(feature = "hmac_clone")]
fn test_clone() { fn test_clone() {
let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 2] = let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 2] =
[(repeat(0xaa_u8).take(80).collect(), [(repeat(0xaa_u8).take(80).collect(),
@ -307,26 +301,26 @@ mod tests {
.to_vec(), .to_vec(),
"6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())]; "6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())];
let p = tests[0].0.len() / 2; let p = tests[0].0.len() / 2;
let h0 = HMAC::new(Type::MD5, &*tests[0].0); let h0 = HMAC::new(Type::MD5, &*tests[0].0).unwrap();
println!("Clone a new hmac"); println!("Clone a new hmac");
let mut h1 = h0.clone(); let mut h1 = h0.clone();
let _ = h1.write_all(&tests[0].1[..p]); h1.write_all(&tests[0].1[..p]).unwrap();
{ {
println!("Clone an updated hmac"); println!("Clone an updated hmac");
let mut h2 = h1.clone(); let mut h2 = h1.clone();
let _ = h2.write_all(&tests[0].1[p..]); h2.write_all(&tests[0].1[p..]).unwrap();
let res = h2.finish(); let res = h2.finish().unwrap();
assert_eq!(res, tests[0].2); assert_eq!(res, tests[0].2);
} }
let _ = h1.write_all(&tests[0].1[p..]); h1.write_all(&tests[0].1[p..]).unwrap();
let res = h1.finish(); let res = h1.finish().unwrap();
assert_eq!(res, tests[0].2); assert_eq!(res, tests[0].2);
println!("Clone a finished hmac"); println!("Clone a finished hmac");
let mut h3 = h1.clone(); let mut h3 = h1.clone();
let _ = h3.write_all(&*tests[1].1); h3.write_all(&*tests[1].1).unwrap();
let res = h3.finish(); let res = h3.finish().unwrap();
assert_eq!(res, tests[1].2); assert_eq!(res, tests[1].2);
} }
@ -373,7 +367,7 @@ mod tests {
.to_vec(), .to_vec(),
"e8e99d0f45237d786d6bbaa7965c7808bbff1a91".from_hex().unwrap())]; "e8e99d0f45237d786d6bbaa7965c7808bbff1a91".from_hex().unwrap())];
let mut h = HMAC::new(SHA1, &*tests[0].0); let mut h = HMAC::new(SHA1, &*tests[0].0).unwrap();
for i in 0..100usize { for i in 0..100usize {
let test = &tests[i % 2]; let test = &tests[i % 2];
test_hmac_recycle(&mut h, test); test_hmac_recycle(&mut h, test);
@ -399,11 +393,11 @@ mod tests {
.to_vec())]; .to_vec())];
for (&(ref key, ref data), res) in tests.iter().zip(results.iter()) { for (&(ref key, ref data), res) in tests.iter().zip(results.iter()) {
assert_eq!(hmac(ty, &**key, &**data), *res); assert_eq!(hmac(ty, &**key, &**data).unwrap(), *res);
} }
// recycle test // recycle test
let mut h = HMAC::new(ty, &*tests[5].0); let mut h = HMAC::new(ty, &*tests[5].0).unwrap();
for i in 0..100usize { for i in 0..100usize {
let test = &tests[4 + i % 2]; let test = &tests[4 + i % 2];
let tup = (test.0.clone(), test.1.clone(), results[4 + i % 2].clone()); let tup = (test.0.clone(), test.1.clone(), results[4 + i % 2].clone());

View File

@ -14,9 +14,8 @@
// limitations under the License. // limitations under the License.
// //
use nid::Nid;
pub mod hash; pub mod hash;
#[cfg(feature = "hmac")]
pub mod hmac; pub mod hmac;
pub mod pkcs5; pub mod pkcs5;
pub mod pkey; pub mod pkey;
@ -24,9 +23,5 @@ pub mod rand;
pub mod symm; pub mod symm;
pub mod memcmp; pub mod memcmp;
pub mod rsa; pub mod rsa;
pub mod dsa;
mod symm_internal; mod util;
trait HashTypeInternals {
fn as_nid(&self) -> Nid;
}

View File

@ -1,10 +1,11 @@
use libc::c_int; use libc::c_int;
use std::ptr::null; use std::ptr;
use ffi;
use crypto::symm_internal::evpc; use HashTypeInternals;
use crypto::hash; use crypto::hash;
use crypto::symm; use crypto::symm;
use ffi; use error::ErrorStack;
#[derive(Clone, Eq, PartialEq, Hash, Debug)] #[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct KeyIvPair { pub struct KeyIvPair {
@ -27,114 +28,91 @@ pub fn evp_bytes_to_key_pbkdf1_compatible(typ: symm::Type,
data: &[u8], data: &[u8],
salt: Option<&[u8]>, salt: Option<&[u8]>,
count: u32) count: u32)
-> KeyIvPair { -> Result<KeyIvPair, ErrorStack> {
unsafe { unsafe {
let salt_ptr = match salt { let salt_ptr = match salt {
Some(salt) => { Some(salt) => {
assert_eq!(salt.len(), ffi::PKCS5_SALT_LEN as usize); assert_eq!(salt.len(), ffi::PKCS5_SALT_LEN as usize);
salt.as_ptr() salt.as_ptr()
} }
None => null(), None => ptr::null(),
}; };
ffi::init(); ffi::init();
let (evp, keylen, _) = evpc(typ); let typ = typ.as_ptr();
let message_digest_type = message_digest_type.evp_md();
let message_digest = message_digest_type.evp_md(); let len = ffi::EVP_BytesToKey(typ,
message_digest_type,
salt_ptr,
data.as_ptr(),
data.len() as c_int,
count as c_int,
ptr::null_mut(),
ptr::null_mut());
if len == 0 {
return Err(ErrorStack::get());
}
let mut key = vec![0; keylen as usize]; let mut key = vec![0; len as usize];
let mut iv = vec![0; keylen as usize]; let mut iv = vec![0; len as usize];
try_ssl!(ffi::EVP_BytesToKey(typ,
let ret: c_int = ffi::EVP_BytesToKey(evp, message_digest_type,
message_digest,
salt_ptr, salt_ptr,
data.as_ptr(), data.as_ptr(),
data.len() as c_int, data.len() as c_int,
count as c_int, count as c_int,
key.as_mut_ptr(), key.as_mut_ptr(),
iv.as_mut_ptr()); iv.as_mut_ptr()));
assert!(ret == keylen as c_int);
KeyIvPair { key: key, iv: iv } Ok(KeyIvPair { key: key, iv: iv })
} }
} }
/// Derives a key from a password and salt using the PBKDF2-HMAC-SHA1 algorithm. /// Derives a key from a password and salt using the PBKDF2-HMAC-SHA1 algorithm.
pub fn pbkdf2_hmac_sha1(pass: &str, salt: &[u8], iter: usize, keylen: usize) -> Vec<u8> { pub fn pbkdf2_hmac_sha1(pass: &[u8],
salt: &[u8],
iter: usize,
keylen: usize)
-> Result<Vec<u8>, ErrorStack> {
unsafe { unsafe {
assert!(iter >= 1); let mut out = vec![0; keylen];
assert!(keylen >= 1);
let mut out = Vec::with_capacity(keylen);
ffi::init(); ffi::init();
let r = ffi::PKCS5_PBKDF2_HMAC_SHA1(pass.as_ptr(), try_ssl!(ffi::PKCS5_PBKDF2_HMAC_SHA1(pass.as_ptr(),
pass.len() as c_int, pass.len() as c_int,
salt.as_ptr(), salt.as_ptr(),
salt.len() as c_int, salt.len() as c_int,
iter as c_int, iter as c_int,
keylen as c_int, keylen as c_int,
out.as_mut_ptr()); out.as_mut_ptr()));
Ok(out)
if r != 1 {
panic!();
} }
out.set_len(keylen);
out
}
}
/// Derives a key from a password and salt using the PBKDF2-HMAC-SHA256 algorithm.
#[cfg(feature = "pkcs5_pbkdf2_hmac")]
pub fn pbkdf2_hmac_sha256(pass: &str, salt: &[u8], iter: usize, keylen: usize) -> Vec<u8> {
pbkdf2_hmac_sha(pass, salt, iter, unsafe { ffi::EVP_sha256() }, keylen)
}
/// Derives a key from a password and salt using the PBKDF2-HMAC-SHA512 algorithm.
#[cfg(feature = "pkcs5_pbkdf2_hmac")]
pub fn pbkdf2_hmac_sha512(pass: &str, salt: &[u8], iter: usize, keylen: usize) -> Vec<u8> {
pbkdf2_hmac_sha(pass, salt, iter, unsafe { ffi::EVP_sha512() }, keylen)
} }
/// Derives a key from a password and salt using the PBKDF2-HMAC algorithm with a digest function. /// Derives a key from a password and salt using the PBKDF2-HMAC algorithm with a digest function.
#[cfg(feature = "pkcs5_pbkdf2_hmac")] #[cfg(feature = "pkcs5_pbkdf2_hmac")]
fn pbkdf2_hmac_sha(pass: &str, pub fn pbkdf2_hmac(pass: &[u8],
salt: &[u8], salt: &[u8],
iter: usize, iter: usize,
digest: *const ffi::EVP_MD, hash: hash::Type,
keylen: usize) keylen: usize)
-> Vec<u8> { -> Result<Vec<u8>, ErrorStack> {
unsafe { unsafe {
assert!(iter >= 1); let mut out = vec![0; keylen];
assert!(keylen >= 1);
let mut out = Vec::with_capacity(keylen);
ffi::init(); ffi::init();
try_ssl!(ffi::PKCS5_PBKDF2_HMAC(pass.as_ptr(),
let r = ffi::PKCS5_PBKDF2_HMAC(pass.as_ptr(),
pass.len() as c_int, pass.len() as c_int,
salt.as_ptr(), salt.as_ptr(),
salt.len() as c_int, salt.len() as c_int,
iter as c_int, iter as c_int,
digest, hash.evp_md(),
keylen as c_int, keylen as c_int,
out.as_mut_ptr()); out.as_mut_ptr()));
Ok(out)
if r != 1 {
panic!();
}
out.set_len(keylen);
out
} }
} }
@ -147,36 +125,36 @@ mod tests {
// http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06 // http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06
#[test] #[test]
fn test_pbkdf2_hmac_sha1() { fn test_pbkdf2_hmac_sha1() {
assert_eq!(super::pbkdf2_hmac_sha1("password", "salt".as_bytes(), 1, 20), assert_eq!(super::pbkdf2_hmac_sha1(b"password", b"salt", 1, 20).unwrap(),
vec![0x0c_u8, 0x60_u8, 0xc8_u8, 0x0f_u8, 0x96_u8, 0x1f_u8, 0x0e_u8, 0x71_u8, vec![0x0c_u8, 0x60_u8, 0xc8_u8, 0x0f_u8, 0x96_u8, 0x1f_u8, 0x0e_u8, 0x71_u8,
0xf3_u8, 0xa9_u8, 0xb5_u8, 0x24_u8, 0xaf_u8, 0x60_u8, 0x12_u8, 0x06_u8, 0xf3_u8, 0xa9_u8, 0xb5_u8, 0x24_u8, 0xaf_u8, 0x60_u8, 0x12_u8, 0x06_u8,
0x2f_u8, 0xe0_u8, 0x37_u8, 0xa6_u8]); 0x2f_u8, 0xe0_u8, 0x37_u8, 0xa6_u8]);
assert_eq!(super::pbkdf2_hmac_sha1("password", "salt".as_bytes(), 2, 20), assert_eq!(super::pbkdf2_hmac_sha1(b"password", b"salt", 2, 20).unwrap(),
vec![0xea_u8, 0x6c_u8, 0x01_u8, 0x4d_u8, 0xc7_u8, 0x2d_u8, 0x6f_u8, 0x8c_u8, vec![0xea_u8, 0x6c_u8, 0x01_u8, 0x4d_u8, 0xc7_u8, 0x2d_u8, 0x6f_u8, 0x8c_u8,
0xcd_u8, 0x1e_u8, 0xd9_u8, 0x2a_u8, 0xce_u8, 0x1d_u8, 0x41_u8, 0xf0_u8, 0xcd_u8, 0x1e_u8, 0xd9_u8, 0x2a_u8, 0xce_u8, 0x1d_u8, 0x41_u8, 0xf0_u8,
0xd8_u8, 0xde_u8, 0x89_u8, 0x57_u8]); 0xd8_u8, 0xde_u8, 0x89_u8, 0x57_u8]);
assert_eq!(super::pbkdf2_hmac_sha1("password", "salt".as_bytes(), 4096, 20), assert_eq!(super::pbkdf2_hmac_sha1(b"password", b"salt", 4096, 20).unwrap(),
vec![0x4b_u8, 0x00_u8, 0x79_u8, 0x01_u8, 0xb7_u8, 0x65_u8, 0x48_u8, 0x9a_u8, vec![0x4b_u8, 0x00_u8, 0x79_u8, 0x01_u8, 0xb7_u8, 0x65_u8, 0x48_u8, 0x9a_u8,
0xbe_u8, 0xad_u8, 0x49_u8, 0xd9_u8, 0x26_u8, 0xf7_u8, 0x21_u8, 0xd0_u8, 0xbe_u8, 0xad_u8, 0x49_u8, 0xd9_u8, 0x26_u8, 0xf7_u8, 0x21_u8, 0xd0_u8,
0x65_u8, 0xa4_u8, 0x29_u8, 0xc1_u8]); 0x65_u8, 0xa4_u8, 0x29_u8, 0xc1_u8]);
assert_eq!(super::pbkdf2_hmac_sha1("password", "salt".as_bytes(), 16777216, 20), assert_eq!(super::pbkdf2_hmac_sha1(b"password", b"salt", 16777216, 20).unwrap(),
vec![0xee_u8, 0xfe_u8, 0x3d_u8, 0x61_u8, 0xcd_u8, 0x4d_u8, 0xa4_u8, 0xe4_u8, vec![0xee_u8, 0xfe_u8, 0x3d_u8, 0x61_u8, 0xcd_u8, 0x4d_u8, 0xa4_u8, 0xe4_u8,
0xe9_u8, 0x94_u8, 0x5b_u8, 0x3d_u8, 0x6b_u8, 0xa2_u8, 0x15_u8, 0x8c_u8, 0xe9_u8, 0x94_u8, 0x5b_u8, 0x3d_u8, 0x6b_u8, 0xa2_u8, 0x15_u8, 0x8c_u8,
0x26_u8, 0x34_u8, 0xe9_u8, 0x84_u8]); 0x26_u8, 0x34_u8, 0xe9_u8, 0x84_u8]);
assert_eq!(super::pbkdf2_hmac_sha1("passwordPASSWORDpassword", assert_eq!(super::pbkdf2_hmac_sha1(b"passwordPASSWORDpassword",
"saltSALTsaltSALTsaltSALTsaltSALTsalt".as_bytes(), b"saltSALTsaltSALTsaltSALTsaltSALTsalt",
4096, 4096,
25), 25).unwrap(),
vec![0x3d_u8, 0x2e_u8, 0xec_u8, 0x4f_u8, 0xe4_u8, 0x1c_u8, 0x84_u8, 0x9b_u8, vec![0x3d_u8, 0x2e_u8, 0xec_u8, 0x4f_u8, 0xe4_u8, 0x1c_u8, 0x84_u8, 0x9b_u8,
0x80_u8, 0xc8_u8, 0xd8_u8, 0x36_u8, 0x62_u8, 0xc0_u8, 0xe4_u8, 0x4a_u8, 0x80_u8, 0xc8_u8, 0xd8_u8, 0x36_u8, 0x62_u8, 0xc0_u8, 0xe4_u8, 0x4a_u8,
0x8b_u8, 0x29_u8, 0x1a_u8, 0x96_u8, 0x4c_u8, 0xf2_u8, 0xf0_u8, 0x70_u8, 0x8b_u8, 0x29_u8, 0x1a_u8, 0x96_u8, 0x4c_u8, 0xf2_u8, 0xf0_u8, 0x70_u8,
0x38_u8]); 0x38_u8]);
assert_eq!(super::pbkdf2_hmac_sha1("pass\x00word", "sa\x00lt".as_bytes(), 4096, 16), assert_eq!(super::pbkdf2_hmac_sha1(b"pass\x00word", b"sa\x00lt", 4096, 16).unwrap(),
vec![0x56_u8, 0xfa_u8, 0x6a_u8, 0xa7_u8, 0x55_u8, 0x48_u8, 0x09_u8, 0x9d_u8, vec![0x56_u8, 0xfa_u8, 0x6a_u8, 0xa7_u8, 0x55_u8, 0x48_u8, 0x09_u8, 0x9d_u8,
0xcc_u8, 0x37_u8, 0xd7_u8, 0xf0_u8, 0x34_u8, 0x25_u8, 0xe0_u8, 0xc3_u8]); 0xcc_u8, 0x37_u8, 0xd7_u8, 0xf0_u8, 0x34_u8, 0x25_u8, 0xe0_u8, 0xc3_u8]);
} }
@ -186,11 +164,11 @@ mod tests {
#[test] #[test]
#[cfg(feature = "pkcs5_pbkdf2_hmac")] #[cfg(feature = "pkcs5_pbkdf2_hmac")]
fn test_pbkdf2_hmac_sha256() { fn test_pbkdf2_hmac_sha256() {
assert_eq!(super::pbkdf2_hmac_sha256("passwd", "salt".as_bytes(), 1, 16), assert_eq!(super::pbkdf2_hmac(b"passwd", b"salt", 1, hash::Type::SHA256, 16).unwrap(),
vec![0x55_u8, 0xac_u8, 0x04_u8, 0x6e_u8, 0x56_u8, 0xe3_u8, 0x08_u8, 0x9f_u8, vec![0x55_u8, 0xac_u8, 0x04_u8, 0x6e_u8, 0x56_u8, 0xe3_u8, 0x08_u8, 0x9f_u8,
0xec_u8, 0x16_u8, 0x91_u8, 0xc2_u8, 0x25_u8, 0x44_u8, 0xb6_u8, 0x05_u8]); 0xec_u8, 0x16_u8, 0x91_u8, 0xc2_u8, 0x25_u8, 0x44_u8, 0xb6_u8, 0x05_u8]);
assert_eq!(super::pbkdf2_hmac_sha256("Password", "NaCl".as_bytes(), 80000, 16), assert_eq!(super::pbkdf2_hmac(b"Password", b"NaCl", 80000, hash::Type::SHA256, 16).unwrap(),
vec![0x4d_u8, 0xdc_u8, 0xd8_u8, 0xf6_u8, 0x0b_u8, 0x98_u8, 0xbe_u8, 0x21_u8, vec![0x4d_u8, 0xdc_u8, 0xd8_u8, 0xf6_u8, 0x0b_u8, 0x98_u8, 0xbe_u8, 0x21_u8,
0x83_u8, 0x0c_u8, 0xee_u8, 0x5e_u8, 0xf2_u8, 0x27_u8, 0x01_u8, 0xf9_u8]); 0x83_u8, 0x0c_u8, 0xee_u8, 0x5e_u8, 0xf2_u8, 0x27_u8, 0x01_u8, 0xf9_u8]);
} }
@ -200,7 +178,7 @@ mod tests {
#[test] #[test]
#[cfg(feature = "pkcs5_pbkdf2_hmac")] #[cfg(feature = "pkcs5_pbkdf2_hmac")]
fn test_pbkdf2_hmac_sha512() { fn test_pbkdf2_hmac_sha512() {
assert_eq!(super::pbkdf2_hmac_sha512("password", "NaCL".as_bytes(), 1, 64), assert_eq!(super::pbkdf2_hmac(b"password", b"NaCL", 1, hash::Type::SHA512, 64).unwrap(),
vec![0x73_u8, 0xde_u8, 0xcf_u8, 0xa5_u8, 0x8a_u8, 0xa2_u8, 0xe8_u8, 0x4f_u8, vec![0x73_u8, 0xde_u8, 0xcf_u8, 0xa5_u8, 0x8a_u8, 0xa2_u8, 0xe8_u8, 0x4f_u8,
0x94_u8, 0x77_u8, 0x1a_u8, 0x75_u8, 0x73_u8, 0x6b_u8, 0xb8_u8, 0x8b_u8, 0x94_u8, 0x77_u8, 0x1a_u8, 0x75_u8, 0x73_u8, 0x6b_u8, 0xb8_u8, 0x8b_u8,
0xd3_u8, 0xc7_u8, 0xb3_u8, 0x82_u8, 0x70_u8, 0xcf_u8, 0xb5_u8, 0x0c_u8, 0xd3_u8, 0xc7_u8, 0xb3_u8, 0x82_u8, 0x70_u8, 0xcf_u8, 0xb5_u8, 0x0c_u8,
@ -210,7 +188,7 @@ mod tests {
0x60_u8, 0x60_u8, 0xa0_u8, 0x9f_u8, 0x76_u8, 0x41_u8, 0x5e_u8, 0x9f_u8, 0x60_u8, 0x60_u8, 0xa0_u8, 0x9f_u8, 0x76_u8, 0x41_u8, 0x5e_u8, 0x9f_u8,
0x71_u8, 0xea_u8, 0x47_u8, 0xf9_u8, 0xe9_u8, 0x06_u8, 0x43_u8, 0x06_u8]); 0x71_u8, 0xea_u8, 0x47_u8, 0xf9_u8, 0xe9_u8, 0x06_u8, 0x43_u8, 0x06_u8]);
assert_eq!(super::pbkdf2_hmac_sha512("pass\0word", "sa\0lt".as_bytes(), 1, 64), assert_eq!(super::pbkdf2_hmac(b"pass\0word", b"sa\0lt", 1, hash::Type::SHA512, 64).unwrap(),
vec![0x71_u8, 0xa0_u8, 0xec_u8, 0x84_u8, 0x2a_u8, 0xbd_u8, 0x5c_u8, 0x67_u8, vec![0x71_u8, 0xa0_u8, 0xec_u8, 0x84_u8, 0x2a_u8, 0xbd_u8, 0x5c_u8, 0x67_u8,
0x8b_u8, 0xcf_u8, 0xd1_u8, 0x45_u8, 0xf0_u8, 0x9d_u8, 0x83_u8, 0x52_u8, 0x8b_u8, 0xcf_u8, 0xd1_u8, 0x45_u8, 0xf0_u8, 0x9d_u8, 0x83_u8, 0x52_u8,
0x2f_u8, 0x93_u8, 0x36_u8, 0x15_u8, 0x60_u8, 0x56_u8, 0x3c_u8, 0x4d_u8, 0x2f_u8, 0x93_u8, 0x36_u8, 0x15_u8, 0x60_u8, 0x56_u8, 0x3c_u8, 0x4d_u8,
@ -220,10 +198,11 @@ mod tests {
0xb2_u8, 0x0f_u8, 0x06_u8, 0xbc_u8, 0x53_u8, 0x5e_u8, 0x5a_u8, 0xb5_u8, 0xb2_u8, 0x0f_u8, 0x06_u8, 0xbc_u8, 0x53_u8, 0x5e_u8, 0x5a_u8, 0xb5_u8,
0x44_u8, 0x0d_u8, 0xf7_u8, 0xe8_u8, 0x78_u8, 0x29_u8, 0x6f_u8, 0xa7_u8]); 0x44_u8, 0x0d_u8, 0xf7_u8, 0xe8_u8, 0x78_u8, 0x29_u8, 0x6f_u8, 0xa7_u8]);
assert_eq!(super::pbkdf2_hmac_sha512("passwordPASSWORDpassword", assert_eq!(super::pbkdf2_hmac(b"passwordPASSWORDpassword",
"salt\0\0\0".as_bytes(), b"salt\0\0\0",
50, 50,
64), hash::Type::SHA512,
64).unwrap(),
vec![0x01_u8, 0x68_u8, 0x71_u8, 0xa4_u8, 0xc4_u8, 0xb7_u8, 0x5f_u8, 0x96_u8, vec![0x01_u8, 0x68_u8, 0x71_u8, 0xa4_u8, 0xc4_u8, 0xb7_u8, 0x5f_u8, 0x96_u8,
0x85_u8, 0x7f_u8, 0xd2_u8, 0xb9_u8, 0xf8_u8, 0xca_u8, 0x28_u8, 0x02_u8, 0x85_u8, 0x7f_u8, 0xd2_u8, 0xb9_u8, 0xf8_u8, 0xca_u8, 0x28_u8, 0x02_u8,
0x3b_u8, 0x30_u8, 0xee_u8, 0x2a_u8, 0x39_u8, 0xf5_u8, 0xad_u8, 0xca_u8, 0x3b_u8, 0x30_u8, 0xee_u8, 0x2a_u8, 0x39_u8, 0xf5_u8, 0xad_u8, 0xca_u8,
@ -257,7 +236,7 @@ mod tests {
hash::Type::SHA1, hash::Type::SHA1,
&data, &data,
Some(&salt), Some(&salt),
1), 1).unwrap(),
super::KeyIvPair { super::KeyIvPair {
key: expected_key, key: expected_key,
iv: expected_iv, iv: expected_iv,

View File

@ -1,260 +1,107 @@
use libc::{c_int, c_uint, c_ulong}; use libc::{c_void, c_char};
use std::io;
use std::io::prelude::*;
use std::iter::repeat;
use std::mem;
use std::ptr; use std::ptr;
use bio::MemBio; use std::mem;
use crypto::HashTypeInternals;
use crypto::hash;
use crypto::hash::Type as HashType;
use ffi; use ffi;
use ssl::error::{SslError, StreamError};
use bio::{MemBio, MemBioSlice};
use crypto::rsa::RSA; use crypto::rsa::RSA;
use error::ErrorStack;
use crypto::util::{CallbackState, invoke_passwd_cb};
#[derive(Copy, Clone)] pub struct PKey(*mut ffi::EVP_PKEY);
pub enum Parts {
Neither,
Public,
Both,
}
/// Represents a role an asymmetric key might be appropriate for.
#[derive(Copy, Clone)]
pub enum Role {
Encrypt,
Decrypt,
Sign,
Verify,
}
/// Type of encryption padding to use.
#[derive(Copy, Clone)]
pub enum EncryptionPadding {
OAEP,
PKCS1v15,
}
fn openssl_padding_code(padding: EncryptionPadding) -> c_int {
match padding {
EncryptionPadding::OAEP => 4,
EncryptionPadding::PKCS1v15 => 1,
}
}
pub struct PKey {
evp: *mut ffi::EVP_PKEY,
parts: Parts,
}
unsafe impl Send for PKey {} unsafe impl Send for PKey {}
unsafe impl Sync for PKey {} unsafe impl Sync for PKey {}
/// Represents a public key, optionally with a private key attached. /// Represents a public key, optionally with a private key attached.
impl PKey { impl PKey {
pub fn new() -> PKey { /// Create a new `PKey` containing an RSA key.
pub fn from_rsa(rsa: RSA) -> Result<PKey, ErrorStack> {
unsafe { unsafe {
ffi::init(); let evp = try_ssl_null!(ffi::EVP_PKEY_new());
let pkey = PKey(evp);
PKey { try_ssl!(ffi::EVP_PKEY_assign(pkey.0, ffi::EVP_PKEY_RSA, rsa.as_ptr() as *mut _));
evp: ffi::EVP_PKEY_new(), mem::forget(rsa);
parts: Parts::Neither, Ok(pkey)
}
} }
} }
pub fn from_handle(handle: *mut ffi::EVP_PKEY, parts: Parts) -> PKey { pub unsafe fn from_ptr(handle: *mut ffi::EVP_PKEY) -> PKey {
ffi::init(); PKey(handle)
assert!(!handle.is_null());
PKey {
evp: handle,
parts: parts,
}
} }
/// Reads private key from PEM, takes ownership of handle /// Reads private key from PEM, takes ownership of handle
pub fn private_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError> pub fn private_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
where R: Read ffi::init();
{ let mem_bio = try!(MemBioSlice::new(buf));
let mut mem_bio = try!(MemBio::new());
try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
unsafe { unsafe {
let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.get_handle(), let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(),
ptr::null_mut(), ptr::null_mut(),
None, None,
ptr::null_mut())); ptr::null_mut()));
Ok(PKey { Ok(PKey::from_ptr(evp))
evp: evp as *mut ffi::EVP_PKEY, }
parts: Parts::Both, }
})
/// Read a private key from PEM, supplying a password callback to be invoked if the private key
/// is encrypted.
///
/// The callback will be passed the password buffer and should return the number of characters
/// placed into the buffer.
pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<PKey, ErrorStack>
where F: FnOnce(&mut [c_char]) -> usize
{
ffi::init();
let mut cb = CallbackState::new(pass_cb);
let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(),
ptr::null_mut(),
Some(invoke_passwd_cb::<F>),
&mut cb as *mut _ as *mut c_void));
Ok(PKey::from_ptr(evp))
} }
} }
/// Reads public key from PEM, takes ownership of handle /// Reads public key from PEM, takes ownership of handle
pub fn public_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError> pub fn public_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
where R: Read ffi::init();
{ let mem_bio = try!(MemBioSlice::new(buf));
let mut mem_bio = try!(MemBio::new());
try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
unsafe { unsafe {
let evp = try_ssl_null!(ffi::PEM_read_bio_PUBKEY(mem_bio.get_handle(), let evp = try_ssl_null!(ffi::PEM_read_bio_PUBKEY(mem_bio.as_ptr(),
ptr::null_mut(), ptr::null_mut(),
None, None,
ptr::null_mut())); ptr::null_mut()));
Ok(PKey { Ok(PKey::from_ptr(evp))
evp: evp as *mut ffi::EVP_PKEY,
parts: Parts::Public,
})
}
}
/// Reads an RSA private key from PEM, takes ownership of handle
pub fn private_rsa_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError>
where R: Read
{
let rsa = try!(RSA::private_key_from_pem(reader));
unsafe {
let evp = try_ssl_null!(ffi::EVP_PKEY_new());
try_ssl!(ffi::EVP_PKEY_set1_RSA(evp, rsa.as_ptr()));
Ok(PKey {
evp: evp,
parts: Parts::Public,
})
}
}
/// Reads an RSA public key from PEM, takes ownership of handle
pub fn public_rsa_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError>
where R: Read
{
let rsa = try!(RSA::public_key_from_pem(reader));
unsafe {
let evp = try_ssl_null!(ffi::EVP_PKEY_new());
try_ssl!(ffi::EVP_PKEY_set1_RSA(evp, rsa.as_ptr()));
Ok(PKey {
evp: evp,
parts: Parts::Public,
})
}
}
fn _tostr(&self, f: unsafe extern "C" fn(*mut ffi::RSA, *const *mut u8) -> c_int) -> Vec<u8> {
unsafe {
let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
let len = f(rsa, ptr::null());
if len < 0 as c_int {
return vec![];
}
let mut s = repeat(0u8).take(len as usize).collect::<Vec<_>>();
let r = f(rsa, &s.as_mut_ptr());
ffi::RSA_free(rsa);
s.truncate(r as usize);
s
}
}
fn _fromstr(&mut self,
s: &[u8],
f: unsafe extern "C" fn(*const *mut ffi::RSA, *const *const u8, c_uint)
-> *mut ffi::RSA)
-> bool {
unsafe {
let rsa = ptr::null_mut();
f(&rsa, &s.as_ptr(), s.len() as c_uint);
if !rsa.is_null() {
ffi::EVP_PKEY_set1_RSA(self.evp, rsa) == 1
} else {
false
}
}
}
pub fn gen(&mut self, keysz: usize) {
unsafe {
let rsa = ffi::RSA_generate_key(keysz as c_int,
65537 as c_ulong,
ptr::null(),
ptr::null());
// XXX: 6 == NID_rsaEncryption
ffi::EVP_PKEY_assign(self.evp, 6 as c_int, mem::transmute(rsa));
self.parts = Parts::Both;
} }
} }
/// assign RSA key to this pkey /// assign RSA key to this pkey
pub fn set_rsa(&mut self, rsa: &RSA) { pub fn set_rsa(&mut self, rsa: &RSA) -> Result<(), ErrorStack> {
unsafe { unsafe {
// this needs to be a reference as the set1_RSA ups the reference count // this needs to be a reference as the set1_RSA ups the reference count
let rsa_ptr = rsa.as_ptr(); let rsa_ptr = rsa.as_ptr();
if ffi::EVP_PKEY_set1_RSA(self.evp, rsa_ptr) == 1 { try_ssl!(ffi::EVP_PKEY_set1_RSA(self.0, rsa_ptr));
if rsa.has_e() && rsa.has_n() { Ok(())
self.parts = Parts::Public;
}
}
} }
} }
/// get a reference to the interal RSA key for direct access to the key components /// Get a reference to the interal RSA key for direct access to the key components
pub fn get_rsa(&self) -> RSA { pub fn get_rsa(&self) -> Result<RSA, ErrorStack> {
unsafe { unsafe {
let evp_pkey: *mut ffi::EVP_PKEY = self.evp; let rsa = try_ssl_null!(ffi::EVP_PKEY_get1_RSA(self.0));
// this is safe as the ffi increments a reference counter to the internal key // this is safe as the ffi increments a reference counter to the internal key
RSA::from_raw(ffi::EVP_PKEY_get1_RSA(evp_pkey)) Ok(RSA::from_ptr(rsa))
}
}
/**
* Returns a DER serialized form of the public key, suitable for load_pub().
*/
pub fn save_pub(&self) -> Vec<u8> {
self._tostr(ffi::i2d_RSA_PUBKEY)
}
/**
* Loads a DER serialized form of the public key, as produced by save_pub().
*/
pub fn load_pub(&mut self, s: &[u8]) {
if self._fromstr(s, ffi::d2i_RSA_PUBKEY) {
self.parts = Parts::Public;
}
}
/**
* Returns a serialized form of the public and private keys, suitable for
* load_priv().
*/
pub fn save_priv(&self) -> Vec<u8> {
self._tostr(ffi::i2d_RSAPrivateKey)
}
/**
* Loads a serialized form of the public and private keys, as produced by
* save_priv().
*/
pub fn load_priv(&mut self, s: &[u8]) {
if self._fromstr(s, ffi::d2i_RSAPrivateKey) {
self.parts = Parts::Both;
} }
} }
/// Stores private key as a PEM /// Stores private key as a PEM
// FIXME: also add password and encryption // FIXME: also add password and encryption
pub fn write_pem<W: Write>(&self, pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
writer: &mut W /* , password: Option<String> */) let mem_bio = try!(MemBio::new());
-> Result<(), SslError> {
let mut mem_bio = try!(MemBio::new());
unsafe { unsafe {
try_ssl!(ffi::PEM_write_bio_PrivateKey(mem_bio.get_handle(), try_ssl!(ffi::PEM_write_bio_PrivateKey(mem_bio.as_ptr(),
self.evp, self.0,
ptr::null(), ptr::null(),
ptr::null_mut(), ptr::null_mut(),
-1, -1,
@ -262,635 +109,58 @@ impl PKey {
ptr::null_mut())); ptr::null_mut()));
} }
let mut buf = vec![]; Ok(mem_bio.get_buf().to_owned())
try!(mem_bio.read_to_end(&mut buf).map_err(StreamError));
writer.write_all(&buf).map_err(StreamError)
} }
/// Stores public key as a PEM /// Stores public key as a PEM
pub fn write_pub_pem<W: Write>(&self, pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
writer: &mut W /* , password: Option<String> */) let mem_bio = try!(MemBio::new());
-> Result<(), SslError> { unsafe { try_ssl!(ffi::PEM_write_bio_PUBKEY(mem_bio.as_ptr(), self.0)) }
let mut mem_bio = try!(MemBio::new()); Ok(mem_bio.get_buf().to_owned())
unsafe { try_ssl!(ffi::PEM_write_bio_PUBKEY(mem_bio.get_handle(), self.evp)) }
let mut buf = vec![];
try!(mem_bio.read_to_end(&mut buf).map_err(StreamError));
writer.write_all(&buf).map_err(StreamError)
} }
/** pub fn as_ptr(&self) -> *mut ffi::EVP_PKEY {
* Returns the size of the public key modulus. return self.0;
*/
pub fn size(&self) -> usize {
unsafe {
let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
if rsa.is_null() {
0
} else {
ffi::RSA_size(rsa) as usize
}
}
}
/**
* Returns whether this pkey object can perform the specified role.
*/
pub fn can(&self, r: Role) -> bool {
match r {
Role::Encrypt => {
match self.parts {
Parts::Neither => false,
_ => true,
}
}
Role::Verify => {
match self.parts {
Parts::Neither => false,
_ => true,
}
}
Role::Decrypt => {
match self.parts {
Parts::Both => true,
_ => false,
}
}
Role::Sign => {
match self.parts {
Parts::Both => true,
_ => false,
}
}
}
}
/**
* Returns the maximum amount of data that can be encrypted by an encrypt()
* call.
*/
pub fn max_data(&self) -> usize {
unsafe {
let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
if rsa.is_null() {
return 0;
}
let len = ffi::RSA_size(rsa);
// 41 comes from RSA_public_encrypt(3) for OAEP
len as usize - 41
}
}
pub fn private_encrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec<u8> {
unsafe {
let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
if rsa.is_null() {
panic!("Could not get RSA key for encryption");
}
let len = ffi::RSA_size(rsa);
assert!(s.len() < self.max_data());
let mut r = repeat(0u8).take(len as usize + 1).collect::<Vec<_>>();
let rv = ffi::RSA_private_encrypt(s.len() as c_int,
s.as_ptr(),
r.as_mut_ptr(),
rsa,
openssl_padding_code(padding));
if rv < 0 as c_int {
// println!("{:?}", SslError::get());
vec![]
} else {
r.truncate(rv as usize);
r
}
}
}
pub fn public_encrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec<u8> {
unsafe {
let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
if rsa.is_null() {
panic!("Could not get RSA key for encryption");
}
let len = ffi::RSA_size(rsa);
assert!(s.len() < self.max_data());
let mut r = repeat(0u8).take(len as usize + 1).collect::<Vec<_>>();
let rv = ffi::RSA_public_encrypt(s.len() as c_int,
s.as_ptr(),
r.as_mut_ptr(),
rsa,
openssl_padding_code(padding));
if rv < 0 as c_int {
vec![]
} else {
r.truncate(rv as usize);
r
}
}
}
pub fn private_decrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec<u8> {
unsafe {
let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
if rsa.is_null() {
panic!("Could not get RSA key for decryption");
}
let len = ffi::RSA_size(rsa);
assert_eq!(s.len() as c_int, ffi::RSA_size(rsa));
let mut r = repeat(0u8).take(len as usize + 1).collect::<Vec<_>>();
let rv = ffi::RSA_private_decrypt(s.len() as c_int,
s.as_ptr(),
r.as_mut_ptr(),
rsa,
openssl_padding_code(padding));
if rv < 0 as c_int {
vec![]
} else {
r.truncate(rv as usize);
r
}
}
}
pub fn public_decrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec<u8> {
unsafe {
let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
if rsa.is_null() {
panic!("Could not get RSA key for decryption");
}
let len = ffi::RSA_size(rsa);
assert_eq!(s.len() as c_int, ffi::RSA_size(rsa));
let mut r = repeat(0u8).take(len as usize + 1).collect::<Vec<_>>();
let rv = ffi::RSA_public_decrypt(s.len() as c_int,
s.as_ptr(),
r.as_mut_ptr(),
rsa,
openssl_padding_code(padding));
if rv < 0 as c_int {
vec![]
} else {
r.truncate(rv as usize);
r
}
}
}
/**
* Encrypts data with the public key, using OAEP padding, returning the encrypted data. The
* supplied data must not be larger than max_data().
*/
pub fn encrypt(&self, s: &[u8]) -> Vec<u8> {
self.public_encrypt_with_padding(s, EncryptionPadding::OAEP)
}
/**
* Encrypts data with the public key, using provided padding, returning the encrypted data. The
* supplied data must not be larger than max_data().
*/
pub fn encrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec<u8> {
self.public_encrypt_with_padding(s, padding)
}
/**
* Encrypts data with the public key, using OAEP padding, returning the encrypted data. The
* supplied data must not be larger than max_data().
*/
pub fn public_encrypt(&self, s: &[u8]) -> Vec<u8> {
self.public_encrypt_with_padding(s, EncryptionPadding::OAEP)
}
/**
* Decrypts data with the public key, using PKCS1v15 padding, returning the decrypted data.
*/
pub fn public_decrypt(&self, s: &[u8]) -> Vec<u8> {
self.public_decrypt_with_padding(s, EncryptionPadding::PKCS1v15)
}
/**
* Decrypts data with the private key, expecting OAEP padding, returning the decrypted data.
*/
pub fn decrypt(&self, s: &[u8]) -> Vec<u8> {
self.private_decrypt_with_padding(s, EncryptionPadding::OAEP)
}
/**
* Decrypts data with the private key, using provided padding, returning the encrypted data. The
* supplied data must not be larger than max_data().
*/
pub fn decrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec<u8> {
self.private_decrypt_with_padding(s, padding)
}
/**
* Decrypts data with the private key, expecting OAEP padding, returning the decrypted data.
*/
pub fn private_decrypt(&self, s: &[u8]) -> Vec<u8> {
self.private_decrypt_with_padding(s, EncryptionPadding::OAEP)
}
/**
* Encrypts data with the private key, using PKCS1v15 padding, returning the encrypted data. The
* supplied data must not be larger than max_data().
*/
pub fn private_encrypt(&self, s: &[u8]) -> Vec<u8> {
self.private_encrypt_with_padding(s, EncryptionPadding::PKCS1v15)
}
/**
* Signs data, using OpenSSL's default scheme and adding sha256 ASN.1 information to the
* signature.
* The bytes to sign must be the result of a sha256 hashing;
* returns the signature.
*/
pub fn sign(&self, s: &[u8]) -> Vec<u8> {
self.sign_with_hash(s, HashType::SHA256)
}
/**
* Verifies a signature s (using OpenSSL's default scheme and sha256) on the SHA256 hash of a
* message.
* Returns true if the signature is valid, and false otherwise.
*/
pub fn verify(&self, h: &[u8], s: &[u8]) -> bool {
self.verify_with_hash(h, s, HashType::SHA256)
}
/**
* Signs data, using OpenSSL's default scheme and add ASN.1 information for the given hash type to the
* signature.
* The bytes to sign must be the result of this type of hashing;
* returns the signature.
*/
pub fn sign_with_hash(&self, s: &[u8], hash: hash::Type) -> Vec<u8> {
unsafe {
let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
if rsa.is_null() {
panic!("Could not get RSA key for signing");
}
let len = ffi::RSA_size(rsa);
let mut r = repeat(0u8).take(len as usize + 1).collect::<Vec<_>>();
let mut len = 0;
let rv = ffi::RSA_sign(hash.as_nid() as c_int,
s.as_ptr(),
s.len() as c_uint,
r.as_mut_ptr(),
&mut len,
rsa);
if rv < 0 as c_int {
vec![]
} else {
r.truncate(len as usize);
r
}
}
}
pub fn verify_with_hash(&self, h: &[u8], s: &[u8], hash: hash::Type) -> bool {
unsafe {
let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
if rsa.is_null() {
panic!("Could not get RSA key for verification");
}
let rv = ffi::RSA_verify(hash.as_nid() as c_int,
h.as_ptr(),
h.len() as c_uint,
s.as_ptr(),
s.len() as c_uint,
rsa);
rv == 1 as c_int
}
}
pub unsafe fn get_handle(&self) -> *mut ffi::EVP_PKEY {
return self.evp;
} }
pub fn public_eq(&self, other: &PKey) -> bool { pub fn public_eq(&self, other: &PKey) -> bool {
unsafe { ffi::EVP_PKEY_cmp(self.evp, other.evp) == 1 } unsafe { ffi::EVP_PKEY_cmp(self.0, other.0) == 1 }
} }
} }
impl Drop for PKey { impl Drop for PKey {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
ffi::EVP_PKEY_free(self.evp); ffi::EVP_PKEY_free(self.0);
} }
} }
} }
impl Clone for PKey {
fn clone(&self) -> Self {
let mut pkey = PKey::from_handle(unsafe { ffi::EVP_PKEY_new() }, self.parts);
// copy by encoding to DER and back
match self.parts {
Parts::Public => {
pkey.load_pub(&self.save_pub()[..]);
}
Parts::Both => {
pkey.load_priv(&self.save_priv()[..]);
}
Parts::Neither => {}
}
pkey
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::path::Path;
use std::fs::File;
use crypto::hash::Type::{MD5, SHA1};
use crypto::rsa::RSA;
#[test]
fn test_gen_pub() {
let mut k0 = super::PKey::new();
let mut k1 = super::PKey::new();
k0.gen(512);
k1.load_pub(&k0.save_pub());
assert_eq!(k0.save_pub(), k1.save_pub());
assert!(k0.public_eq(&k1));
assert_eq!(k0.size(), k1.size());
assert!(k0.can(super::Role::Encrypt));
assert!(k0.can(super::Role::Decrypt));
assert!(k0.can(super::Role::Verify));
assert!(k0.can(super::Role::Sign));
assert!(k1.can(super::Role::Encrypt));
assert!(!k1.can(super::Role::Decrypt));
assert!(k1.can(super::Role::Verify));
assert!(!k1.can(super::Role::Sign));
}
#[test]
fn test_gen_priv() {
let mut k0 = super::PKey::new();
let mut k1 = super::PKey::new();
k0.gen(512);
k1.load_priv(&k0.save_priv());
assert_eq!(k0.save_priv(), k1.save_priv());
assert!(k0.public_eq(&k1));
assert_eq!(k0.size(), k1.size());
assert!(k0.can(super::Role::Encrypt));
assert!(k0.can(super::Role::Decrypt));
assert!(k0.can(super::Role::Verify));
assert!(k0.can(super::Role::Sign));
assert!(k1.can(super::Role::Encrypt));
assert!(k1.can(super::Role::Decrypt));
assert!(k1.can(super::Role::Verify));
assert!(k1.can(super::Role::Sign));
}
#[test] #[test]
fn test_private_key_from_pem() { fn test_private_key_from_pem() {
let key_path = Path::new("test/key.pem"); let key = include_bytes!("../../test/key.pem");
let mut file = File::open(&key_path) super::PKey::private_key_from_pem(key).unwrap();
.ok()
.expect("Failed to open `test/key.pem`");
super::PKey::private_key_from_pem(&mut file).unwrap();
} }
#[test] #[test]
fn test_public_key_from_pem() { fn test_public_key_from_pem() {
let key_path = Path::new("test/key.pem.pub"); let key = include_bytes!("../../test/key.pem.pub");
let mut file = File::open(&key_path) super::PKey::public_key_from_pem(key).unwrap();
.ok()
.expect("Failed to open `test/key.pem.pub`");
super::PKey::public_key_from_pem(&mut file).unwrap();
}
#[test]
fn test_private_rsa_key_from_pem() {
let key_path = Path::new("test/key.pem");
let mut file = File::open(&key_path)
.ok()
.expect("Failed to open `test/key.pem`");
super::PKey::private_rsa_key_from_pem(&mut file).unwrap();
}
#[test]
fn test_public_rsa_key_from_pem() {
let key_path = Path::new("test/key.pem.pub");
let mut file = File::open(&key_path)
.ok()
.expect("Failed to open `test/key.pem.pub`");
super::PKey::public_rsa_key_from_pem(&mut file).unwrap();
}
#[test]
fn test_private_encrypt() {
let mut k0 = super::PKey::new();
let mut k1 = super::PKey::new();
let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
k0.gen(512);
k1.load_pub(&k0.save_pub());
let emsg = k0.private_encrypt(&msg);
let dmsg = k1.public_decrypt(&emsg);
assert!(msg == dmsg);
}
#[test]
fn test_public_encrypt() {
let mut k0 = super::PKey::new();
let mut k1 = super::PKey::new();
let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
k0.gen(512);
k1.load_pub(&k0.save_pub());
let emsg = k1.public_encrypt(&msg);
let dmsg = k0.private_decrypt(&emsg);
assert!(msg == dmsg);
}
#[test]
fn test_public_encrypt_pkcs() {
let mut k0 = super::PKey::new();
let mut k1 = super::PKey::new();
let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
k0.gen(512);
k1.load_pub(&k0.save_pub());
let emsg = k1.public_encrypt_with_padding(&msg, super::EncryptionPadding::PKCS1v15);
let dmsg = k0.private_decrypt_with_padding(&emsg, super::EncryptionPadding::PKCS1v15);
assert!(msg == dmsg);
}
#[test]
fn test_sign() {
let mut k0 = super::PKey::new();
let mut k1 = super::PKey::new();
let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
k0.gen(512);
k1.load_pub(&k0.save_pub());
let sig = k0.sign(&msg);
let rv = k1.verify(&msg, &sig);
assert!(rv == true);
}
#[test]
fn test_sign_hashes() {
let mut k0 = super::PKey::new();
let mut k1 = super::PKey::new();
let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
k0.gen(512);
k1.load_pub(&k0.save_pub());
let sig = k0.sign_with_hash(&msg, MD5);
assert!(k1.verify_with_hash(&msg, &sig, MD5));
assert!(!k1.verify_with_hash(&msg, &sig, SHA1));
}
#[test]
fn test_eq() {
let mut k0 = super::PKey::new();
let mut p0 = super::PKey::new();
let mut k1 = super::PKey::new();
let mut p1 = super::PKey::new();
k0.gen(512);
k1.gen(512);
p0.load_pub(&k0.save_pub());
p1.load_pub(&k1.save_pub());
assert!(k0.public_eq(&k0));
assert!(k1.public_eq(&k1));
assert!(p0.public_eq(&p0));
assert!(p1.public_eq(&p1));
assert!(k0.public_eq(&p0));
assert!(k1.public_eq(&p1));
assert!(!k0.public_eq(&k1));
assert!(!p0.public_eq(&p1));
assert!(!k0.public_eq(&p1));
assert!(!p0.public_eq(&k1));
} }
#[test] #[test]
fn test_pem() { fn test_pem() {
let key_path = Path::new("test/key.pem"); let key = include_bytes!("../../test/key.pem");
let mut file = File::open(&key_path) let key = super::PKey::private_key_from_pem(key).unwrap();
.ok()
.expect("Failed to open `test/key.pem`");
let key = super::PKey::private_key_from_pem(&mut file).unwrap(); let priv_key = key.private_key_to_pem().unwrap();
let pub_key = key.public_key_to_pem().unwrap();
let mut priv_key = Vec::new();
let mut pub_key = Vec::new();
key.write_pem(&mut priv_key).unwrap();
key.write_pub_pem(&mut pub_key).unwrap();
// As a super-simple verification, just check that the buffers contain // As a super-simple verification, just check that the buffers contain
// the `PRIVATE KEY` or `PUBLIC KEY` strings. // the `PRIVATE KEY` or `PUBLIC KEY` strings.
assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY")); assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY"));
assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY")); assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY"));
} }
#[test]
fn test_public_key_from_raw() {
let mut k0 = super::PKey::new();
let mut k1 = super::PKey::new();
let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
k0.gen(512);
let sig = k0.sign(&msg);
let r0 = k0.get_rsa();
let r1 = RSA::from_public_components(r0.n().expect("n"), r0.e().expect("e")).expect("r1");
k1.set_rsa(&r1);
assert!(k1.can(super::Role::Encrypt));
assert!(!k1.can(super::Role::Decrypt));
assert!(k1.can(super::Role::Verify));
assert!(!k1.can(super::Role::Sign));
let rv = k1.verify(&msg, &sig);
assert!(rv == true);
}
#[test]
#[should_panic(expected = "Could not get RSA key for encryption")]
fn test_nokey_encrypt() {
let mut pkey = super::PKey::new();
pkey.load_pub(&[]);
pkey.encrypt(&[]);
}
#[test]
#[should_panic(expected = "Could not get RSA key for decryption")]
fn test_nokey_decrypt() {
let mut pkey = super::PKey::new();
pkey.load_priv(&[]);
pkey.decrypt(&[]);
}
#[test]
#[should_panic(expected = "Could not get RSA key for signing")]
fn test_nokey_sign() {
let mut pkey = super::PKey::new();
pkey.load_priv(&[]);
pkey.sign(&[]);
}
#[test]
#[should_panic(expected = "Could not get RSA key for verification")]
fn test_nokey_verify() {
let mut pkey = super::PKey::new();
pkey.load_pub(&[]);
pkey.verify(&[], &[]);
}
#[test]
fn test_pkey_clone_creates_copy() {
let mut pkey = super::PKey::new();
pkey.gen(512);
let old_pkey_n = pkey.get_rsa().n().unwrap();
let mut pkey2 = pkey.clone();
pkey2.gen(512);
assert!(old_pkey_n == pkey.get_rsa().n().unwrap());
}
#[test]
fn test_pkey_clone_copies_private() {
let mut pkey = super::PKey::new();
pkey.gen(512);
let pkey2 = pkey.clone();
assert!(pkey.get_rsa().q().unwrap() == pkey2.get_rsa().q().unwrap());
}
#[test]
fn test_pkey_clone_copies_public() {
let mut pkey = super::PKey::new();
pkey.gen(512);
let mut pub_key = super::PKey::new();
pub_key.load_pub(&pkey.save_pub()[..]);
let pub_key2 = pub_key.clone();
assert!(pub_key.get_rsa().n().unwrap() == pub_key2.get_rsa().n().unwrap());
}
} }

View File

@ -1,19 +1,13 @@
use libc::c_int; use libc::c_int;
use ffi; use ffi;
use error::ErrorStack;
pub fn rand_bytes(len: usize) -> Vec<u8> { pub fn rand_bytes(buf: &mut [u8]) -> Result<(), ErrorStack> {
unsafe { unsafe {
let mut out = Vec::with_capacity(len);
ffi::init(); ffi::init();
let r = ffi::RAND_bytes(out.as_mut_ptr(), len as c_int); assert!(buf.len() <= c_int::max_value() as usize);
if r != 1 as c_int { try_ssl_if!(ffi::RAND_bytes(buf.as_mut_ptr(), buf.len() as c_int) != 1);
panic!() Ok(())
}
out.set_len(len);
out
} }
} }
@ -23,7 +17,7 @@ mod tests {
#[test] #[test]
fn test_rand_bytes() { fn test_rand_bytes() {
let bytes = rand_bytes(32); let mut buf = [0; 32];
println!("{:?}", bytes); rand_bytes(&mut buf).unwrap();
} }
} }

View File

@ -1,14 +1,15 @@
use ffi; use ffi;
use std::fmt; use std::fmt;
use ssl::error::{SslError, StreamError};
use std::ptr; use std::ptr;
use std::io::{self, Read, Write}; use std::mem;
use libc::c_int; use libc::{c_int, c_void, c_char, c_ulong};
use bn::BigNum; use bn::{BigNum, BigNumRef};
use bio::MemBio; use bio::{MemBio, MemBioSlice};
use crypto::HashTypeInternals; use error::ErrorStack;
use HashTypeInternals;
use crypto::hash; use crypto::hash;
use crypto::util::{CallbackState, invoke_passwd_cb};
pub struct RSA(*mut ffi::RSA); pub struct RSA(*mut ffi::RSA);
@ -23,11 +24,13 @@ impl Drop for RSA {
impl RSA { impl RSA {
/// only useful for associating the key material directly with the key, it's safer to use /// only useful for associating the key material directly with the key, it's safer to use
/// the supplied load and save methods for DER formatted keys. /// the supplied load and save methods for DER formatted keys.
pub fn from_public_components(n: BigNum, e: BigNum) -> Result<RSA, SslError> { pub fn from_public_components(n: BigNum, e: BigNum) -> Result<RSA, ErrorStack> {
unsafe { unsafe {
let rsa = try_ssl_null!(ffi::RSA_new()); let rsa = try_ssl_null!(ffi::RSA_new());
(*rsa).n = n.into_raw(); (*rsa).n = n.as_ptr();
(*rsa).e = e.into_raw(); (*rsa).e = e.as_ptr();
mem::forget(n);
mem::forget(e);
Ok(RSA(rsa)) Ok(RSA(rsa))
} }
} }
@ -40,35 +43,83 @@ impl RSA {
dp: BigNum, dp: BigNum,
dq: BigNum, dq: BigNum,
qi: BigNum) qi: BigNum)
-> Result<RSA, SslError> { -> Result<RSA, ErrorStack> {
unsafe { unsafe {
let rsa = try_ssl_null!(ffi::RSA_new()); let rsa = try_ssl_null!(ffi::RSA_new());
(*rsa).n = n.into_raw(); (*rsa).n = n.as_ptr();
(*rsa).e = e.into_raw(); (*rsa).e = e.as_ptr();
(*rsa).d = d.into_raw(); (*rsa).d = d.as_ptr();
(*rsa).p = p.into_raw(); (*rsa).p = p.as_ptr();
(*rsa).q = q.into_raw(); (*rsa).q = q.as_ptr();
(*rsa).dmp1 = dp.into_raw(); (*rsa).dmp1 = dp.as_ptr();
(*rsa).dmq1 = dq.into_raw(); (*rsa).dmq1 = dq.as_ptr();
(*rsa).iqmp = qi.into_raw(); (*rsa).iqmp = qi.as_ptr();
mem::forget(n);
mem::forget(e);
mem::forget(d);
mem::forget(p);
mem::forget(q);
mem::forget(dp);
mem::forget(dq);
mem::forget(qi);
Ok(RSA(rsa)) Ok(RSA(rsa))
} }
} }
/// the caller should assert that the rsa pointer is valid. pub unsafe fn from_ptr(rsa: *mut ffi::RSA) -> RSA {
pub unsafe fn from_raw(rsa: *mut ffi::RSA) -> RSA {
RSA(rsa) RSA(rsa)
} }
/// Generates a public/private key pair with the specified size.
///
/// The public exponent will be 65537.
pub fn generate(bits: u32) -> Result<RSA, ErrorStack> {
unsafe {
let rsa = try_ssl_null!(ffi::RSA_new());
let rsa = RSA(rsa);
let e = try!(BigNum::new_from(ffi::RSA_F4 as c_ulong));
try_ssl!(ffi::RSA_generate_key_ex(rsa.0, bits as c_int, e.as_ptr(), ptr::null_mut()));
Ok(rsa)
}
}
/// Reads an RSA private key from PEM formatted data. /// Reads an RSA private key from PEM formatted data.
pub fn private_key_from_pem<R>(reader: &mut R) -> Result<RSA, SslError> pub fn private_key_from_pem(buf: &[u8]) -> Result<RSA, ErrorStack> {
where R: Read let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(),
ptr::null_mut(),
None,
ptr::null_mut()));
Ok(RSA(rsa))
}
}
/// Reads an RSA private key from PEM formatted data and supplies a password callback.
pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<RSA, ErrorStack>
where F: FnOnce(&mut [c_char]) -> usize
{ {
let mut mem_bio = try!(MemBio::new()); let mut cb = CallbackState::new(pass_cb);
try!(io::copy(reader, &mut mem_bio).map_err(StreamError)); let mem_bio = try!(MemBioSlice::new(buf));
unsafe { unsafe {
let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.get_handle(), let cb_ptr = &mut cb as *mut _ as *mut c_void;
let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(),
ptr::null_mut(),
Some(invoke_passwd_cb::<F>),
cb_ptr));
Ok(RSA(rsa))
}
}
/// Reads an RSA public key from PEM formatted data.
pub fn public_key_from_pem(buf: &[u8]) -> Result<RSA, ErrorStack> {
let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let rsa = try_ssl_null!(ffi::PEM_read_bio_RSA_PUBKEY(mem_bio.as_ptr(),
ptr::null_mut(), ptr::null_mut(),
None, None,
ptr::null_mut())); ptr::null_mut()));
@ -77,137 +128,126 @@ impl RSA {
} }
/// Writes an RSA private key as unencrypted PEM formatted data /// Writes an RSA private key as unencrypted PEM formatted data
pub fn private_key_to_pem<W>(&self, writer: &mut W) -> Result<(), SslError> pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
where W: Write let mem_bio = try!(MemBio::new());
{
let mut mem_bio = try!(MemBio::new());
let result = unsafe { unsafe {
ffi::PEM_write_bio_RSAPrivateKey(mem_bio.get_handle(), try_ssl!(ffi::PEM_write_bio_RSAPrivateKey(mem_bio.as_ptr(),
self.0, self.0,
ptr::null(), ptr::null(),
ptr::null_mut(), ptr::null_mut(),
0, 0,
None, None,
ptr::null_mut())
};
if result == 1 {
try!(io::copy(&mut mem_bio, writer).map_err(StreamError));
Ok(())
} else {
Err(SslError::OpenSslErrors(vec![]))
}
}
/// Reads an RSA public key from PEM formatted data.
pub fn public_key_from_pem<R>(reader: &mut R) -> Result<RSA, SslError>
where R: Read
{
let mut mem_bio = try!(MemBio::new());
try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
unsafe {
let rsa = try_ssl_null!(ffi::PEM_read_bio_RSA_PUBKEY(mem_bio.get_handle(),
ptr::null_mut(),
None,
ptr::null_mut())); ptr::null_mut()));
Ok(RSA(rsa))
} }
Ok(mem_bio.get_buf().to_owned())
} }
/// Writes an RSA public key as PEM formatted data /// Writes an RSA public key as PEM formatted data
pub fn public_key_to_pem<W>(&self, writer: &mut W) -> Result<(), SslError> pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
where W: Write let mem_bio = try!(MemBio::new());
{
let mut mem_bio = try!(MemBio::new());
let result = unsafe { ffi::PEM_write_bio_RSA_PUBKEY(mem_bio.get_handle(), self.0) }; unsafe {
try_ssl!(ffi::PEM_write_bio_RSA_PUBKEY(mem_bio.as_ptr(), self.0))
};
if result == 1 { Ok(mem_bio.get_buf().to_owned())
try!(io::copy(&mut mem_bio, writer).map_err(StreamError)); }
Ok(()) pub fn size(&self) -> Option<u32> {
if self.n().is_some() {
unsafe { Some(ffi::RSA_size(self.0) as u32) }
} else { } else {
Err(SslError::OpenSslErrors(vec![])) None
} }
} }
pub fn size(&self) -> Result<u32, SslError> { pub fn sign(&self, hash: hash::Type, message: &[u8]) -> Result<Vec<u8>, ErrorStack> {
if self.has_n() { let k_len = self.size().expect("RSA missing an n");
unsafe { Ok(ffi::RSA_size(self.0) as u32) }
} else {
Err(SslError::OpenSslErrors(vec![]))
}
}
pub fn sign(&self, hash: hash::Type, message: &[u8]) -> Result<Vec<u8>, SslError> {
let k_len = try!(self.size());
let mut sig = vec![0; k_len as usize]; let mut sig = vec![0; k_len as usize];
let mut sig_len = k_len; let mut sig_len = k_len;
unsafe { unsafe {
let result = ffi::RSA_sign(hash.as_nid() as c_int, try_ssl!(ffi::RSA_sign(hash.as_nid() as c_int,
message.as_ptr(), message.as_ptr(),
message.len() as u32, message.len() as u32,
sig.as_mut_ptr(), sig.as_mut_ptr(),
&mut sig_len, &mut sig_len,
self.0); self.0));
assert!(sig_len == k_len); assert!(sig_len == k_len);
if result == 1 {
Ok(sig) Ok(sig)
} else {
Err(SslError::OpenSslErrors(vec![]))
}
} }
} }
pub fn verify(&self, hash: hash::Type, message: &[u8], sig: &[u8]) -> Result<bool, SslError> { pub fn verify(&self, hash: hash::Type, message: &[u8], sig: &[u8]) -> Result<(), ErrorStack> {
unsafe { unsafe {
let result = ffi::RSA_verify(hash.as_nid() as c_int, try_ssl!(ffi::RSA_verify(hash.as_nid() as c_int,
message.as_ptr(), message.as_ptr(),
message.len() as u32, message.len() as u32,
sig.as_ptr(), sig.as_ptr(),
sig.len() as u32, sig.len() as u32,
self.0); self.0));
Ok(result == 1)
} }
Ok(())
} }
pub fn as_ptr(&self) -> *mut ffi::RSA { pub fn as_ptr(&self) -> *mut ffi::RSA {
self.0 self.0
} }
// The following getters are unsafe, since BigNum::new_from_ffi fails upon null pointers pub fn n<'a>(&'a self) -> Option<BigNumRef<'a>> {
pub fn n(&self) -> Result<BigNum, SslError> { unsafe {
unsafe { BigNum::new_from_ffi((*self.0).n) } let n = (*self.0).n;
if n.is_null() {
None
} else {
Some(BigNumRef::from_ptr(n))
}
}
} }
pub fn has_n(&self) -> bool { pub fn d<'a>(&self) -> Option<BigNumRef<'a>> {
unsafe { !(*self.0).n.is_null() } unsafe {
let d = (*self.0).d;
if d.is_null() {
None
} else {
Some(BigNumRef::from_ptr(d))
}
}
} }
pub fn d(&self) -> Result<BigNum, SslError> { pub fn e<'a>(&'a self) -> Option<BigNumRef<'a>> {
unsafe { BigNum::new_from_ffi((*self.0).d) } unsafe {
let e = (*self.0).e;
if e.is_null() {
None
} else {
Some(BigNumRef::from_ptr(e))
}
}
} }
pub fn e(&self) -> Result<BigNum, SslError> { pub fn p<'a>(&'a self) -> Option<BigNumRef<'a>> {
unsafe { BigNum::new_from_ffi((*self.0).e) } unsafe {
let p = (*self.0).p;
if p.is_null() {
None
} else {
Some(BigNumRef::from_ptr(p))
}
}
} }
pub fn has_e(&self) -> bool { pub fn q<'a>(&'a self) -> Option<BigNumRef<'a>> {
unsafe { !(*self.0).e.is_null() } unsafe {
let q = (*self.0).q;
if q.is_null() {
None
} else {
Some(BigNumRef::from_ptr(q))
} }
pub fn p(&self) -> Result<BigNum, SslError> {
unsafe { BigNum::new_from_ffi((*self.0).p) }
} }
pub fn q(&self) -> Result<BigNum, SslError> {
unsafe { BigNum::new_from_ffi((*self.0).q) }
} }
} }
@ -219,8 +259,9 @@ impl fmt::Debug for RSA {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use std::fs::File;
use std::io::Write; use std::io::Write;
use libc::c_char;
use super::*; use super::*;
use crypto::hash::*; use crypto::hash::*;
@ -252,12 +293,12 @@ mod test {
#[test] #[test]
pub fn test_sign() { pub fn test_sign() {
let mut buffer = File::open("test/rsa.pem").unwrap(); let key = include_bytes!("../../test/rsa.pem");
let private_key = RSA::private_key_from_pem(&mut buffer).unwrap(); let private_key = RSA::private_key_from_pem(key).unwrap();
let mut sha = Hasher::new(Type::SHA256); let mut sha = Hasher::new(Type::SHA256).unwrap();
sha.write_all(&signing_input_rs256()).unwrap(); sha.write_all(&signing_input_rs256()).unwrap();
let digest = sha.finish(); let digest = sha.finish().unwrap();
let result = private_key.sign(Type::SHA256, &digest).unwrap(); let result = private_key.sign(Type::SHA256, &digest).unwrap();
@ -266,15 +307,31 @@ mod test {
#[test] #[test]
pub fn test_verify() { pub fn test_verify() {
let mut buffer = File::open("test/rsa.pem.pub").unwrap(); let key = include_bytes!("../../test/rsa.pem.pub");
let public_key = RSA::public_key_from_pem(&mut buffer).unwrap(); let public_key = RSA::public_key_from_pem(key).unwrap();
let mut sha = Hasher::new(Type::SHA256); let mut sha = Hasher::new(Type::SHA256).unwrap();
sha.write_all(&signing_input_rs256()).unwrap(); sha.write_all(&signing_input_rs256()).unwrap();
let digest = sha.finish(); let digest = sha.finish().unwrap();
let result = public_key.verify(Type::SHA256, &digest, &signature_rs256()).unwrap(); assert!(public_key.verify(Type::SHA256, &digest, &signature_rs256()).is_ok());
}
assert!(result); #[test]
pub fn test_password() {
let mut password_queried = false;
let key = include_bytes!("../../test/rsa-encrypted.pem");
RSA::private_key_from_pem_cb(key, |password| {
password_queried = true;
password[0] = b'm' as c_char;
password[1] = b'y' as c_char;
password[2] = b'p' as c_char;
password[3] = b'a' as c_char;
password[4] = b's' as c_char;
password[5] = b's' as c_char;
6
}).unwrap();
assert!(password_queried);
} }
} }

View File

@ -1,9 +1,10 @@
use std::iter::repeat; use std::cmp;
use std::ptr;
use libc::c_int; use libc::c_int;
use crypto::symm_internal::evpc;
use ffi; use ffi;
use error::ErrorStack;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum Mode { pub enum Mode {
Encrypt, Encrypt,
@ -43,94 +44,184 @@ pub enum Type {
RC4_128, RC4_128,
} }
impl Type {
pub fn as_ptr(&self) -> *const ffi::EVP_CIPHER {
unsafe {
match *self {
Type::AES_128_ECB => ffi::EVP_aes_128_ecb(),
Type::AES_128_CBC => ffi::EVP_aes_128_cbc(),
#[cfg(feature = "aes_xts")]
Type::AES_128_XTS => ffi::EVP_aes_128_xts(),
#[cfg(feature = "aes_ctr")]
Type::AES_128_CTR => ffi::EVP_aes_128_ctr(),
// AES_128_GCM => (EVP_aes_128_gcm(), 16, 16),
Type::AES_128_CFB1 => ffi::EVP_aes_128_cfb1(),
Type::AES_128_CFB128 => ffi::EVP_aes_128_cfb128(),
Type::AES_128_CFB8 => ffi::EVP_aes_128_cfb8(),
Type::AES_256_ECB => ffi::EVP_aes_256_ecb(),
Type::AES_256_CBC => ffi::EVP_aes_256_cbc(),
#[cfg(feature = "aes_xts")]
Type::AES_256_XTS => ffi::EVP_aes_256_xts(),
#[cfg(feature = "aes_ctr")]
Type::AES_256_CTR => ffi::EVP_aes_256_ctr(),
// AES_256_GCM => (EVP_aes_256_gcm(), 32, 16),
Type::AES_256_CFB1 => ffi::EVP_aes_256_cfb1(),
Type::AES_256_CFB128 => ffi::EVP_aes_256_cfb128(),
Type::AES_256_CFB8 => ffi::EVP_aes_256_cfb8(),
Type::DES_CBC => ffi::EVP_des_cbc(),
Type::DES_ECB => ffi::EVP_des_ecb(),
Type::RC4_128 => ffi::EVP_rc4(),
}
}
}
/// Returns the length of keys used with this cipher.
pub fn key_len(&self) -> usize {
unsafe {
ffi::EVP_CIPHER_key_length(self.as_ptr()) as usize
}
}
/// Returns the length of the IV used with this cipher, or `None` if the
/// cipher does not use an IV.
pub fn iv_len(&self) -> Option<usize> {
unsafe {
let len = ffi::EVP_CIPHER_iv_length(self.as_ptr()) as usize;
if len == 0 {
None
} else {
Some(len)
}
}
}
/// Returns the block size of the cipher.
///
/// # Note
///
/// Stream ciphers such as RC4 have a block size of 1.
pub fn block_size(&self) -> usize {
unsafe {
ffi::EVP_CIPHER_block_size(self.as_ptr()) as usize
}
}
}
/// Represents a symmetric cipher context. /// Represents a symmetric cipher context.
pub struct Crypter { pub struct Crypter {
evp: *const ffi::EVP_CIPHER,
ctx: *mut ffi::EVP_CIPHER_CTX, ctx: *mut ffi::EVP_CIPHER_CTX,
keylen: u32, block_size: usize,
blocksize: u32,
} }
impl Crypter { impl Crypter {
pub fn new(t: Type) -> Crypter { /// Creates a new `Crypter`.
///
/// # Panics
///
/// Panics if an IV is required by the cipher but not provided, or if the
/// IV's length does not match the expected length (see `Type::iv_len`).
pub fn new(t: Type, mode: Mode, key: &[u8], iv: Option<&[u8]>) -> Result<Crypter, ErrorStack> {
ffi::init(); ffi::init();
let ctx = unsafe { ffi::EVP_CIPHER_CTX_new() }; unsafe {
let (evp, keylen, blocksz) = evpc(t); let ctx = try_ssl_null!(ffi::EVP_CIPHER_CTX_new());
Crypter { let crypter = Crypter {
evp: evp,
ctx: ctx, ctx: ctx,
keylen: keylen, block_size: t.block_size(),
blocksize: blocksz,
}
}
/**
* Enables or disables padding. If padding is disabled, total amount of
* data encrypted must be a multiple of block size.
*/
pub fn pad(&self, padding: bool) {
if self.blocksize > 0 {
unsafe {
let v = if padding {
1 as c_int
} else {
0
}; };
ffi::EVP_CIPHER_CTX_set_padding(self.ctx, v);
}
}
}
/**
* Initializes this crypter.
*/
pub fn init(&self, mode: Mode, key: &[u8], iv: &[u8]) {
unsafe {
let mode = match mode { let mode = match mode {
Mode::Encrypt => 1 as c_int, Mode::Encrypt => 1,
Mode::Decrypt => 0 as c_int, Mode::Decrypt => 0,
}; };
assert_eq!(key.len(), self.keylen as usize);
ffi::EVP_CipherInit(self.ctx, self.evp, key.as_ptr(), iv.as_ptr(), mode); try_ssl!(ffi::EVP_CipherInit_ex(crypter.ctx,
t.as_ptr(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
mode));
assert!(key.len() <= c_int::max_value() as usize);
try_ssl!(ffi::EVP_CIPHER_CTX_set_key_length(crypter.ctx, key.len() as c_int));
let key = key.as_ptr() as *mut _;
let iv = match (iv, t.iv_len()) {
(Some(iv), Some(len)) => {
assert!(iv.len() == len);
iv.as_ptr() as *mut _
}
(Some(_), None) | (None, None) => ptr::null_mut(),
(None, Some(_)) => panic!("an IV is required for this cipher"),
};
try_ssl!(ffi::EVP_CipherInit_ex(crypter.ctx,
ptr::null(),
ptr::null_mut(),
key,
iv,
mode));
Ok(crypter)
} }
} }
/** /// Enables or disables padding.
* Update this crypter with more data to encrypt or decrypt. Returns ///
* encrypted or decrypted bytes. /// If padding is disabled, total amount of data encrypted/decrypted must
*/ /// be a multiple of the cipher's block size.
pub fn update(&self, data: &[u8]) -> Vec<u8> { pub fn pad(&mut self, padding: bool) {
unsafe { ffi::EVP_CIPHER_CTX_set_padding(self.ctx, padding as c_int); }
}
/// Feeds data from `input` through the cipher, writing encrypted/decrypted
/// bytes into `output`.
///
/// The number of bytes written to `output` is returned. Note that this may
/// not be equal to the length of `input`.
///
/// # Panics
///
/// Panics if `output.len() < input.len() + block_size` where
/// `block_size` is the block size of the cipher (see `Type::block_size`),
/// or if `output.len() > c_int::max_value()`.
pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result<usize, ErrorStack> {
unsafe { unsafe {
let sum = data.len() + (self.blocksize as usize); assert!(output.len() >= input.len() + self.block_size);
let mut res = repeat(0u8).take(sum).collect::<Vec<_>>(); assert!(output.len() <= c_int::max_value() as usize);
let mut reslen = sum as c_int; let mut outl = output.len() as c_int;
let inl = input.len() as c_int;
ffi::EVP_CipherUpdate(self.ctx, try_ssl!(ffi::EVP_CipherUpdate(self.ctx,
res.as_mut_ptr(), output.as_mut_ptr(),
&mut reslen, &mut outl,
data.as_ptr(), input.as_ptr(),
data.len() as c_int); inl));
res.truncate(reslen as usize); Ok(outl as usize)
res
} }
} }
/** /// Finishes the encryption/decryption process, writing any remaining data
* Finish crypting. Returns the remaining partial block of output, if any. /// to `output`.
*/ ///
pub fn finalize(&self) -> Vec<u8> { /// The number of bytes written to `output` is returned.
///
/// `update` should not be called after this method.
///
/// # Panics
///
/// Panics if `output` is less than the cipher's block size.
pub fn finalize(&mut self, output: &mut [u8]) -> Result<usize, ErrorStack> {
unsafe { unsafe {
let mut res = repeat(0u8).take(self.blocksize as usize).collect::<Vec<_>>(); assert!(output.len() >= self.block_size);
let mut reslen = self.blocksize as c_int; let mut outl = cmp::min(output.len(), c_int::max_value() as usize) as c_int;
ffi::EVP_CipherFinal(self.ctx, res.as_mut_ptr(), &mut reslen); try_ssl!(ffi::EVP_CipherFinal(self.ctx, output.as_mut_ptr(), &mut outl));
res.truncate(reslen as usize); Ok(outl as usize)
res
} }
} }
} }
@ -147,31 +238,43 @@ impl Drop for Crypter {
* Encrypts data, using the specified crypter type in encrypt mode with the * Encrypts data, using the specified crypter type in encrypt mode with the
* specified key and iv; returns the resulting (encrypted) data. * specified key and iv; returns the resulting (encrypted) data.
*/ */
pub fn encrypt(t: Type, key: &[u8], iv: &[u8], data: &[u8]) -> Vec<u8> { pub fn encrypt(t: Type,
let c = Crypter::new(t); key: &[u8],
c.init(Mode::Encrypt, key, iv); iv: Option<&[u8]>,
let mut r = c.update(data); data: &[u8])
let rest = c.finalize(); -> Result<Vec<u8>, ErrorStack> {
r.extend(rest.into_iter()); cipher(t, Mode::Encrypt, key, iv, data)
r
} }
/** /**
* Decrypts data, using the specified crypter type in decrypt mode with the * Decrypts data, using the specified crypter type in decrypt mode with the
* specified key and iv; returns the resulting (decrypted) data. * specified key and iv; returns the resulting (decrypted) data.
*/ */
pub fn decrypt(t: Type, key: &[u8], iv: &[u8], data: &[u8]) -> Vec<u8> { pub fn decrypt(t: Type,
let c = Crypter::new(t); key: &[u8],
c.init(Mode::Decrypt, key, iv); iv: Option<&[u8]>,
let mut r = c.update(data); data: &[u8])
let rest = c.finalize(); -> Result<Vec<u8>, ErrorStack> {
r.extend(rest.into_iter()); cipher(t, Mode::Decrypt, key, iv, data)
r }
fn cipher(t: Type,
mode: Mode,
key: &[u8],
iv: Option<&[u8]>,
data: &[u8])
-> Result<Vec<u8>, ErrorStack> {
let mut c = try!(Crypter::new(t, mode, key, iv));
let mut out = vec![0; data.len() + t.block_size()];
let count = try!(c.update(data, &mut out));
let rest = try!(c.finalize(&mut out[count..]));
out.truncate(count + rest);
Ok(out)
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use serialize::hex::FromHex; use serialize::hex::{FromHex, ToHex};
// Test vectors from FIPS-197: // Test vectors from FIPS-197:
// http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf // http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
@ -185,25 +288,33 @@ mod tests {
0xaau8, 0xbbu8, 0xccu8, 0xddu8, 0xeeu8, 0xffu8]; 0xaau8, 0xbbu8, 0xccu8, 0xddu8, 0xeeu8, 0xffu8];
let c0 = [0x8eu8, 0xa2u8, 0xb7u8, 0xcau8, 0x51u8, 0x67u8, 0x45u8, 0xbfu8, 0xeau8, 0xfcu8, let c0 = [0x8eu8, 0xa2u8, 0xb7u8, 0xcau8, 0x51u8, 0x67u8, 0x45u8, 0xbfu8, 0xeau8, 0xfcu8,
0x49u8, 0x90u8, 0x4bu8, 0x49u8, 0x60u8, 0x89u8]; 0x49u8, 0x90u8, 0x4bu8, 0x49u8, 0x60u8, 0x89u8];
let c = super::Crypter::new(super::Type::AES_256_ECB); let mut c = super::Crypter::new(super::Type::AES_256_ECB,
c.init(super::Mode::Encrypt, &k0, &[]); super::Mode::Encrypt,
&k0,
None).unwrap();
c.pad(false); c.pad(false);
let mut r0 = c.update(&p0); let mut r0 = vec![0; c0.len() + super::Type::AES_256_ECB.block_size()];
r0.extend(c.finalize().into_iter()); let count = c.update(&p0, &mut r0).unwrap();
assert!(r0 == c0); let rest = c.finalize(&mut r0[count..]).unwrap();
c.init(super::Mode::Decrypt, &k0, &[]); r0.truncate(count + rest);
assert_eq!(r0.to_hex(), c0.to_hex());
let mut c = super::Crypter::new(super::Type::AES_256_ECB,
super::Mode::Decrypt,
&k0,
None).unwrap();
c.pad(false); c.pad(false);
let mut p1 = c.update(&r0); let mut p1 = vec![0; r0.len() + super::Type::AES_256_ECB.block_size()];
p1.extend(c.finalize().into_iter()); let count = c.update(&r0, &mut p1).unwrap();
assert!(p1 == p0); let rest = c.finalize(&mut p1[count..]).unwrap();
p1.truncate(count + rest);
assert_eq!(p1.to_hex(), p0.to_hex());
} }
#[test] #[test]
fn test_aes_256_cbc_decrypt() { fn test_aes_256_cbc_decrypt() {
let cr = super::Crypter::new(super::Type::AES_256_CBC);
let iv = [4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8, 69_u8, let iv = [4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8, 69_u8,
98_u8, 107_u8, 208_u8, 14_u8, 236_u8, 60_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 98_u8, 107_u8, 208_u8, 14_u8, 236_u8, 60_u8];
0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8];
let data = [143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8, 241_u8, 242_u8, 31_u8, let data = [143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8, 241_u8, 242_u8, 31_u8,
154_u8, 56_u8, 198_u8, 145_u8, 192_u8, 64_u8, 2_u8, 245_u8, 167_u8, 220_u8, 154_u8, 56_u8, 198_u8, 145_u8, 192_u8, 64_u8, 2_u8, 245_u8, 167_u8, 220_u8,
55_u8, 119_u8, 233_u8, 136_u8, 139_u8, 27_u8, 71_u8, 242_u8, 119_u8, 175_u8, 55_u8, 119_u8, 233_u8, 136_u8, 139_u8, 27_u8, 71_u8, 242_u8, 119_u8, 175_u8,
@ -211,29 +322,31 @@ mod tests {
let ciphered_data = [0x4a_u8, 0x2e_u8, 0xe5_u8, 0x6_u8, 0xbf_u8, 0xcf_u8, 0xf2_u8, let ciphered_data = [0x4a_u8, 0x2e_u8, 0xe5_u8, 0x6_u8, 0xbf_u8, 0xcf_u8, 0xf2_u8,
0xd7_u8, 0xea_u8, 0x2d_u8, 0xb1_u8, 0x85_u8, 0x6c_u8, 0x93_u8, 0xd7_u8, 0xea_u8, 0x2d_u8, 0xb1_u8, 0x85_u8, 0x6c_u8, 0x93_u8,
0x65_u8, 0x6f_u8]; 0x65_u8, 0x6f_u8];
cr.init(super::Mode::Decrypt, &data, &iv); let mut cr = super::Crypter::new(super::Type::AES_256_CBC,
super::Mode::Decrypt,
&data,
Some(&iv)).unwrap();
cr.pad(false); cr.pad(false);
let unciphered_data_1 = cr.update(&ciphered_data); let mut unciphered_data = vec![0; data.len() + super::Type::AES_256_CBC.block_size()];
let unciphered_data_2 = cr.finalize(); let count = cr.update(&ciphered_data, &mut unciphered_data).unwrap();
let rest = cr.finalize(&mut unciphered_data[count..]).unwrap();
unciphered_data.truncate(count + rest);
let expected_unciphered_data = b"I love turtles.\x01"; let expected_unciphered_data = b"I love turtles.\x01";
assert!(unciphered_data_2.len() == 0); assert_eq!(&unciphered_data, expected_unciphered_data);
assert_eq!(&unciphered_data_1, expected_unciphered_data);
} }
fn cipher_test(ciphertype: super::Type, pt: &str, ct: &str, key: &str, iv: &str) { fn cipher_test(ciphertype: super::Type, pt: &str, ct: &str, key: &str, iv: &str) {
use serialize::hex::ToHex; use serialize::hex::ToHex;
let cipher = super::Crypter::new(ciphertype); let pt = pt.from_hex().unwrap();
cipher.init(super::Mode::Encrypt, let ct = ct.from_hex().unwrap();
&key.from_hex().unwrap(), let key = key.from_hex().unwrap();
&iv.from_hex().unwrap()); let iv = iv.from_hex().unwrap();
let expected = ct.from_hex().unwrap(); let computed = super::decrypt(ciphertype, &key, Some(&iv), &ct).unwrap();
let mut computed = cipher.update(&pt.from_hex().unwrap()); let expected = pt;
computed.extend(cipher.finalize().into_iter());
if computed != expected { if computed != expected {
println!("Computed: {}", computed.to_hex()); println!("Computed: {}", computed.to_hex());

View File

@ -1,35 +0,0 @@
use crypto::symm;
use ffi;
pub fn evpc(t: symm::Type) -> (*const ffi::EVP_CIPHER, u32, u32) {
unsafe {
match t {
symm::Type::AES_128_ECB => (ffi::EVP_aes_128_ecb(), 16, 16),
symm::Type::AES_128_CBC => (ffi::EVP_aes_128_cbc(), 16, 16),
#[cfg(feature = "aes_xts")]
symm::Type::AES_128_XTS => (ffi::EVP_aes_128_xts(), 32, 16),
#[cfg(feature = "aes_ctr")]
symm::Type::AES_128_CTR => (ffi::EVP_aes_128_ctr(), 16, 0),
// AES_128_GCM => (EVP_aes_128_gcm(), 16, 16),
symm::Type::AES_128_CFB1 => (ffi::EVP_aes_128_cfb1(), 16, 16),
symm::Type::AES_128_CFB128 => (ffi::EVP_aes_128_cfb128(), 16, 16),
symm::Type::AES_128_CFB8 => (ffi::EVP_aes_128_cfb8(), 16, 16),
symm::Type::AES_256_ECB => (ffi::EVP_aes_256_ecb(), 32, 16),
symm::Type::AES_256_CBC => (ffi::EVP_aes_256_cbc(), 32, 16),
#[cfg(feature = "aes_xts")]
symm::Type::AES_256_XTS => (ffi::EVP_aes_256_xts(), 64, 16),
#[cfg(feature = "aes_ctr")]
symm::Type::AES_256_CTR => (ffi::EVP_aes_256_ctr(), 32, 0),
// AES_256_GCM => (EVP_aes_256_gcm(), 32, 16),
symm::Type::AES_256_CFB1 => (ffi::EVP_aes_256_cfb1(), 32, 16),
symm::Type::AES_256_CFB128 => (ffi::EVP_aes_256_cfb128(), 32, 16),
symm::Type::AES_256_CFB8 => (ffi::EVP_aes_256_cfb8(), 32, 16),
symm::Type::DES_CBC => (ffi::EVP_des_cbc(), 8, 8),
symm::Type::DES_ECB => (ffi::EVP_des_ecb(), 8, 8),
symm::Type::RC4_128 => (ffi::EVP_rc4(), 16, 0),
}
}
}

View File

@ -0,0 +1,58 @@
use libc::{c_int, c_char, c_void};
use std::any::Any;
use std::panic;
use std::slice;
/// Wraps a user-supplied callback and a slot for panics thrown inside the callback (while FFI
/// frames are on the stack).
///
/// When dropped, checks if the callback has panicked, and resumes unwinding if so.
pub struct CallbackState<F> {
/// The user callback. Taken out of the `Option` when called.
cb: Option<F>,
/// If the callback panics, we place the panic object here, to be re-thrown once OpenSSL
/// returns.
panic: Option<Box<Any + Send + 'static>>,
}
impl<F> CallbackState<F> {
pub fn new(callback: F) -> Self {
CallbackState {
cb: Some(callback),
panic: None,
}
}
}
impl<F> Drop for CallbackState<F> {
fn drop(&mut self) {
if let Some(panic) = self.panic.take() {
panic::resume_unwind(panic);
}
}
}
/// Password callback function, passed to private key loading functions.
///
/// `cb_state` is expected to be a pointer to a `CallbackState`.
pub extern "C" fn invoke_passwd_cb<F>(buf: *mut c_char,
size: c_int,
_rwflag: c_int,
cb_state: *mut c_void)
-> c_int
where F: FnOnce(&mut [i8]) -> usize {
let result = panic::catch_unwind(|| {
// build a `i8` slice to pass to the user callback
let pass_slice = unsafe { slice::from_raw_parts_mut(buf, size as usize) };
let callback = unsafe { &mut *(cb_state as *mut CallbackState<F>) };
callback.cb.take().unwrap()(pass_slice)
});
if let Ok(len) = result {
return len as c_int;
} else {
return 0;
}
}

View File

@ -1,78 +1,71 @@
use ffi; use ffi;
use std::io; use error::ErrorStack;
use std::io::prelude::*; use bio::MemBioSlice;
use ssl::error::{SslError, StreamError};
use bio::MemBio;
use bn::BigNum;
use std::mem;
use std::ptr; use std::ptr;
#[cfg(feature = "dh_from_params")]
use bn::BigNum;
#[cfg(feature = "dh_from_params")]
use std::mem;
pub struct DH(*mut ffi::DH); pub struct DH(*mut ffi::DH);
impl DH { impl DH {
pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result<DH, SslError> { /// Requires the `dh_from_params` feature.
let dh = try_ssl_null!(unsafe { ffi::DH_new_from_params(p.raw(), g.raw(), q.raw()) }); #[cfg(feature = "dh_from_params")]
pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result<DH, ErrorStack> {
let dh = unsafe {
try_ssl_null!(::c_helpers::rust_DH_new_from_params(p.as_ptr(), g.as_ptr(), q.as_ptr()))
};
mem::forget(p); mem::forget(p);
mem::forget(g); mem::forget(g);
mem::forget(q); mem::forget(q);
Ok(DH(dh)) Ok(DH(dh))
} }
pub fn from_pem<R>(reader: &mut R) -> Result<DH, SslError> pub fn from_pem(buf: &[u8]) -> Result<DH, ErrorStack> {
where R: Read let mem_bio = try!(MemBioSlice::new(buf));
{
let mut mem_bio = try!(MemBio::new());
try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
let dh = unsafe { let dh = unsafe {
ffi::PEM_read_bio_DHparams(mem_bio.get_handle(), ptr::null_mut(), None, ptr::null_mut()) ffi::PEM_read_bio_DHparams(mem_bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut())
}; };
try_ssl_null!(dh); try_ssl_null!(dh);
Ok(DH(dh)) Ok(DH(dh))
} }
#[cfg(feature = "rfc5114")] #[cfg(feature = "rfc5114")]
pub fn get_1024_160() -> Result<DH, SslError> { pub fn get_1024_160() -> Result<DH, ErrorStack> {
let dh = try_ssl_null!(unsafe { ffi::DH_get_1024_160() }); let dh = try_ssl_null!(unsafe { ffi::DH_get_1024_160() });
Ok(DH(dh)) Ok(DH(dh))
} }
#[cfg(feature = "rfc5114")] #[cfg(feature = "rfc5114")]
pub fn get_2048_224() -> Result<DH, SslError> { pub fn get_2048_224() -> Result<DH, ErrorStack> {
let dh = try_ssl_null!(unsafe { ffi::DH_get_2048_224() }); let dh = try_ssl_null!(unsafe { ffi::DH_get_2048_224() });
Ok(DH(dh)) Ok(DH(dh))
} }
#[cfg(feature = "rfc5114")] #[cfg(feature = "rfc5114")]
pub fn get_2048_256() -> Result<DH, SslError> { pub fn get_2048_256() -> Result<DH, ErrorStack> {
let dh = try_ssl_null!(unsafe { ffi::DH_get_2048_256() }); let dh = try_ssl_null!(unsafe { ffi::DH_get_2048_256() });
Ok(DH(dh)) Ok(DH(dh))
} }
pub unsafe fn raw(&self) -> *mut ffi::DH { pub unsafe fn as_ptr(&self) -> *mut ffi::DH {
let DH(n) = *self; let DH(n) = *self;
n n
} }
pub unsafe fn raw_ptr(&self) -> *const *mut ffi::DH {
let DH(ref n) = *self;
n
}
} }
impl Drop for DH { impl Drop for DH {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
if !self.raw().is_null() { ffi::DH_free(self.as_ptr())
ffi::DH_free(self.raw())
}
} }
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::fs::File;
use std::path::Path;
use super::DH; use super::DH;
use bn::BigNum; use bn::BigNum;
use ssl::SslContext; use ssl::SslContext;
@ -81,18 +74,19 @@ mod tests {
#[test] #[test]
#[cfg(feature = "rfc5114")] #[cfg(feature = "rfc5114")]
fn test_dh_rfc5114() { fn test_dh_rfc5114() {
let ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
let dh1 = DH::get_1024_160().unwrap(); let dh1 = DH::get_1024_160().unwrap();
ctx.set_tmp_dh(dh1).unwrap(); ctx.set_tmp_dh(&dh1).unwrap();
let dh2 = DH::get_2048_224().unwrap(); let dh2 = DH::get_2048_224().unwrap();
ctx.set_tmp_dh(dh2).unwrap(); ctx.set_tmp_dh(&dh2).unwrap();
let dh3 = DH::get_2048_256().unwrap(); let dh3 = DH::get_2048_256().unwrap();
ctx.set_tmp_dh(dh3).unwrap(); ctx.set_tmp_dh(&dh3).unwrap();
} }
#[test] #[test]
#[cfg(feature = "dh_from_params")]
fn test_dh() { fn test_dh() {
let ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
let p = BigNum::from_hex_str("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435\ let p = BigNum::from_hex_str("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435\
E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF429\ E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF429\
6D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C02\ 6D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C02\
@ -117,17 +111,14 @@ mod tests {
5FBD3") 5FBD3")
.unwrap(); .unwrap();
let dh = DH::from_params(p, g, q).unwrap(); let dh = DH::from_params(p, g, q).unwrap();
ctx.set_tmp_dh(dh).unwrap(); ctx.set_tmp_dh(&dh).unwrap();
} }
#[test] #[test]
fn test_dh_from_pem() { fn test_dh_from_pem() {
let ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
let pem_path = Path::new("test/dhparams.pem"); let params = include_bytes!("../../test/dhparams.pem");
let mut file = File::open(&pem_path) let dh = DH::from_pem(params).ok().expect("Failed to load PEM");
.ok() ctx.set_tmp_dh(&dh).unwrap();
.expect("Failed to open `test/dhparams.pem`");
let dh = DH::from_pem(&mut file).ok().expect("Failed to load PEM");
ctx.set_tmp_dh(dh).unwrap();
} }
} }

137
openssl/src/error.rs Normal file
View File

@ -0,0 +1,137 @@
use libc::c_ulong;
use std::fmt;
use std::error;
use std::ffi::CStr;
use std::io;
use std::str;
use ffi;
#[derive(Debug)]
pub struct ErrorStack(Vec<Error>);
impl ErrorStack {
/// Returns the contents of the OpenSSL error stack.
pub fn get() -> ErrorStack {
let mut vec = vec![];
while let Some(err) = Error::get() {
vec.push(err);
}
ErrorStack(vec)
}
}
impl ErrorStack {
/// Returns the errors in the stack.
pub fn errors(&self) -> &[Error] {
&self.0
}
}
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 {
try!(fmt.write_str(", "));
first = false;
}
try!(write!(fmt, "{}", err));
}
Ok(())
}
}
impl error::Error for ErrorStack {
fn description(&self) -> &str {
"An OpenSSL error stack"
}
}
impl From<ErrorStack> for io::Error {
fn from(e: ErrorStack) -> io::Error {
io::Error::new(io::ErrorKind::Other, e)
}
}
/// An error reported from OpenSSL.
pub struct Error(c_ulong);
impl Error {
/// Returns the first error on the OpenSSL error stack.
pub fn get() -> Option<Error> {
ffi::init();
match unsafe { ffi::ERR_get_error() } {
0 => None,
err => Some((Error(err))),
}
}
/// Returns the raw OpenSSL error code for this error.
pub fn error_code(&self) -> c_ulong {
self.0
}
/// Returns the name of the library reporting the error.
pub fn library(&self) -> &'static str {
get_lib(self.0)
}
/// Returns the name of the function reporting the error.
pub fn function(&self) -> &'static str {
get_func(self.0)
}
/// Returns the reason for the error.
pub fn reason(&self) -> &'static str {
get_reason(self.0)
}
}
impl fmt::Debug for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Error")
.field("library", &self.library())
.field("function", &self.function())
.field("reason", &self.reason())
.finish()
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(&self.reason())
}
}
impl error::Error for Error {
fn description(&self) -> &str {
"An OpenSSL error"
}
}
fn get_lib(err: c_ulong) -> &'static str {
unsafe {
let cstr = ffi::ERR_lib_error_string(err);
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
str::from_utf8(bytes).unwrap()
}
}
fn get_func(err: c_ulong) -> &'static str {
unsafe {
let cstr = ffi::ERR_func_error_string(err);
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
str::from_utf8(bytes).unwrap()
}
}
fn get_reason(err: c_ulong) -> &'static str {
unsafe {
let cstr = ffi::ERR_reason_error_string(err);
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
str::from_utf8(bytes).unwrap()
}
}

View File

@ -1,5 +1,4 @@
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.14")] #![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.8.0")]
#![cfg_attr(feature = "nightly", feature(const_fn))]
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;
@ -7,7 +6,6 @@ extern crate libc;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
extern crate openssl_sys as ffi; extern crate openssl_sys as ffi;
extern crate openssl_sys_extras as ffi_extras;
#[cfg(test)] #[cfg(test)]
extern crate rustc_serialize as serialize; extern crate rustc_serialize as serialize;
@ -15,14 +13,27 @@ extern crate rustc_serialize as serialize;
#[cfg(test)] #[cfg(test)]
extern crate net2; extern crate net2;
#[doc(inline)]
pub use ffi::init;
use nid::Nid;
mod macros; mod macros;
pub mod asn1; pub mod asn1;
mod bio;
pub mod bn; pub mod bn;
pub mod bio; #[cfg(feature = "c_helpers")]
mod c_helpers;
pub mod crypto; pub mod crypto;
pub mod dh; pub mod dh;
pub mod ssl; pub mod error;
pub mod x509;
pub mod nid; pub mod nid;
pub mod ssl;
pub mod version; pub mod version;
pub mod x509;
trait HashTypeInternals {
fn as_nid(&self) -> Nid;
fn evp_md(&self) -> *const ffi::EVP_MD;
}

View File

@ -13,7 +13,7 @@ macro_rules! try_ssl_stream {
macro_rules! try_ssl_if { macro_rules! try_ssl_if {
($e:expr) => ( ($e:expr) => (
if $e { if $e {
return Err(SslError::get()) return Err(::error::ErrorStack::get().into())
} }
) )
} }
@ -45,7 +45,7 @@ macro_rules! try_ssl_null{
macro_rules! lift_ssl_if{ macro_rules! lift_ssl_if{
($e:expr) => ( { ($e:expr) => ( {
if $e { if $e {
Err(SslError::get()) Err(::error::ErrorStack::get().into())
} else { } else {
Ok(()) Ok(())
} }

View File

@ -1,6 +1,6 @@
use libc::{c_char, c_int, c_long, c_void, strlen}; use libc::{c_char, c_int, c_long, c_void, strlen};
use ffi::{self, BIO, BIO_CTRL_FLUSH, BIO_TYPE_NONE, BIO_new}; use ffi::{self, BIO, BIO_CTRL_FLUSH, BIO_TYPE_NONE, BIO_new, BIO_clear_retry_flags,
use ffi_extras::{BIO_clear_retry_flags, BIO_set_retry_read, BIO_set_retry_write}; BIO_set_retry_read, BIO_set_retry_write};
use std::any::Any; use std::any::Any;
use std::io; use std::io;
use std::io::prelude::*; use std::io::prelude::*;
@ -9,7 +9,7 @@ use std::ptr;
use std::slice; use std::slice;
use std::sync::Arc; use std::sync::Arc;
use ssl::error::SslError; use error::ErrorStack;
pub struct StreamState<S> { pub struct StreamState<S> {
pub stream: S, pub stream: S,
@ -39,7 +39,7 @@ impl BioMethod {
unsafe impl Send for BioMethod {} unsafe impl Send for BioMethod {}
pub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, Arc<BioMethod>), SslError> { pub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, Arc<BioMethod>), ErrorStack> {
let method = Arc::new(BioMethod::new::<S>()); let method = Arc::new(BioMethod::new::<S>());
let state = Box::new(StreamState { let state = Box::new(StreamState {

View File

@ -1,15 +1,8 @@
pub use self::SslError::*;
pub use self::OpensslError::*;
use libc::c_ulong;
use std::error; use std::error;
use std::error::Error as StdError; use std::error::Error as StdError;
use std::fmt; use std::fmt;
use std::ffi::CStr;
use std::io; use std::io;
use std::str; use error::ErrorStack;
use ffi;
/// An SSL error. /// An SSL error.
#[derive(Debug)] #[derive(Debug)]
@ -27,31 +20,17 @@ pub enum Error {
/// An error reported by the underlying stream. /// An error reported by the underlying stream.
Stream(io::Error), Stream(io::Error),
/// An error in the OpenSSL library. /// An error in the OpenSSL library.
Ssl(Vec<OpenSslError>), Ssl(ErrorStack),
} }
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
try!(fmt.write_str(self.description())); try!(fmt.write_str(self.description()));
match *self { if let Some(err) = self.cause() {
Error::Stream(ref err) => write!(fmt, ": {}", err), write!(fmt, ": {}", err)
Error::WantRead(ref err) => write!(fmt, ": {}", err),
Error::WantWrite(ref err) => write!(fmt, ": {}", err),
Error::Ssl(ref errs) => {
let mut first = true;
for err in errs {
if first {
try!(fmt.write_str(": "));
first = false;
} else { } else {
try!(fmt.write_str(", "));
}
try!(fmt.write_str(&err.reason()))
}
Ok(()) Ok(())
} }
_ => Ok(()),
}
} }
} }
@ -72,247 +51,14 @@ impl error::Error for Error {
Error::WantRead(ref err) => Some(err), Error::WantRead(ref err) => Some(err),
Error::WantWrite(ref err) => Some(err), Error::WantWrite(ref err) => Some(err),
Error::Stream(ref err) => Some(err), Error::Stream(ref err) => Some(err),
Error::Ssl(ref err) => Some(err),
_ => None, _ => None,
} }
} }
} }
/// An error reported from OpenSSL. impl From<ErrorStack> for Error {
pub struct OpenSslError(c_ulong); fn from(e: ErrorStack) -> Error {
Error::Ssl(e)
impl OpenSslError {
/// Returns the contents of the OpenSSL error stack.
pub fn get_stack() -> Vec<OpenSslError> {
ffi::init();
let mut errs = vec![];
loop {
match unsafe { ffi::ERR_get_error() } {
0 => break,
err => errs.push(OpenSslError(err)),
} }
} }
errs
}
/// Returns the raw OpenSSL error code for this error.
pub fn error_code(&self) -> c_ulong {
self.0
}
/// Returns the name of the library reporting the error.
pub fn library(&self) -> &'static str {
get_lib(self.0)
}
/// Returns the name of the function reporting the error.
pub fn function(&self) -> &'static str {
get_func(self.0)
}
/// Returns the reason for the error.
pub fn reason(&self) -> &'static str {
get_reason(self.0)
}
}
impl fmt::Debug for OpenSslError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("OpenSslError")
.field("library", &self.library())
.field("function", &self.function())
.field("reason", &self.reason())
.finish()
}
}
impl fmt::Display for OpenSslError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(&self.reason())
}
}
impl error::Error for OpenSslError {
fn description(&self) -> &str {
"An OpenSSL error"
}
}
/// An SSL error
#[derive(Debug)]
pub enum SslError {
/// The underlying stream reported an error
StreamError(io::Error),
/// The SSL session has been closed by the other end
SslSessionClosed,
/// An error in the OpenSSL library
OpenSslErrors(Vec<OpensslError>),
}
/// An error on a nonblocking stream.
#[derive(Debug)]
pub enum NonblockingSslError {
/// A standard SSL error occurred.
SslError(SslError),
/// The OpenSSL library wants data from the remote socket;
/// the caller should wait for read readiness.
WantRead,
/// The OpenSSL library wants to send data to the remote socket;
/// the caller should wait for write readiness.
WantWrite,
}
impl fmt::Display for SslError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
try!(fmt.write_str(error::Error::description(self)));
if let OpenSslErrors(ref errs) = *self {
let mut first = true;
for err in errs {
if first {
try!(fmt.write_str(": "));
first = false;
} else {
try!(fmt.write_str(", "));
}
match *err {
UnknownError { ref reason, .. } => try!(fmt.write_str(reason)),
}
}
}
Ok(())
}
}
impl error::Error for SslError {
fn description(&self) -> &str {
match *self {
StreamError(_) => "The underlying stream reported an error",
SslSessionClosed => "The SSL session has been closed by the other end",
OpenSslErrors(_) => "An error in the OpenSSL library",
}
}
fn cause(&self) -> Option<&error::Error> {
match *self {
StreamError(ref err) => Some(err as &error::Error),
_ => None,
}
}
}
impl fmt::Display for NonblockingSslError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(error::Error::description(self))
}
}
impl error::Error for NonblockingSslError {
fn description(&self) -> &str {
match *self {
NonblockingSslError::SslError(ref e) => e.description(),
NonblockingSslError::WantRead => {
"The OpenSSL library wants data from the remote socket"
}
NonblockingSslError::WantWrite => {
"The OpenSSL library want to send data to the remote socket"
}
}
}
fn cause(&self) -> Option<&error::Error> {
match *self {
NonblockingSslError::SslError(ref e) => e.cause(),
_ => None,
}
}
}
impl From<SslError> for NonblockingSslError {
fn from(e: SslError) -> NonblockingSslError {
NonblockingSslError::SslError(e)
}
}
/// An error from the OpenSSL library
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OpensslError {
/// An unknown error
UnknownError {
/// The library reporting the error
library: String,
/// The function reporting the error
function: String,
/// The reason for the error
reason: String,
},
}
impl OpensslError {
pub fn from_error_code(err: c_ulong) -> OpensslError {
ffi::init();
UnknownError {
library: get_lib(err).to_owned(),
function: get_func(err).to_owned(),
reason: get_reason(err).to_owned(),
}
}
}
fn get_lib(err: c_ulong) -> &'static str {
unsafe {
let cstr = ffi::ERR_lib_error_string(err);
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
str::from_utf8(bytes).unwrap()
}
}
fn get_func(err: c_ulong) -> &'static str {
unsafe {
let cstr = ffi::ERR_func_error_string(err);
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
str::from_utf8(bytes).unwrap()
}
}
fn get_reason(err: c_ulong) -> &'static str {
unsafe {
let cstr = ffi::ERR_reason_error_string(err);
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
str::from_utf8(bytes).unwrap()
}
}
impl SslError {
/// Creates a new `OpenSslErrors` with the current contents of the error
/// stack.
pub fn get() -> SslError {
let mut errs = vec![];
loop {
match unsafe { ffi::ERR_get_error() } {
0 => break,
err => errs.push(OpensslError::from_error_code(err)),
}
}
OpenSslErrors(errs)
}
/// Creates an `SslError` from the raw numeric error code.
pub fn from_error(err: c_ulong) -> SslError {
OpenSslErrors(vec![OpensslError::from_error_code(err)])
}
}
#[test]
fn test_uknown_error_should_have_correct_messages() {
let errs = match SslError::from_error(336032784) {
OpenSslErrors(errs) => errs,
_ => panic!("This should always be an `OpenSslErrors` variant."),
};
let UnknownError { ref library, ref function, ref reason } = errs[0];
assert_eq!(&library[..], "SSL routines");
assert_eq!(&function[..], "SSL23_GET_SERVER_HELLO");
assert_eq!(&reason[..], "sslv3 alert handshake failure");
}

File diff suppressed because it is too large Load Diff

View File

@ -17,9 +17,9 @@ use crypto::hash::Type::SHA256;
use ssl; use ssl;
use ssl::SSL_VERIFY_PEER; use ssl::SSL_VERIFY_PEER;
use ssl::SslMethod::Sslv23; use ssl::SslMethod::Sslv23;
use ssl::SslMethod; use ssl::{SslMethod, HandshakeError};
use ssl::error::NonblockingSslError; use ssl::error::Error;
use ssl::{SslContext, SslStream, VerifyCallback, NonblockingSslStream}; use ssl::{SslContext, SslStream};
use x509::X509StoreContext; use x509::X509StoreContext;
use x509::X509FileType; use x509::X509FileType;
use x509::X509; use x509::X509;
@ -133,6 +133,7 @@ impl Drop for Server {
} }
#[cfg(feature = "dtlsv1")] #[cfg(feature = "dtlsv1")]
#[derive(Debug)]
struct UdpConnected(UdpSocket); struct UdpConnected(UdpSocket);
#[cfg(feature = "dtlsv1")] #[cfg(feature = "dtlsv1")]
@ -194,9 +195,9 @@ macro_rules! run_test(
use std::net::TcpStream; use std::net::TcpStream;
use ssl; use ssl;
use ssl::SslMethod; use ssl::SslMethod;
use ssl::{SslContext, Ssl, SslStream, VerifyCallback}; use ssl::{SslContext, Ssl, SslStream};
use ssl::SSL_VERIFY_PEER; use ssl::SSL_VERIFY_PEER;
use crypto::hash::Type::SHA1; use crypto::hash::Type::{SHA1, SHA256};
use x509::X509StoreContext; use x509::X509StoreContext;
use serialize::hex::FromHex; use serialize::hex::FromHex;
use super::Server; use super::Server;
@ -222,19 +223,19 @@ run_test!(new_ctx, |method, _| {
}); });
run_test!(new_sslstream, |method, stream| { run_test!(new_sslstream, |method, stream| {
SslStream::connect_generic(&SslContext::new(method).unwrap(), stream).unwrap(); SslStream::connect(&SslContext::new(method).unwrap(), stream).unwrap();
}); });
run_test!(get_ssl_method, |method, _| { run_test!(get_ssl_method, |method, _| {
let ssl = Ssl::new(&SslContext::new(method).unwrap()).unwrap(); let ssl = Ssl::new(&SslContext::new(method).unwrap()).unwrap();
assert_eq!(ssl.get_ssl_method(), Some(method)); assert_eq!(ssl.ssl_method(), method);
}); });
run_test!(verify_untrusted, |method, stream| { run_test!(verify_untrusted, |method, stream| {
let mut ctx = SslContext::new(method).unwrap(); let mut ctx = SslContext::new(method).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, None); ctx.set_verify(SSL_VERIFY_PEER);
match SslStream::connect_generic(&ctx, stream) { match SslStream::connect(&ctx, stream) {
Ok(_) => panic!("expected failure"), Ok(_) => panic!("expected failure"),
Err(err) => println!("error {:?}", err), Err(err) => println!("error {:?}", err),
} }
@ -242,127 +243,95 @@ run_test!(verify_untrusted, |method, stream| {
run_test!(verify_trusted, |method, stream| { run_test!(verify_trusted, |method, stream| {
let mut ctx = SslContext::new(method).unwrap(); let mut ctx = SslContext::new(method).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, None); ctx.set_verify(SSL_VERIFY_PEER);
match ctx.set_CA_file(&Path::new("test/cert.pem")) { match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {} Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err), Err(err) => panic!("Unexpected error {:?}", err),
} }
match SslStream::connect_generic(&ctx, stream) { match SslStream::connect(&ctx, stream) {
Ok(_) => (), Ok(_) => (),
Err(err) => panic!("Expected success, got {:?}", err), Err(err) => panic!("Expected success, got {:?}", err),
} }
}); });
run_test!(verify_untrusted_callback_override_ok, |method, stream| { run_test!(verify_untrusted_callback_override_ok, |method, stream| {
fn callback(_preverify_ok: bool, _x509_ctx: &X509StoreContext) -> bool {
true
}
let mut ctx = SslContext::new(method).unwrap(); let mut ctx = SslContext::new(method).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); ctx.set_verify_callback(SSL_VERIFY_PEER, |_, _| true);
match SslStream::connect_generic(&ctx, stream) { match SslStream::connect(&ctx, stream) {
Ok(_) => (), Ok(_) => (),
Err(err) => panic!("Expected success, got {:?}", err), Err(err) => panic!("Expected success, got {:?}", err),
} }
}); });
run_test!(verify_untrusted_callback_override_bad, |method, stream| { run_test!(verify_untrusted_callback_override_bad, |method, stream| {
fn callback(_preverify_ok: bool, _x509_ctx: &X509StoreContext) -> bool {
false
}
let mut ctx = SslContext::new(method).unwrap(); let mut ctx = SslContext::new(method).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); ctx.set_verify_callback(SSL_VERIFY_PEER, |_, _| false);
assert!(SslStream::connect_generic(&ctx, stream).is_err()); assert!(SslStream::connect(&ctx, stream).is_err());
}); });
run_test!(verify_trusted_callback_override_ok, |method, stream| { run_test!(verify_trusted_callback_override_ok, |method, stream| {
fn callback(_preverify_ok: bool, _x509_ctx: &X509StoreContext) -> bool {
true
}
let mut ctx = SslContext::new(method).unwrap(); let mut ctx = SslContext::new(method).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); ctx.set_verify_callback(SSL_VERIFY_PEER, |_, _| true);
match ctx.set_CA_file(&Path::new("test/cert.pem")) { match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {} Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err), Err(err) => panic!("Unexpected error {:?}", err),
} }
match SslStream::connect_generic(&ctx, stream) { match SslStream::connect(&ctx, stream) {
Ok(_) => (), Ok(_) => (),
Err(err) => panic!("Expected success, got {:?}", err), Err(err) => panic!("Expected success, got {:?}", err),
} }
}); });
run_test!(verify_trusted_callback_override_bad, |method, stream| { run_test!(verify_trusted_callback_override_bad, |method, stream| {
fn callback(_preverify_ok: bool, _x509_ctx: &X509StoreContext) -> bool {
false
}
let mut ctx = SslContext::new(method).unwrap(); let mut ctx = SslContext::new(method).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); ctx.set_verify_callback(SSL_VERIFY_PEER, |_, _| false);
match ctx.set_CA_file(&Path::new("test/cert.pem")) { match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {} Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err), Err(err) => panic!("Unexpected error {:?}", err),
} }
assert!(SslStream::connect_generic(&ctx, stream).is_err()); assert!(SslStream::connect(&ctx, stream).is_err());
}); });
run_test!(verify_callback_load_certs, |method, stream| { run_test!(verify_callback_load_certs, |method, stream| {
fn callback(_preverify_ok: bool, x509_ctx: &X509StoreContext) -> bool {
assert!(x509_ctx.get_current_cert().is_some());
true
}
let mut ctx = SslContext::new(method).unwrap(); let mut ctx = SslContext::new(method).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); ctx.set_verify_callback(SSL_VERIFY_PEER, |_, x509_ctx| {
assert!(x509_ctx.current_cert().is_some());
true
});
assert!(SslStream::connect_generic(&ctx, stream).is_ok()); assert!(SslStream::connect(&ctx, stream).is_ok());
}); });
run_test!(verify_trusted_get_error_ok, |method, stream| { run_test!(verify_trusted_get_error_ok, |method, stream| {
fn callback(_preverify_ok: bool, x509_ctx: &X509StoreContext) -> bool {
assert!(x509_ctx.get_error().is_none());
true
}
let mut ctx = SslContext::new(method).unwrap(); let mut ctx = SslContext::new(method).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); ctx.set_verify_callback(SSL_VERIFY_PEER, |_, x509_ctx| {
assert!(x509_ctx.error().is_none());
true
});
match ctx.set_CA_file(&Path::new("test/cert.pem")) { match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {} Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err), Err(err) => panic!("Unexpected error {:?}", err),
} }
assert!(SslStream::connect_generic(&ctx, stream).is_ok()); assert!(SslStream::connect(&ctx, stream).is_ok());
}); });
run_test!(verify_trusted_get_error_err, |method, stream| { run_test!(verify_trusted_get_error_err, |method, stream| {
fn callback(_preverify_ok: bool, x509_ctx: &X509StoreContext) -> bool {
assert!(x509_ctx.get_error().is_some());
false
}
let mut ctx = SslContext::new(method).unwrap(); let mut ctx = SslContext::new(method).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); ctx.set_verify_callback(SSL_VERIFY_PEER, |_, x509_ctx| {
assert!(x509_ctx.error().is_some());
false
});
assert!(SslStream::connect_generic(&ctx, stream).is_err()); assert!(SslStream::connect(&ctx, stream).is_err());
}); });
run_test!(verify_callback_data, |method, stream| { run_test!(verify_callback_data, |method, stream| {
fn callback(_preverify_ok: bool, x509_ctx: &X509StoreContext, node_id: &Vec<u8>) -> bool {
let cert = x509_ctx.get_current_cert();
match cert {
None => false,
Some(cert) => {
let fingerprint = cert.fingerprint(SHA1).unwrap();
&fingerprint == node_id
}
}
}
let mut ctx = SslContext::new(method).unwrap(); let mut ctx = SslContext::new(method).unwrap();
// Node id was generated as SHA256 hash of certificate "test/cert.pem" // Node id was generated as SHA256 hash of certificate "test/cert.pem"
@ -371,10 +340,19 @@ run_test!(verify_callback_data, |method, stream| {
// Please update if "test/cert.pem" will ever change // Please update if "test/cert.pem" will ever change
let node_hash_str = "E19427DAC79FBE758394945276A6E4F15F0BEBE6"; let node_hash_str = "E19427DAC79FBE758394945276A6E4F15F0BEBE6";
let node_id = node_hash_str.from_hex().unwrap(); let node_id = node_hash_str.from_hex().unwrap();
ctx.set_verify_with_data(SSL_VERIFY_PEER, callback, node_id); ctx.set_verify_callback(SSL_VERIFY_PEER, move |_preverify_ok, x509_ctx| {
let cert = x509_ctx.current_cert();
match cert {
None => false,
Some(cert) => {
let fingerprint = cert.fingerprint(SHA1).unwrap();
fingerprint == node_id
}
}
});
ctx.set_verify_depth(1); ctx.set_verify_depth(1);
match SslStream::connect_generic(&ctx, stream) { match SslStream::connect(&ctx, stream) {
Ok(_) => (), Ok(_) => (),
Err(err) => panic!("Expected success, got {:?}", err), Err(err) => panic!("Expected success, got {:?}", err),
} }
@ -393,7 +371,7 @@ run_test!(ssl_verify_callback, |method, stream| {
let node_id = node_hash_str.from_hex().unwrap(); let node_id = node_hash_str.from_hex().unwrap();
ssl.set_verify_callback(SSL_VERIFY_PEER, move |_, x509| { ssl.set_verify_callback(SSL_VERIFY_PEER, move |_, x509| {
CHECKED.store(1, Ordering::SeqCst); CHECKED.store(1, Ordering::SeqCst);
match x509.get_current_cert() { match x509.current_cert() {
None => false, None => false,
Some(cert) => { Some(cert) => {
let fingerprint = cert.fingerprint(SHA1).unwrap(); let fingerprint = cert.fingerprint(SHA1).unwrap();
@ -402,7 +380,7 @@ run_test!(ssl_verify_callback, |method, stream| {
} }
}); });
match SslStream::connect_generic(ssl, stream) { match SslStream::connect(ssl, stream) {
Ok(_) => (), Ok(_) => (),
Err(err) => panic!("Expected success, got {:?}", err), Err(err) => panic!("Expected success, got {:?}", err),
} }
@ -419,14 +397,14 @@ fn test_write_hits_stream() {
let guard = thread::spawn(move || { let guard = thread::spawn(move || {
let ctx = SslContext::new(Sslv23).unwrap(); let ctx = SslContext::new(Sslv23).unwrap();
let stream = TcpStream::connect(addr).unwrap(); let stream = TcpStream::connect(addr).unwrap();
let mut stream = SslStream::connect_generic(&ctx, stream).unwrap(); let mut stream = SslStream::connect(&ctx, stream).unwrap();
stream.write_all(b"hello").unwrap(); stream.write_all(b"hello").unwrap();
stream stream
}); });
let mut ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, None); ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM).unwrap(); ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM).unwrap();
ctx.set_private_key_file(&Path::new("test/key.pem"), X509FileType::PEM).unwrap(); ctx.set_private_key_file(&Path::new("test/key.pem"), X509FileType::PEM).unwrap();
let stream = listener.accept().unwrap().0; let stream = listener.accept().unwrap().0;
@ -440,17 +418,10 @@ fn test_write_hits_stream() {
#[test] #[test]
fn test_set_certificate_and_private_key() { fn test_set_certificate_and_private_key() {
let key_path = Path::new("test/key.pem"); let key = include_bytes!("../../../test/key.pem");
let cert_path = Path::new("test/cert.pem"); let key = PKey::private_key_from_pem(key).unwrap();
let mut key_file = File::open(&key_path) let cert = include_bytes!("../../../test/cert.pem");
.ok() let cert = X509::from_pem(cert).unwrap();
.expect("Failed to open `test/key.pem`");
let mut cert_file = File::open(&cert_path)
.ok()
.expect("Failed to open `test/cert.pem`");
let key = PKey::private_key_from_pem(&mut key_file).unwrap();
let cert = X509::from_pem(&mut cert_file).unwrap();
let mut ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
ctx.set_private_key(&key).unwrap(); ctx.set_private_key(&key).unwrap();
@ -460,8 +431,8 @@ fn test_set_certificate_and_private_key() {
} }
run_test!(get_ctx_options, |method, _| { run_test!(get_ctx_options, |method, _| {
let mut ctx = SslContext::new(method).unwrap(); let ctx = SslContext::new(method).unwrap();
ctx.get_options(); ctx.options();
}); });
run_test!(set_ctx_options, |method, _| { run_test!(set_ctx_options, |method, _| {
@ -480,7 +451,7 @@ run_test!(clear_ctx_options, |method, _| {
#[test] #[test]
fn test_write() { fn test_write() {
let (_s, stream) = Server::new(); let (_s, stream) = Server::new();
let mut stream = SslStream::connect_generic(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), stream).unwrap();
stream.write_all("hello".as_bytes()).unwrap(); stream.write_all("hello".as_bytes()).unwrap();
stream.flush().unwrap(); stream.flush().unwrap();
stream.write_all(" there".as_bytes()).unwrap(); stream.write_all(" there".as_bytes()).unwrap();
@ -498,7 +469,7 @@ fn test_write_direct() {
} }
run_test!(get_peer_certificate, |method, stream| { run_test!(get_peer_certificate, |method, stream| {
let stream = SslStream::connect_generic(&SslContext::new(method).unwrap(), stream).unwrap(); let stream = SslStream::connect(&SslContext::new(method).unwrap(), stream).unwrap();
let cert = stream.ssl().peer_certificate().unwrap(); let cert = stream.ssl().peer_certificate().unwrap();
let fingerprint = cert.fingerprint(SHA1).unwrap(); let fingerprint = cert.fingerprint(SHA1).unwrap();
let node_hash_str = "E19427DAC79FBE758394945276A6E4F15F0BEBE6"; let node_hash_str = "E19427DAC79FBE758394945276A6E4F15F0BEBE6";
@ -511,7 +482,7 @@ run_test!(get_peer_certificate, |method, stream| {
fn test_write_dtlsv1() { fn test_write_dtlsv1() {
let (_s, stream) = Server::new_dtlsv1(iter::repeat("y\n")); let (_s, stream) = Server::new_dtlsv1(iter::repeat("y\n"));
let mut stream = SslStream::connect_generic(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap(); let mut stream = SslStream::connect(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap();
stream.write_all(b"hello").unwrap(); stream.write_all(b"hello").unwrap();
stream.flush().unwrap(); stream.flush().unwrap();
stream.write_all(b" there").unwrap(); stream.write_all(b" there").unwrap();
@ -521,7 +492,7 @@ fn test_write_dtlsv1() {
#[test] #[test]
fn test_read() { fn test_read() {
let (_s, tcp) = Server::new(); let (_s, tcp) = Server::new();
let mut stream = SslStream::connect_generic(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap();
stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap();
stream.flush().unwrap(); stream.flush().unwrap();
io::copy(&mut stream, &mut io::sink()).ok().expect("read error"); io::copy(&mut stream, &mut io::sink()).ok().expect("read error");
@ -539,7 +510,7 @@ fn test_read_direct() {
#[test] #[test]
fn test_pending() { fn test_pending() {
let (_s, tcp) = Server::new(); let (_s, tcp) = Server::new();
let mut stream = SslStream::connect_generic(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap();
stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap();
stream.flush().unwrap(); stream.flush().unwrap();
@ -562,7 +533,7 @@ fn test_pending() {
#[test] #[test]
fn test_state() { fn test_state() {
let (_s, tcp) = Server::new(); let (_s, tcp) = Server::new();
let stream = SslStream::connect_generic(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); let stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap();
assert_eq!(stream.ssl().state_string(), "SSLOK "); assert_eq!(stream.ssl().state_string(), "SSLOK ");
assert_eq!(stream.ssl().state_string_long(), assert_eq!(stream.ssl().state_string_long(),
"SSL negotiation finished successfully"); "SSL negotiation finished successfully");
@ -575,7 +546,7 @@ fn test_state() {
fn test_connect_with_unilateral_alpn() { fn test_connect_with_unilateral_alpn() {
let (_s, stream) = Server::new(); let (_s, stream) = Server::new();
let mut ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, None); ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]); ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) { match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {} Ok(_) => {}
@ -597,13 +568,13 @@ fn test_connect_with_unilateral_alpn() {
fn test_connect_with_unilateral_npn() { fn test_connect_with_unilateral_npn() {
let (_s, stream) = Server::new(); let (_s, stream) = Server::new();
let mut ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, None); ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_npn_protocols(&[b"http/1.1", b"spdy/3.1"]); ctx.set_npn_protocols(&[b"http/1.1", b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) { match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {} Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err), Err(err) => panic!("Unexpected error {:?}", err),
} }
let stream = match SslStream::connect_generic(&ctx, stream) { let stream = match SslStream::connect(&ctx, stream) {
Ok(stream) => stream, Ok(stream) => stream,
Err(err) => panic!("Expected success, got {:?}", err), Err(err) => panic!("Expected success, got {:?}", err),
}; };
@ -619,7 +590,7 @@ fn test_connect_with_unilateral_npn() {
fn test_connect_with_alpn_successful_multiple_matching() { fn test_connect_with_alpn_successful_multiple_matching() {
let (_s, stream) = Server::new_alpn(); let (_s, stream) = Server::new_alpn();
let mut ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, None); ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"spdy/3.1", b"http/1.1"]); ctx.set_alpn_protocols(&[b"spdy/3.1", b"http/1.1"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) { match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {} Ok(_) => {}
@ -641,13 +612,13 @@ fn test_connect_with_alpn_successful_multiple_matching() {
fn test_connect_with_npn_successful_multiple_matching() { fn test_connect_with_npn_successful_multiple_matching() {
let (_s, stream) = Server::new_alpn(); let (_s, stream) = Server::new_alpn();
let mut ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, None); ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_npn_protocols(&[b"spdy/3.1", b"http/1.1"]); ctx.set_npn_protocols(&[b"spdy/3.1", b"http/1.1"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) { match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {} Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err), Err(err) => panic!("Unexpected error {:?}", err),
} }
let stream = match SslStream::connect_generic(&ctx, stream) { let stream = match SslStream::connect(&ctx, stream) {
Ok(stream) => stream, Ok(stream) => stream,
Err(err) => panic!("Expected success, got {:?}", err), Err(err) => panic!("Expected success, got {:?}", err),
}; };
@ -664,7 +635,7 @@ fn test_connect_with_npn_successful_multiple_matching() {
fn test_connect_with_alpn_successful_single_match() { fn test_connect_with_alpn_successful_single_match() {
let (_s, stream) = Server::new_alpn(); let (_s, stream) = Server::new_alpn();
let mut ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, None); ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"spdy/3.1"]); ctx.set_alpn_protocols(&[b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) { match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {} Ok(_) => {}
@ -688,13 +659,13 @@ fn test_connect_with_alpn_successful_single_match() {
fn test_connect_with_npn_successful_single_match() { fn test_connect_with_npn_successful_single_match() {
let (_s, stream) = Server::new_alpn(); let (_s, stream) = Server::new_alpn();
let mut ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, None); ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_npn_protocols(&[b"spdy/3.1"]); ctx.set_npn_protocols(&[b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) { match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {} Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err), Err(err) => panic!("Unexpected error {:?}", err),
} }
let stream = match SslStream::connect_generic(&ctx, stream) { let stream = match SslStream::connect(&ctx, stream) {
Ok(stream) => stream, Ok(stream) => stream,
Err(err) => panic!("Expected success, got {:?}", err), Err(err) => panic!("Expected success, got {:?}", err),
}; };
@ -713,7 +684,7 @@ fn test_npn_server_advertise_multiple() {
// We create a different context instance for the server... // We create a different context instance for the server...
let listener_ctx = { let listener_ctx = {
let mut ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, None); ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_npn_protocols(&[b"http/1.1", b"spdy/3.1"]); ctx.set_npn_protocols(&[b"http/1.1", b"spdy/3.1"]);
assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM) assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM)
.is_ok()); .is_ok());
@ -728,7 +699,7 @@ fn test_npn_server_advertise_multiple() {
}); });
let mut ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, None); ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_npn_protocols(&[b"spdy/3.1"]); ctx.set_npn_protocols(&[b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) { match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {} Ok(_) => {}
@ -736,7 +707,7 @@ fn test_npn_server_advertise_multiple() {
} }
// Now connect to the socket and make sure the protocol negotiation works... // Now connect to the socket and make sure the protocol negotiation works...
let stream = TcpStream::connect(localhost).unwrap(); let stream = TcpStream::connect(localhost).unwrap();
let stream = match SslStream::connect_generic(&ctx, stream) { let stream = match SslStream::connect(&ctx, stream) {
Ok(stream) => stream, Ok(stream) => stream,
Err(err) => panic!("Expected success, got {:?}", err), Err(err) => panic!("Expected success, got {:?}", err),
}; };
@ -754,7 +725,7 @@ fn test_alpn_server_advertise_multiple() {
// We create a different context instance for the server... // We create a different context instance for the server...
let listener_ctx = { let listener_ctx = {
let mut ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, None); ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]); ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]);
assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM) assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM)
.is_ok()); .is_ok());
@ -769,7 +740,7 @@ fn test_alpn_server_advertise_multiple() {
}); });
let mut ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, None); ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"spdy/3.1"]); ctx.set_alpn_protocols(&[b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) { match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {} Ok(_) => {}
@ -795,7 +766,7 @@ fn test_alpn_server_select_none() {
// We create a different context instance for the server... // We create a different context instance for the server...
let listener_ctx = { let listener_ctx = {
let mut ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, None); ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]); ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]);
assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM) assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM)
.is_ok()); .is_ok());
@ -810,7 +781,7 @@ fn test_alpn_server_select_none() {
}); });
let mut ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, None); ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"http/2"]); ctx.set_alpn_protocols(&[b"http/2"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) { match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {} Ok(_) => {}
@ -838,7 +809,7 @@ mod dtlsv1 {
use crypto::hash::Type::SHA256; use crypto::hash::Type::SHA256;
use ssl::SslMethod; use ssl::SslMethod;
use ssl::SslMethod::Dtlsv1; use ssl::SslMethod::Dtlsv1;
use ssl::{SslContext, SslStream, VerifyCallback}; use ssl::{SslContext, SslStream};
use ssl::SSL_VERIFY_PEER; use ssl::SSL_VERIFY_PEER;
use x509::X509StoreContext; use x509::X509StoreContext;
@ -855,7 +826,7 @@ mod dtlsv1 {
fn test_read_dtlsv1() { fn test_read_dtlsv1() {
let (_s, stream) = Server::new_dtlsv1(Some("hello")); let (_s, stream) = Server::new_dtlsv1(Some("hello"));
let mut stream = SslStream::connect_generic(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap(); let mut stream = SslStream::connect(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap();
let mut buf = [0u8; 100]; let mut buf = [0u8; 100];
assert!(stream.read(&mut buf).is_ok()); assert!(stream.read(&mut buf).is_ok());
} }
@ -864,15 +835,15 @@ fn test_read_dtlsv1() {
#[cfg(feature = "sslv2")] #[cfg(feature = "sslv2")]
fn test_sslv2_connect_failure() { fn test_sslv2_connect_failure() {
let (_s, tcp) = Server::new_tcp(&["-no_ssl2", "-www"]); let (_s, tcp) = Server::new_tcp(&["-no_ssl2", "-www"]);
SslStream::connect_generic(&SslContext::new(Sslv2).unwrap(), tcp) SslStream::connect(&SslContext::new(Sslv2).unwrap(), tcp)
.err() .err()
.unwrap(); .unwrap();
} }
fn wait_io(stream: &NonblockingSslStream<TcpStream>, read: bool, timeout_ms: u32) -> bool { fn wait_io(stream: &TcpStream, read: bool, timeout_ms: u32) -> bool {
unsafe { unsafe {
let mut set: select::fd_set = mem::zeroed(); let mut set: select::fd_set = mem::zeroed();
select::fd_set(&mut set, stream.get_ref()); select::fd_set(&mut set, stream);
let write = if read { let write = if read {
0 as *mut _ 0 as *mut _
@ -884,7 +855,19 @@ fn wait_io(stream: &NonblockingSslStream<TcpStream>, read: bool, timeout_ms: u32
} else { } else {
&mut set as *mut _ &mut set as *mut _
}; };
select::select(stream.get_ref(), read, write, 0 as *mut _, timeout_ms).unwrap() select::select(stream, read, write, 0 as *mut _, timeout_ms).unwrap()
}
}
fn handshake(res: Result<SslStream<TcpStream>, HandshakeError<TcpStream>>)
-> SslStream<TcpStream> {
match res {
Ok(s) => s,
Err(HandshakeError::Interrupted(s)) => {
wait_io(s.get_ref(), true, 1_000);
handshake(s.handshake())
}
Err(err) => panic!("error on handshake {:?}", err),
} }
} }
@ -893,7 +876,7 @@ fn test_write_nonblocking() {
let (_s, stream) = Server::new(); let (_s, stream) = Server::new();
stream.set_nonblocking(true).unwrap(); stream.set_nonblocking(true).unwrap();
let cx = SslContext::new(Sslv23).unwrap(); let cx = SslContext::new(Sslv23).unwrap();
let mut stream = NonblockingSslStream::connect(&cx, stream).unwrap(); let mut stream = handshake(SslStream::connect(&cx, stream));
let mut iterations = 0; let mut iterations = 0;
loop { loop {
@ -903,16 +886,16 @@ fn test_write_nonblocking() {
// openssl. // openssl.
panic!("Too many read/write round trips in handshake!!"); panic!("Too many read/write round trips in handshake!!");
} }
let result = stream.write(b"hello"); let result = stream.ssl_write(b"hello");
match result { match result {
Ok(_) => { Ok(_) => {
break; break;
} }
Err(NonblockingSslError::WantRead) => { Err(Error::WantRead(_)) => {
assert!(wait_io(&stream, true, 1000)); assert!(wait_io(stream.get_ref(), true, 1000));
} }
Err(NonblockingSslError::WantWrite) => { Err(Error::WantWrite(_)) => {
assert!(wait_io(&stream, false, 1000)); assert!(wait_io(stream.get_ref(), false, 1000));
} }
Err(other) => { Err(other) => {
panic!("Unexpected SSL Error: {:?}", other); panic!("Unexpected SSL Error: {:?}", other);
@ -930,7 +913,7 @@ fn test_read_nonblocking() {
let (_s, stream) = Server::new(); let (_s, stream) = Server::new();
stream.set_nonblocking(true).unwrap(); stream.set_nonblocking(true).unwrap();
let cx = SslContext::new(Sslv23).unwrap(); let cx = SslContext::new(Sslv23).unwrap();
let mut stream = NonblockingSslStream::connect(&cx, stream).unwrap(); let mut stream = handshake(SslStream::connect(&cx, stream));
let mut iterations = 0; let mut iterations = 0;
loop { loop {
@ -940,17 +923,17 @@ fn test_read_nonblocking() {
// openssl. // openssl.
panic!("Too many read/write round trips in handshake!!"); panic!("Too many read/write round trips in handshake!!");
} }
let result = stream.write(b"GET /\r\n\r\n"); let result = stream.ssl_write(b"GET /\r\n\r\n");
match result { match result {
Ok(n) => { Ok(n) => {
assert_eq!(n, 9); assert_eq!(n, 9);
break; break;
} }
Err(NonblockingSslError::WantRead) => { Err(Error::WantRead(..)) => {
assert!(wait_io(&stream, true, 1000)); assert!(wait_io(stream.get_ref(), true, 1000));
} }
Err(NonblockingSslError::WantWrite) => { Err(Error::WantWrite(..)) => {
assert!(wait_io(&stream, false, 1000)); assert!(wait_io(stream.get_ref(), false, 1000));
} }
Err(other) => { Err(other) => {
panic!("Unexpected SSL Error: {:?}", other); panic!("Unexpected SSL Error: {:?}", other);
@ -958,7 +941,7 @@ fn test_read_nonblocking() {
} }
} }
let mut input_buffer = [0u8; 1500]; let mut input_buffer = [0u8; 1500];
let result = stream.read(&mut input_buffer); let result = stream.ssl_read(&mut input_buffer);
let bytes_read = match result { let bytes_read = match result {
Ok(n) => { Ok(n) => {
// This branch is unlikely, but on an overloaded VM with // This branch is unlikely, but on an overloaded VM with
@ -966,8 +949,8 @@ fn test_read_nonblocking() {
// be in the receive buffer before we issue the read() syscall... // be in the receive buffer before we issue the read() syscall...
n n
} }
Err(NonblockingSslError::WantRead) => { Err(Error::WantRead(..)) => {
assert!(wait_io(&stream, true, 3000)); assert!(wait_io(stream.get_ref(), true, 3000));
// Second read should return application data. // Second read should return application data.
stream.read(&mut input_buffer).unwrap() stream.read(&mut input_buffer).unwrap()
} }
@ -979,14 +962,6 @@ fn test_read_nonblocking() {
assert_eq!(&input_buffer[..5], b"HTTP/"); assert_eq!(&input_buffer[..5], b"HTTP/");
} }
#[test]
fn broken_try_clone_doesnt_crash() {
let context = SslContext::new(SslMethod::Sslv23).unwrap();
let inner = TcpStream::connect("example.com:443").unwrap();
let stream1 = SslStream::connect(&context, inner).unwrap();
let _stream2 = stream1.try_clone().unwrap();
}
#[test] #[test]
#[should_panic(expected = "blammo")] #[should_panic(expected = "blammo")]
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
@ -1077,7 +1052,7 @@ fn flush_panic() {
#[test] #[test]
fn refcount_ssl_context() { fn refcount_ssl_context() {
let ssl = { let mut ssl = {
let ctx = SslContext::new(SslMethod::Sslv23).unwrap(); let ctx = SslContext::new(SslMethod::Sslv23).unwrap();
ssl::Ssl::new(&ctx).unwrap() ssl::Ssl::new(&ctx).unwrap()
}; };
@ -1093,7 +1068,7 @@ fn refcount_ssl_context() {
fn default_verify_paths() { fn default_verify_paths() {
let mut ctx = SslContext::new(SslMethod::Sslv23).unwrap(); let mut ctx = SslContext::new(SslMethod::Sslv23).unwrap();
ctx.set_default_verify_paths().unwrap(); ctx.set_default_verify_paths().unwrap();
ctx.set_verify(SSL_VERIFY_PEER, None); ctx.set_verify(SSL_VERIFY_PEER);
let s = TcpStream::connect("google.com:443").unwrap(); let s = TcpStream::connect("google.com:443").unwrap();
let mut socket = SslStream::connect(&ctx, s).unwrap(); let mut socket = SslStream::connect(&ctx, s).unwrap();

View File

@ -1,9 +1,5 @@
use libc::{c_char, c_int, c_long, c_ulong, c_uint, c_void}; use libc::{c_char, c_int, c_long, c_ulong, c_void};
use std::io;
use std::io::prelude::*;
use std::cmp::Ordering;
use std::ffi::CString; use std::ffi::CString;
use std::iter::repeat;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
use std::ops::Deref; use std::ops::Deref;
@ -13,16 +9,16 @@ use std::slice;
use std::collections::HashMap; use std::collections::HashMap;
use std::marker::PhantomData; use std::marker::PhantomData;
use HashTypeInternals;
use asn1::Asn1Time; use asn1::Asn1Time;
use bio::MemBio; use bio::{MemBio, MemBioSlice};
use crypto::hash; use crypto::hash;
use crypto::hash::Type as HashType; use crypto::hash::Type as HashType;
use crypto::pkey::{PKey, Parts}; use crypto::pkey::PKey;
use crypto::rand::rand_bytes; use crypto::rand::rand_bytes;
use ffi; use ffi;
use ffi_extras;
use ssl::error::{SslError, StreamError};
use nid::Nid; use nid::Nid;
use error::ErrorStack;
pub mod extension; pub mod extension;
@ -86,22 +82,20 @@ impl X509StoreContext {
X509StoreContext { ctx: ctx } X509StoreContext { ctx: ctx }
} }
pub fn get_error(&self) -> Option<X509ValidationError> { pub fn error(&self) -> Option<X509ValidationError> {
let err = unsafe { ffi::X509_STORE_CTX_get_error(self.ctx) }; let err = unsafe { ffi::X509_STORE_CTX_get_error(self.ctx) };
X509ValidationError::from_raw(err) X509ValidationError::from_raw(err)
} }
pub fn get_current_cert<'a>(&'a self) -> Option<X509<'a>> { pub fn current_cert<'a>(&'a self) -> Option<X509Ref<'a>> {
let ptr = unsafe { ffi::X509_STORE_CTX_get_current_cert(self.ctx) }; unsafe {
let ptr = ffi::X509_STORE_CTX_get_current_cert(self.ctx);
if ptr.is_null() { if ptr.is_null() {
None None
} else { } else {
Some(X509 { Some(X509Ref::new(ptr))
ctx: Some(self), }
handle: ptr,
owned: false,
})
} }
} }
@ -116,39 +110,26 @@ impl X509StoreContext {
/// # Example /// # Example
/// ///
/// ``` /// ```
/// # #[allow(unstable)]
/// # fn main() {
/// use std::fs;
/// use std::fs::File;
/// use std::io::prelude::*;
/// use std::path::Path;
///
/// use openssl::crypto::hash::Type; /// use openssl::crypto::hash::Type;
/// use openssl::crypto::pkey::PKey;
/// use openssl::crypto::rsa::RSA;
/// use openssl::x509::X509Generator; /// use openssl::x509::X509Generator;
/// use openssl::x509::extension::{Extension, KeyUsageOption}; /// use openssl::x509::extension::{Extension, KeyUsageOption};
/// ///
/// let rsa = RSA::generate(2048).unwrap();
/// let pkey = PKey::from_rsa(rsa).unwrap();
///
/// let gen = X509Generator::new() /// let gen = X509Generator::new()
/// .set_bitlength(2048)
/// .set_valid_period(365*2) /// .set_valid_period(365*2)
/// .add_name("CN".to_owned(), "SuperMegaCorp Inc.".to_owned()) /// .add_name("CN".to_owned(), "SuperMegaCorp Inc.".to_owned())
/// .set_sign_hash(Type::SHA256) /// .set_sign_hash(Type::SHA256)
/// .add_extension(Extension::KeyUsage(vec![KeyUsageOption::DigitalSignature])); /// .add_extension(Extension::KeyUsage(vec![KeyUsageOption::DigitalSignature]));
/// ///
/// let (cert, pkey) = gen.generate().unwrap(); /// let cert = gen.sign(&pkey).unwrap();
/// /// let cert_pem = cert.to_pem().unwrap();
/// let cert_path = "doc_cert.pem"; /// let pkey_pem = pkey.private_key_to_pem().unwrap();
/// let mut file = File::create(cert_path).unwrap();
/// assert!(cert.write_pem(&mut file).is_ok());
/// # let _ = fs::remove_file(cert_path);
///
/// let pkey_path = "doc_key.pem";
/// let mut file = File::create(pkey_path).unwrap();
/// assert!(pkey.write_pem(&mut file).is_ok());
/// # let _ = fs::remove_file(pkey_path);
/// # }
/// ``` /// ```
pub struct X509Generator { pub struct X509Generator {
bits: u32,
days: u32, days: u32,
names: Vec<(String, String)>, names: Vec<(String, String)>,
extensions: Extensions, extensions: Extensions,
@ -158,8 +139,6 @@ pub struct X509Generator {
impl X509Generator { impl X509Generator {
/// Creates a new generator with the following defaults: /// Creates a new generator with the following defaults:
/// ///
/// bit length: 1024
///
/// validity period: 365 days /// validity period: 365 days
/// ///
/// CN: "rust-openssl" /// CN: "rust-openssl"
@ -167,7 +146,6 @@ impl X509Generator {
/// hash: SHA1 /// hash: SHA1
pub fn new() -> X509Generator { pub fn new() -> X509Generator {
X509Generator { X509Generator {
bits: 1024,
days: 365, days: 365,
names: vec![], names: vec![],
extensions: Extensions::new(), extensions: Extensions::new(),
@ -175,12 +153,6 @@ impl X509Generator {
} }
} }
/// Sets desired bit length
pub fn set_bitlength(mut self, bits: u32) -> X509Generator {
self.bits = bits;
self
}
/// Sets certificate validity period in days since today /// Sets certificate validity period in days since today
pub fn set_valid_period(mut self, days: u32) -> X509Generator { pub fn set_valid_period(mut self, days: u32) -> X509Generator {
self.days = days; self.days = days;
@ -256,7 +228,7 @@ impl X509Generator {
fn add_extension_internal(x509: *mut ffi::X509, fn add_extension_internal(x509: *mut ffi::X509,
exttype: &extension::ExtensionType, exttype: &extension::ExtensionType,
value: &str) value: &str)
-> Result<(), SslError> { -> Result<(), ErrorStack> {
unsafe { unsafe {
let mut ctx: ffi::X509V3_CTX = mem::zeroed(); let mut ctx: ffi::X509V3_CTX = mem::zeroed();
ffi::X509V3_set_ctx(&mut ctx, x509, x509, ptr::null_mut(), ptr::null_mut(), 0); ffi::X509V3_set_ctx(&mut ctx, x509, x509, ptr::null_mut(), ptr::null_mut(), 0);
@ -288,7 +260,7 @@ impl X509Generator {
fn add_name_internal(name: *mut ffi::X509_NAME, fn add_name_internal(name: *mut ffi::X509_NAME,
key: &str, key: &str,
value: &str) value: &str)
-> Result<(), SslError> { -> Result<(), ErrorStack> {
let value_len = value.len() as c_int; let value_len = value.len() as c_int;
lift_ssl!(unsafe { lift_ssl!(unsafe {
let key = CString::new(key.as_bytes()).unwrap(); let key = CString::new(key.as_bytes()).unwrap();
@ -303,9 +275,10 @@ impl X509Generator {
}) })
} }
fn random_serial() -> c_long { fn random_serial() -> Result<c_long, ErrorStack> {
let len = mem::size_of::<c_long>(); let len = mem::size_of::<c_long>();
let bytes = rand_bytes(len); let mut bytes = vec![0; len];
try!(rand_bytes(&mut bytes));
let mut res = 0; let mut res = 0;
for b in bytes.iter() { for b in bytes.iter() {
res = res << 8; res = res << 8;
@ -315,54 +288,36 @@ impl X509Generator {
// While OpenSSL is actually OK to have negative serials // While OpenSSL is actually OK to have negative serials
// other libraries (for example, Go crypto) can drop // other libraries (for example, Go crypto) can drop
// such certificates as invalid, so we clear the high bit // such certificates as invalid, so we clear the high bit
((res as c_ulong) >> 1) as c_long Ok(((res as c_ulong) >> 1) as c_long)
}
/// Generates a private key and a self-signed certificate and returns them
pub fn generate<'a>(&self) -> Result<(X509<'a>, PKey), SslError> {
ffi::init();
let mut p_key = PKey::new();
p_key.gen(self.bits as usize);
let x509 = try!(self.sign(&p_key));
Ok((x509, p_key))
} }
/// Sets the certificate public-key, then self-sign and return it /// Sets the certificate public-key, then self-sign and return it
/// Note: That the bit-length of the private key is used (set_bitlength is ignored) /// Note: That the bit-length of the private key is used (set_bitlength is ignored)
pub fn sign<'a>(&self, p_key: &PKey) -> Result<X509<'a>, SslError> { pub fn sign(&self, p_key: &PKey) -> Result<X509, ErrorStack> {
ffi::init(); ffi::init();
unsafe { unsafe {
let x509 = ffi::X509_new(); let x509 = try_ssl_null!(ffi::X509_new());
try_ssl_null!(x509); let x509 = X509::new(x509);
let x509 = X509 { try_ssl!(ffi::X509_set_version(x509.as_ptr(), 2));
handle: x509, try_ssl!(ffi::ASN1_INTEGER_set(ffi::X509_get_serialNumber(x509.as_ptr()),
ctx: None, try!(X509Generator::random_serial())));
owned: true,
};
try_ssl!(ffi::X509_set_version(x509.handle, 2));
try_ssl!(ffi::ASN1_INTEGER_set(ffi::X509_get_serialNumber(x509.handle),
X509Generator::random_serial()));
let not_before = try!(Asn1Time::days_from_now(0)); let not_before = try!(Asn1Time::days_from_now(0));
let not_after = try!(Asn1Time::days_from_now(self.days)); let not_after = try!(Asn1Time::days_from_now(self.days));
try_ssl!(ffi::X509_set_notBefore(x509.handle, mem::transmute(not_before.get_handle()))); try_ssl!(ffi::X509_set_notBefore(x509.as_ptr(), not_before.as_ptr() as *const _));
// If prev line succeded - ownership should go to cert // If prev line succeded - ownership should go to cert
mem::forget(not_before); mem::forget(not_before);
try_ssl!(ffi::X509_set_notAfter(x509.handle, mem::transmute(not_after.get_handle()))); try_ssl!(ffi::X509_set_notAfter(x509.as_ptr(), not_after.as_ptr() as *const _));
// If prev line succeded - ownership should go to cert // If prev line succeded - ownership should go to cert
mem::forget(not_after); mem::forget(not_after);
try_ssl!(ffi::X509_set_pubkey(x509.handle, p_key.get_handle())); try_ssl!(ffi::X509_set_pubkey(x509.as_ptr(), p_key.as_ptr()));
let name = ffi::X509_get_subject_name(x509.handle); let name = try_ssl_null!(ffi::X509_get_subject_name(x509.as_ptr()));
try_ssl_null!(name);
let default = [("CN", "rust-openssl")]; let default = [("CN", "rust-openssl")];
let default_iter = &mut default.iter().map(|&(k, v)| (k, v)); let default_iter = &mut default.iter().map(|&(k, v)| (k, v));
@ -376,105 +331,69 @@ impl X509Generator {
for (key, val) in iter { for (key, val) in iter {
try!(X509Generator::add_name_internal(name, &key, &val)); try!(X509Generator::add_name_internal(name, &key, &val));
} }
ffi::X509_set_issuer_name(x509.handle, name); try_ssl!(ffi::X509_set_issuer_name(x509.as_ptr(), name));
for (exttype, ext) in self.extensions.iter() { for (exttype, ext) in self.extensions.iter() {
try!(X509Generator::add_extension_internal(x509.handle, try!(X509Generator::add_extension_internal(x509.as_ptr(),
&exttype, &exttype,
&ext.to_string())); &ext.to_string()));
} }
let hash_fn = self.hash_type.evp_md(); let hash_fn = self.hash_type.evp_md();
try_ssl!(ffi::X509_sign(x509.handle, p_key.get_handle(), hash_fn)); try_ssl!(ffi::X509_sign(x509.as_ptr(), p_key.as_ptr(), hash_fn));
Ok(x509) Ok(x509)
} }
} }
/// Obtain a certificate signing request (CSR) /// Obtain a certificate signing request (CSR)
pub fn request(&self, p_key: &PKey) -> Result<X509Req, SslError> { ///
/// Requries the `x509_generator_request` feature.
#[cfg(feature = "x509_generator_request")]
pub fn request(&self, p_key: &PKey) -> Result<X509Req, ErrorStack> {
let cert = match self.sign(p_key) { let cert = match self.sign(p_key) {
Ok(c) => c, Ok(c) => c,
Err(x) => return Err(x), Err(x) => return Err(x),
}; };
unsafe { unsafe {
let req = ffi::X509_to_X509_REQ(cert.handle, ptr::null_mut(), ptr::null()); let req = ffi::X509_to_X509_REQ(cert.as_ptr(), ptr::null_mut(), ptr::null());
try_ssl_null!(req); try_ssl_null!(req);
let exts = ffi_extras::X509_get_extensions(cert.handle); let exts = ::c_helpers::rust_X509_get_extensions(cert.as_ptr());
if exts != ptr::null_mut() { if exts != ptr::null_mut() {
try_ssl!(ffi::X509_REQ_add_extensions(req, exts)); try_ssl!(ffi::X509_REQ_add_extensions(req, exts));
} }
let hash_fn = self.hash_type.evp_md(); let hash_fn = self.hash_type.evp_md();
try_ssl!(ffi::X509_REQ_sign(req, p_key.get_handle(), hash_fn)); try_ssl!(ffi::X509_REQ_sign(req, p_key.as_ptr(), hash_fn));
Ok(X509Req::new(req)) Ok(X509Req::new(req))
} }
} }
} }
/// A borrowed public key certificate.
pub struct X509Ref<'a>(*mut ffi::X509, PhantomData<&'a ()>);
#[allow(dead_code)] impl<'a> X509Ref<'a> {
/// A public key certificate /// Creates a new `X509Ref` wrapping the provided handle.
pub struct X509<'ctx> { pub unsafe fn new(handle: *mut ffi::X509) -> X509Ref<'a> {
ctx: Option<&'ctx X509StoreContext>, X509Ref(handle, PhantomData)
handle: *mut ffi::X509,
owned: bool,
} }
impl<'ctx> X509<'ctx> { pub fn as_ptr(&self) -> *mut ffi::X509 {
/// Creates new from handle with desired ownership. self.0
pub fn new(handle: *mut ffi::X509, owned: bool) -> X509<'ctx> {
X509 {
ctx: None,
handle: handle,
owned: owned,
}
} }
/// Creates a new certificate from context. Doesn't take ownership pub fn subject_name<'b>(&'b self) -> X509Name<'b> {
/// of handle. let name = unsafe { ffi::X509_get_subject_name(self.0) };
pub fn new_in_ctx(handle: *mut ffi::X509, ctx: &'ctx X509StoreContext) -> X509<'ctx> { X509Name(name, PhantomData)
X509 {
ctx: Some(ctx),
handle: handle,
owned: false,
}
}
/// Reads certificate from PEM, takes ownership of handle
pub fn from_pem<R>(reader: &mut R) -> Result<X509<'ctx>, SslError>
where R: Read
{
let mut mem_bio = try!(MemBio::new());
try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
unsafe {
let handle = try_ssl_null!(ffi::PEM_read_bio_X509(mem_bio.get_handle(),
ptr::null_mut(),
None,
ptr::null_mut()));
Ok(X509::new(handle, true))
}
}
pub fn get_handle(&self) -> *mut ffi::X509 {
self.handle
}
pub fn subject_name<'a>(&'a self) -> X509Name<'a> {
let name = unsafe { ffi::X509_get_subject_name(self.handle) };
X509Name {
x509: self,
name: name,
}
} }
/// Returns this certificate's SAN entries, if they exist. /// Returns this certificate's SAN entries, if they exist.
pub fn subject_alt_names<'a>(&'a self) -> Option<GeneralNames<'a>> { pub fn subject_alt_names<'b>(&'b self) -> Option<GeneralNames<'b>> {
unsafe { unsafe {
let stack = ffi::X509_get_ext_d2i(self.handle, let stack = ffi::X509_get_ext_d2i(self.0,
Nid::SubjectAltName as c_int, Nid::SubjectAltName as c_int,
ptr::null_mut(), ptr::null_mut(),
ptr::null_mut()); ptr::null_mut());
@ -489,94 +408,102 @@ impl<'ctx> X509<'ctx> {
} }
} }
pub fn public_key(&self) -> PKey { pub fn public_key(&self) -> Result<PKey, ErrorStack> {
let pkey = unsafe { ffi::X509_get_pubkey(self.handle) }; unsafe {
assert!(!pkey.is_null()); let pkey = try_ssl_null!(ffi::X509_get_pubkey(self.0));
Ok(PKey::from_ptr(pkey))
PKey::from_handle(pkey, Parts::Public) }
} }
/// Returns certificate fingerprint calculated using provided hash /// Returns certificate fingerprint calculated using provided hash
pub fn fingerprint(&self, hash_type: hash::Type) -> Option<Vec<u8>> { pub fn fingerprint(&self, hash_type: hash::Type) -> Result<Vec<u8>, ErrorStack> {
unsafe {
let evp = hash_type.evp_md(); let evp = hash_type.evp_md();
let len = hash_type.md_len(); let mut len = ffi::EVP_MAX_MD_SIZE;
let v: Vec<u8> = repeat(0).take(len as usize).collect(); let mut buf = vec![0u8; len as usize];
let act_len: c_uint = 0; try_ssl!(ffi::X509_digest(self.0, evp, buf.as_mut_ptr() as *mut _, &mut len));
let res = unsafe { buf.truncate(len as usize);
ffi::X509_digest(self.handle, Ok(buf)
evp,
mem::transmute(v.as_ptr()),
mem::transmute(&act_len))
};
match res {
0 => None,
_ => {
let act_len = act_len as usize;
match len.cmp(&act_len) {
Ordering::Greater => None,
Ordering::Equal => Some(v),
Ordering::Less => panic!("Fingerprint buffer was corrupted!"),
}
}
} }
} }
/// Writes certificate as PEM /// Writes certificate as PEM
pub fn write_pem<W>(&self, writer: &mut W) -> Result<(), SslError> pub fn to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
where W: Write let mem_bio = try!(MemBio::new());
{
let mut mem_bio = try!(MemBio::new());
unsafe { unsafe {
try_ssl!(ffi::PEM_write_bio_X509(mem_bio.get_handle(), self.handle)); try_ssl!(ffi::PEM_write_bio_X509(mem_bio.as_ptr(), self.0));
} }
io::copy(&mut mem_bio, writer).map_err(StreamError).map(|_| ()) 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());
unsafe {
ffi::i2d_X509_bio(mem_bio.as_ptr(), self.0);
}
Ok(mem_bio.get_buf().to_owned())
} }
} }
extern "C" { /// An owned public key certificate.
fn rust_X509_clone(x509: *mut ffi::X509); pub struct X509(X509Ref<'static>);
impl X509 {
/// Returns a new `X509`, taking ownership of the handle.
pub unsafe fn new(x509: *mut ffi::X509) -> X509 {
X509(X509Ref::new(x509))
} }
impl<'ctx> Clone for X509<'ctx> { /// Reads a certificate from PEM.
fn clone(&self) -> X509<'ctx> { pub fn from_pem(buf: &[u8]) -> Result<X509, ErrorStack> {
unsafe { rust_X509_clone(self.handle) } let mem_bio = try!(MemBioSlice::new(buf));
// FIXME: given that we now have refcounting control, 'owned' should be uneeded, the 'ctx unsafe {
// is probably also uneeded. We can remove both to condense the x509 api quite a bit let handle = try_ssl_null!(ffi::PEM_read_bio_X509(mem_bio.as_ptr(),
// ptr::null_mut(),
X509::new(self.handle, true) None,
ptr::null_mut()));
Ok(X509::new(handle))
}
} }
} }
impl<'ctx> Drop for X509<'ctx> { impl Deref for X509 {
type Target = X509Ref<'static>;
fn deref(&self) -> &X509Ref<'static> {
&self.0
}
}
#[cfg(feature = "x509_clone")]
impl Clone for X509 {
/// Requires the `x509_clone` feature.
fn clone(&self) -> X509 {
unsafe {
::c_helpers::rust_X509_clone(self.as_ptr());
X509::new(self.as_ptr())
}
}
}
impl Drop for X509 {
fn drop(&mut self) { fn drop(&mut self) {
if self.owned { unsafe { ffi::X509_free(self.as_ptr()) };
unsafe { ffi::X509_free(self.handle) };
}
} }
} }
#[allow(dead_code)] pub struct X509Name<'x>(*mut ffi::X509_NAME, PhantomData<&'x ()>);
pub struct X509Name<'x> {
x509: &'x X509<'x>,
name: *mut ffi::X509_NAME,
}
#[allow(dead_code)]
pub struct X509NameEntry<'x> {
x509_name: &'x X509Name<'x>,
ne: *mut ffi::X509_NAME_ENTRY,
}
impl<'x> X509Name<'x> { impl<'x> X509Name<'x> {
pub fn text_by_nid(&self, nid: Nid) -> Option<SslString> { pub fn text_by_nid(&self, nid: Nid) -> Option<SslString> {
unsafe { unsafe {
let loc = ffi::X509_NAME_get_index_by_NID(self.name, nid as c_int, -1); let loc = ffi::X509_NAME_get_index_by_NID(self.0, nid as c_int, -1);
if loc == -1 { if loc == -1 {
return None; return None;
} }
let ne = ffi::X509_NAME_get_entry(self.name, loc); let ne = ffi::X509_NAME_get_entry(self.0, loc);
if ne.is_null() { if ne.is_null() {
return None; return None;
} }
@ -601,25 +528,23 @@ impl<'x> X509Name<'x> {
} }
/// A certificate signing request /// A certificate signing request
pub struct X509Req { pub struct X509Req(*mut ffi::X509_REQ);
handle: *mut ffi::X509_REQ,
}
impl X509Req { impl X509Req {
/// Creates new from handle /// Creates new from handle
pub fn new(handle: *mut ffi::X509_REQ) -> X509Req { pub unsafe fn new(handle: *mut ffi::X509_REQ) -> X509Req {
X509Req { handle: handle } X509Req(handle)
}
pub fn as_ptr(&self) -> *mut ffi::X509_REQ {
self.0
} }
/// Reads CSR from PEM /// Reads CSR from PEM
pub fn from_pem<R>(reader: &mut R) -> Result<X509Req, SslError> pub fn from_pem(buf: &[u8]) -> Result<X509Req, ErrorStack> {
where R: Read let mem_bio = try!(MemBioSlice::new(buf));
{
let mut mem_bio = try!(MemBio::new());
try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
unsafe { unsafe {
let handle = try_ssl_null!(ffi::PEM_read_bio_X509_REQ(mem_bio.get_handle(), let handle = try_ssl_null!(ffi::PEM_read_bio_X509_REQ(mem_bio.as_ptr(),
ptr::null_mut(), ptr::null_mut(),
None, None,
ptr::null_mut())); ptr::null_mut()));
@ -628,20 +553,27 @@ impl X509Req {
} }
/// Writes CSR as PEM /// Writes CSR as PEM
pub fn write_pem<W>(&self, writer: &mut W) -> Result<(), SslError> pub fn to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
where W: Write let mem_bio = try!(MemBio::new());
{ if unsafe { ffi::PEM_write_bio_X509_REQ(mem_bio.as_ptr(), self.0) } != 1 {
let mut mem_bio = try!(MemBio::new()); return Err(ErrorStack::get());
unsafe {
try_ssl!(ffi::PEM_write_bio_X509_REQ(mem_bio.get_handle(), self.handle));
} }
io::copy(&mut mem_bio, writer).map_err(StreamError).map(|_| ()) 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());
unsafe {
ffi::i2d_X509_REQ_bio(mem_bio.as_ptr(), self.0);
}
Ok(mem_bio.get_buf().to_owned())
} }
} }
impl Drop for X509Req { impl Drop for X509Req {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { ffi::X509_REQ_free(self.handle) }; unsafe { ffi::X509_REQ_free(self.0) };
} }
} }
@ -908,7 +840,7 @@ impl<'a> GeneralName<'a> {
fn test_negative_serial() { fn test_negative_serial() {
// I guess that's enough to get a random negative number // I guess that's enough to get a random negative number
for _ in 0..1000 { for _ in 0..1000 {
assert!(X509Generator::random_serial() > 0, assert!(X509Generator::random_serial().unwrap() > 0,
"All serials should be positive"); "All serials should be positive");
} }
} }

View File

@ -1,10 +1,8 @@
use serialize::hex::FromHex; use serialize::hex::FromHex;
use std::io;
use std::path::Path;
use std::fs::File;
use crypto::hash::Type::SHA1; use crypto::hash::Type::SHA1;
use crypto::pkey::PKey; use crypto::pkey::PKey;
use crypto::rsa::RSA;
use x509::{X509, X509Generator}; use x509::{X509, X509Generator};
use x509::extension::Extension::{KeyUsage, ExtKeyUsage, SubjectAltName, OtherNid, OtherStr}; use x509::extension::Extension::{KeyUsage, ExtKeyUsage, SubjectAltName, OtherNid, OtherStr};
use x509::extension::AltNameOption as SAN; use x509::extension::AltNameOption as SAN;
@ -14,7 +12,6 @@ use nid::Nid;
fn get_generator() -> X509Generator { fn get_generator() -> X509Generator {
X509Generator::new() X509Generator::new()
.set_bitlength(2048)
.set_valid_period(365 * 2) .set_valid_period(365 * 2)
.add_name("CN".to_string(), "test_me".to_string()) .add_name("CN".to_string(), "test_me".to_string())
.set_sign_hash(SHA1) .set_sign_hash(SHA1)
@ -27,16 +24,21 @@ fn get_generator() -> X509Generator {
.add_extension(OtherStr("2.999.2".to_owned(), "ASN1:UTF8:example value".to_owned())) .add_extension(OtherStr("2.999.2".to_owned(), "ASN1:UTF8:example value".to_owned()))
} }
fn pkey() -> PKey {
let rsa = RSA::generate(2048).unwrap();
PKey::from_rsa(rsa).unwrap()
}
#[test] #[test]
fn test_cert_gen() { fn test_cert_gen() {
let (cert, pkey) = get_generator().generate().unwrap(); let pkey = pkey();
cert.write_pem(&mut io::sink()).unwrap(); let cert = get_generator().sign(&pkey).unwrap();
pkey.write_pem(&mut io::sink()).unwrap();
// FIXME: check data in result to be correct, needs implementation // FIXME: check data in result to be correct, needs implementation
// of X509 getters // of X509 getters
assert_eq!(pkey.save_pub(), cert.public_key().save_pub()); assert_eq!(pkey.public_key_to_pem().unwrap(),
cert.public_key().unwrap().public_key_to_pem().unwrap());
} }
/// SubjectKeyIdentifier must be added before AuthorityKeyIdentifier or OpenSSL /// SubjectKeyIdentifier must be added before AuthorityKeyIdentifier or OpenSSL
@ -44,10 +46,11 @@ fn test_cert_gen() {
/// for extensions is preserved when the cert is signed. /// for extensions is preserved when the cert is signed.
#[test] #[test]
fn test_cert_gen_extension_ordering() { fn test_cert_gen_extension_ordering() {
let pkey = pkey();
get_generator() get_generator()
.add_extension(OtherNid(Nid::SubjectKeyIdentifier, "hash".to_owned())) .add_extension(OtherNid(Nid::SubjectKeyIdentifier, "hash".to_owned()))
.add_extension(OtherNid(Nid::AuthorityKeyIdentifier, "keyid:always".to_owned())) .add_extension(OtherNid(Nid::AuthorityKeyIdentifier, "keyid:always".to_owned()))
.generate() .sign(&pkey)
.expect("Failed to generate cert with order-dependent extensions"); .expect("Failed to generate cert with order-dependent extensions");
} }
@ -55,22 +58,23 @@ fn test_cert_gen_extension_ordering() {
/// deterministic by reversing the order of extensions and asserting failure. /// deterministic by reversing the order of extensions and asserting failure.
#[test] #[test]
fn test_cert_gen_extension_bad_ordering() { fn test_cert_gen_extension_bad_ordering() {
let pkey = pkey();
let result = get_generator() let result = get_generator()
.add_extension(OtherNid(Nid::AuthorityKeyIdentifier, .add_extension(OtherNid(Nid::AuthorityKeyIdentifier,
"keyid:always".to_owned())) "keyid:always".to_owned()))
.add_extension(OtherNid(Nid::SubjectKeyIdentifier, "hash".to_owned())) .add_extension(OtherNid(Nid::SubjectKeyIdentifier, "hash".to_owned()))
.generate(); .sign(&pkey);
assert!(result.is_err()); assert!(result.is_err());
} }
#[test] #[test]
#[cfg(feature = "x509_generator_request")]
fn test_req_gen() { fn test_req_gen() {
let mut pkey = PKey::new(); let pkey = pkey();
pkey.gen(512);
let req = get_generator().request(&pkey).unwrap(); let req = get_generator().request(&pkey).unwrap();
req.write_pem(&mut io::sink()).unwrap(); req.to_pem().unwrap();
// FIXME: check data in result to be correct, needs implementation // FIXME: check data in result to be correct, needs implementation
// of X509_REQ getters // of X509_REQ getters
@ -78,12 +82,8 @@ fn test_req_gen() {
#[test] #[test]
fn test_cert_loading() { fn test_cert_loading() {
let cert_path = Path::new("test/cert.pem"); let cert = include_bytes!("../../test/cert.pem");
let mut file = File::open(&cert_path) let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
.ok()
.expect("Failed to open `test/cert.pem`");
let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM");
let fingerprint = cert.fingerprint(SHA1).unwrap(); let fingerprint = cert.fingerprint(SHA1).unwrap();
let hash_str = "E19427DAC79FBE758394945276A6E4F15F0BEBE6"; let hash_str = "E19427DAC79FBE758394945276A6E4F15F0BEBE6";
@ -93,13 +93,18 @@ fn test_cert_loading() {
} }
#[test] #[test]
fn test_subject_read_cn() { fn test_save_der() {
let cert_path = Path::new("test/cert.pem"); let cert = include_bytes!("../../test/cert.pem");
let mut file = File::open(&cert_path) let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
.ok()
.expect("Failed to open `test/cert.pem`");
let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM"); let der = cert.to_der().unwrap();
assert!(!der.is_empty());
}
#[test]
fn test_subject_read_cn() {
let cert = include_bytes!("../../test/cert.pem");
let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
let subject = cert.subject_name(); let subject = cert.subject_name();
let cn = match subject.text_by_nid(Nid::CN) { let cn = match subject.text_by_nid(Nid::CN) {
Some(x) => x, Some(x) => x,
@ -111,12 +116,8 @@ fn test_subject_read_cn() {
#[test] #[test]
fn test_nid_values() { fn test_nid_values() {
let cert_path = Path::new("test/nid_test_cert.pem"); let cert = include_bytes!("../../test/nid_test_cert.pem");
let mut file = File::open(&cert_path) let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
.ok()
.expect("Failed to open `test/nid_test_cert.pem`");
let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM");
let subject = cert.subject_name(); let subject = cert.subject_name();
let cn = match subject.text_by_nid(Nid::CN) { let cn = match subject.text_by_nid(Nid::CN) {
@ -140,12 +141,8 @@ fn test_nid_values() {
#[test] #[test]
fn test_nid_uid_value() { fn test_nid_uid_value() {
let cert_path = Path::new("test/nid_uid_test_cert.pem"); let cert = include_bytes!("../../test/nid_uid_test_cert.pem");
let mut file = File::open(&cert_path) let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
.ok()
.expect("Failed to open `test/nid_uid_test_cert.pem`");
let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM");
let subject = cert.subject_name(); let subject = cert.subject_name();
let cn = match subject.text_by_nid(Nid::UserId) { let cn = match subject.text_by_nid(Nid::UserId) {
@ -157,8 +154,8 @@ fn test_nid_uid_value() {
#[test] #[test]
fn test_subject_alt_name() { fn test_subject_alt_name() {
let mut file = File::open("test/alt_name_cert.pem").unwrap(); let cert = include_bytes!("../../test/alt_name_cert.pem");
let cert = X509::from_pem(&mut file).unwrap(); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
let subject_alt_names = cert.subject_alt_names().unwrap(); let subject_alt_names = cert.subject_alt_names().unwrap();
assert_eq!(3, subject_alt_names.len()); assert_eq!(3, subject_alt_names.len());
@ -171,8 +168,8 @@ fn test_subject_alt_name() {
#[test] #[test]
fn test_subject_alt_name_iter() { fn test_subject_alt_name_iter() {
let mut file = File::open("test/alt_name_cert.pem").unwrap(); let cert = include_bytes!("../../test/alt_name_cert.pem");
let cert = X509::from_pem(&mut file).unwrap(); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
let subject_alt_names = cert.subject_alt_names().unwrap(); let subject_alt_names = cert.subject_alt_names().unwrap();
let mut subject_alt_names_iter = subject_alt_names.iter(); let mut subject_alt_names_iter = subject_alt_names.iter();

View File

@ -0,0 +1,15 @@
-----BEGIN DSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,5B99FC62C376CA1F
5nN039tLa3AHnSaQ0lk+Zsguu1EE+EyUlW1GHKs7ls2gOsZH1kR0+A+MiwNKlP24
Syy8KYyAbgsirhtwN5IOSsA97feR/vHTY4xQ8nEef8tB7VeRJzOFLHGgS0hwIxOM
Tb8gb4y0FtoWdAgorieP4c1emu8VwTTkHd44AArDXsP1Y7s+a3IEMcHcc3tW+qBk
xuVnqBEETL1t0I5rKy+AYvPmGgEZ0dGRRnUlVMC5jMTozJFcStdSzKUY27prUBz2
FREOJOA/dIjVn1UGijI64Io5sPCAbDPPmG2k4kywbEbd7Ee/MxEvRNcAyv4boyA8
GnHZTILKi/WY5+SNlHE3YepCFo1XU+59SovB1lDhRmi43L4vfdGc/6y8L/+rbLuU
Y58DxLdOZLTjpf9GLLf9WcpHhNZhwFfBFA8HuT8FtKDPqlf2t65z+1AVV8JTH2wM
BrRHXTrBKn8YgafXD5MisKFmajoAtNZTvhYGm0D8BLIiNwOwLsGfXZ0hYAie0eoI
Xl6MbHp1n/e+R+XKJ3M9DPM8mzWntlltAhS5+Az0Zi4aBdzqQaTpqvEku21sygq8
Hwm0fpAq7y4bMnjNbMqQVw==
-----END DSA PRIVATE KEY-----

12
openssl/test/dsa.pem Normal file
View File

@ -0,0 +1,12 @@
-----BEGIN DSA PRIVATE KEY-----
MIIBuwIBAAKBgQCkKe/jtYKJNQafaE7kg2aaJOEPUV0Doi451jkXHp5UfLh6+t42
eabSGkE9WBAlILgaB8yHckLe9+zozN39+SUDp94kb2r38/8w/9Ffhbsep9uiyOj2
ZRQur6SkpKQDKcnAd6IMZXZcvdSgPC90A6qraYUZKq7Csjn63gbC+IvXHwIVAIgS
PE43lXD8/rGYxos4cxCgGGAxAoGASMV56WhLvVQtWMVI36WSIxbZnC2EsnNIKeVW
yXnP/OmPJ2mdezG7i1alcwsO2TnSLbvjvGPlyzIqZzHvWC8EmDqsfbU+n8we/Eal
sm5nloC8m9ECWpbTzbNdvrAAj9UPVWjcDwg7grAGGysh6lGbBv5P+4zL/niq1UiE
LnKcifgCgYEAo6mAasO0+MVcu8shxxUXXNeTLsZ8NB/BIx9EZ/dzE23ivNW8dq1A
eecAAYhssI2m/CspQvyKw+seCvg4FccxJgB3+mGOe+blFHwO3eAwoyRn/t3DZDHh
FjxKKRsQdy4BkZv+vhTyIYYCw0iPZ5Wfln+pyGGTveIDED1MPG+J6c8CFCJAUlEl
4nHvbC15xLXXpd46zycY
-----END DSA PRIVATE KEY-----

12
openssl/test/dsa.pem.pub Normal file
View File

@ -0,0 +1,12 @@
-----BEGIN PUBLIC KEY-----
MIIBtzCCASsGByqGSM44BAEwggEeAoGBAKQp7+O1gok1Bp9oTuSDZpok4Q9RXQOi
LjnWORcenlR8uHr63jZ5ptIaQT1YECUguBoHzIdyQt737OjM3f35JQOn3iRvavfz
/zD/0V+Fux6n26LI6PZlFC6vpKSkpAMpycB3ogxldly91KA8L3QDqqtphRkqrsKy
OfreBsL4i9cfAhUAiBI8TjeVcPz+sZjGizhzEKAYYDECgYBIxXnpaEu9VC1YxUjf
pZIjFtmcLYSyc0gp5VbJec/86Y8naZ17MbuLVqVzCw7ZOdItu+O8Y+XLMipnMe9Y
LwSYOqx9tT6fzB78RqWybmeWgLyb0QJaltPNs12+sACP1Q9VaNwPCDuCsAYbKyHq
UZsG/k/7jMv+eKrVSIQucpyJ+AOBhQACgYEAo6mAasO0+MVcu8shxxUXXNeTLsZ8
NB/BIx9EZ/dzE23ivNW8dq1AeecAAYhssI2m/CspQvyKw+seCvg4FccxJgB3+mGO
e+blFHwO3eAwoyRn/t3DZDHhFjxKKRsQdy4BkZv+vhTyIYYCw0iPZ5Wfln+pyGGT
veIDED1MPG+J6c8=
-----END PUBLIC KEY-----

View File

@ -0,0 +1,9 @@
-----BEGIN DSA PARAMETERS-----
MIIBHgKBgQCkKe/jtYKJNQafaE7kg2aaJOEPUV0Doi451jkXHp5UfLh6+t42eabS
GkE9WBAlILgaB8yHckLe9+zozN39+SUDp94kb2r38/8w/9Ffhbsep9uiyOj2ZRQu
r6SkpKQDKcnAd6IMZXZcvdSgPC90A6qraYUZKq7Csjn63gbC+IvXHwIVAIgSPE43
lXD8/rGYxos4cxCgGGAxAoGASMV56WhLvVQtWMVI36WSIxbZnC2EsnNIKeVWyXnP
/OmPJ2mdezG7i1alcwsO2TnSLbvjvGPlyzIqZzHvWC8EmDqsfbU+n8we/Ealsm5n
loC8m9ECWpbTzbNdvrAAj9UPVWjcDwg7grAGGysh6lGbBv5P+4zL/niq1UiELnKc
ifg=
-----END DSA PARAMETERS-----

View File

@ -0,0 +1,30 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,E2F16153E2BA3D617285A68C896BA6AF
vO9SnhtGjGe8pG1pN//vsONnvJr+DjU+lFCiSqGMPT7tezDnbehLfS+9kus2HV7r
HmI14JvVG9O7NpF7zMyBRlHYdWcCCWED9Yar0NsWN9419e5pMe/bqIXAzAiJbtT4
OB9U5XF3m+349zjN1dVXPPLGRmMC1pcHAlofeb5nIUFTvUi5xcsbe1itGjgkkvHb
Bt8NioHTBun8kKrlsFQOuB55ylBU/eWG8DQBtvFOmQ7iWp0RnGQfh8k5e5rcZNpQ
fD9ygc7UVISl0xTrIG4IH15g34H+nrBauKtIPOpNPuXQPOMHCZv3XH8wnhrWHHwT
ZFnQBdXbSpQtMsRh0phG2G+VIlyCgSn4+CxjCJ+TgFtsoK/tU0unmRYc59QnTxxb
qkHYsPs3E0NApQAgH1ENEGl1M+FGLYQH7gftjc3ophBTeRA17sRmD7Y4QBInggsq
Gv6tImPVBdekAjz/Ls/EyMwjAvvrL5eAokqrIsAarGo+zmbJKHzknw2KUz2En0+k
YYaxB4oy9u7bzuQlvio6xYHJEb4K197bby4Dldmqv7YCCJBJwhOBAInMD687viKv
vcUwL8YuS6cW5E8MbvEENlY4+lvKKj3M8Bnyb79cYIPQe92EuCwXU9DZXPRMLwwM
oFEJpF5E/PmNJzu+B52ahHtDrh83WSx71fWqjdTqwkPZhAYo3ztsfFkb/UqUcq8u
rBSebeUjZh0XZ9B04eshZQ5vJUcXGtYIe/77beV3Pv89/fw+zTZjpiP9Q3sZALzf
Qt0YGp0/6qBuqR1tcqdu65AS2hun7yFw7uRavqYKvww4axRiz2do+xWmZFuoCAwD
EWktaUujltpvAc1lo7lg4C6nByefJB9Xqk22N/vpqOsWr1NbAntT42Qj/HF9BVWR
osvN3yMnKYWYe6oSTVnNBDM5obWAIHd3I9gcxTOTb1KsEwt2RrDs5EpB5ptS3Fjo
JfBRhNZQ3cXttrIIhsHgDn9BDNg865/xpIgktKj0gEd60Abx0PqkAIm6IZTh4Efg
7uZwfzxB+saOcddbrW2gNdzVZMC0s2Ye3sqHhtLbAJ3BlXYTxE4CAvTg54Ny+5hF
IjvjlOKgXceSG1cSfk21/wyp9RY3Ft0AEYvvp0kZScWZaoA2aSFDUrchXVhgrEbn
lJ7UptjefwRFIreAlwbKSbIDDNWnyzvIWyHfQ2aYqgnb7W7XqNPSgH9cALCfzirI
dlRHjha0bMUtrjPCC/YfMXzJBVniy0gG6Pd5uC7vz/Awn6/6HRQVNaTQASphPBQ7
bJuz+JTfzI9OUVCMRMdnb6b35U4P9tibFmnPvzTIPe+3WUmf8aRsLS3NN3G1Webd
PMYVZpMycPaAI0Ht87axhsOzlxCWHYWjdHa+WoNNc1J90TxLCmAHquh5BDaWvjMK
0DySftJZjV7Tf1p2KosmU83LRl39B5NHMbZb1xOEZl9IWwhT/PVKTVZ25xdxWLfb
hF4l8rfvKehIp5r4t8zW1bvI2Hl6vrUvmcUVWt3BfKjxlgwRVD0vvwonMt1INesF
204vUBeXbDsUUicLwOyUgaFvJ3XU3dOyvL9MhOgM5OgoFRRhG+4AS8a5JCD8iLtq
-----END RSA PRIVATE KEY-----

View File

@ -4,11 +4,7 @@ set -e
MAIN_TARGETS=https://static.rust-lang.org/dist MAIN_TARGETS=https://static.rust-lang.org/dist
if [ "$TEST_FEATURES" == "true" ]; then if [ "$TEST_FEATURES" == "true" ]; then
FEATURES="tlsv1_2 tlsv1_1 dtlsv1 dtlsv1_2 sslv3 aes_xts aes_ctr npn alpn rfc5114 ecdh_auto pkcs5_pbkdf2_hmac" FEATURES="tlsv1_2 tlsv1_1 dtlsv1 dtlsv1_2 sslv3 aes_xts aes_ctr npn alpn rfc5114 ecdh_auto pkcs5_pbkdf2_hmac x509_clone ssl_context_clone x509_generator_request hmac hmac_clone dh_from_params"
fi
if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then
FEATURES="$FEATURES nightly"
fi fi
if [ "$TRAVIS_OS_NAME" != "osx" ]; then if [ "$TRAVIS_OS_NAME" != "osx" ]; then
@ -33,4 +29,4 @@ else
fi fi
export PATH=$HOME/openssl/bin:$PATH export PATH=$HOME/openssl/bin:$PATH
(cd openssl && cargo $COMMAND $FLAGS --features "$FEATURES") (cd openssl && RUST_BACKTRACE=1 cargo $COMMAND $FLAGS --features "$FEATURES")