Merge branch 'release-v0.7.15-sys-v0.8.0' into release
This commit is contained in:
commit
652326003c
|
|
@ -6,7 +6,7 @@ addons:
|
|||
- gcc-arm-linux-gnueabihf
|
||||
rust:
|
||||
- nightly
|
||||
- 1.8.0
|
||||
- 1.9.0
|
||||
os:
|
||||
- osx
|
||||
- linux
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
[workspace]
|
||||
members = ["openssl", "openssl-sys"]
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[](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
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ environment:
|
|||
install:
|
||||
- ps: Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-1_0_2h.exe"
|
||||
- Win%BITS%OpenSSL-1_0_2h.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL"
|
||||
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.8.0-${env:TARGET}.exe"
|
||||
- rust-1.8.0-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
|
||||
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.9.0-${env:TARGET}.exe"
|
||||
- rust-1.9.0-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
|
||||
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
|
||||
- SET PATH=%PATH%;C:\MinGW\bin
|
||||
- rustc -V
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -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©_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©_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
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
[package]
|
||||
name = "openssl-sys"
|
||||
version = "0.7.14"
|
||||
version = "0.7.15"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>",
|
||||
"Steven Fackler <sfackler@gmail.com>"]
|
||||
license = "MIT"
|
||||
description = "FFI bindings to OpenSSL"
|
||||
repository = "https://github.com/sfackler/rust-openssl"
|
||||
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.14/openssl_sys"
|
||||
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.15/openssl_sys"
|
||||
links = "openssl"
|
||||
build = "build.rs"
|
||||
|
||||
|
|
@ -23,6 +23,8 @@ npn = []
|
|||
alpn = []
|
||||
rfc5114 = []
|
||||
pkcs5_pbkdf2_hmac = []
|
||||
ecdh_auto = []
|
||||
hmac_clone = []
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
|
|
@ -40,15 +42,6 @@ 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
|
||||
[target.i686-pc-windows-gnu.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]
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
user32-sys = "0.2"
|
||||
gdi32-sys = "0.2"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)]
|
||||
#![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;
|
||||
|
||||
|
|
@ -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 std::mem;
|
||||
use std::ptr;
|
||||
use std::sync::{Mutex, MutexGuard};
|
||||
use std::sync::{Once, ONCE_INIT};
|
||||
|
||||
pub type ASN1_INTEGER = c_void;
|
||||
pub type ASN1_STRING = c_void;
|
||||
pub type ASN1_TIME = c_void;
|
||||
pub type ASN1_TYPE = c_void;
|
||||
pub type BN_CTX = c_void;
|
||||
pub type BN_GENCB = c_void;
|
||||
pub type COMP_METHOD = c_void;
|
||||
pub type DH = c_void;
|
||||
pub type ENGINE = c_void;
|
||||
pub type EVP_CIPHER = c_void;
|
||||
pub type EVP_CIPHER_CTX = c_void;
|
||||
pub type EVP_MD = c_void;
|
||||
pub type EVP_PKEY_CTX = c_void;
|
||||
|
|
@ -114,6 +116,28 @@ pub struct RSA {
|
|||
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)]
|
||||
pub struct EVP_PKEY {
|
||||
pub type_: c_int,
|
||||
|
|
@ -172,6 +196,39 @@ impl Clone for EVP_MD_CTX {
|
|||
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)]
|
||||
pub struct HMAC_CTX {
|
||||
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_CTRL_EOF: c_int = 2;
|
||||
pub const BIO_CTRL_INFO: c_int = 3;
|
||||
pub const BIO_CTRL_FLUSH: c_int = 11;
|
||||
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 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_BMP: c_int = MBSTRING_FLAG | 2;
|
||||
pub const MBSTRING_FLAG: c_int = 0x1000;
|
||||
pub const MBSTRING_UNIV: c_int = MBSTRING_FLAG | 4;
|
||||
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_key_usage: c_int = 83;
|
||||
|
||||
pub const PKCS5_SALT_LEN: c_int = 8;
|
||||
|
||||
pub const SSL_CTRL_OPTIONS: c_int = 32;
|
||||
pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77;
|
||||
pub const RSA_F4: c_long = 0x10001;
|
||||
|
||||
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_ARG: c_int = 54;
|
||||
pub const SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55;
|
||||
pub const SSL_CTRL_EXTRA_CHAIN_CERT: c_int = 14;
|
||||
pub const SSL_CTRL_SET_READ_AHEAD: c_int = 41;
|
||||
pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77;
|
||||
#[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_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_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 SSL_TLSEXT_ERR_OK: c_int = 0;
|
||||
|
|
@ -430,6 +540,78 @@ fn set_id_callback() {
|
|||
#[cfg(not(unix))]
|
||||
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
|
||||
extern "C" {
|
||||
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_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int;
|
||||
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_dup(n: *mut BIGNUM) -> *mut BIGNUM;
|
||||
|
|
@ -532,6 +717,7 @@ extern "C" {
|
|||
#[cfg(feature = "rfc5114")]
|
||||
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 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_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_CipherInit(ctx: *mut EVP_CIPHER_CTX, evp: *const EVP_CIPHER,
|
||||
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,
|
||||
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;
|
||||
|
|
@ -609,6 +802,8 @@ extern "C" {
|
|||
|
||||
pub fn HMAC_CTX_init(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>,
|
||||
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>,
|
||||
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>,
|
||||
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>,
|
||||
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_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,
|
||||
kstr: *mut c_char, klen: c_int,
|
||||
kstr: *mut c_uchar, klen: c_int,
|
||||
callback: Option<PasswordCallback>,
|
||||
user_data: *mut c_void) -> c_int;
|
||||
pub fn PEM_write_bio_PUBKEY(bp: *mut BIO, x: *mut EVP_PKEY) -> c_int;
|
||||
pub fn PEM_write_bio_RSAPrivateKey(bp: *mut BIO, rsa: *mut RSA, cipher: *const EVP_CIPHER,
|
||||
kstr: *mut c_char, klen: c_int,
|
||||
kstr: *mut c_uchar, klen: c_int,
|
||||
callback: Option<PasswordCallback>,
|
||||
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_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_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_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_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,
|
||||
pad: c_int) -> c_int;
|
||||
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,
|
||||
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_load_error_strings();
|
||||
|
|
@ -694,6 +913,7 @@ extern "C" {
|
|||
pub fn SSL_get_wbio(ssl: *mut SSL) -> *mut BIO;
|
||||
pub fn SSL_accept(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,
|
||||
parg: *mut c_void) -> c_long;
|
||||
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_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,
|
||||
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);
|
||||
|
|
@ -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_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 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;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
[package]
|
||||
name = "openssl"
|
||||
version = "0.7.14"
|
||||
version = "0.8.0"
|
||||
authors = ["Steven Fackler <sfackler@gmail.com>"]
|
||||
license = "Apache-2.0"
|
||||
description = "OpenSSL bindings"
|
||||
repository = "https://github.com/sfackler/rust-openssl"
|
||||
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.14/openssl"
|
||||
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.8.0/openssl"
|
||||
readme = "../README.md"
|
||||
keywords = ["crypto", "tls", "ssl", "dtls"]
|
||||
build = "build.rs"
|
||||
|
|
@ -23,20 +23,25 @@ aes_ctr = ["openssl-sys/aes_ctr"]
|
|||
npn = ["openssl-sys/npn"]
|
||||
alpn = ["openssl-sys/alpn"]
|
||||
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"]
|
||||
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]
|
||||
bitflags = ">= 0.5.0, < 0.8.0"
|
||||
bitflags = "0.7"
|
||||
lazy_static = "0.2"
|
||||
libc = "0.2"
|
||||
openssl-sys = { version = "0.7.14", path = "../openssl-sys" }
|
||||
openssl-sys-extras = { version = "0.7.14", path = "../openssl-sys-extras" }
|
||||
openssl-sys = { version = "0.7.15", path = "../openssl-sys" }
|
||||
|
||||
[build-dependencies]
|
||||
gcc = "0.3"
|
||||
gcc = { version = "0.3", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rustc-serialize = "0.3"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
extern crate gcc;
|
||||
#[cfg(feature = "c_helpers")]
|
||||
mod imp {
|
||||
extern crate gcc;
|
||||
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
pub fn main() {
|
||||
let mut config = gcc::Config::new();
|
||||
|
||||
if let Some(paths) = env::var_os("DEP_OPENSSL_INCLUDE") {
|
||||
|
|
@ -13,4 +15,14 @@ fn main() {
|
|||
}
|
||||
|
||||
config.file("src/c_helpers.c").compile("libc_helpers.a");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "c_helpers"))]
|
||||
mod imp {
|
||||
pub fn main() {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
imp::main()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,47 +2,38 @@ use libc::c_long;
|
|||
use std::ptr;
|
||||
|
||||
use ffi;
|
||||
use ssl::error::SslError;
|
||||
use error::ErrorStack;
|
||||
|
||||
|
||||
pub struct Asn1Time {
|
||||
handle: *mut ffi::ASN1_TIME,
|
||||
owned: bool,
|
||||
}
|
||||
pub struct Asn1Time(*mut ffi::ASN1_TIME);
|
||||
|
||||
impl Asn1Time {
|
||||
/// Wraps existing ASN1_TIME and takes ownership
|
||||
pub fn new(handle: *mut ffi::ASN1_TIME) -> Asn1Time {
|
||||
Asn1Time {
|
||||
handle: handle,
|
||||
owned: true,
|
||||
}
|
||||
pub unsafe fn from_ptr(handle: *mut ffi::ASN1_TIME) -> Asn1Time {
|
||||
Asn1Time(handle)
|
||||
}
|
||||
|
||||
fn new_with_period(period: u64) -> Result<Asn1Time, SslError> {
|
||||
fn from_period(period: c_long) -> Result<Asn1Time, ErrorStack> {
|
||||
ffi::init();
|
||||
|
||||
let handle = unsafe {
|
||||
try_ssl_null!(ffi::X509_gmtime_adj(ptr::null_mut(), period as c_long))
|
||||
};
|
||||
Ok(Asn1Time::new(handle))
|
||||
unsafe {
|
||||
let handle = try_ssl_null!(ffi::X509_gmtime_adj(ptr::null_mut(), period));
|
||||
Ok(Asn1Time::from_ptr(handle))
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new time on specified interval in days from now
|
||||
pub fn days_from_now(days: u32) -> Result<Asn1Time, SslError> {
|
||||
Asn1Time::new_with_period(days as u64 * 60 * 60 * 24)
|
||||
pub fn days_from_now(days: u32) -> Result<Asn1Time, ErrorStack> {
|
||||
Asn1Time::from_period(days as c_long * 60 * 60 * 24)
|
||||
}
|
||||
|
||||
/// Returns raw handle
|
||||
pub unsafe fn get_handle(&self) -> *mut ffi::ASN1_TIME {
|
||||
return self.handle;
|
||||
/// Returns the raw handle
|
||||
pub fn as_ptr(&self) -> *mut ffi::ASN1_TIME {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Asn1Time {
|
||||
fn drop(&mut self) {
|
||||
if self.owned {
|
||||
unsafe { ffi::ASN1_TIME_free(self.handle) };
|
||||
}
|
||||
unsafe { ffi::ASN1_TIME_free(self.0) };
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
|
@ -1,8 +1,7 @@
|
|||
#include <openssl/hmac.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
void rust_SSL_clone(SSL *ssl) {
|
||||
CRYPTO_add(&ssl->references, 1, CRYPTO_LOCK_SSL);
|
||||
}
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/bn.h>
|
||||
|
||||
void rust_SSL_CTX_clone(SSL_CTX *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) {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
use libc::c_uint;
|
||||
use std::iter::repeat;
|
||||
use std::io::prelude::*;
|
||||
use std::io;
|
||||
use std::ptr;
|
||||
use std::cmp;
|
||||
use ffi;
|
||||
|
||||
use crypto::HashTypeInternals;
|
||||
use HashTypeInternals;
|
||||
use error::ErrorStack;
|
||||
use nid::Nid;
|
||||
|
||||
/// Message digest (hash) type.
|
||||
|
|
@ -31,26 +33,8 @@ impl HashTypeInternals for Type {
|
|||
Type::RIPEMD160 => Nid::RIPEMD160,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Type {
|
||||
/// 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 {
|
||||
fn evp_md(&self) -> *const ffi::EVP_MD {
|
||||
unsafe {
|
||||
match *self {
|
||||
Type::MD5 => ffi::EVP_md5(),
|
||||
|
|
@ -84,21 +68,20 @@ use self::State::*;
|
|||
/// use openssl::crypto::hash::{hash, Type};
|
||||
/// let data = b"\x42\xF4\x97\xE0";
|
||||
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
|
||||
/// let res = hash(Type::MD5, data);
|
||||
/// let res = hash(Type::MD5, data).unwrap();
|
||||
/// assert_eq!(res, spec);
|
||||
/// ```
|
||||
///
|
||||
/// Use the `Write` trait to supply the input in chunks.
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::prelude::*;
|
||||
/// use openssl::crypto::hash::{Hasher, Type};
|
||||
/// let data = [b"\x42\xF4", b"\x97\xE0"];
|
||||
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
|
||||
/// let mut h = Hasher::new(Type::MD5);
|
||||
/// h.write_all(data[0]);
|
||||
/// h.write_all(data[1]);
|
||||
/// let res = h.finish();
|
||||
/// let mut h = Hasher::new(Type::MD5).unwrap();
|
||||
/// h.update(data[0]).unwrap();
|
||||
/// h.update(data[1]).unwrap();
|
||||
/// let res = h.finish().unwrap();
|
||||
/// assert_eq!(res, spec);
|
||||
/// ```
|
||||
///
|
||||
|
|
@ -116,14 +99,10 @@ pub struct Hasher {
|
|||
|
||||
impl Hasher {
|
||||
/// 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();
|
||||
|
||||
let ctx = unsafe {
|
||||
let r = ffi::EVP_MD_CTX_create();
|
||||
assert!(!r.is_null());
|
||||
r
|
||||
};
|
||||
let ctx = unsafe { try_ssl_null!(ffi::EVP_MD_CTX_create()) };
|
||||
let md = ty.evp_md();
|
||||
|
||||
let mut h = Hasher {
|
||||
|
|
@ -132,67 +111,60 @@ impl Hasher {
|
|||
type_: ty,
|
||||
state: Finalized,
|
||||
};
|
||||
h.init();
|
||||
h
|
||||
try!(h.init());
|
||||
Ok(h)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn init(&mut self) {
|
||||
fn init(&mut self) -> Result<(), ErrorStack> {
|
||||
match self.state {
|
||||
Reset => return,
|
||||
Reset => return Ok(()),
|
||||
Updated => {
|
||||
self.finalize();
|
||||
try!(self.finish());
|
||||
}
|
||||
Finalized => (),
|
||||
}
|
||||
unsafe {
|
||||
let r = ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *const _);
|
||||
assert_eq!(r, 1);
|
||||
}
|
||||
unsafe { try_ssl!(ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *const _)); }
|
||||
self.state = Reset;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn update(&mut self, data: &[u8]) {
|
||||
/// Feeds data into the hasher.
|
||||
pub fn update(&mut self, mut data: &[u8]) -> Result<(), ErrorStack> {
|
||||
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 {
|
||||
let r = ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), data.len() as c_uint);
|
||||
assert_eq!(r, 1);
|
||||
try_ssl!(ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), len as c_uint));
|
||||
}
|
||||
data = &data[len..];
|
||||
}
|
||||
self.state = Updated;
|
||||
}
|
||||
|
||||
#[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
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the hash of the data written since creation or
|
||||
/// the last `finish` and resets the hasher.
|
||||
#[inline]
|
||||
pub fn finish(&mut self) -> Vec<u8> {
|
||||
self.finalize()
|
||||
pub fn finish(&mut self) -> Result<Vec<u8>, ErrorStack> {
|
||||
if self.state == Finalized {
|
||||
try!(self.init());
|
||||
}
|
||||
unsafe {
|
||||
let mut len = ffi::EVP_MAX_MD_SIZE;
|
||||
let mut res = vec![0; len as usize];
|
||||
try_ssl!(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 {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.update(buf);
|
||||
try!(self.update(buf));
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
|
|
@ -223,9 +195,7 @@ impl Drop for Hasher {
|
|||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if self.state != Finalized {
|
||||
let mut buf: Vec<u8> = repeat(0).take(self.type_.md_len()).collect();
|
||||
let mut len = 0;
|
||||
ffi::EVP_DigestFinal_ex(self.ctx, buf.as_mut_ptr(), &mut len);
|
||||
drop(self.finish());
|
||||
}
|
||||
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`.
|
||||
pub fn hash(t: Type, data: &[u8]) -> Vec<u8> {
|
||||
let mut h = Hasher::new(t);
|
||||
let _ = h.write_all(data);
|
||||
pub fn hash(t: Type, data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mut h = try!(Hasher::new(t));
|
||||
try!(h.update(data));
|
||||
h.finish()
|
||||
}
|
||||
|
||||
|
|
@ -246,13 +216,13 @@ mod tests {
|
|||
use std::io::prelude::*;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) {
|
||||
let _ = h.write_all(&*hashtest.0.from_hex().unwrap());
|
||||
let res = h.finish();
|
||||
let _ = h.write_all(&*hashtest.0.from_hex().unwrap()).unwrap();
|
||||
let res = h.finish().unwrap();
|
||||
assert_eq!(res.to_hex(), hashtest.1);
|
||||
}
|
||||
|
||||
|
|
@ -294,7 +264,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
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() {
|
||||
hash_recycle_test(&mut h, test);
|
||||
}
|
||||
|
|
@ -302,11 +272,11 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_finish_twice() {
|
||||
let mut h = Hasher::new(Type::MD5);
|
||||
let _ = h.write_all(&*md5_tests[6].0.from_hex().unwrap());
|
||||
let _ = h.finish();
|
||||
let res = h.finish();
|
||||
let null = hash(Type::MD5, &[]);
|
||||
let mut h = Hasher::new(Type::MD5).unwrap();
|
||||
h.write_all(&*md5_tests[6].0.from_hex().unwrap()).unwrap();
|
||||
h.finish().unwrap();
|
||||
let res = h.finish().unwrap();
|
||||
let null = hash(Type::MD5, &[]).unwrap();
|
||||
assert_eq!(res, null);
|
||||
}
|
||||
|
||||
|
|
@ -316,26 +286,26 @@ mod tests {
|
|||
let inp = md5_tests[i].0.from_hex().unwrap();
|
||||
assert!(inp.len() > 2);
|
||||
let p = inp.len() / 2;
|
||||
let h0 = Hasher::new(Type::MD5);
|
||||
let h0 = Hasher::new(Type::MD5).unwrap();
|
||||
|
||||
println!("Clone a new hasher");
|
||||
let mut h1 = h0.clone();
|
||||
let _ = h1.write_all(&inp[..p]);
|
||||
h1.write_all(&inp[..p]).unwrap();
|
||||
{
|
||||
println!("Clone an updated hasher");
|
||||
let mut h2 = h1.clone();
|
||||
let _ = h2.write_all(&inp[p..]);
|
||||
let res = h2.finish();
|
||||
h2.write_all(&inp[p..]).unwrap();
|
||||
let res = h2.finish().unwrap();
|
||||
assert_eq!(res.to_hex(), md5_tests[i].1);
|
||||
}
|
||||
let _ = h1.write_all(&inp[p..]);
|
||||
let res = h1.finish();
|
||||
h1.write_all(&inp[p..]).unwrap();
|
||||
let res = h1.finish().unwrap();
|
||||
assert_eq!(res.to_hex(), md5_tests[i].1);
|
||||
|
||||
println!("Clone a finished hasher");
|
||||
let mut h3 = h1.clone();
|
||||
let _ = h3.write_all(&*md5_tests[i + 1].0.from_hex().unwrap());
|
||||
let res = h3.finish();
|
||||
h3.write_all(&*md5_tests[i + 1].0.from_hex().unwrap()).unwrap();
|
||||
let res = h3.finish().unwrap();
|
||||
assert_eq!(res.to_hex(), md5_tests[i + 1].1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,13 +14,15 @@
|
|||
//
|
||||
|
||||
use libc::{c_int, c_uint};
|
||||
use std::iter::repeat;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
|
||||
use crypto::hash::Type;
|
||||
use std::cmp;
|
||||
use ffi;
|
||||
use ffi_extras;
|
||||
|
||||
use HashTypeInternals;
|
||||
use crypto::hash::Type;
|
||||
use error::ErrorStack;
|
||||
use c_helpers;
|
||||
|
||||
#[derive(PartialEq, Copy, Clone)]
|
||||
enum State {
|
||||
|
|
@ -33,6 +35,8 @@ use self::State::*;
|
|||
|
||||
/// Provides HMAC computation.
|
||||
///
|
||||
/// Requires the `hmac` feature.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Calculate a HMAC in one go.
|
||||
|
|
@ -43,34 +47,32 @@ use self::State::*;
|
|||
/// let key = b"Jefe";
|
||||
/// let data = b"what do ya want for nothing?";
|
||||
/// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38";
|
||||
/// let res = hmac(Type::MD5, key, data);
|
||||
/// let res = hmac(Type::MD5, key, data).unwrap();
|
||||
/// assert_eq!(res, spec);
|
||||
/// ```
|
||||
///
|
||||
/// Use the `Write` trait to supply the input in chunks.
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::prelude::*;
|
||||
/// use openssl::crypto::hash::Type;
|
||||
/// use openssl::crypto::hmac::HMAC;
|
||||
/// let key = b"Jefe";
|
||||
/// let data: &[&[u8]] = &[b"what do ya ", b"want for nothing?"];
|
||||
/// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38";
|
||||
/// let mut h = HMAC::new(Type::MD5, &*key);
|
||||
/// h.write_all(data[0]);
|
||||
/// h.write_all(data[1]);
|
||||
/// let res = h.finish();
|
||||
/// let mut h = HMAC::new(Type::MD5, &*key).unwrap();
|
||||
/// h.update(data[0]).unwrap();
|
||||
/// h.update(data[1]).unwrap();
|
||||
/// let res = h.finish().unwrap();
|
||||
/// assert_eq!(res, spec);
|
||||
/// ```
|
||||
pub struct HMAC {
|
||||
ctx: ffi::HMAC_CTX,
|
||||
type_: Type,
|
||||
state: State,
|
||||
}
|
||||
|
||||
impl HMAC {
|
||||
/// 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();
|
||||
|
||||
let ctx = unsafe {
|
||||
|
|
@ -82,89 +84,81 @@ impl HMAC {
|
|||
|
||||
let mut h = HMAC {
|
||||
ctx: ctx,
|
||||
type_: ty,
|
||||
state: Finalized,
|
||||
};
|
||||
h.init_once(md, key);
|
||||
h
|
||||
try!(h.init_once(md, key));
|
||||
Ok(h)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn init_once(&mut self, md: *const ffi::EVP_MD, key: &[u8]) {
|
||||
fn init_once(&mut self, md: *const ffi::EVP_MD, key: &[u8]) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
let r = ffi_extras::HMAC_Init_ex(&mut self.ctx,
|
||||
key.as_ptr(),
|
||||
try_ssl!(c_helpers::rust_HMAC_Init_ex(&mut self.ctx,
|
||||
key.as_ptr() as *const _,
|
||||
key.len() as c_int,
|
||||
md,
|
||||
0 as *const _);
|
||||
assert_eq!(r, 1);
|
||||
0 as *mut _));
|
||||
}
|
||||
self.state = Reset;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn init(&mut self) {
|
||||
fn init(&mut self) -> Result<(), ErrorStack> {
|
||||
match self.state {
|
||||
Reset => return,
|
||||
Reset => return Ok(()),
|
||||
Updated => {
|
||||
self.finalize();
|
||||
try!(self.finish());
|
||||
}
|
||||
Finalized => (),
|
||||
}
|
||||
// If the key and/or md is not supplied it's reused from the last time
|
||||
// avoiding redundant initializations
|
||||
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,
|
||||
0 as *const _,
|
||||
0 as *const _);
|
||||
assert_eq!(r, 1);
|
||||
0 as *mut _));
|
||||
}
|
||||
self.state = Reset;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn update(&mut self, data: &[u8]) {
|
||||
pub fn update(&mut self, mut data: &[u8]) -> Result<(), ErrorStack> {
|
||||
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 {
|
||||
let r = ffi_extras::HMAC_Update(&mut self.ctx, data.as_ptr(), data.len() as c_uint);
|
||||
assert_eq!(r, 1);
|
||||
try_ssl!(c_helpers::rust_HMAC_Update(&mut self.ctx, data.as_ptr(), len as c_uint));
|
||||
}
|
||||
data = &data[len..];
|
||||
}
|
||||
self.state = Updated;
|
||||
}
|
||||
|
||||
#[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
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the hash of the data written since creation or
|
||||
/// the last `finish` and resets the hasher.
|
||||
#[inline]
|
||||
pub fn finish(&mut self) -> Vec<u8> {
|
||||
self.finalize()
|
||||
pub fn finish(&mut self) -> Result<Vec<u8>, ErrorStack> {
|
||||
if self.state == Finalized {
|
||||
try!(self.init());
|
||||
}
|
||||
unsafe {
|
||||
let mut len = ffi::EVP_MAX_MD_SIZE;
|
||||
let mut res = vec![0; len as usize];
|
||||
try_ssl!(c_helpers::rust_HMAC_Final(&mut self.ctx, res.as_mut_ptr(), &mut len));
|
||||
res.truncate(len as usize);
|
||||
self.state = Finalized;
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for HMAC {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.update(buf);
|
||||
try!(self.update(buf));
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
|
|
@ -173,17 +167,18 @@ impl Write for HMAC {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "hmac_clone")]
|
||||
impl Clone for HMAC {
|
||||
/// Requires the `hmac_clone` feature.
|
||||
fn clone(&self) -> HMAC {
|
||||
let mut ctx: ffi::HMAC_CTX;
|
||||
unsafe {
|
||||
ctx = ::std::mem::uninitialized();
|
||||
let r = ffi_extras::HMAC_CTX_copy(&mut ctx, &self.ctx);
|
||||
let r = ffi::HMAC_CTX_copy(&mut ctx, &self.ctx);
|
||||
assert_eq!(r, 1);
|
||||
}
|
||||
HMAC {
|
||||
ctx: ctx,
|
||||
type_: self.type_,
|
||||
state: self.state,
|
||||
}
|
||||
}
|
||||
|
|
@ -193,9 +188,7 @@ impl Drop for HMAC {
|
|||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if self.state != Finalized {
|
||||
let mut buf: Vec<u8> = repeat(0).take(self.type_.md_len()).collect();
|
||||
let mut len = 0;
|
||||
ffi_extras::HMAC_Final(&mut self.ctx, buf.as_mut_ptr(), &mut len);
|
||||
drop(self.finish());
|
||||
}
|
||||
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`.
|
||||
pub fn hmac(t: Type, key: &[u8], data: &[u8]) -> Vec<u8> {
|
||||
let mut h = HMAC::new(t, key);
|
||||
let _ = h.write_all(data);
|
||||
pub fn hmac(t: Type, key: &[u8], data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mut h = try!(HMAC::new(t, key));
|
||||
try!(h.update(data));
|
||||
h.finish()
|
||||
}
|
||||
|
||||
|
|
@ -220,14 +213,14 @@ mod tests {
|
|||
|
||||
fn test_hmac(ty: Type, tests: &[(Vec<u8>, Vec<u8>, Vec<u8>)]) {
|
||||
for &(ref key, ref data, ref res) in tests.iter() {
|
||||
assert_eq!(hmac(ty, &**key, &**data), *res);
|
||||
assert_eq!(hmac(ty, &**key, &**data).unwrap(), *res);
|
||||
}
|
||||
}
|
||||
|
||||
fn test_hmac_recycle(h: &mut HMAC, test: &(Vec<u8>, Vec<u8>, Vec<u8>)) {
|
||||
let &(_, ref data, ref res) = test;
|
||||
let _ = h.write_all(&**data);
|
||||
assert_eq!(h.finish(), *res);
|
||||
h.write_all(&**data).unwrap();
|
||||
assert_eq!(h.finish().unwrap(), *res);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -273,7 +266,7 @@ mod tests {
|
|||
.to_vec(),
|
||||
"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 {
|
||||
let test = &tests[i % 2];
|
||||
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(),
|
||||
"6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap());
|
||||
|
||||
let mut h = HMAC::new(Type::MD5, &*test.0);
|
||||
let _ = h.write_all(&*test.1);
|
||||
let _ = h.finish();
|
||||
let res = h.finish();
|
||||
let null = hmac(Type::MD5, &*test.0, &[]);
|
||||
let mut h = HMAC::new(Type::MD5, &*test.0).unwrap();
|
||||
h.write_all(&*test.1).unwrap();
|
||||
h.finish().unwrap();
|
||||
let res = h.finish().unwrap();
|
||||
let null = hmac(Type::MD5, &*test.0, &[]).unwrap();
|
||||
assert_eq!(res, null);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "hmac_clone")]
|
||||
fn test_clone() {
|
||||
let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 2] =
|
||||
[(repeat(0xaa_u8).take(80).collect(),
|
||||
|
|
@ -307,26 +301,26 @@ mod tests {
|
|||
.to_vec(),
|
||||
"6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())];
|
||||
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");
|
||||
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");
|
||||
let mut h2 = h1.clone();
|
||||
let _ = h2.write_all(&tests[0].1[p..]);
|
||||
let res = h2.finish();
|
||||
h2.write_all(&tests[0].1[p..]).unwrap();
|
||||
let res = h2.finish().unwrap();
|
||||
assert_eq!(res, tests[0].2);
|
||||
}
|
||||
let _ = h1.write_all(&tests[0].1[p..]);
|
||||
let res = h1.finish();
|
||||
h1.write_all(&tests[0].1[p..]).unwrap();
|
||||
let res = h1.finish().unwrap();
|
||||
assert_eq!(res, tests[0].2);
|
||||
|
||||
println!("Clone a finished hmac");
|
||||
let mut h3 = h1.clone();
|
||||
let _ = h3.write_all(&*tests[1].1);
|
||||
let res = h3.finish();
|
||||
h3.write_all(&*tests[1].1).unwrap();
|
||||
let res = h3.finish().unwrap();
|
||||
assert_eq!(res, tests[1].2);
|
||||
}
|
||||
|
||||
|
|
@ -373,7 +367,7 @@ mod tests {
|
|||
.to_vec(),
|
||||
"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 {
|
||||
let test = &tests[i % 2];
|
||||
test_hmac_recycle(&mut h, test);
|
||||
|
|
@ -399,11 +393,11 @@ mod tests {
|
|||
.to_vec())];
|
||||
|
||||
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
|
||||
let mut h = HMAC::new(ty, &*tests[5].0);
|
||||
let mut h = HMAC::new(ty, &*tests[5].0).unwrap();
|
||||
for i in 0..100usize {
|
||||
let test = &tests[4 + i % 2];
|
||||
let tup = (test.0.clone(), test.1.clone(), results[4 + i % 2].clone());
|
||||
|
|
|
|||
|
|
@ -14,9 +14,8 @@
|
|||
// limitations under the License.
|
||||
//
|
||||
|
||||
use nid::Nid;
|
||||
|
||||
pub mod hash;
|
||||
#[cfg(feature = "hmac")]
|
||||
pub mod hmac;
|
||||
pub mod pkcs5;
|
||||
pub mod pkey;
|
||||
|
|
@ -24,9 +23,5 @@ pub mod rand;
|
|||
pub mod symm;
|
||||
pub mod memcmp;
|
||||
pub mod rsa;
|
||||
|
||||
mod symm_internal;
|
||||
|
||||
trait HashTypeInternals {
|
||||
fn as_nid(&self) -> Nid;
|
||||
}
|
||||
pub mod dsa;
|
||||
mod util;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
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::symm;
|
||||
use ffi;
|
||||
use error::ErrorStack;
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct KeyIvPair {
|
||||
|
|
@ -27,114 +28,91 @@ pub fn evp_bytes_to_key_pbkdf1_compatible(typ: symm::Type,
|
|||
data: &[u8],
|
||||
salt: Option<&[u8]>,
|
||||
count: u32)
|
||||
-> KeyIvPair {
|
||||
|
||||
-> Result<KeyIvPair, ErrorStack> {
|
||||
unsafe {
|
||||
|
||||
let salt_ptr = match salt {
|
||||
Some(salt) => {
|
||||
assert_eq!(salt.len(), ffi::PKCS5_SALT_LEN as usize);
|
||||
salt.as_ptr()
|
||||
}
|
||||
None => null(),
|
||||
None => ptr::null(),
|
||||
};
|
||||
|
||||
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 iv = vec![0; keylen as usize];
|
||||
let mut key = vec![0; len as usize];
|
||||
let mut iv = vec![0; len as usize];
|
||||
|
||||
|
||||
let ret: c_int = ffi::EVP_BytesToKey(evp,
|
||||
message_digest,
|
||||
try_ssl!(ffi::EVP_BytesToKey(typ,
|
||||
message_digest_type,
|
||||
salt_ptr,
|
||||
data.as_ptr(),
|
||||
data.len() as c_int,
|
||||
count as c_int,
|
||||
key.as_mut_ptr(),
|
||||
iv.as_mut_ptr());
|
||||
assert!(ret == keylen as c_int);
|
||||
iv.as_mut_ptr()));
|
||||
|
||||
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.
|
||||
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 {
|
||||
assert!(iter >= 1);
|
||||
assert!(keylen >= 1);
|
||||
|
||||
let mut out = Vec::with_capacity(keylen);
|
||||
let mut out = vec![0; keylen];
|
||||
|
||||
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,
|
||||
salt.as_ptr(),
|
||||
salt.len() as c_int,
|
||||
iter as c_int,
|
||||
keylen as c_int,
|
||||
out.as_mut_ptr());
|
||||
|
||||
if r != 1 {
|
||||
panic!();
|
||||
out.as_mut_ptr()));
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
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.
|
||||
#[cfg(feature = "pkcs5_pbkdf2_hmac")]
|
||||
fn pbkdf2_hmac_sha(pass: &str,
|
||||
pub fn pbkdf2_hmac(pass: &[u8],
|
||||
salt: &[u8],
|
||||
iter: usize,
|
||||
digest: *const ffi::EVP_MD,
|
||||
hash: hash::Type,
|
||||
keylen: usize)
|
||||
-> Vec<u8> {
|
||||
-> Result<Vec<u8>, ErrorStack> {
|
||||
unsafe {
|
||||
assert!(iter >= 1);
|
||||
assert!(keylen >= 1);
|
||||
|
||||
let mut out = Vec::with_capacity(keylen);
|
||||
|
||||
let mut out = vec![0; keylen];
|
||||
ffi::init();
|
||||
|
||||
let r = ffi::PKCS5_PBKDF2_HMAC(pass.as_ptr(),
|
||||
try_ssl!(ffi::PKCS5_PBKDF2_HMAC(pass.as_ptr(),
|
||||
pass.len() as c_int,
|
||||
salt.as_ptr(),
|
||||
salt.len() as c_int,
|
||||
iter as c_int,
|
||||
digest,
|
||||
hash.evp_md(),
|
||||
keylen as c_int,
|
||||
out.as_mut_ptr());
|
||||
|
||||
if r != 1 {
|
||||
panic!();
|
||||
}
|
||||
|
||||
out.set_len(keylen);
|
||||
|
||||
out
|
||||
out.as_mut_ptr()));
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -147,36 +125,36 @@ mod tests {
|
|||
// http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06
|
||||
#[test]
|
||||
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,
|
||||
0xf3_u8, 0xa9_u8, 0xb5_u8, 0x24_u8, 0xaf_u8, 0x60_u8, 0x12_u8, 0x06_u8,
|
||||
0x2f_u8, 0xe0_u8, 0x37_u8, 0xa6_u8]);
|
||||
|
||||
assert_eq!(super::pbkdf2_hmac_sha1("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,
|
||||
0xcd_u8, 0x1e_u8, 0xd9_u8, 0x2a_u8, 0xce_u8, 0x1d_u8, 0x41_u8, 0xf0_u8,
|
||||
0xd8_u8, 0xde_u8, 0x89_u8, 0x57_u8]);
|
||||
|
||||
assert_eq!(super::pbkdf2_hmac_sha1("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,
|
||||
0xbe_u8, 0xad_u8, 0x49_u8, 0xd9_u8, 0x26_u8, 0xf7_u8, 0x21_u8, 0xd0_u8,
|
||||
0x65_u8, 0xa4_u8, 0x29_u8, 0xc1_u8]);
|
||||
|
||||
assert_eq!(super::pbkdf2_hmac_sha1("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,
|
||||
0xe9_u8, 0x94_u8, 0x5b_u8, 0x3d_u8, 0x6b_u8, 0xa2_u8, 0x15_u8, 0x8c_u8,
|
||||
0x26_u8, 0x34_u8, 0xe9_u8, 0x84_u8]);
|
||||
|
||||
assert_eq!(super::pbkdf2_hmac_sha1("passwordPASSWORDpassword",
|
||||
"saltSALTsaltSALTsaltSALTsaltSALTsalt".as_bytes(),
|
||||
assert_eq!(super::pbkdf2_hmac_sha1(b"passwordPASSWORDpassword",
|
||||
b"saltSALTsaltSALTsaltSALTsaltSALTsalt",
|
||||
4096,
|
||||
25),
|
||||
25).unwrap(),
|
||||
vec![0x3d_u8, 0x2e_u8, 0xec_u8, 0x4f_u8, 0xe4_u8, 0x1c_u8, 0x84_u8, 0x9b_u8,
|
||||
0x80_u8, 0xc8_u8, 0xd8_u8, 0x36_u8, 0x62_u8, 0xc0_u8, 0xe4_u8, 0x4a_u8,
|
||||
0x8b_u8, 0x29_u8, 0x1a_u8, 0x96_u8, 0x4c_u8, 0xf2_u8, 0xf0_u8, 0x70_u8,
|
||||
0x38_u8]);
|
||||
|
||||
assert_eq!(super::pbkdf2_hmac_sha1("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,
|
||||
0xcc_u8, 0x37_u8, 0xd7_u8, 0xf0_u8, 0x34_u8, 0x25_u8, 0xe0_u8, 0xc3_u8]);
|
||||
}
|
||||
|
|
@ -186,11 +164,11 @@ mod tests {
|
|||
#[test]
|
||||
#[cfg(feature = "pkcs5_pbkdf2_hmac")]
|
||||
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,
|
||||
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,
|
||||
0x83_u8, 0x0c_u8, 0xee_u8, 0x5e_u8, 0xf2_u8, 0x27_u8, 0x01_u8, 0xf9_u8]);
|
||||
}
|
||||
|
|
@ -200,7 +178,7 @@ mod tests {
|
|||
#[test]
|
||||
#[cfg(feature = "pkcs5_pbkdf2_hmac")]
|
||||
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,
|
||||
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,
|
||||
|
|
@ -210,7 +188,7 @@ mod tests {
|
|||
0x60_u8, 0x60_u8, 0xa0_u8, 0x9f_u8, 0x76_u8, 0x41_u8, 0x5e_u8, 0x9f_u8,
|
||||
0x71_u8, 0xea_u8, 0x47_u8, 0xf9_u8, 0xe9_u8, 0x06_u8, 0x43_u8, 0x06_u8]);
|
||||
|
||||
assert_eq!(super::pbkdf2_hmac_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,
|
||||
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,
|
||||
|
|
@ -220,10 +198,11 @@ mod tests {
|
|||
0xb2_u8, 0x0f_u8, 0x06_u8, 0xbc_u8, 0x53_u8, 0x5e_u8, 0x5a_u8, 0xb5_u8,
|
||||
0x44_u8, 0x0d_u8, 0xf7_u8, 0xe8_u8, 0x78_u8, 0x29_u8, 0x6f_u8, 0xa7_u8]);
|
||||
|
||||
assert_eq!(super::pbkdf2_hmac_sha512("passwordPASSWORDpassword",
|
||||
"salt\0\0\0".as_bytes(),
|
||||
assert_eq!(super::pbkdf2_hmac(b"passwordPASSWORDpassword",
|
||||
b"salt\0\0\0",
|
||||
50,
|
||||
64),
|
||||
hash::Type::SHA512,
|
||||
64).unwrap(),
|
||||
vec![0x01_u8, 0x68_u8, 0x71_u8, 0xa4_u8, 0xc4_u8, 0xb7_u8, 0x5f_u8, 0x96_u8,
|
||||
0x85_u8, 0x7f_u8, 0xd2_u8, 0xb9_u8, 0xf8_u8, 0xca_u8, 0x28_u8, 0x02_u8,
|
||||
0x3b_u8, 0x30_u8, 0xee_u8, 0x2a_u8, 0x39_u8, 0xf5_u8, 0xad_u8, 0xca_u8,
|
||||
|
|
@ -257,7 +236,7 @@ mod tests {
|
|||
hash::Type::SHA1,
|
||||
&data,
|
||||
Some(&salt),
|
||||
1),
|
||||
1).unwrap(),
|
||||
super::KeyIvPair {
|
||||
key: expected_key,
|
||||
iv: expected_iv,
|
||||
|
|
|
|||
|
|
@ -1,260 +1,107 @@
|
|||
use libc::{c_int, c_uint, c_ulong};
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::iter::repeat;
|
||||
use std::mem;
|
||||
use libc::{c_void, c_char};
|
||||
use std::ptr;
|
||||
use bio::MemBio;
|
||||
|
||||
use crypto::HashTypeInternals;
|
||||
use crypto::hash;
|
||||
use crypto::hash::Type as HashType;
|
||||
use std::mem;
|
||||
use ffi;
|
||||
use ssl::error::{SslError, StreamError};
|
||||
|
||||
use bio::{MemBio, MemBioSlice};
|
||||
use crypto::rsa::RSA;
|
||||
use error::ErrorStack;
|
||||
use crypto::util::{CallbackState, invoke_passwd_cb};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
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,
|
||||
}
|
||||
pub struct PKey(*mut ffi::EVP_PKEY);
|
||||
|
||||
unsafe impl Send for PKey {}
|
||||
unsafe impl Sync for PKey {}
|
||||
|
||||
/// Represents a public key, optionally with a private key attached.
|
||||
impl PKey {
|
||||
pub fn new() -> PKey {
|
||||
/// Create a new `PKey` containing an RSA key.
|
||||
pub fn from_rsa(rsa: RSA) -> Result<PKey, ErrorStack> {
|
||||
unsafe {
|
||||
ffi::init();
|
||||
|
||||
PKey {
|
||||
evp: ffi::EVP_PKEY_new(),
|
||||
parts: Parts::Neither,
|
||||
}
|
||||
let evp = try_ssl_null!(ffi::EVP_PKEY_new());
|
||||
let pkey = PKey(evp);
|
||||
try_ssl!(ffi::EVP_PKEY_assign(pkey.0, ffi::EVP_PKEY_RSA, rsa.as_ptr() as *mut _));
|
||||
mem::forget(rsa);
|
||||
Ok(pkey)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_handle(handle: *mut ffi::EVP_PKEY, parts: Parts) -> PKey {
|
||||
ffi::init();
|
||||
assert!(!handle.is_null());
|
||||
|
||||
PKey {
|
||||
evp: handle,
|
||||
parts: parts,
|
||||
}
|
||||
pub unsafe fn from_ptr(handle: *mut ffi::EVP_PKEY) -> PKey {
|
||||
PKey(handle)
|
||||
}
|
||||
|
||||
/// Reads private key from PEM, takes ownership of handle
|
||||
pub fn private_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError>
|
||||
where R: Read
|
||||
{
|
||||
let mut mem_bio = try!(MemBio::new());
|
||||
try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
|
||||
|
||||
pub fn private_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
|
||||
ffi::init();
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.get_handle(),
|
||||
let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut()));
|
||||
Ok(PKey {
|
||||
evp: evp as *mut ffi::EVP_PKEY,
|
||||
parts: Parts::Both,
|
||||
})
|
||||
Ok(PKey::from_ptr(evp))
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a private key from PEM, supplying a password callback to be invoked if the private key
|
||||
/// is encrypted.
|
||||
///
|
||||
/// The callback will be passed the password buffer and should return the number of characters
|
||||
/// placed into the buffer.
|
||||
pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<PKey, ErrorStack>
|
||||
where F: FnOnce(&mut [c_char]) -> usize
|
||||
{
|
||||
ffi::init();
|
||||
let mut cb = CallbackState::new(pass_cb);
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
Some(invoke_passwd_cb::<F>),
|
||||
&mut cb as *mut _ as *mut c_void));
|
||||
Ok(PKey::from_ptr(evp))
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads public key from PEM, takes ownership of handle
|
||||
pub fn public_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError>
|
||||
where R: Read
|
||||
{
|
||||
let mut mem_bio = try!(MemBio::new());
|
||||
try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
|
||||
|
||||
pub fn public_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
|
||||
ffi::init();
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let evp = try_ssl_null!(ffi::PEM_read_bio_PUBKEY(mem_bio.get_handle(),
|
||||
let evp = try_ssl_null!(ffi::PEM_read_bio_PUBKEY(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut()));
|
||||
Ok(PKey {
|
||||
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;
|
||||
Ok(PKey::from_ptr(evp))
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
// this needs to be a reference as the set1_RSA ups the reference count
|
||||
let rsa_ptr = rsa.as_ptr();
|
||||
if ffi::EVP_PKEY_set1_RSA(self.evp, rsa_ptr) == 1 {
|
||||
if rsa.has_e() && rsa.has_n() {
|
||||
self.parts = Parts::Public;
|
||||
}
|
||||
}
|
||||
try_ssl!(ffi::EVP_PKEY_set1_RSA(self.0, rsa_ptr));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// get a reference to the interal RSA key for direct access to the key components
|
||||
pub fn get_rsa(&self) -> RSA {
|
||||
/// Get a reference to the interal RSA key for direct access to the key components
|
||||
pub fn get_rsa(&self) -> Result<RSA, ErrorStack> {
|
||||
unsafe {
|
||||
let 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
|
||||
RSA::from_raw(ffi::EVP_PKEY_get1_RSA(evp_pkey))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
Ok(RSA::from_ptr(rsa))
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores private key as a PEM
|
||||
// FIXME: also add password and encryption
|
||||
pub fn write_pem<W: Write>(&self,
|
||||
writer: &mut W /* , password: Option<String> */)
|
||||
-> Result<(), SslError> {
|
||||
let mut mem_bio = try!(MemBio::new());
|
||||
pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
unsafe {
|
||||
try_ssl!(ffi::PEM_write_bio_PrivateKey(mem_bio.get_handle(),
|
||||
self.evp,
|
||||
try_ssl!(ffi::PEM_write_bio_PrivateKey(mem_bio.as_ptr(),
|
||||
self.0,
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
-1,
|
||||
|
|
@ -262,635 +109,58 @@ impl PKey {
|
|||
ptr::null_mut()));
|
||||
|
||||
}
|
||||
let mut buf = vec![];
|
||||
try!(mem_bio.read_to_end(&mut buf).map_err(StreamError));
|
||||
writer.write_all(&buf).map_err(StreamError)
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
/// Stores public key as a PEM
|
||||
pub fn write_pub_pem<W: Write>(&self,
|
||||
writer: &mut W /* , password: Option<String> */)
|
||||
-> Result<(), SslError> {
|
||||
let mut mem_bio = try!(MemBio::new());
|
||||
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 public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
unsafe { try_ssl!(ffi::PEM_write_bio_PUBKEY(mem_bio.as_ptr(), self.0)) }
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the public key modulus.
|
||||
*/
|
||||
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 as_ptr(&self) -> *mut ffi::EVP_PKEY {
|
||||
return self.0;
|
||||
}
|
||||
|
||||
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 {
|
||||
fn drop(&mut self) {
|
||||
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)]
|
||||
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]
|
||||
fn test_private_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_key_from_pem(&mut file).unwrap();
|
||||
let key = include_bytes!("../../test/key.pem");
|
||||
super::PKey::private_key_from_pem(key).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_public_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_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));
|
||||
let key = include_bytes!("../../test/key.pem.pub");
|
||||
super::PKey::public_key_from_pem(key).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pem() {
|
||||
let key_path = Path::new("test/key.pem");
|
||||
let mut file = File::open(&key_path)
|
||||
.ok()
|
||||
.expect("Failed to open `test/key.pem`");
|
||||
let key = include_bytes!("../../test/key.pem");
|
||||
let key = super::PKey::private_key_from_pem(key).unwrap();
|
||||
|
||||
let key = super::PKey::private_key_from_pem(&mut file).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();
|
||||
let priv_key = key.private_key_to_pem().unwrap();
|
||||
let pub_key = key.public_key_to_pem().unwrap();
|
||||
|
||||
// As a super-simple verification, just check that the buffers contain
|
||||
// the `PRIVATE KEY` or `PUBLIC KEY` strings.
|
||||
assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY"));
|
||||
assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY"));
|
||||
}
|
||||
|
||||
#[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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,13 @@
|
|||
use libc::c_int;
|
||||
use ffi;
|
||||
use error::ErrorStack;
|
||||
|
||||
pub fn rand_bytes(len: usize) -> Vec<u8> {
|
||||
pub fn rand_bytes(buf: &mut [u8]) -> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
let mut out = Vec::with_capacity(len);
|
||||
|
||||
ffi::init();
|
||||
let r = ffi::RAND_bytes(out.as_mut_ptr(), len as c_int);
|
||||
if r != 1 as c_int {
|
||||
panic!()
|
||||
}
|
||||
|
||||
out.set_len(len);
|
||||
|
||||
out
|
||||
assert!(buf.len() <= c_int::max_value() as usize);
|
||||
try_ssl_if!(ffi::RAND_bytes(buf.as_mut_ptr(), buf.len() as c_int) != 1);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -23,7 +17,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_rand_bytes() {
|
||||
let bytes = rand_bytes(32);
|
||||
println!("{:?}", bytes);
|
||||
let mut buf = [0; 32];
|
||||
rand_bytes(&mut buf).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
use ffi;
|
||||
use std::fmt;
|
||||
use ssl::error::{SslError, StreamError};
|
||||
use std::ptr;
|
||||
use std::io::{self, Read, Write};
|
||||
use libc::c_int;
|
||||
use std::mem;
|
||||
use libc::{c_int, c_void, c_char, c_ulong};
|
||||
|
||||
use bn::BigNum;
|
||||
use bio::MemBio;
|
||||
use crypto::HashTypeInternals;
|
||||
use bn::{BigNum, BigNumRef};
|
||||
use bio::{MemBio, MemBioSlice};
|
||||
use error::ErrorStack;
|
||||
use HashTypeInternals;
|
||||
use crypto::hash;
|
||||
use crypto::util::{CallbackState, invoke_passwd_cb};
|
||||
|
||||
pub struct RSA(*mut ffi::RSA);
|
||||
|
||||
|
|
@ -23,11 +24,13 @@ impl Drop for RSA {
|
|||
impl RSA {
|
||||
/// only useful for associating the key material directly with the key, it's safer to use
|
||||
/// the supplied load and save methods for DER formatted keys.
|
||||
pub fn from_public_components(n: BigNum, e: BigNum) -> Result<RSA, SslError> {
|
||||
pub fn from_public_components(n: BigNum, e: BigNum) -> Result<RSA, ErrorStack> {
|
||||
unsafe {
|
||||
let rsa = try_ssl_null!(ffi::RSA_new());
|
||||
(*rsa).n = n.into_raw();
|
||||
(*rsa).e = e.into_raw();
|
||||
(*rsa).n = n.as_ptr();
|
||||
(*rsa).e = e.as_ptr();
|
||||
mem::forget(n);
|
||||
mem::forget(e);
|
||||
Ok(RSA(rsa))
|
||||
}
|
||||
}
|
||||
|
|
@ -40,35 +43,83 @@ impl RSA {
|
|||
dp: BigNum,
|
||||
dq: BigNum,
|
||||
qi: BigNum)
|
||||
-> Result<RSA, SslError> {
|
||||
-> Result<RSA, ErrorStack> {
|
||||
unsafe {
|
||||
let rsa = try_ssl_null!(ffi::RSA_new());
|
||||
(*rsa).n = n.into_raw();
|
||||
(*rsa).e = e.into_raw();
|
||||
(*rsa).d = d.into_raw();
|
||||
(*rsa).p = p.into_raw();
|
||||
(*rsa).q = q.into_raw();
|
||||
(*rsa).dmp1 = dp.into_raw();
|
||||
(*rsa).dmq1 = dq.into_raw();
|
||||
(*rsa).iqmp = qi.into_raw();
|
||||
(*rsa).n = n.as_ptr();
|
||||
(*rsa).e = e.as_ptr();
|
||||
(*rsa).d = d.as_ptr();
|
||||
(*rsa).p = p.as_ptr();
|
||||
(*rsa).q = q.as_ptr();
|
||||
(*rsa).dmp1 = dp.as_ptr();
|
||||
(*rsa).dmq1 = dq.as_ptr();
|
||||
(*rsa).iqmp = qi.as_ptr();
|
||||
mem::forget(n);
|
||||
mem::forget(e);
|
||||
mem::forget(d);
|
||||
mem::forget(p);
|
||||
mem::forget(q);
|
||||
mem::forget(dp);
|
||||
mem::forget(dq);
|
||||
mem::forget(qi);
|
||||
Ok(RSA(rsa))
|
||||
}
|
||||
}
|
||||
|
||||
/// the caller should assert that the rsa pointer is valid.
|
||||
pub unsafe fn from_raw(rsa: *mut ffi::RSA) -> RSA {
|
||||
pub unsafe fn from_ptr(rsa: *mut ffi::RSA) -> RSA {
|
||||
RSA(rsa)
|
||||
}
|
||||
|
||||
/// Generates a public/private key pair with the specified size.
|
||||
///
|
||||
/// The public exponent will be 65537.
|
||||
pub fn generate(bits: u32) -> Result<RSA, ErrorStack> {
|
||||
unsafe {
|
||||
let rsa = try_ssl_null!(ffi::RSA_new());
|
||||
let rsa = RSA(rsa);
|
||||
let e = try!(BigNum::new_from(ffi::RSA_F4 as c_ulong));
|
||||
|
||||
try_ssl!(ffi::RSA_generate_key_ex(rsa.0, bits as c_int, e.as_ptr(), ptr::null_mut()));
|
||||
|
||||
Ok(rsa)
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads an RSA private key from PEM formatted data.
|
||||
pub fn private_key_from_pem<R>(reader: &mut R) -> Result<RSA, SslError>
|
||||
where R: Read
|
||||
pub fn private_key_from_pem(buf: &[u8]) -> Result<RSA, ErrorStack> {
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut()));
|
||||
Ok(RSA(rsa))
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads an RSA private key from PEM formatted data and supplies a password callback.
|
||||
pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<RSA, ErrorStack>
|
||||
where F: FnOnce(&mut [c_char]) -> usize
|
||||
{
|
||||
let mut mem_bio = try!(MemBio::new());
|
||||
try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
|
||||
let mut cb = CallbackState::new(pass_cb);
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
|
||||
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(),
|
||||
None,
|
||||
ptr::null_mut()));
|
||||
|
|
@ -77,137 +128,126 @@ impl RSA {
|
|||
}
|
||||
|
||||
/// Writes an RSA private key as unencrypted PEM formatted data
|
||||
pub fn private_key_to_pem<W>(&self, writer: &mut W) -> Result<(), SslError>
|
||||
where W: Write
|
||||
{
|
||||
let mut mem_bio = try!(MemBio::new());
|
||||
pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
|
||||
let result = unsafe {
|
||||
ffi::PEM_write_bio_RSAPrivateKey(mem_bio.get_handle(),
|
||||
unsafe {
|
||||
try_ssl!(ffi::PEM_write_bio_RSAPrivateKey(mem_bio.as_ptr(),
|
||||
self.0,
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
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()));
|
||||
Ok(RSA(rsa))
|
||||
}
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
/// Writes an RSA public key as PEM formatted data
|
||||
pub fn public_key_to_pem<W>(&self, writer: &mut W) -> Result<(), SslError>
|
||||
where W: Write
|
||||
{
|
||||
let mut mem_bio = try!(MemBio::new());
|
||||
pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let 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 {
|
||||
try!(io::copy(&mut mem_bio, writer).map_err(StreamError));
|
||||
Ok(mem_bio.get_buf().to_owned())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
pub fn size(&self) -> Option<u32> {
|
||||
if self.n().is_some() {
|
||||
unsafe { Some(ffi::RSA_size(self.0) as u32) }
|
||||
} else {
|
||||
Err(SslError::OpenSslErrors(vec![]))
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> Result<u32, SslError> {
|
||||
if self.has_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];
|
||||
pub fn sign(&self, hash: hash::Type, message: &[u8]) -> Result<Vec<u8>, ErrorStack> {
|
||||
let k_len = self.size().expect("RSA missing an n");
|
||||
let mut sig = vec![0; k_len as usize];
|
||||
let mut sig_len = k_len;
|
||||
|
||||
unsafe {
|
||||
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.len() as u32,
|
||||
sig.as_mut_ptr(),
|
||||
&mut sig_len,
|
||||
self.0);
|
||||
self.0));
|
||||
assert!(sig_len == k_len);
|
||||
|
||||
if result == 1 {
|
||||
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 {
|
||||
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.len() as u32,
|
||||
sig.as_ptr(),
|
||||
sig.len() as u32,
|
||||
self.0);
|
||||
|
||||
Ok(result == 1)
|
||||
self.0));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *mut ffi::RSA {
|
||||
self.0
|
||||
}
|
||||
|
||||
// The following getters are unsafe, since BigNum::new_from_ffi fails upon null pointers
|
||||
pub fn n(&self) -> Result<BigNum, SslError> {
|
||||
unsafe { BigNum::new_from_ffi((*self.0).n) }
|
||||
pub fn n<'a>(&'a self) -> Option<BigNumRef<'a>> {
|
||||
unsafe {
|
||||
let n = (*self.0).n;
|
||||
if n.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(n))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_n(&self) -> bool {
|
||||
unsafe { !(*self.0).n.is_null() }
|
||||
pub fn d<'a>(&self) -> Option<BigNumRef<'a>> {
|
||||
unsafe {
|
||||
let d = (*self.0).d;
|
||||
if d.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(d))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn d(&self) -> Result<BigNum, SslError> {
|
||||
unsafe { BigNum::new_from_ffi((*self.0).d) }
|
||||
pub fn e<'a>(&'a self) -> Option<BigNumRef<'a>> {
|
||||
unsafe {
|
||||
let e = (*self.0).e;
|
||||
if e.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn e(&self) -> Result<BigNum, SslError> {
|
||||
unsafe { BigNum::new_from_ffi((*self.0).e) }
|
||||
pub fn p<'a>(&'a self) -> Option<BigNumRef<'a>> {
|
||||
unsafe {
|
||||
let p = (*self.0).p;
|
||||
if p.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(p))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_e(&self) -> bool {
|
||||
unsafe { !(*self.0).e.is_null() }
|
||||
pub fn q<'a>(&'a self) -> Option<BigNumRef<'a>> {
|
||||
unsafe {
|
||||
let q = (*self.0).q;
|
||||
if q.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(BigNumRef::from_ptr(q))
|
||||
}
|
||||
|
||||
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)]
|
||||
mod test {
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use libc::c_char;
|
||||
|
||||
use super::*;
|
||||
use crypto::hash::*;
|
||||
|
||||
|
|
@ -252,12 +293,12 @@ mod test {
|
|||
|
||||
#[test]
|
||||
pub fn test_sign() {
|
||||
let mut buffer = File::open("test/rsa.pem").unwrap();
|
||||
let private_key = RSA::private_key_from_pem(&mut buffer).unwrap();
|
||||
let key = include_bytes!("../../test/rsa.pem");
|
||||
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();
|
||||
let digest = sha.finish();
|
||||
let digest = sha.finish().unwrap();
|
||||
|
||||
let result = private_key.sign(Type::SHA256, &digest).unwrap();
|
||||
|
||||
|
|
@ -266,15 +307,31 @@ mod test {
|
|||
|
||||
#[test]
|
||||
pub fn test_verify() {
|
||||
let mut buffer = File::open("test/rsa.pem.pub").unwrap();
|
||||
let public_key = RSA::public_key_from_pem(&mut buffer).unwrap();
|
||||
let key = include_bytes!("../../test/rsa.pem.pub");
|
||||
let public_key = RSA::public_key_from_pem(key).unwrap();
|
||||
|
||||
let mut sha = Hasher::new(Type::SHA256);
|
||||
let mut sha = Hasher::new(Type::SHA256).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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use std::iter::repeat;
|
||||
use std::cmp;
|
||||
use std::ptr;
|
||||
use libc::c_int;
|
||||
|
||||
use crypto::symm_internal::evpc;
|
||||
use ffi;
|
||||
|
||||
use error::ErrorStack;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Mode {
|
||||
Encrypt,
|
||||
|
|
@ -43,94 +44,184 @@ pub enum Type {
|
|||
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.
|
||||
pub struct Crypter {
|
||||
evp: *const ffi::EVP_CIPHER,
|
||||
ctx: *mut ffi::EVP_CIPHER_CTX,
|
||||
keylen: u32,
|
||||
blocksize: u32,
|
||||
block_size: usize,
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
let ctx = unsafe { ffi::EVP_CIPHER_CTX_new() };
|
||||
let (evp, keylen, blocksz) = evpc(t);
|
||||
Crypter {
|
||||
evp: evp,
|
||||
unsafe {
|
||||
let ctx = try_ssl_null!(ffi::EVP_CIPHER_CTX_new());
|
||||
let crypter = Crypter {
|
||||
ctx: ctx,
|
||||
keylen: keylen,
|
||||
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
|
||||
block_size: t.block_size(),
|
||||
};
|
||||
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 {
|
||||
Mode::Encrypt => 1 as c_int,
|
||||
Mode::Decrypt => 0 as c_int,
|
||||
Mode::Encrypt => 1,
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this crypter with more data to encrypt or decrypt. Returns
|
||||
* encrypted or decrypted bytes.
|
||||
*/
|
||||
pub fn update(&self, data: &[u8]) -> Vec<u8> {
|
||||
/// Enables or disables padding.
|
||||
///
|
||||
/// If padding is disabled, total amount of data encrypted/decrypted must
|
||||
/// be a multiple of the cipher's block size.
|
||||
pub fn pad(&mut self, padding: bool) {
|
||||
unsafe { ffi::EVP_CIPHER_CTX_set_padding(self.ctx, padding as c_int); }
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
let sum = data.len() + (self.blocksize as usize);
|
||||
let mut res = repeat(0u8).take(sum).collect::<Vec<_>>();
|
||||
let mut reslen = sum as c_int;
|
||||
assert!(output.len() >= input.len() + self.block_size);
|
||||
assert!(output.len() <= c_int::max_value() as usize);
|
||||
let mut outl = output.len() as c_int;
|
||||
let inl = input.len() as c_int;
|
||||
|
||||
ffi::EVP_CipherUpdate(self.ctx,
|
||||
res.as_mut_ptr(),
|
||||
&mut reslen,
|
||||
data.as_ptr(),
|
||||
data.len() as c_int);
|
||||
try_ssl!(ffi::EVP_CipherUpdate(self.ctx,
|
||||
output.as_mut_ptr(),
|
||||
&mut outl,
|
||||
input.as_ptr(),
|
||||
inl));
|
||||
|
||||
res.truncate(reslen as usize);
|
||||
res
|
||||
Ok(outl as usize)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish crypting. Returns the remaining partial block of output, if any.
|
||||
*/
|
||||
pub fn finalize(&self) -> Vec<u8> {
|
||||
/// Finishes the encryption/decryption process, writing any remaining data
|
||||
/// to `output`.
|
||||
///
|
||||
/// 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 {
|
||||
let mut res = repeat(0u8).take(self.blocksize as usize).collect::<Vec<_>>();
|
||||
let mut reslen = self.blocksize as c_int;
|
||||
assert!(output.len() >= self.block_size);
|
||||
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);
|
||||
res
|
||||
Ok(outl as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -147,31 +238,43 @@ impl Drop for Crypter {
|
|||
* Encrypts data, using the specified crypter type in encrypt mode with the
|
||||
* specified key and iv; returns the resulting (encrypted) data.
|
||||
*/
|
||||
pub fn encrypt(t: Type, key: &[u8], iv: &[u8], data: &[u8]) -> Vec<u8> {
|
||||
let c = Crypter::new(t);
|
||||
c.init(Mode::Encrypt, key, iv);
|
||||
let mut r = c.update(data);
|
||||
let rest = c.finalize();
|
||||
r.extend(rest.into_iter());
|
||||
r
|
||||
pub fn encrypt(t: Type,
|
||||
key: &[u8],
|
||||
iv: Option<&[u8]>,
|
||||
data: &[u8])
|
||||
-> Result<Vec<u8>, ErrorStack> {
|
||||
cipher(t, Mode::Encrypt, key, iv, data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts data, using the specified crypter type in decrypt mode with the
|
||||
* specified key and iv; returns the resulting (decrypted) data.
|
||||
*/
|
||||
pub fn decrypt(t: Type, key: &[u8], iv: &[u8], data: &[u8]) -> Vec<u8> {
|
||||
let c = Crypter::new(t);
|
||||
c.init(Mode::Decrypt, key, iv);
|
||||
let mut r = c.update(data);
|
||||
let rest = c.finalize();
|
||||
r.extend(rest.into_iter());
|
||||
r
|
||||
pub fn decrypt(t: Type,
|
||||
key: &[u8],
|
||||
iv: Option<&[u8]>,
|
||||
data: &[u8])
|
||||
-> Result<Vec<u8>, ErrorStack> {
|
||||
cipher(t, Mode::Decrypt, key, iv, data)
|
||||
}
|
||||
|
||||
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)]
|
||||
mod tests {
|
||||
use serialize::hex::FromHex;
|
||||
use serialize::hex::{FromHex, ToHex};
|
||||
|
||||
// Test vectors from FIPS-197:
|
||||
// http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
|
||||
|
|
@ -185,25 +288,33 @@ mod tests {
|
|||
0xaau8, 0xbbu8, 0xccu8, 0xddu8, 0xeeu8, 0xffu8];
|
||||
let c0 = [0x8eu8, 0xa2u8, 0xb7u8, 0xcau8, 0x51u8, 0x67u8, 0x45u8, 0xbfu8, 0xeau8, 0xfcu8,
|
||||
0x49u8, 0x90u8, 0x4bu8, 0x49u8, 0x60u8, 0x89u8];
|
||||
let c = super::Crypter::new(super::Type::AES_256_ECB);
|
||||
c.init(super::Mode::Encrypt, &k0, &[]);
|
||||
let mut c = super::Crypter::new(super::Type::AES_256_ECB,
|
||||
super::Mode::Encrypt,
|
||||
&k0,
|
||||
None).unwrap();
|
||||
c.pad(false);
|
||||
let mut r0 = c.update(&p0);
|
||||
r0.extend(c.finalize().into_iter());
|
||||
assert!(r0 == c0);
|
||||
c.init(super::Mode::Decrypt, &k0, &[]);
|
||||
let mut r0 = vec![0; c0.len() + super::Type::AES_256_ECB.block_size()];
|
||||
let count = c.update(&p0, &mut r0).unwrap();
|
||||
let rest = c.finalize(&mut r0[count..]).unwrap();
|
||||
r0.truncate(count + rest);
|
||||
assert_eq!(r0.to_hex(), c0.to_hex());
|
||||
|
||||
let mut c = super::Crypter::new(super::Type::AES_256_ECB,
|
||||
super::Mode::Decrypt,
|
||||
&k0,
|
||||
None).unwrap();
|
||||
c.pad(false);
|
||||
let mut p1 = c.update(&r0);
|
||||
p1.extend(c.finalize().into_iter());
|
||||
assert!(p1 == p0);
|
||||
let mut p1 = vec![0; r0.len() + super::Type::AES_256_ECB.block_size()];
|
||||
let count = c.update(&r0, &mut p1).unwrap();
|
||||
let rest = c.finalize(&mut p1[count..]).unwrap();
|
||||
p1.truncate(count + rest);
|
||||
assert_eq!(p1.to_hex(), p0.to_hex());
|
||||
}
|
||||
|
||||
#[test]
|
||||
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,
|
||||
98_u8, 107_u8, 208_u8, 14_u8, 236_u8, 60_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8,
|
||||
0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8];
|
||||
98_u8, 107_u8, 208_u8, 14_u8, 236_u8, 60_u8];
|
||||
let data = [143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8, 241_u8, 242_u8, 31_u8,
|
||||
154_u8, 56_u8, 198_u8, 145_u8, 192_u8, 64_u8, 2_u8, 245_u8, 167_u8, 220_u8,
|
||||
55_u8, 119_u8, 233_u8, 136_u8, 139_u8, 27_u8, 71_u8, 242_u8, 119_u8, 175_u8,
|
||||
|
|
@ -211,29 +322,31 @@ mod tests {
|
|||
let ciphered_data = [0x4a_u8, 0x2e_u8, 0xe5_u8, 0x6_u8, 0xbf_u8, 0xcf_u8, 0xf2_u8,
|
||||
0xd7_u8, 0xea_u8, 0x2d_u8, 0xb1_u8, 0x85_u8, 0x6c_u8, 0x93_u8,
|
||||
0x65_u8, 0x6f_u8];
|
||||
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);
|
||||
let unciphered_data_1 = cr.update(&ciphered_data);
|
||||
let unciphered_data_2 = cr.finalize();
|
||||
let mut unciphered_data = vec![0; data.len() + super::Type::AES_256_CBC.block_size()];
|
||||
let count = cr.update(&ciphered_data, &mut unciphered_data).unwrap();
|
||||
let rest = cr.finalize(&mut unciphered_data[count..]).unwrap();
|
||||
unciphered_data.truncate(count + rest);
|
||||
|
||||
let expected_unciphered_data = b"I love turtles.\x01";
|
||||
|
||||
assert!(unciphered_data_2.len() == 0);
|
||||
|
||||
assert_eq!(&unciphered_data_1, expected_unciphered_data);
|
||||
assert_eq!(&unciphered_data, expected_unciphered_data);
|
||||
}
|
||||
|
||||
fn cipher_test(ciphertype: super::Type, pt: &str, ct: &str, key: &str, iv: &str) {
|
||||
use serialize::hex::ToHex;
|
||||
|
||||
let cipher = super::Crypter::new(ciphertype);
|
||||
cipher.init(super::Mode::Encrypt,
|
||||
&key.from_hex().unwrap(),
|
||||
&iv.from_hex().unwrap());
|
||||
let pt = pt.from_hex().unwrap();
|
||||
let ct = ct.from_hex().unwrap();
|
||||
let key = key.from_hex().unwrap();
|
||||
let iv = iv.from_hex().unwrap();
|
||||
|
||||
let expected = ct.from_hex().unwrap();
|
||||
let mut computed = cipher.update(&pt.from_hex().unwrap());
|
||||
computed.extend(cipher.finalize().into_iter());
|
||||
let computed = super::decrypt(ciphertype, &key, Some(&iv), &ct).unwrap();
|
||||
let expected = pt;
|
||||
|
||||
if computed != expected {
|
||||
println!("Computed: {}", computed.to_hex());
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,78 +1,71 @@
|
|||
use ffi;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use ssl::error::{SslError, StreamError};
|
||||
use bio::MemBio;
|
||||
use bn::BigNum;
|
||||
use std::mem;
|
||||
use error::ErrorStack;
|
||||
use bio::MemBioSlice;
|
||||
use std::ptr;
|
||||
|
||||
#[cfg(feature = "dh_from_params")]
|
||||
use bn::BigNum;
|
||||
#[cfg(feature = "dh_from_params")]
|
||||
use std::mem;
|
||||
|
||||
pub struct DH(*mut ffi::DH);
|
||||
|
||||
impl DH {
|
||||
pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result<DH, SslError> {
|
||||
let dh = try_ssl_null!(unsafe { ffi::DH_new_from_params(p.raw(), g.raw(), q.raw()) });
|
||||
/// Requires the `dh_from_params` feature.
|
||||
#[cfg(feature = "dh_from_params")]
|
||||
pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result<DH, ErrorStack> {
|
||||
let dh = unsafe {
|
||||
try_ssl_null!(::c_helpers::rust_DH_new_from_params(p.as_ptr(), g.as_ptr(), q.as_ptr()))
|
||||
};
|
||||
mem::forget(p);
|
||||
mem::forget(g);
|
||||
mem::forget(q);
|
||||
Ok(DH(dh))
|
||||
}
|
||||
|
||||
pub fn from_pem<R>(reader: &mut R) -> Result<DH, SslError>
|
||||
where R: Read
|
||||
{
|
||||
let mut mem_bio = try!(MemBio::new());
|
||||
try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
|
||||
pub fn from_pem(buf: &[u8]) -> Result<DH, ErrorStack> {
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
let dh = unsafe {
|
||||
ffi::PEM_read_bio_DHparams(mem_bio.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);
|
||||
Ok(DH(dh))
|
||||
}
|
||||
|
||||
#[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() });
|
||||
Ok(DH(dh))
|
||||
}
|
||||
|
||||
#[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() });
|
||||
Ok(DH(dh))
|
||||
}
|
||||
|
||||
#[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() });
|
||||
Ok(DH(dh))
|
||||
}
|
||||
|
||||
pub unsafe fn raw(&self) -> *mut ffi::DH {
|
||||
pub unsafe fn as_ptr(&self) -> *mut ffi::DH {
|
||||
let DH(n) = *self;
|
||||
n
|
||||
}
|
||||
|
||||
pub unsafe fn raw_ptr(&self) -> *const *mut ffi::DH {
|
||||
let DH(ref n) = *self;
|
||||
n
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DH {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if !self.raw().is_null() {
|
||||
ffi::DH_free(self.raw())
|
||||
}
|
||||
ffi::DH_free(self.as_ptr())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
use super::DH;
|
||||
use bn::BigNum;
|
||||
use ssl::SslContext;
|
||||
|
|
@ -81,18 +74,19 @@ mod tests {
|
|||
#[test]
|
||||
#[cfg(feature = "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();
|
||||
ctx.set_tmp_dh(dh1).unwrap();
|
||||
ctx.set_tmp_dh(&dh1).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();
|
||||
ctx.set_tmp_dh(dh3).unwrap();
|
||||
ctx.set_tmp_dh(&dh3).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "dh_from_params")]
|
||||
fn test_dh() {
|
||||
let ctx = SslContext::new(Sslv23).unwrap();
|
||||
let mut ctx = SslContext::new(Sslv23).unwrap();
|
||||
let p = BigNum::from_hex_str("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435\
|
||||
E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF429\
|
||||
6D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C02\
|
||||
|
|
@ -117,17 +111,14 @@ mod tests {
|
|||
5FBD3")
|
||||
.unwrap();
|
||||
let dh = DH::from_params(p, g, q).unwrap();
|
||||
ctx.set_tmp_dh(dh).unwrap();
|
||||
ctx.set_tmp_dh(&dh).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dh_from_pem() {
|
||||
let ctx = SslContext::new(Sslv23).unwrap();
|
||||
let pem_path = Path::new("test/dhparams.pem");
|
||||
let mut file = File::open(&pem_path)
|
||||
.ok()
|
||||
.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();
|
||||
let mut ctx = SslContext::new(Sslv23).unwrap();
|
||||
let params = include_bytes!("../../test/dhparams.pem");
|
||||
let dh = DH::from_pem(params).ok().expect("Failed to load PEM");
|
||||
ctx.set_tmp_dh(&dh).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.14")]
|
||||
#![cfg_attr(feature = "nightly", feature(const_fn))]
|
||||
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.8.0")]
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
|
|
@ -7,7 +6,6 @@ extern crate libc;
|
|||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate openssl_sys as ffi;
|
||||
extern crate openssl_sys_extras as ffi_extras;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate rustc_serialize as serialize;
|
||||
|
|
@ -15,14 +13,27 @@ extern crate rustc_serialize as serialize;
|
|||
#[cfg(test)]
|
||||
extern crate net2;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use ffi::init;
|
||||
|
||||
use nid::Nid;
|
||||
|
||||
mod macros;
|
||||
|
||||
pub mod asn1;
|
||||
mod bio;
|
||||
pub mod bn;
|
||||
pub mod bio;
|
||||
#[cfg(feature = "c_helpers")]
|
||||
mod c_helpers;
|
||||
pub mod crypto;
|
||||
pub mod dh;
|
||||
pub mod ssl;
|
||||
pub mod x509;
|
||||
pub mod error;
|
||||
pub mod nid;
|
||||
pub mod ssl;
|
||||
pub mod version;
|
||||
pub mod x509;
|
||||
|
||||
trait HashTypeInternals {
|
||||
fn as_nid(&self) -> Nid;
|
||||
fn evp_md(&self) -> *const ffi::EVP_MD;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ macro_rules! try_ssl_stream {
|
|||
macro_rules! try_ssl_if {
|
||||
($e:expr) => (
|
||||
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{
|
||||
($e:expr) => ( {
|
||||
if $e {
|
||||
Err(SslError::get())
|
||||
Err(::error::ErrorStack::get().into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
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_extras::{BIO_clear_retry_flags, BIO_set_retry_read, BIO_set_retry_write};
|
||||
use ffi::{self, BIO, BIO_CTRL_FLUSH, BIO_TYPE_NONE, BIO_new, BIO_clear_retry_flags,
|
||||
BIO_set_retry_read, BIO_set_retry_write};
|
||||
use std::any::Any;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
|
|
@ -9,7 +9,7 @@ use std::ptr;
|
|||
use std::slice;
|
||||
use std::sync::Arc;
|
||||
|
||||
use ssl::error::SslError;
|
||||
use error::ErrorStack;
|
||||
|
||||
pub struct StreamState<S> {
|
||||
pub stream: S,
|
||||
|
|
@ -39,7 +39,7 @@ impl 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 state = Box::new(StreamState {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,8 @@
|
|||
pub use self::SslError::*;
|
||||
pub use self::OpensslError::*;
|
||||
|
||||
use libc::c_ulong;
|
||||
use std::error;
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt;
|
||||
use std::ffi::CStr;
|
||||
use std::io;
|
||||
use std::str;
|
||||
|
||||
use ffi;
|
||||
use error::ErrorStack;
|
||||
|
||||
/// An SSL error.
|
||||
#[derive(Debug)]
|
||||
|
|
@ -27,31 +20,17 @@ pub enum Error {
|
|||
/// An error reported by the underlying stream.
|
||||
Stream(io::Error),
|
||||
/// An error in the OpenSSL library.
|
||||
Ssl(Vec<OpenSslError>),
|
||||
Ssl(ErrorStack),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(fmt.write_str(self.description()));
|
||||
match *self {
|
||||
Error::Stream(ref 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;
|
||||
if let Some(err) = self.cause() {
|
||||
write!(fmt, ": {}", err)
|
||||
} else {
|
||||
try!(fmt.write_str(", "));
|
||||
}
|
||||
try!(fmt.write_str(&err.reason()))
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,247 +51,14 @@ impl error::Error for Error {
|
|||
Error::WantRead(ref err) => Some(err),
|
||||
Error::WantWrite(ref err) => Some(err),
|
||||
Error::Stream(ref err) => Some(err),
|
||||
Error::Ssl(ref err) => Some(err),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An error reported from OpenSSL.
|
||||
pub struct OpenSslError(c_ulong);
|
||||
|
||||
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 From<ErrorStack> for Error {
|
||||
fn from(e: ErrorStack) -> Error {
|
||||
Error::Ssl(e)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
|
@ -17,9 +17,9 @@ use crypto::hash::Type::SHA256;
|
|||
use ssl;
|
||||
use ssl::SSL_VERIFY_PEER;
|
||||
use ssl::SslMethod::Sslv23;
|
||||
use ssl::SslMethod;
|
||||
use ssl::error::NonblockingSslError;
|
||||
use ssl::{SslContext, SslStream, VerifyCallback, NonblockingSslStream};
|
||||
use ssl::{SslMethod, HandshakeError};
|
||||
use ssl::error::Error;
|
||||
use ssl::{SslContext, SslStream};
|
||||
use x509::X509StoreContext;
|
||||
use x509::X509FileType;
|
||||
use x509::X509;
|
||||
|
|
@ -133,6 +133,7 @@ impl Drop for Server {
|
|||
}
|
||||
|
||||
#[cfg(feature = "dtlsv1")]
|
||||
#[derive(Debug)]
|
||||
struct UdpConnected(UdpSocket);
|
||||
|
||||
#[cfg(feature = "dtlsv1")]
|
||||
|
|
@ -194,9 +195,9 @@ macro_rules! run_test(
|
|||
use std::net::TcpStream;
|
||||
use ssl;
|
||||
use ssl::SslMethod;
|
||||
use ssl::{SslContext, Ssl, SslStream, VerifyCallback};
|
||||
use ssl::{SslContext, Ssl, SslStream};
|
||||
use ssl::SSL_VERIFY_PEER;
|
||||
use crypto::hash::Type::SHA1;
|
||||
use crypto::hash::Type::{SHA1, SHA256};
|
||||
use x509::X509StoreContext;
|
||||
use serialize::hex::FromHex;
|
||||
use super::Server;
|
||||
|
|
@ -222,19 +223,19 @@ run_test!(new_ctx, |method, _| {
|
|||
});
|
||||
|
||||
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, _| {
|
||||
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| {
|
||||
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"),
|
||||
Err(err) => println!("error {:?}", err),
|
||||
}
|
||||
|
|
@ -242,127 +243,95 @@ run_test!(verify_untrusted, |method, stream| {
|
|||
|
||||
run_test!(verify_trusted, |method, stream| {
|
||||
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")) {
|
||||
Ok(_) => {}
|
||||
Err(err) => panic!("Unexpected error {:?}", err),
|
||||
}
|
||||
match SslStream::connect_generic(&ctx, stream) {
|
||||
match SslStream::connect(&ctx, stream) {
|
||||
Ok(_) => (),
|
||||
Err(err) => panic!("Expected success, got {:?}", err),
|
||||
}
|
||||
});
|
||||
|
||||
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();
|
||||
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(_) => (),
|
||||
Err(err) => panic!("Expected success, got {:?}", err),
|
||||
}
|
||||
});
|
||||
|
||||
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();
|
||||
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| {
|
||||
fn callback(_preverify_ok: bool, _x509_ctx: &X509StoreContext) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
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")) {
|
||||
Ok(_) => {}
|
||||
Err(err) => panic!("Unexpected error {:?}", err),
|
||||
}
|
||||
match SslStream::connect_generic(&ctx, stream) {
|
||||
match SslStream::connect(&ctx, stream) {
|
||||
Ok(_) => (),
|
||||
Err(err) => panic!("Expected success, got {:?}", err),
|
||||
}
|
||||
});
|
||||
|
||||
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();
|
||||
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")) {
|
||||
Ok(_) => {}
|
||||
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| {
|
||||
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();
|
||||
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| {
|
||||
fn callback(_preverify_ok: bool, x509_ctx: &X509StoreContext) -> bool {
|
||||
assert!(x509_ctx.get_error().is_none());
|
||||
true
|
||||
}
|
||||
|
||||
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")) {
|
||||
Ok(_) => {}
|
||||
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| {
|
||||
fn callback(_preverify_ok: bool, x509_ctx: &X509StoreContext) -> bool {
|
||||
assert!(x509_ctx.get_error().is_some());
|
||||
false
|
||||
}
|
||||
|
||||
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| {
|
||||
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();
|
||||
|
||||
// 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
|
||||
let node_hash_str = "E19427DAC79FBE758394945276A6E4F15F0BEBE6";
|
||||
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);
|
||||
|
||||
match SslStream::connect_generic(&ctx, stream) {
|
||||
match SslStream::connect(&ctx, stream) {
|
||||
Ok(_) => (),
|
||||
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();
|
||||
ssl.set_verify_callback(SSL_VERIFY_PEER, move |_, x509| {
|
||||
CHECKED.store(1, Ordering::SeqCst);
|
||||
match x509.get_current_cert() {
|
||||
match x509.current_cert() {
|
||||
None => false,
|
||||
Some(cert) => {
|
||||
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(_) => (),
|
||||
Err(err) => panic!("Expected success, got {:?}", err),
|
||||
}
|
||||
|
|
@ -419,14 +397,14 @@ fn test_write_hits_stream() {
|
|||
let guard = thread::spawn(move || {
|
||||
let ctx = SslContext::new(Sslv23).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
|
||||
});
|
||||
|
||||
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_private_key_file(&Path::new("test/key.pem"), X509FileType::PEM).unwrap();
|
||||
let stream = listener.accept().unwrap().0;
|
||||
|
|
@ -440,17 +418,10 @@ fn test_write_hits_stream() {
|
|||
|
||||
#[test]
|
||||
fn test_set_certificate_and_private_key() {
|
||||
let key_path = Path::new("test/key.pem");
|
||||
let cert_path = Path::new("test/cert.pem");
|
||||
let mut key_file = File::open(&key_path)
|
||||
.ok()
|
||||
.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 key = include_bytes!("../../../test/key.pem");
|
||||
let key = PKey::private_key_from_pem(key).unwrap();
|
||||
let cert = include_bytes!("../../../test/cert.pem");
|
||||
let cert = X509::from_pem(cert).unwrap();
|
||||
|
||||
let mut ctx = SslContext::new(Sslv23).unwrap();
|
||||
ctx.set_private_key(&key).unwrap();
|
||||
|
|
@ -460,8 +431,8 @@ fn test_set_certificate_and_private_key() {
|
|||
}
|
||||
|
||||
run_test!(get_ctx_options, |method, _| {
|
||||
let mut ctx = SslContext::new(method).unwrap();
|
||||
ctx.get_options();
|
||||
let ctx = SslContext::new(method).unwrap();
|
||||
ctx.options();
|
||||
});
|
||||
|
||||
run_test!(set_ctx_options, |method, _| {
|
||||
|
|
@ -480,7 +451,7 @@ run_test!(clear_ctx_options, |method, _| {
|
|||
#[test]
|
||||
fn test_write() {
|
||||
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.flush().unwrap();
|
||||
stream.write_all(" there".as_bytes()).unwrap();
|
||||
|
|
@ -498,7 +469,7 @@ fn test_write_direct() {
|
|||
}
|
||||
|
||||
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 fingerprint = cert.fingerprint(SHA1).unwrap();
|
||||
let node_hash_str = "E19427DAC79FBE758394945276A6E4F15F0BEBE6";
|
||||
|
|
@ -511,7 +482,7 @@ run_test!(get_peer_certificate, |method, stream| {
|
|||
fn test_write_dtlsv1() {
|
||||
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.flush().unwrap();
|
||||
stream.write_all(b" there").unwrap();
|
||||
|
|
@ -521,7 +492,7 @@ fn test_write_dtlsv1() {
|
|||
#[test]
|
||||
fn test_read() {
|
||||
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.flush().unwrap();
|
||||
io::copy(&mut stream, &mut io::sink()).ok().expect("read error");
|
||||
|
|
@ -539,7 +510,7 @@ fn test_read_direct() {
|
|||
#[test]
|
||||
fn test_pending() {
|
||||
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.flush().unwrap();
|
||||
|
||||
|
|
@ -562,7 +533,7 @@ fn test_pending() {
|
|||
#[test]
|
||||
fn test_state() {
|
||||
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_long(),
|
||||
"SSL negotiation finished successfully");
|
||||
|
|
@ -575,7 +546,7 @@ fn test_state() {
|
|||
fn test_connect_with_unilateral_alpn() {
|
||||
let (_s, stream) = Server::new();
|
||||
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"]);
|
||||
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
|
||||
Ok(_) => {}
|
||||
|
|
@ -597,13 +568,13 @@ fn test_connect_with_unilateral_alpn() {
|
|||
fn test_connect_with_unilateral_npn() {
|
||||
let (_s, stream) = Server::new();
|
||||
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"]);
|
||||
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
|
||||
Ok(_) => {}
|
||||
Err(err) => panic!("Unexpected error {:?}", err),
|
||||
}
|
||||
let stream = match SslStream::connect_generic(&ctx, stream) {
|
||||
let stream = match SslStream::connect(&ctx, stream) {
|
||||
Ok(stream) => stream,
|
||||
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() {
|
||||
let (_s, stream) = Server::new_alpn();
|
||||
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"]);
|
||||
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
|
||||
Ok(_) => {}
|
||||
|
|
@ -641,13 +612,13 @@ fn test_connect_with_alpn_successful_multiple_matching() {
|
|||
fn test_connect_with_npn_successful_multiple_matching() {
|
||||
let (_s, stream) = Server::new_alpn();
|
||||
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"]);
|
||||
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
|
||||
Ok(_) => {}
|
||||
Err(err) => panic!("Unexpected error {:?}", err),
|
||||
}
|
||||
let stream = match SslStream::connect_generic(&ctx, stream) {
|
||||
let stream = match SslStream::connect(&ctx, stream) {
|
||||
Ok(stream) => stream,
|
||||
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() {
|
||||
let (_s, stream) = Server::new_alpn();
|
||||
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"]);
|
||||
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
|
||||
Ok(_) => {}
|
||||
|
|
@ -688,13 +659,13 @@ fn test_connect_with_alpn_successful_single_match() {
|
|||
fn test_connect_with_npn_successful_single_match() {
|
||||
let (_s, stream) = Server::new_alpn();
|
||||
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"]);
|
||||
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
|
||||
Ok(_) => {}
|
||||
Err(err) => panic!("Unexpected error {:?}", err),
|
||||
}
|
||||
let stream = match SslStream::connect_generic(&ctx, stream) {
|
||||
let stream = match SslStream::connect(&ctx, stream) {
|
||||
Ok(stream) => stream,
|
||||
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...
|
||||
let listener_ctx = {
|
||||
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"]);
|
||||
assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM)
|
||||
.is_ok());
|
||||
|
|
@ -728,7 +699,7 @@ fn test_npn_server_advertise_multiple() {
|
|||
});
|
||||
|
||||
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"]);
|
||||
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
|
||||
Ok(_) => {}
|
||||
|
|
@ -736,7 +707,7 @@ fn test_npn_server_advertise_multiple() {
|
|||
}
|
||||
// Now connect to the socket and make sure the protocol negotiation works...
|
||||
let stream = TcpStream::connect(localhost).unwrap();
|
||||
let stream = match SslStream::connect_generic(&ctx, stream) {
|
||||
let stream = match SslStream::connect(&ctx, stream) {
|
||||
Ok(stream) => stream,
|
||||
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...
|
||||
let listener_ctx = {
|
||||
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"]);
|
||||
assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM)
|
||||
.is_ok());
|
||||
|
|
@ -769,7 +740,7 @@ fn test_alpn_server_advertise_multiple() {
|
|||
});
|
||||
|
||||
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"]);
|
||||
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
|
||||
Ok(_) => {}
|
||||
|
|
@ -795,7 +766,7 @@ fn test_alpn_server_select_none() {
|
|||
// We create a different context instance for the server...
|
||||
let listener_ctx = {
|
||||
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"]);
|
||||
assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM)
|
||||
.is_ok());
|
||||
|
|
@ -810,7 +781,7 @@ fn test_alpn_server_select_none() {
|
|||
});
|
||||
|
||||
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"]);
|
||||
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
|
||||
Ok(_) => {}
|
||||
|
|
@ -838,7 +809,7 @@ mod dtlsv1 {
|
|||
use crypto::hash::Type::SHA256;
|
||||
use ssl::SslMethod;
|
||||
use ssl::SslMethod::Dtlsv1;
|
||||
use ssl::{SslContext, SslStream, VerifyCallback};
|
||||
use ssl::{SslContext, SslStream};
|
||||
use ssl::SSL_VERIFY_PEER;
|
||||
use x509::X509StoreContext;
|
||||
|
||||
|
|
@ -855,7 +826,7 @@ mod dtlsv1 {
|
|||
fn test_read_dtlsv1() {
|
||||
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];
|
||||
assert!(stream.read(&mut buf).is_ok());
|
||||
}
|
||||
|
|
@ -864,15 +835,15 @@ fn test_read_dtlsv1() {
|
|||
#[cfg(feature = "sslv2")]
|
||||
fn test_sslv2_connect_failure() {
|
||||
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()
|
||||
.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 {
|
||||
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 {
|
||||
0 as *mut _
|
||||
|
|
@ -884,7 +855,19 @@ fn wait_io(stream: &NonblockingSslStream<TcpStream>, read: bool, timeout_ms: u32
|
|||
} else {
|
||||
&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();
|
||||
stream.set_nonblocking(true).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;
|
||||
loop {
|
||||
|
|
@ -903,16 +886,16 @@ fn test_write_nonblocking() {
|
|||
// openssl.
|
||||
panic!("Too many read/write round trips in handshake!!");
|
||||
}
|
||||
let result = stream.write(b"hello");
|
||||
let result = stream.ssl_write(b"hello");
|
||||
match result {
|
||||
Ok(_) => {
|
||||
break;
|
||||
}
|
||||
Err(NonblockingSslError::WantRead) => {
|
||||
assert!(wait_io(&stream, true, 1000));
|
||||
Err(Error::WantRead(_)) => {
|
||||
assert!(wait_io(stream.get_ref(), true, 1000));
|
||||
}
|
||||
Err(NonblockingSslError::WantWrite) => {
|
||||
assert!(wait_io(&stream, false, 1000));
|
||||
Err(Error::WantWrite(_)) => {
|
||||
assert!(wait_io(stream.get_ref(), false, 1000));
|
||||
}
|
||||
Err(other) => {
|
||||
panic!("Unexpected SSL Error: {:?}", other);
|
||||
|
|
@ -930,7 +913,7 @@ fn test_read_nonblocking() {
|
|||
let (_s, stream) = Server::new();
|
||||
stream.set_nonblocking(true).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;
|
||||
loop {
|
||||
|
|
@ -940,17 +923,17 @@ fn test_read_nonblocking() {
|
|||
// openssl.
|
||||
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 {
|
||||
Ok(n) => {
|
||||
assert_eq!(n, 9);
|
||||
break;
|
||||
}
|
||||
Err(NonblockingSslError::WantRead) => {
|
||||
assert!(wait_io(&stream, true, 1000));
|
||||
Err(Error::WantRead(..)) => {
|
||||
assert!(wait_io(stream.get_ref(), true, 1000));
|
||||
}
|
||||
Err(NonblockingSslError::WantWrite) => {
|
||||
assert!(wait_io(&stream, false, 1000));
|
||||
Err(Error::WantWrite(..)) => {
|
||||
assert!(wait_io(stream.get_ref(), false, 1000));
|
||||
}
|
||||
Err(other) => {
|
||||
panic!("Unexpected SSL Error: {:?}", other);
|
||||
|
|
@ -958,7 +941,7 @@ fn test_read_nonblocking() {
|
|||
}
|
||||
}
|
||||
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 {
|
||||
Ok(n) => {
|
||||
// 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...
|
||||
n
|
||||
}
|
||||
Err(NonblockingSslError::WantRead) => {
|
||||
assert!(wait_io(&stream, true, 3000));
|
||||
Err(Error::WantRead(..)) => {
|
||||
assert!(wait_io(stream.get_ref(), true, 3000));
|
||||
// Second read should return application data.
|
||||
stream.read(&mut input_buffer).unwrap()
|
||||
}
|
||||
|
|
@ -979,14 +962,6 @@ fn test_read_nonblocking() {
|
|||
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]
|
||||
#[should_panic(expected = "blammo")]
|
||||
#[cfg(feature = "nightly")]
|
||||
|
|
@ -1077,7 +1052,7 @@ fn flush_panic() {
|
|||
|
||||
#[test]
|
||||
fn refcount_ssl_context() {
|
||||
let ssl = {
|
||||
let mut ssl = {
|
||||
let ctx = SslContext::new(SslMethod::Sslv23).unwrap();
|
||||
ssl::Ssl::new(&ctx).unwrap()
|
||||
};
|
||||
|
|
@ -1093,7 +1068,7 @@ fn refcount_ssl_context() {
|
|||
fn default_verify_paths() {
|
||||
let mut ctx = SslContext::new(SslMethod::Sslv23).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 mut socket = SslStream::connect(&ctx, s).unwrap();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
use libc::{c_char, c_int, c_long, c_ulong, c_uint, c_void};
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::cmp::Ordering;
|
||||
use libc::{c_char, c_int, c_long, c_ulong, c_void};
|
||||
use std::ffi::CString;
|
||||
use std::iter::repeat;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::ops::Deref;
|
||||
|
|
@ -13,16 +9,16 @@ use std::slice;
|
|||
use std::collections::HashMap;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use HashTypeInternals;
|
||||
use asn1::Asn1Time;
|
||||
use bio::MemBio;
|
||||
use bio::{MemBio, MemBioSlice};
|
||||
use crypto::hash;
|
||||
use crypto::hash::Type as HashType;
|
||||
use crypto::pkey::{PKey, Parts};
|
||||
use crypto::pkey::PKey;
|
||||
use crypto::rand::rand_bytes;
|
||||
use ffi;
|
||||
use ffi_extras;
|
||||
use ssl::error::{SslError, StreamError};
|
||||
use nid::Nid;
|
||||
use error::ErrorStack;
|
||||
|
||||
pub mod extension;
|
||||
|
||||
|
|
@ -86,22 +82,20 @@ impl X509StoreContext {
|
|||
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) };
|
||||
X509ValidationError::from_raw(err)
|
||||
}
|
||||
|
||||
pub fn get_current_cert<'a>(&'a self) -> Option<X509<'a>> {
|
||||
let ptr = unsafe { ffi::X509_STORE_CTX_get_current_cert(self.ctx) };
|
||||
pub fn current_cert<'a>(&'a self) -> Option<X509Ref<'a>> {
|
||||
unsafe {
|
||||
let ptr = ffi::X509_STORE_CTX_get_current_cert(self.ctx);
|
||||
|
||||
if ptr.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(X509 {
|
||||
ctx: Some(self),
|
||||
handle: ptr,
|
||||
owned: false,
|
||||
})
|
||||
Some(X509Ref::new(ptr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -116,39 +110,26 @@ impl X509StoreContext {
|
|||
/// # 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::pkey::PKey;
|
||||
/// use openssl::crypto::rsa::RSA;
|
||||
/// use openssl::x509::X509Generator;
|
||||
/// use openssl::x509::extension::{Extension, KeyUsageOption};
|
||||
///
|
||||
/// let rsa = RSA::generate(2048).unwrap();
|
||||
/// let pkey = PKey::from_rsa(rsa).unwrap();
|
||||
///
|
||||
/// let gen = X509Generator::new()
|
||||
/// .set_bitlength(2048)
|
||||
/// .set_valid_period(365*2)
|
||||
/// .add_name("CN".to_owned(), "SuperMegaCorp Inc.".to_owned())
|
||||
/// .set_sign_hash(Type::SHA256)
|
||||
/// .add_extension(Extension::KeyUsage(vec![KeyUsageOption::DigitalSignature]));
|
||||
///
|
||||
/// let (cert, pkey) = gen.generate().unwrap();
|
||||
///
|
||||
/// let cert_path = "doc_cert.pem";
|
||||
/// 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);
|
||||
/// # }
|
||||
/// let cert = gen.sign(&pkey).unwrap();
|
||||
/// let cert_pem = cert.to_pem().unwrap();
|
||||
/// let pkey_pem = pkey.private_key_to_pem().unwrap();
|
||||
/// ```
|
||||
pub struct X509Generator {
|
||||
bits: u32,
|
||||
days: u32,
|
||||
names: Vec<(String, String)>,
|
||||
extensions: Extensions,
|
||||
|
|
@ -158,8 +139,6 @@ pub struct X509Generator {
|
|||
impl X509Generator {
|
||||
/// Creates a new generator with the following defaults:
|
||||
///
|
||||
/// bit length: 1024
|
||||
///
|
||||
/// validity period: 365 days
|
||||
///
|
||||
/// CN: "rust-openssl"
|
||||
|
|
@ -167,7 +146,6 @@ impl X509Generator {
|
|||
/// hash: SHA1
|
||||
pub fn new() -> X509Generator {
|
||||
X509Generator {
|
||||
bits: 1024,
|
||||
days: 365,
|
||||
names: vec![],
|
||||
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
|
||||
pub fn set_valid_period(mut self, days: u32) -> X509Generator {
|
||||
self.days = days;
|
||||
|
|
@ -256,7 +228,7 @@ impl X509Generator {
|
|||
fn add_extension_internal(x509: *mut ffi::X509,
|
||||
exttype: &extension::ExtensionType,
|
||||
value: &str)
|
||||
-> Result<(), SslError> {
|
||||
-> Result<(), ErrorStack> {
|
||||
unsafe {
|
||||
let mut ctx: ffi::X509V3_CTX = mem::zeroed();
|
||||
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,
|
||||
key: &str,
|
||||
value: &str)
|
||||
-> Result<(), SslError> {
|
||||
-> Result<(), ErrorStack> {
|
||||
let value_len = value.len() as c_int;
|
||||
lift_ssl!(unsafe {
|
||||
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 bytes = rand_bytes(len);
|
||||
let mut bytes = vec![0; len];
|
||||
try!(rand_bytes(&mut bytes));
|
||||
let mut res = 0;
|
||||
for b in bytes.iter() {
|
||||
res = res << 8;
|
||||
|
|
@ -315,54 +288,36 @@ impl X509Generator {
|
|||
// While OpenSSL is actually OK to have negative serials
|
||||
// other libraries (for example, Go crypto) can drop
|
||||
// such certificates as invalid, so we clear the high bit
|
||||
((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))
|
||||
Ok(((res as c_ulong) >> 1) as c_long)
|
||||
}
|
||||
|
||||
/// 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)
|
||||
pub fn sign<'a>(&self, p_key: &PKey) -> Result<X509<'a>, SslError> {
|
||||
pub fn sign(&self, p_key: &PKey) -> Result<X509, ErrorStack> {
|
||||
ffi::init();
|
||||
|
||||
unsafe {
|
||||
let x509 = ffi::X509_new();
|
||||
try_ssl_null!(x509);
|
||||
let x509 = try_ssl_null!(ffi::X509_new());
|
||||
let x509 = X509::new(x509);
|
||||
|
||||
let x509 = X509 {
|
||||
handle: x509,
|
||||
ctx: None,
|
||||
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()));
|
||||
try_ssl!(ffi::X509_set_version(x509.as_ptr(), 2));
|
||||
try_ssl!(ffi::ASN1_INTEGER_set(ffi::X509_get_serialNumber(x509.as_ptr()),
|
||||
try!(X509Generator::random_serial())));
|
||||
|
||||
let not_before = try!(Asn1Time::days_from_now(0));
|
||||
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
|
||||
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
|
||||
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);
|
||||
try_ssl_null!(name);
|
||||
let name = try_ssl_null!(ffi::X509_get_subject_name(x509.as_ptr()));
|
||||
|
||||
let default = [("CN", "rust-openssl")];
|
||||
let default_iter = &mut default.iter().map(|&(k, v)| (k, v));
|
||||
|
|
@ -376,105 +331,69 @@ impl X509Generator {
|
|||
for (key, val) in iter {
|
||||
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() {
|
||||
try!(X509Generator::add_extension_internal(x509.handle,
|
||||
try!(X509Generator::add_extension_internal(x509.as_ptr(),
|
||||
&exttype,
|
||||
&ext.to_string()));
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
Ok(c) => c,
|
||||
Err(x) => return Err(x),
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
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() {
|
||||
try_ssl!(ffi::X509_REQ_add_extensions(req, exts));
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A borrowed public key certificate.
|
||||
pub struct X509Ref<'a>(*mut ffi::X509, PhantomData<&'a ()>);
|
||||
|
||||
#[allow(dead_code)]
|
||||
/// A public key certificate
|
||||
pub struct X509<'ctx> {
|
||||
ctx: Option<&'ctx X509StoreContext>,
|
||||
handle: *mut ffi::X509,
|
||||
owned: bool,
|
||||
}
|
||||
|
||||
impl<'ctx> X509<'ctx> {
|
||||
/// Creates new from handle with desired ownership.
|
||||
pub fn new(handle: *mut ffi::X509, owned: bool) -> X509<'ctx> {
|
||||
X509 {
|
||||
ctx: None,
|
||||
handle: handle,
|
||||
owned: owned,
|
||||
}
|
||||
impl<'a> X509Ref<'a> {
|
||||
/// Creates a new `X509Ref` wrapping the provided handle.
|
||||
pub unsafe fn new(handle: *mut ffi::X509) -> X509Ref<'a> {
|
||||
X509Ref(handle, PhantomData)
|
||||
}
|
||||
|
||||
/// Creates a new certificate from context. Doesn't take ownership
|
||||
/// of handle.
|
||||
pub fn new_in_ctx(handle: *mut ffi::X509, ctx: &'ctx X509StoreContext) -> X509<'ctx> {
|
||||
X509 {
|
||||
ctx: Some(ctx),
|
||||
handle: handle,
|
||||
owned: false,
|
||||
}
|
||||
pub fn as_ptr(&self) -> *mut ffi::X509 {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// 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,
|
||||
}
|
||||
pub fn subject_name<'b>(&'b self) -> X509Name<'b> {
|
||||
let name = unsafe { ffi::X509_get_subject_name(self.0) };
|
||||
X509Name(name, PhantomData)
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
let stack = ffi::X509_get_ext_d2i(self.handle,
|
||||
let stack = ffi::X509_get_ext_d2i(self.0,
|
||||
Nid::SubjectAltName as c_int,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut());
|
||||
|
|
@ -489,94 +408,102 @@ impl<'ctx> X509<'ctx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn public_key(&self) -> PKey {
|
||||
let pkey = unsafe { ffi::X509_get_pubkey(self.handle) };
|
||||
assert!(!pkey.is_null());
|
||||
|
||||
PKey::from_handle(pkey, Parts::Public)
|
||||
pub fn public_key(&self) -> Result<PKey, ErrorStack> {
|
||||
unsafe {
|
||||
let pkey = try_ssl_null!(ffi::X509_get_pubkey(self.0));
|
||||
Ok(PKey::from_ptr(pkey))
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 len = hash_type.md_len();
|
||||
let v: Vec<u8> = repeat(0).take(len as usize).collect();
|
||||
let act_len: c_uint = 0;
|
||||
let res = unsafe {
|
||||
ffi::X509_digest(self.handle,
|
||||
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!"),
|
||||
}
|
||||
}
|
||||
let mut len = ffi::EVP_MAX_MD_SIZE;
|
||||
let mut buf = vec![0u8; len as usize];
|
||||
try_ssl!(ffi::X509_digest(self.0, evp, buf.as_mut_ptr() as *mut _, &mut len));
|
||||
buf.truncate(len as usize);
|
||||
Ok(buf)
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes certificate as PEM
|
||||
pub fn write_pem<W>(&self, writer: &mut W) -> Result<(), SslError>
|
||||
where W: Write
|
||||
{
|
||||
let mut mem_bio = try!(MemBio::new());
|
||||
pub fn to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
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" {
|
||||
fn rust_X509_clone(x509: *mut ffi::X509);
|
||||
}
|
||||
/// An owned public key certificate.
|
||||
pub struct X509(X509Ref<'static>);
|
||||
|
||||
impl<'ctx> Clone for X509<'ctx> {
|
||||
fn clone(&self) -> X509<'ctx> {
|
||||
unsafe { rust_X509_clone(self.handle) }
|
||||
// FIXME: given that we now have refcounting control, 'owned' should be uneeded, the 'ctx
|
||||
// is probably also uneeded. We can remove both to condense the x509 api quite a bit
|
||||
//
|
||||
X509::new(self.handle, true)
|
||||
impl X509 {
|
||||
/// Returns a new `X509`, taking ownership of the handle.
|
||||
pub unsafe fn new(x509: *mut ffi::X509) -> X509 {
|
||||
X509(X509Ref::new(x509))
|
||||
}
|
||||
|
||||
/// Reads a certificate from PEM.
|
||||
pub fn from_pem(buf: &[u8]) -> Result<X509, ErrorStack> {
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
unsafe {
|
||||
let handle = try_ssl_null!(ffi::PEM_read_bio_X509(mem_bio.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
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) {
|
||||
if self.owned {
|
||||
unsafe { ffi::X509_free(self.handle) };
|
||||
}
|
||||
unsafe { ffi::X509_free(self.as_ptr()) };
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
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,
|
||||
}
|
||||
pub struct X509Name<'x>(*mut ffi::X509_NAME, PhantomData<&'x ()>);
|
||||
|
||||
impl<'x> X509Name<'x> {
|
||||
pub fn text_by_nid(&self, nid: Nid) -> Option<SslString> {
|
||||
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 {
|
||||
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() {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -601,25 +528,23 @@ impl<'x> X509Name<'x> {
|
|||
}
|
||||
|
||||
/// A certificate signing request
|
||||
pub struct X509Req {
|
||||
handle: *mut ffi::X509_REQ,
|
||||
}
|
||||
pub struct X509Req(*mut ffi::X509_REQ);
|
||||
|
||||
impl X509Req {
|
||||
/// Creates new from handle
|
||||
pub fn new(handle: *mut ffi::X509_REQ) -> X509Req {
|
||||
X509Req { handle: handle }
|
||||
pub unsafe fn new(handle: *mut ffi::X509_REQ) -> X509Req {
|
||||
X509Req(handle)
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *mut ffi::X509_REQ {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Reads CSR from PEM
|
||||
pub fn from_pem<R>(reader: &mut R) -> Result<X509Req, SslError>
|
||||
where R: Read
|
||||
{
|
||||
let mut mem_bio = try!(MemBio::new());
|
||||
try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
|
||||
|
||||
pub fn from_pem(buf: &[u8]) -> Result<X509Req, ErrorStack> {
|
||||
let mem_bio = try!(MemBioSlice::new(buf));
|
||||
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(),
|
||||
None,
|
||||
ptr::null_mut()));
|
||||
|
|
@ -628,20 +553,27 @@ impl X509Req {
|
|||
}
|
||||
|
||||
/// Writes CSR as PEM
|
||||
pub fn write_pem<W>(&self, writer: &mut W) -> Result<(), SslError>
|
||||
where W: Write
|
||||
{
|
||||
let mut mem_bio = try!(MemBio::new());
|
||||
unsafe {
|
||||
try_ssl!(ffi::PEM_write_bio_X509_REQ(mem_bio.get_handle(), self.handle));
|
||||
pub fn to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
|
||||
let mem_bio = try!(MemBio::new());
|
||||
if unsafe { ffi::PEM_write_bio_X509_REQ(mem_bio.as_ptr(), self.0) } != 1 {
|
||||
return Err(ErrorStack::get());
|
||||
}
|
||||
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 {
|
||||
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() {
|
||||
// I guess that's enough to get a random negative number
|
||||
for _ in 0..1000 {
|
||||
assert!(X509Generator::random_serial() > 0,
|
||||
assert!(X509Generator::random_serial().unwrap() > 0,
|
||||
"All serials should be positive");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
use serialize::hex::FromHex;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
use std::fs::File;
|
||||
|
||||
use crypto::hash::Type::SHA1;
|
||||
use crypto::pkey::PKey;
|
||||
use crypto::rsa::RSA;
|
||||
use x509::{X509, X509Generator};
|
||||
use x509::extension::Extension::{KeyUsage, ExtKeyUsage, SubjectAltName, OtherNid, OtherStr};
|
||||
use x509::extension::AltNameOption as SAN;
|
||||
|
|
@ -14,7 +12,6 @@ use nid::Nid;
|
|||
|
||||
fn get_generator() -> X509Generator {
|
||||
X509Generator::new()
|
||||
.set_bitlength(2048)
|
||||
.set_valid_period(365 * 2)
|
||||
.add_name("CN".to_string(), "test_me".to_string())
|
||||
.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()))
|
||||
}
|
||||
|
||||
fn pkey() -> PKey {
|
||||
let rsa = RSA::generate(2048).unwrap();
|
||||
PKey::from_rsa(rsa).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cert_gen() {
|
||||
let (cert, pkey) = get_generator().generate().unwrap();
|
||||
cert.write_pem(&mut io::sink()).unwrap();
|
||||
pkey.write_pem(&mut io::sink()).unwrap();
|
||||
let pkey = pkey();
|
||||
let cert = get_generator().sign(&pkey).unwrap();
|
||||
|
||||
// FIXME: check data in result to be correct, needs implementation
|
||||
// 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
|
||||
|
|
@ -44,10 +46,11 @@ fn test_cert_gen() {
|
|||
/// for extensions is preserved when the cert is signed.
|
||||
#[test]
|
||||
fn test_cert_gen_extension_ordering() {
|
||||
let pkey = pkey();
|
||||
get_generator()
|
||||
.add_extension(OtherNid(Nid::SubjectKeyIdentifier, "hash".to_owned()))
|
||||
.add_extension(OtherNid(Nid::AuthorityKeyIdentifier, "keyid:always".to_owned()))
|
||||
.generate()
|
||||
.sign(&pkey)
|
||||
.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.
|
||||
#[test]
|
||||
fn test_cert_gen_extension_bad_ordering() {
|
||||
let pkey = pkey();
|
||||
let result = get_generator()
|
||||
.add_extension(OtherNid(Nid::AuthorityKeyIdentifier,
|
||||
"keyid:always".to_owned()))
|
||||
.add_extension(OtherNid(Nid::SubjectKeyIdentifier, "hash".to_owned()))
|
||||
.generate();
|
||||
.sign(&pkey);
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "x509_generator_request")]
|
||||
fn test_req_gen() {
|
||||
let mut pkey = PKey::new();
|
||||
pkey.gen(512);
|
||||
let pkey = pkey();
|
||||
|
||||
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
|
||||
// of X509_REQ getters
|
||||
|
|
@ -78,12 +82,8 @@ fn test_req_gen() {
|
|||
|
||||
#[test]
|
||||
fn test_cert_loading() {
|
||||
let cert_path = Path::new("test/cert.pem");
|
||||
let mut file = File::open(&cert_path)
|
||||
.ok()
|
||||
.expect("Failed to open `test/cert.pem`");
|
||||
|
||||
let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM");
|
||||
let cert = include_bytes!("../../test/cert.pem");
|
||||
let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
|
||||
let fingerprint = cert.fingerprint(SHA1).unwrap();
|
||||
|
||||
let hash_str = "E19427DAC79FBE758394945276A6E4F15F0BEBE6";
|
||||
|
|
@ -93,13 +93,18 @@ fn test_cert_loading() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_subject_read_cn() {
|
||||
let cert_path = Path::new("test/cert.pem");
|
||||
let mut file = File::open(&cert_path)
|
||||
.ok()
|
||||
.expect("Failed to open `test/cert.pem`");
|
||||
fn test_save_der() {
|
||||
let cert = include_bytes!("../../test/cert.pem");
|
||||
let cert = X509::from_pem(cert).ok().expect("Failed to load 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 cn = match subject.text_by_nid(Nid::CN) {
|
||||
Some(x) => x,
|
||||
|
|
@ -111,12 +116,8 @@ fn test_subject_read_cn() {
|
|||
|
||||
#[test]
|
||||
fn test_nid_values() {
|
||||
let cert_path = Path::new("test/nid_test_cert.pem");
|
||||
let mut file = File::open(&cert_path)
|
||||
.ok()
|
||||
.expect("Failed to open `test/nid_test_cert.pem`");
|
||||
|
||||
let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM");
|
||||
let cert = include_bytes!("../../test/nid_test_cert.pem");
|
||||
let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
|
||||
let subject = cert.subject_name();
|
||||
|
||||
let cn = match subject.text_by_nid(Nid::CN) {
|
||||
|
|
@ -140,12 +141,8 @@ fn test_nid_values() {
|
|||
|
||||
#[test]
|
||||
fn test_nid_uid_value() {
|
||||
let cert_path = Path::new("test/nid_uid_test_cert.pem");
|
||||
let mut file = File::open(&cert_path)
|
||||
.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 cert = include_bytes!("../../test/nid_uid_test_cert.pem");
|
||||
let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
|
||||
let subject = cert.subject_name();
|
||||
|
||||
let cn = match subject.text_by_nid(Nid::UserId) {
|
||||
|
|
@ -157,8 +154,8 @@ fn test_nid_uid_value() {
|
|||
|
||||
#[test]
|
||||
fn test_subject_alt_name() {
|
||||
let mut file = File::open("test/alt_name_cert.pem").unwrap();
|
||||
let cert = X509::from_pem(&mut file).unwrap();
|
||||
let cert = include_bytes!("../../test/alt_name_cert.pem");
|
||||
let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
|
||||
|
||||
let subject_alt_names = cert.subject_alt_names().unwrap();
|
||||
assert_eq!(3, subject_alt_names.len());
|
||||
|
|
@ -171,8 +168,8 @@ fn test_subject_alt_name() {
|
|||
|
||||
#[test]
|
||||
fn test_subject_alt_name_iter() {
|
||||
let mut file = File::open("test/alt_name_cert.pem").unwrap();
|
||||
let cert = X509::from_pem(&mut file).unwrap();
|
||||
let cert = include_bytes!("../../test/alt_name_cert.pem");
|
||||
let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
|
||||
|
||||
let subject_alt_names = cert.subject_alt_names().unwrap();
|
||||
let mut subject_alt_names_iter = subject_alt_names.iter();
|
||||
|
|
|
|||
|
|
@ -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-----
|
||||
|
|
@ -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-----
|
||||
|
|
@ -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-----
|
||||
|
|
@ -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-----
|
||||
|
|
@ -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-----
|
||||
|
|
@ -4,11 +4,7 @@ set -e
|
|||
MAIN_TARGETS=https://static.rust-lang.org/dist
|
||||
|
||||
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"
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then
|
||||
FEATURES="$FEATURES nightly"
|
||||
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_OS_NAME" != "osx" ]; then
|
||||
|
|
@ -33,4 +29,4 @@ else
|
|||
fi
|
||||
|
||||
export PATH=$HOME/openssl/bin:$PATH
|
||||
(cd openssl && cargo $COMMAND $FLAGS --features "$FEATURES")
|
||||
(cd openssl && RUST_BACKTRACE=1 cargo $COMMAND $FLAGS --features "$FEATURES")
|
||||
|
|
|
|||
Loading…
Reference in New Issue