aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Fackler <[email protected]>2016-08-11 21:01:27 -0700
committerSteven Fackler <[email protected]>2016-08-11 21:01:27 -0700
commit652326003cefe215dbfc838051e6114515cc5190 (patch)
tree22dc99a726321cd8228004c34c40ca4a0648c594
parentMerge branch 'release-v0.7.14' into release (diff)
parentRelease openssl-sys v0.7.15, openssl v0.8.0 (diff)
downloadrust-openssl-openssl-sys-v0.7.15.tar.xz
rust-openssl-openssl-sys-v0.7.15.zip
Merge branch 'release-v0.7.15-sys-v0.8.0' into releaseopenssl-v0.8.0openssl-sys-v0.7.15
-rw-r--r--.travis.yml2
-rw-r--r--Cargo.toml2
-rw-r--r--README.md2
-rw-r--r--appveyor.yml4
-rw-r--r--openssl-sys-extras/Cargo.toml19
-rw-r--r--openssl-sys-extras/build.rs77
-rw-r--r--openssl-sys-extras/src/lib.rs82
-rw-r--r--openssl-sys-extras/src/openssl_shim.c144
-rw-r--r--openssl-sys-extras/src/ssl_options.rs46
-rw-r--r--openssl-sys/Cargo.toml17
-rw-r--r--openssl-sys/src/lib.rs247
-rw-r--r--openssl/Cargo.toml21
-rw-r--r--openssl/build.rs30
-rw-r--r--openssl/src/asn1/mod.rs39
-rw-r--r--openssl/src/bio.rs67
-rw-r--r--openssl/src/bio/mod.rs107
-rw-r--r--openssl/src/bn/mod.rs790
-rw-r--r--openssl/src/c_helpers.c54
-rw-r--r--openssl/src/c_helpers.rs14
-rw-r--r--openssl/src/crypto/dsa.rs338
-rw-r--r--openssl/src/crypto/hash.rs150
-rw-r--r--openssl/src/crypto/hmac.rs162
-rw-r--r--openssl/src/crypto/mod.rs11
-rw-r--r--openssl/src/crypto/pkcs5.rs179
-rw-r--r--openssl/src/crypto/pkey.rs876
-rw-r--r--openssl/src/crypto/rand.rs20
-rw-r--r--openssl/src/crypto/rsa.rs303
-rw-r--r--openssl/src/crypto/symm.rs329
-rw-r--r--openssl/src/crypto/symm_internal.rs35
-rw-r--r--openssl/src/crypto/util.rs58
-rw-r--r--openssl/src/dh/mod.rs71
-rw-r--r--openssl/src/error.rs137
-rw-r--r--openssl/src/lib.rs23
-rw-r--r--openssl/src/macros.rs4
-rw-r--r--openssl/src/ssl/bio.rs8
-rw-r--r--openssl/src/ssl/error.rs274
-rw-r--r--openssl/src/ssl/mod.rs1256
-rw-r--r--openssl/src/ssl/tests/mod.rs251
-rw-r--r--openssl/src/x509/mod.rs370
-rw-r--r--openssl/src/x509/tests.rs79
-rw-r--r--openssl/test/dsa-encrypted.pem15
-rw-r--r--openssl/test/dsa.pem12
-rw-r--r--openssl/test/dsa.pem.pub12
-rw-r--r--openssl/test/dsaparam.pem9
-rw-r--r--openssl/test/rsa-encrypted.pem30
-rwxr-xr-xopenssl/test/run.sh8
46 files changed, 3061 insertions, 3723 deletions
diff --git a/.travis.yml b/.travis.yml
index 91c6ad62..0d76be3d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,7 +6,7 @@ addons:
- gcc-arm-linux-gnueabihf
rust:
- nightly
-- 1.8.0
+- 1.9.0
os:
- osx
- linux
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 00000000..0bd2c005
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,2 @@
+[workspace]
+members = ["openssl", "openssl-sys"]
diff --git a/README.md b/README.md
index b3ce0bc0..ec7eecf1 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
[![Build Status](https://travis-ci.org/sfackler/rust-openssl.svg?branch=master)](https://travis-ci.org/sfackler/rust-openssl)
-[Documentation](https://sfackler.github.io/rust-openssl/doc/v0.7.14/openssl).
+[Documentation](https://sfackler.github.io/rust-openssl/doc/v0.8.0/openssl).
## Building
diff --git a/appveyor.yml b/appveyor.yml
index f835d9f6..054b88f2 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -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
diff --git a/openssl-sys-extras/Cargo.toml b/openssl-sys-extras/Cargo.toml
deleted file mode 100644
index 903305d7..00000000
--- a/openssl-sys-extras/Cargo.toml
+++ /dev/null
@@ -1,19 +0,0 @@
-[package]
-name = "openssl-sys-extras"
-version = "0.7.14"
-authors = ["Steven Fackler <[email protected]>"]
-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"
diff --git a/openssl-sys-extras/build.rs b/openssl-sys-extras/build.rs
deleted file mode 100644
index e3c695b1..00000000
--- a/openssl-sys-extras/build.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-extern crate gcc;
-
-use std::env;
-use std::path::PathBuf;
-use std::fs::File;
-use std::io::Write as IoWrite;
-use std::fmt::Write;
-
-fn main() {
- let options_shim_file = generate_options_shim();
- let mut config = gcc::Config::new();
-
- if let Some(paths) = env::var_os("DEP_OPENSSL_INCLUDE") {
- for path in env::split_paths(&paths) {
- config.include(PathBuf::from(path));
- }
- }
-
- config.file("src/openssl_shim.c")
- .file(options_shim_file)
- .compile("libopenssl_shim.a");
-}
-
-macro_rules! import_options {
- ( $( $name:ident $val:expr )* ) => {
- &[ $( (stringify!($name),$val), )* ]
- };
-}
-
-fn generate_options_shim() -> PathBuf {
- let options: &[(&'static str,u64)]=include!("src/ssl_options.rs");
- let mut shim = String::new();
- writeln!(shim,"#include <stdint.h>").unwrap();
- writeln!(shim,"#include <openssl/ssl.h>").unwrap();
-
- for &(name,value) in options {
- writeln!(shim,"#define RUST_{} UINT64_C({})",name,value).unwrap();
- writeln!(shim,"#ifndef {}",name).unwrap();
- writeln!(shim,"# define {} 0",name).unwrap();
- writeln!(shim,"#endif").unwrap();
- }
-
- writeln!(shim,"#define COPY_MASK ( \\").unwrap();
-
- let mut it=options.iter().peekable();
- while let Some(&(name,_))=it.next() {
- let eol=match it.peek() {
- Some(_) => " | \\",
- None => " )"
- };
- writeln!(shim," ((RUST_{0}==(uint64_t)(uint32_t){0})?RUST_{0}:UINT64_C(0)){1}",name,eol).unwrap();
- }
-
- writeln!(shim,"long rust_openssl_ssl_ctx_options_rust_to_c(uint64_t rustval) {{").unwrap();
- writeln!(shim," long cval=rustval&COPY_MASK;").unwrap();
- for &(name,_) in options {
- writeln!(shim," if (rustval&RUST_{0}) cval|={0};",name).unwrap();
- }
- writeln!(shim," return cval;").unwrap();
- writeln!(shim,"}}").unwrap();
-
- writeln!(shim,"uint64_t rust_openssl_ssl_ctx_options_c_to_rust(long cval) {{").unwrap();
- writeln!(shim," uint64_t rustval=cval&COPY_MASK;").unwrap();
- for &(name,_) in options {
- writeln!(shim," if (cval&{0}) rustval|=RUST_{0};",name).unwrap();
- }
- writeln!(shim," return rustval;").unwrap();
- writeln!(shim,"}}").unwrap();
-
- let out_dir = env::var("OUT_DIR").unwrap();
- let dest_file = PathBuf::from(&out_dir).join("ssl_ctx_options_shim.c");
- let mut f = File::create(&dest_file).unwrap();
-
- f.write_all(shim.as_bytes()).unwrap();
-
- dest_file
-}
diff --git a/openssl-sys-extras/src/lib.rs b/openssl-sys-extras/src/lib.rs
deleted file mode 100644
index 8e7542fc..00000000
--- a/openssl-sys-extras/src/lib.rs
+++ /dev/null
@@ -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);
-}
diff --git a/openssl-sys-extras/src/openssl_shim.c b/openssl-sys-extras/src/openssl_shim.c
deleted file mode 100644
index db2a8786..00000000
--- a/openssl-sys-extras/src/openssl_shim.c
+++ /dev/null
@@ -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;
-}
diff --git a/openssl-sys-extras/src/ssl_options.rs b/openssl-sys-extras/src/ssl_options.rs
deleted file mode 100644
index a1c778ac..00000000
--- a/openssl-sys-extras/src/ssl_options.rs
+++ /dev/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
-}
diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml
index c203b6d6..e09c2020 100644
--- a/openssl-sys/Cargo.toml
+++ b/openssl-sys/Cargo.toml
@@ -1,12 +1,12 @@
[package]
name = "openssl-sys"
-version = "0.7.14"
+version = "0.7.15"
authors = ["Alex Crichton <[email protected]>",
"Steven Fackler <[email protected]>"]
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"
diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs
index ef327a93..24d3bf57 100644
--- a/openssl-sys/src/lib.rs
+++ b/openssl-sys/src/lib.rs
@@ -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;
@@ -115,6 +117,28 @@ pub struct RSA {
}
#[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,
pub save_type: c_int,
@@ -173,6 +197,39 @@ impl Clone for EVP_MD_CTX {
}
#[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,
md_ctx: EVP_MD_CTX,
@@ -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;
diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml
index ed90a6a5..a5d0de8b 100644
--- a/openssl/Cargo.toml
+++ b/openssl/Cargo.toml
@@ -1,11 +1,11 @@
[package]
name = "openssl"
-version = "0.7.14"
+version = "0.8.0"
authors = ["Steven Fackler <[email protected]>"]
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"
diff --git a/openssl/build.rs b/openssl/build.rs
index 640b024c..b07c1b3e 100644
--- a/openssl/build.rs
+++ b/openssl/build.rs
@@ -1,16 +1,28 @@
-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() {
- let mut config = gcc::Config::new();
+ pub fn main() {
+ let mut config = gcc::Config::new();
- if let Some(paths) = env::var_os("DEP_OPENSSL_INCLUDE") {
- for path in env::split_paths(&paths) {
- config.include(PathBuf::from(path));
+ if let Some(paths) = env::var_os("DEP_OPENSSL_INCLUDE") {
+ for path in env::split_paths(&paths) {
+ config.include(PathBuf::from(path));
+ }
}
+
+ config.file("src/c_helpers.c").compile("libc_helpers.a");
}
+}
- config.file("src/c_helpers.c").compile("libc_helpers.a");
+#[cfg(not(feature = "c_helpers"))]
+mod imp {
+ pub fn main() {}
+}
+
+fn main() {
+ imp::main()
}
diff --git a/openssl/src/asn1/mod.rs b/openssl/src/asn1/mod.rs
index d5561b62..7d209775 100644
--- a/openssl/src/asn1/mod.rs
+++ b/openssl/src/asn1/mod.rs
@@ -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) };
}
}
diff --git a/openssl/src/bio.rs b/openssl/src/bio.rs
new file mode 100644
index 00000000..0d82a6c3
--- /dev/null
+++ b/openssl/src/bio.rs
@@ -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)
+ }
+ }
+}
diff --git a/openssl/src/bio/mod.rs b/openssl/src/bio/mod.rs
deleted file mode 100644
index 4c9b20b0..00000000
--- a/openssl/src/bio/mod.rs
+++ /dev/null
@@ -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(())
- }
-}
diff --git a/openssl/src/bn/mod.rs b/openssl/src/bn/mod.rs
index 5054f0ab..de9d0d2a 100644
--- a/openssl/src/bn/mod.rs
+++ b/openssl/src/bn/mod.rs
@@ -1,17 +1,12 @@
use libc::{c_int, c_ulong, c_void};
use std::ffi::{CStr, CString};
use std::cmp::Ordering;
-use std::{fmt, ptr, mem};
+use std::{fmt, ptr};
+use std::marker::PhantomData;
+use std::ops::{Add, Div, Mul, Neg, Rem, Shl, Shr, Sub, Deref, DerefMut};
use ffi;
-use ssl::error::SslError;
-
-/// A signed arbitrary-precision integer.
-///
-/// `BigNum` provides wrappers around OpenSSL's checked arithmetic functions. Additionally, it
-/// implements the standard operators (`std::ops`), which perform unchecked arithmetic, unwrapping
-/// the returned `Result` of the checked operations.
-pub struct BigNum(*mut ffi::BIGNUM);
+use error::ErrorStack;
/// Specifies the desired properties of a randomly generated `BigNum`.
#[derive(Copy, Clone)]
@@ -30,7 +25,7 @@ macro_rules! with_ctx(
($name:ident, $action:block) => ({
let $name = ffi::BN_CTX_new();
if ($name).is_null() {
- Err(SslError::get())
+ Err(ErrorStack::get())
} else {
let r = $action;
ffi::BN_CTX_free($name);
@@ -47,7 +42,7 @@ macro_rules! with_bn(
if $action {
Ok($name)
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
},
Err(err) => Err(err),
@@ -62,13 +57,13 @@ macro_rules! with_bn_in_ctx(
Ok($name) => {
let $ctx_name = ffi::BN_CTX_new();
if ($ctx_name).is_null() {
- Err(SslError::get())
+ Err(ErrorStack::get())
} else {
let r =
if $action {
Ok($name)
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
};
ffi::BN_CTX_free($ctx_name);
r
@@ -79,68 +74,14 @@ macro_rules! with_bn_in_ctx(
});
);
-impl BigNum {
- /// Creates a new `BigNum` with the value 0.
- pub fn new() -> Result<BigNum, SslError> {
- unsafe {
- ffi::init();
-
- let v = try_ssl_null!(ffi::BN_new());
- Ok(BigNum(v))
- }
- }
-
- /// Creates a new `BigNum` with the given value.
- pub fn new_from(n: u64) -> Result<BigNum, SslError> {
- BigNum::new().and_then(|v| unsafe {
- try_ssl!(ffi::BN_set_word(v.raw(), n as c_ulong));
- Ok(v)
- })
- }
-
- /// Creates a `BigNum` from a decimal string.
- pub fn from_dec_str(s: &str) -> Result<BigNum, SslError> {
- BigNum::new().and_then(|v| unsafe {
- let c_str = CString::new(s.as_bytes()).unwrap();
- try_ssl!(ffi::BN_dec2bn(v.raw_ptr(), c_str.as_ptr() as *const _));
- Ok(v)
- })
- }
+/// A borrowed, signed, arbitrary-precision integer.
+#[derive(Copy, Clone)]
+pub struct BigNumRef<'a>(*mut ffi::BIGNUM, PhantomData<&'a ()>);
- /// Creates a `BigNum` from a hexadecimal string.
- pub fn from_hex_str(s: &str) -> Result<BigNum, SslError> {
- BigNum::new().and_then(|v| unsafe {
- let c_str = CString::new(s.as_bytes()).unwrap();
- try_ssl!(ffi::BN_hex2bn(v.raw_ptr(), c_str.as_ptr() as *const _));
- Ok(v)
- })
- }
- pub unsafe fn new_from_ffi(orig: *mut ffi::BIGNUM) -> Result<BigNum, SslError> {
- if orig.is_null() {
- panic!("Null Pointer was supplied to BigNum::new_from_ffi");
- }
- let r = ffi::BN_dup(orig);
- if r.is_null() {
- Err(SslError::get())
- } else {
- Ok(BigNum(r))
- }
- }
-
- /// Creates a new `BigNum` from an unsigned, big-endian encoded number of arbitrary length.
- ///
- /// ```
- /// # use openssl::bn::BigNum;
- /// let bignum = BigNum::new_from_slice(&[0x12, 0x00, 0x34]).unwrap();
- ///
- /// assert_eq!(bignum, BigNum::new_from(0x120034).unwrap());
- /// ```
- pub fn new_from_slice(n: &[u8]) -> Result<BigNum, SslError> {
- BigNum::new().and_then(|v| unsafe {
- try_ssl_null!(ffi::BN_bin2bn(n.as_ptr(), n.len() as c_int, v.raw()));
- Ok(v)
- })
+impl<'a> BigNumRef<'a> {
+ pub unsafe fn from_ptr(handle: *mut ffi::BIGNUM) -> BigNumRef<'a> {
+ BigNumRef(handle, PhantomData)
}
/// Returns the square of `self`.
@@ -153,19 +94,19 @@ impl BigNum {
/// assert_eq!(n.checked_sqr().unwrap(), squared);
/// assert_eq!(n * n, squared);
/// ```
- pub fn checked_sqr(&self) -> Result<BigNum, SslError> {
+ pub fn checked_sqr(&self) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
- ffi::BN_sqr(r.raw(), self.raw(), ctx) == 1
+ ffi::BN_sqr(r.as_ptr(), self.as_ptr(), ctx) == 1
})
}
}
/// Returns the unsigned remainder of the division `self / n`.
- pub fn checked_nnmod(&self, n: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_nnmod(&self, n: &BigNumRef) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
- ffi::BN_nnmod(r.raw(), self.raw(), n.raw(), ctx) == 1
+ ffi::BN_nnmod(r.as_ptr(), self.as_ptr(), n.as_ptr(), ctx) == 1
})
}
}
@@ -181,155 +122,127 @@ impl BigNum {
///
/// assert_eq!(s.checked_mod_add(a, n).unwrap(), result);
/// ```
- pub fn checked_mod_add(&self, a: &BigNum, n: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_mod_add(&self, a: &BigNumRef, n: &BigNumRef) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
- ffi::BN_mod_add(r.raw(), self.raw(), a.raw(), n.raw(), ctx) == 1
+ ffi::BN_mod_add(r.as_ptr(), self.as_ptr(), a.as_ptr(), n.as_ptr(), ctx) == 1
})
}
}
/// Equivalent to `(self - a) mod n`.
- pub fn checked_mod_sub(&self, a: &BigNum, n: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_mod_sub(&self, a: &BigNumRef, n: &BigNumRef) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
- ffi::BN_mod_sub(r.raw(), self.raw(), a.raw(), n.raw(), ctx) == 1
+ ffi::BN_mod_sub(r.as_ptr(), self.as_ptr(), a.as_ptr(), n.as_ptr(), ctx) == 1
})
}
}
/// Equivalent to `(self * a) mod n`.
- pub fn checked_mod_mul(&self, a: &BigNum, n: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_mod_mul(&self, a: &BigNumRef, n: &BigNumRef) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
- ffi::BN_mod_mul(r.raw(), self.raw(), a.raw(), n.raw(), ctx) == 1
+ ffi::BN_mod_mul(r.as_ptr(), self.as_ptr(), a.as_ptr(), n.as_ptr(), ctx) == 1
})
}
}
/// Equivalent to `self² mod n`.
- pub fn checked_mod_sqr(&self, n: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_mod_sqr(&self, n: &BigNumRef) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
- ffi::BN_mod_sqr(r.raw(), self.raw(), n.raw(), ctx) == 1
+ ffi::BN_mod_sqr(r.as_ptr(), self.as_ptr(), n.as_ptr(), ctx) == 1
})
}
}
/// Raises `self` to the `p`th power.
- pub fn checked_exp(&self, p: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_exp(&self, p: &BigNumRef) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
- ffi::BN_exp(r.raw(), self.raw(), p.raw(), ctx) == 1
+ ffi::BN_exp(r.as_ptr(), self.as_ptr(), p.as_ptr(), ctx) == 1
})
}
}
/// Equivalent to `self.checked_exp(p) mod n`.
- pub fn checked_mod_exp(&self, p: &BigNum, n: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_mod_exp(&self, p: &BigNumRef, n: &BigNumRef) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
- ffi::BN_mod_exp(r.raw(), self.raw(), p.raw(), n.raw(), ctx) == 1
+ ffi::BN_mod_exp(r.as_ptr(), self.as_ptr(), p.as_ptr(), n.as_ptr(), ctx) == 1
})
}
}
/// Calculates the modular multiplicative inverse of `self` modulo `n`, that is, an integer `r`
/// such that `(self * r) % n == 1`.
- pub fn checked_mod_inv(&self, n: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_mod_inv(&self, n: &BigNumRef) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
- !ffi::BN_mod_inverse(r.raw(), self.raw(), n.raw(), ctx).is_null()
+ !ffi::BN_mod_inverse(r.as_ptr(), self.as_ptr(), n.as_ptr(), ctx).is_null()
})
}
}
/// Add an `unsigned long` to `self`. This is more efficient than adding a `BigNum`.
- pub fn add_word(&mut self, w: c_ulong) -> Result<(), SslError> {
+ pub fn add_word(&mut self, w: c_ulong) -> Result<(), ErrorStack> {
unsafe {
- if ffi::BN_add_word(self.raw(), w) == 1 {
+ if ffi::BN_add_word(self.as_ptr(), w) == 1 {
Ok(())
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
}
}
- pub fn sub_word(&mut self, w: c_ulong) -> Result<(), SslError> {
+ pub fn sub_word(&mut self, w: c_ulong) -> Result<(), ErrorStack> {
unsafe {
- if ffi::BN_sub_word(self.raw(), w) == 1 {
+ if ffi::BN_sub_word(self.as_ptr(), w) == 1 {
Ok(())
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
}
}
- pub fn mul_word(&mut self, w: c_ulong) -> Result<(), SslError> {
+ pub fn mul_word(&mut self, w: c_ulong) -> Result<(), ErrorStack> {
unsafe {
- if ffi::BN_mul_word(self.raw(), w) == 1 {
+ if ffi::BN_mul_word(self.as_ptr(), w) == 1 {
Ok(())
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
}
}
- pub fn div_word(&mut self, w: c_ulong) -> Result<c_ulong, SslError> {
+ pub fn div_word(&mut self, w: c_ulong) -> Result<c_ulong, ErrorStack> {
unsafe {
- let result = ffi::BN_div_word(self.raw(), w);
+ let result = ffi::BN_div_word(self.as_ptr(), w);
if result != !0 as c_ulong {
Ok(result)
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
}
}
- pub fn mod_word(&self, w: c_ulong) -> Result<c_ulong, SslError> {
+ pub fn mod_word(&self, w: c_ulong) -> Result<c_ulong, ErrorStack> {
unsafe {
- let result = ffi::BN_mod_word(self.raw(), w);
+ let result = ffi::BN_mod_word(self.as_ptr(), w);
if result != !0 as c_ulong {
Ok(result)
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
}
}
/// Computes the greatest common denominator of `self` and `a`.
- pub fn checked_gcd(&self, a: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_gcd(&self, a: &BigNumRef) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
- ffi::BN_gcd(r.raw(), self.raw(), a.raw(), ctx) == 1
- })
- }
- }
-
- /// Generates a prime number.
- ///
- /// # Parameters
- ///
- /// * `bits`: The length of the prime in bits (lower bound).
- /// * `safe`: If true, returns a "safe" prime `p` so that `(p-1)/2` is also prime.
- /// * `add`/`rem`: If `add` is set to `Some(add)`, `p % add == rem` will hold, where `p` is the
- /// generated prime and `rem` is `1` if not specified (`None`).
- pub fn checked_generate_prime(bits: i32,
- safe: bool,
- add: Option<&BigNum>,
- rem: Option<&BigNum>)
- -> Result<BigNum, SslError> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- let add_arg = add.map(|a| a.raw()).unwrap_or(ptr::null_mut());
- let rem_arg = rem.map(|r| r.raw()).unwrap_or(ptr::null_mut());
-
- ffi::BN_generate_prime_ex(r.raw(),
- bits as c_int,
- safe as c_int,
- add_arg,
- rem_arg,
- ptr::null()) == 1
+ ffi::BN_gcd(r.as_ptr(), self.as_ptr(), a.as_ptr(), ctx) == 1
})
}
}
@@ -341,10 +254,10 @@ impl BigNum {
/// # Return Value
///
/// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`.
- pub fn is_prime(&self, checks: i32) -> Result<bool, SslError> {
+ pub fn is_prime(&self, checks: i32) -> Result<bool, ErrorStack> {
unsafe {
with_ctx!(ctx, {
- Ok(ffi::BN_is_prime_ex(self.raw(), checks as c_int, ctx, ptr::null()) == 1)
+ Ok(ffi::BN_is_prime_ex(self.as_ptr(), checks as c_int, ctx, ptr::null()) == 1)
})
}
}
@@ -358,10 +271,10 @@ impl BigNum {
/// # Return Value
///
/// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`.
- pub fn is_prime_fast(&self, checks: i32, do_trial_division: bool) -> Result<bool, SslError> {
+ pub fn is_prime_fast(&self, checks: i32, do_trial_division: bool) -> Result<bool, ErrorStack> {
unsafe {
with_ctx!(ctx, {
- Ok(ffi::BN_is_prime_fasttest_ex(self.raw(),
+ Ok(ffi::BN_is_prime_fasttest_ex(self.as_ptr(),
checks as c_int,
ctx,
do_trial_division as c_int,
@@ -370,48 +283,21 @@ impl BigNum {
}
}
- /// Generates a cryptographically strong pseudo-random `BigNum`.
- ///
- /// # Parameters
- ///
- /// * `bits`: Length of the number in bits.
- /// * `prop`: The desired properties of the number.
- /// * `odd`: If `true`, the generated number will be odd.
- pub fn checked_new_random(bits: i32, prop: RNGProperty, odd: bool) -> Result<BigNum, SslError> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_rand(r.raw(), bits as c_int, prop as c_int, odd as c_int) == 1
- })
- }
- }
-
- /// The cryptographically weak counterpart to `checked_new_random`.
- pub fn checked_new_pseudo_random(bits: i32,
- prop: RNGProperty,
- odd: bool)
- -> Result<BigNum, SslError> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_pseudo_rand(r.raw(), bits as c_int, prop as c_int, odd as c_int) == 1
- })
- }
- }
-
/// Generates a cryptographically strong pseudo-random `BigNum` `r` in the range
/// `0 <= r < self`.
- pub fn checked_rand_in_range(&self) -> Result<BigNum, SslError> {
+ pub fn checked_rand_in_range(&self) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
- ffi::BN_rand_range(r.raw(), self.raw()) == 1
+ ffi::BN_rand_range(r.as_ptr(), self.as_ptr()) == 1
})
}
}
/// The cryptographically weak counterpart to `checked_rand_in_range`.
- pub fn checked_pseudo_rand_in_range(&self) -> Result<BigNum, SslError> {
+ pub fn checked_pseudo_rand_in_range(&self) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
- ffi::BN_pseudo_rand_range(r.raw(), self.raw()) == 1
+ ffi::BN_pseudo_rand_range(r.as_ptr(), self.as_ptr()) == 1
})
}
}
@@ -419,12 +305,12 @@ impl BigNum {
/// Sets bit `n`. Equivalent to `self |= (1 << n)`.
///
/// When setting a bit outside of `self`, it is expanded.
- pub fn set_bit(&mut self, n: i32) -> Result<(), SslError> {
+ pub fn set_bit(&mut self, n: i32) -> Result<(), ErrorStack> {
unsafe {
- if ffi::BN_set_bit(self.raw(), n as c_int) == 1 {
+ if ffi::BN_set_bit(self.as_ptr(), n as c_int) == 1 {
Ok(())
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
}
}
@@ -432,30 +318,30 @@ impl BigNum {
/// Clears bit `n`, setting it to 0. Equivalent to `self &= ~(1 << n)`.
///
/// When clearing a bit outside of `self`, an error is returned.
- pub fn clear_bit(&mut self, n: i32) -> Result<(), SslError> {
+ pub fn clear_bit(&mut self, n: i32) -> Result<(), ErrorStack> {
unsafe {
- if ffi::BN_clear_bit(self.raw(), n as c_int) == 1 {
+ if ffi::BN_clear_bit(self.as_ptr(), n as c_int) == 1 {
Ok(())
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
}
}
/// Returns `true` if the `n`th bit of `self` is set to 1, `false` otherwise.
pub fn is_bit_set(&self, n: i32) -> bool {
- unsafe { ffi::BN_is_bit_set(self.raw(), n as c_int) == 1 }
+ unsafe { ffi::BN_is_bit_set(self.as_ptr(), n as c_int) == 1 }
}
/// Truncates `self` to the lowest `n` bits.
///
/// An error occurs if `self` is already shorter than `n` bits.
- pub fn mask_bits(&mut self, n: i32) -> Result<(), SslError> {
+ pub fn mask_bits(&mut self, n: i32) -> Result<(), ErrorStack> {
unsafe {
- if ffi::BN_mask_bits(self.raw(), n as c_int) == 1 {
+ if ffi::BN_mask_bits(self.as_ptr(), n as c_int) == 1 {
Ok(())
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
}
}
@@ -478,79 +364,86 @@ impl BigNum {
/// // (-8) << 1 == -16
/// assert_eq!(s.checked_shl1().unwrap(), result);
/// ```
- pub fn checked_shl1(&self) -> Result<BigNum, SslError> {
+ pub fn checked_shl1(&self) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn!(r, {
- ffi::BN_lshift1(r.raw(), self.raw()) == 1
+ ffi::BN_lshift1(r.as_ptr(), self.as_ptr()) == 1
})
}
}
/// Returns `self`, shifted right by 1 bit. `self` may be negative.
- pub fn checked_shr1(&self) -> Result<BigNum, SslError> {
+ pub fn checked_shr1(&self) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn!(r, {
- ffi::BN_rshift1(r.raw(), self.raw()) == 1
+ ffi::BN_rshift1(r.as_ptr(), self.as_ptr()) == 1
})
}
}
- pub fn checked_add(&self, a: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_add(&self, a: &BigNumRef) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn!(r, {
- ffi::BN_add(r.raw(), self.raw(), a.raw()) == 1
+ ffi::BN_add(r.as_ptr(), self.as_ptr(), a.as_ptr()) == 1
})
}
}
- pub fn checked_sub(&self, a: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_sub(&self, a: &BigNumRef) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn!(r, {
- ffi::BN_sub(r.raw(), self.raw(), a.raw()) == 1
+ ffi::BN_sub(r.as_ptr(), self.as_ptr(), a.as_ptr()) == 1
})
}
}
- pub fn checked_mul(&self, a: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_mul(&self, a: &BigNumRef) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
- ffi::BN_mul(r.raw(), self.raw(), a.raw(), ctx) == 1
+ ffi::BN_mul(r.as_ptr(), self.as_ptr(), a.as_ptr(), ctx) == 1
})
}
}
- pub fn checked_div(&self, a: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_div(&self, a: &BigNumRef) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
- ffi::BN_div(r.raw(), ptr::null_mut(), self.raw(), a.raw(), ctx) == 1
+ ffi::BN_div(r.as_ptr(), ptr::null_mut(), self.as_ptr(), a.as_ptr(), ctx) == 1
})
}
}
- pub fn checked_mod(&self, a: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_mod(&self, a: &BigNumRef) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
- ffi::BN_div(ptr::null_mut(), r.raw(), self.raw(), a.raw(), ctx) == 1
+ ffi::BN_div(ptr::null_mut(), r.as_ptr(), self.as_ptr(), a.as_ptr(), ctx) == 1
})
}
}
- pub fn checked_shl(&self, a: &i32) -> Result<BigNum, SslError> {
+ pub fn checked_shl(&self, a: &i32) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn!(r, {
- ffi::BN_lshift(r.raw(), self.raw(), *a as c_int) == 1
+ ffi::BN_lshift(r.as_ptr(), self.as_ptr(), *a as c_int) == 1
})
}
}
- pub fn checked_shr(&self, a: &i32) -> Result<BigNum, SslError> {
+ pub fn checked_shr(&self, a: &i32) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn!(r, {
- ffi::BN_rshift(r.raw(), self.raw(), *a as c_int) == 1
+ ffi::BN_rshift(r.as_ptr(), self.as_ptr(), *a as c_int) == 1
})
}
}
+ pub fn to_owned(&self) -> Result<BigNum, ErrorStack> {
+ unsafe {
+ let r = try_ssl_null!(ffi::BN_dup(self.as_ptr()));
+ Ok(BigNum::from_ptr(r))
+ }
+ }
+
/// Inverts the sign of `self`.
///
/// ```
@@ -563,7 +456,7 @@ impl BigNum {
/// assert_eq!(s, BigNum::new_from(8).unwrap());
/// ```
pub fn negate(&mut self) {
- unsafe { ffi::BN_set_negative(self.raw(), !self.is_negative() as c_int) }
+ unsafe { ffi::BN_set_negative(self.as_ptr(), !self.is_negative() as c_int) }
}
/// Compare the absolute values of `self` and `oth`.
@@ -574,11 +467,11 @@ impl BigNum {
/// let s = -BigNum::new_from(8).unwrap();
/// let o = BigNum::new_from(8).unwrap();
///
- /// assert_eq!(s.abs_cmp(o), Ordering::Equal);
+ /// assert_eq!(s.abs_cmp(&o), Ordering::Equal);
/// ```
- pub fn abs_cmp(&self, oth: BigNum) -> Ordering {
+ pub fn abs_cmp(&self, oth: &BigNumRef) -> Ordering {
unsafe {
- let res = ffi::BN_ucmp(self.raw(), oth.raw()) as i32;
+ let res = ffi::BN_ucmp(self.as_ptr(), oth.as_ptr()) as i32;
if res < 0 {
Ordering::Less
} else if res > 0 {
@@ -590,12 +483,12 @@ impl BigNum {
}
pub fn is_negative(&self) -> bool {
- unsafe { (*self.raw()).neg == 1 }
+ unsafe { (*self.as_ptr()).neg == 1 }
}
/// Returns the number of significant bits in `self`.
pub fn num_bits(&self) -> i32 {
- unsafe { ffi::BN_num_bits(self.raw()) as i32 }
+ unsafe { ffi::BN_num_bits(self.as_ptr()) as i32 }
}
/// Returns the size of `self` in bytes.
@@ -603,19 +496,8 @@ impl BigNum {
(self.num_bits() + 7) / 8
}
- pub unsafe fn raw(&self) -> *mut ffi::BIGNUM {
- let BigNum(n) = *self;
- n
- }
-
- pub unsafe fn raw_ptr(&self) -> *const *mut ffi::BIGNUM {
- let BigNum(ref n) = *self;
- n
- }
-
- pub fn into_raw(self) -> *mut ffi::BIGNUM {
- let mut me = self;
- mem::replace(&mut me.0, ptr::null_mut())
+ pub fn as_ptr(&self) -> *mut ffi::BIGNUM {
+ self.0
}
/// Returns a big-endian byte vector representation of the absolute value of `self`.
@@ -634,7 +516,7 @@ impl BigNum {
let size = self.num_bytes() as usize;
let mut v = Vec::with_capacity(size);
unsafe {
- ffi::BN_bn2bin(self.raw(), v.as_mut_ptr());
+ ffi::BN_bn2bin(self.as_ptr(), v.as_mut_ptr());
v.set_len(size);
}
v
@@ -650,7 +532,7 @@ impl BigNum {
/// ```
pub fn to_dec_str(&self) -> String {
unsafe {
- let buf = ffi::BN_bn2dec(self.raw());
+ let buf = ffi::BN_bn2dec(self.as_ptr());
assert!(!buf.is_null());
let str = String::from_utf8(CStr::from_ptr(buf as *const _).to_bytes().to_vec())
.unwrap();
@@ -669,7 +551,7 @@ impl BigNum {
/// ```
pub fn to_hex_str(&self) -> String {
unsafe {
- let buf = ffi::BN_bn2hex(self.raw());
+ let buf = ffi::BN_bn2hex(self.as_ptr());
assert!(!buf.is_null());
let str = String::from_utf8(CStr::from_ptr(buf as *const _).to_bytes().to_vec())
.unwrap();
@@ -679,134 +561,432 @@ impl BigNum {
}
}
+/// An owned, signed, arbitrary-precision integer.
+///
+/// `BigNum` provides wrappers around OpenSSL's checked arithmetic functions.
+/// Additionally, it implements the standard operators (`std::ops`), which
+/// perform unchecked arithmetic, unwrapping the returned `Result` of the
+/// checked operations.
+pub struct BigNum(BigNumRef<'static>);
+
+impl BigNum {
+ /// Creates a new `BigNum` with the value 0.
+ pub fn new() -> Result<BigNum, ErrorStack> {
+ unsafe {
+ ffi::init();
+ let v = try_ssl_null!(ffi::BN_new());
+ Ok(BigNum::from_ptr(v))
+ }
+ }
+
+ /// Creates a new `BigNum` with the given value.
+ pub fn new_from(n: c_ulong) -> Result<BigNum, ErrorStack> {
+ BigNum::new().and_then(|v| unsafe {
+ try_ssl!(ffi::BN_set_word(v.as_ptr(), n));
+ Ok(v)
+ })
+ }
+
+ /// Creates a `BigNum` from a decimal string.
+ pub fn from_dec_str(s: &str) -> Result<BigNum, ErrorStack> {
+ BigNum::new().and_then(|v| unsafe {
+ let c_str = CString::new(s.as_bytes()).unwrap();
+ try_ssl!(ffi::BN_dec2bn(&(v.0).0, c_str.as_ptr() as *const _));
+ Ok(v)
+ })
+ }
+
+ /// Creates a `BigNum` from a hexadecimal string.
+ pub fn from_hex_str(s: &str) -> Result<BigNum, ErrorStack> {
+ BigNum::new().and_then(|v| unsafe {
+ let c_str = CString::new(s.as_bytes()).unwrap();
+ try_ssl!(ffi::BN_hex2bn(&(v.0).0, c_str.as_ptr() as *const _));
+ Ok(v)
+ })
+ }
+
+ pub unsafe fn from_ptr(handle: *mut ffi::BIGNUM) -> BigNum {
+ BigNum(BigNumRef::from_ptr(handle))
+ }
+
+ /// Creates a new `BigNum` from an unsigned, big-endian encoded number of arbitrary length.
+ ///
+ /// ```
+ /// # use openssl::bn::BigNum;
+ /// let bignum = BigNum::new_from_slice(&[0x12, 0x00, 0x34]).unwrap();
+ ///
+ /// assert_eq!(bignum, BigNum::new_from(0x120034).unwrap());
+ /// ```
+ pub fn new_from_slice(n: &[u8]) -> Result<BigNum, ErrorStack> {
+ BigNum::new().and_then(|v| unsafe {
+ try_ssl_null!(ffi::BN_bin2bn(n.as_ptr(), n.len() as c_int, v.as_ptr()));
+ Ok(v)
+ })
+ }
+ /// Generates a prime number.
+ ///
+ /// # Parameters
+ ///
+ /// * `bits`: The length of the prime in bits (lower bound).
+ /// * `safe`: If true, returns a "safe" prime `p` so that `(p-1)/2` is also prime.
+ /// * `add`/`rem`: If `add` is set to `Some(add)`, `p % add == rem` will hold, where `p` is the
+ /// generated prime and `rem` is `1` if not specified (`None`).
+ pub fn checked_generate_prime(bits: i32,
+ safe: bool,
+ add: Option<&BigNum>,
+ rem: Option<&BigNum>)
+ -> Result<BigNum, ErrorStack> {
+ unsafe {
+ with_bn_in_ctx!(r, ctx, {
+ let add_arg = add.map(|a| a.as_ptr()).unwrap_or(ptr::null_mut());
+ let rem_arg = rem.map(|r| r.as_ptr()).unwrap_or(ptr::null_mut());
+
+ ffi::BN_generate_prime_ex(r.as_ptr(),
+ bits as c_int,
+ safe as c_int,
+ add_arg,
+ rem_arg,
+ ptr::null()) == 1
+ })
+ }
+ }
+
+ /// Generates a cryptographically strong pseudo-random `BigNum`.
+ ///
+ /// # Parameters
+ ///
+ /// * `bits`: Length of the number in bits.
+ /// * `prop`: The desired properties of the number.
+ /// * `odd`: If `true`, the generated number will be odd.
+ pub fn checked_new_random(bits: i32, prop: RNGProperty, odd: bool) -> Result<BigNum, ErrorStack> {
+ unsafe {
+ with_bn_in_ctx!(r, ctx, {
+ ffi::BN_rand(r.as_ptr(), bits as c_int, prop as c_int, odd as c_int) == 1
+ })
+ }
+ }
+
+ /// The cryptographically weak counterpart to `checked_new_random`.
+ pub fn checked_new_pseudo_random(bits: i32,
+ prop: RNGProperty,
+ odd: bool)
+ -> Result<BigNum, ErrorStack> {
+ unsafe {
+ with_bn_in_ctx!(r, ctx, {
+ ffi::BN_pseudo_rand(r.as_ptr(), bits as c_int, prop as c_int, odd as c_int) == 1
+ })
+ }
+ }
+}
+
+impl Drop for BigNum {
+ fn drop(&mut self) {
+ unsafe { ffi::BN_clear_free(self.as_ptr()); }
+ }
+}
+
+impl Deref for BigNum {
+ type Target = BigNumRef<'static>;
+
+ fn deref(&self) -> &BigNumRef<'static> {
+ &self.0
+ }
+}
+
+impl DerefMut for BigNum {
+ fn deref_mut(&mut self) -> &mut BigNumRef<'static> {
+ &mut self.0
+ }
+}
+
+impl AsRef<BigNumRef<'static>> for BigNum {
+ fn as_ref(&self) -> &BigNumRef<'static> {
+ self.deref()
+ }
+}
+
+impl<'a> fmt::Debug for BigNumRef<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.to_dec_str())
+ }
+}
+
impl fmt::Debug for BigNum {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.to_dec_str())
}
}
-impl Eq for BigNum {}
+impl<'a> fmt::Display for BigNumRef<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.to_dec_str())
+ }
+}
+
+impl fmt::Display for BigNum {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.to_dec_str())
+ }
+}
+
+impl<'a, 'b> PartialEq<BigNumRef<'b>> for BigNumRef<'a> {
+ fn eq(&self, oth: &BigNumRef) -> bool {
+ unsafe { ffi::BN_cmp(self.as_ptr(), oth.as_ptr()) == 0 }
+ }
+}
+
+impl<'a> PartialEq<BigNum> for BigNumRef<'a> {
+ fn eq(&self, oth: &BigNum) -> bool {
+ self.eq(oth.deref())
+ }
+}
+
+impl<'a> Eq for BigNumRef<'a> {}
+
impl PartialEq for BigNum {
fn eq(&self, oth: &BigNum) -> bool {
- unsafe { ffi::BN_cmp(self.raw(), oth.raw()) == 0 }
+ self.deref().eq(oth)
}
}
-impl Ord for BigNum {
- fn cmp(&self, oth: &BigNum) -> Ordering {
- self.partial_cmp(oth).unwrap()
+impl<'a> PartialEq<BigNumRef<'a>> for BigNum {
+ fn eq(&self, oth: &BigNumRef) -> bool {
+ self.deref().eq(oth)
+ }
+}
+
+impl Eq for BigNum {}
+
+impl<'a, 'b> PartialOrd<BigNumRef<'b>> for BigNumRef<'a> {
+ fn partial_cmp(&self, oth: &BigNumRef) -> Option<Ordering> {
+ Some(self.cmp(oth))
+ }
+}
+
+impl<'a> PartialOrd<BigNum> for BigNumRef<'a> {
+ fn partial_cmp(&self, oth: &BigNum) -> Option<Ordering> {
+ Some(self.cmp(oth.deref()))
+ }
+}
+
+impl<'a> Ord for BigNumRef<'a> {
+ fn cmp(&self, oth: &BigNumRef) -> Ordering {
+ unsafe { ffi::BN_cmp(self.as_ptr(), oth.as_ptr()).cmp(&0) }
}
}
impl PartialOrd for BigNum {
fn partial_cmp(&self, oth: &BigNum) -> Option<Ordering> {
- unsafe {
- let v = ffi::BN_cmp(self.raw(), oth.raw());
- let ret = if v == 0 {
- Ordering::Equal
- } else if v < 0 {
- Ordering::Less
- } else {
- Ordering::Greater
- };
- Some(ret)
- }
+ self.deref().partial_cmp(oth.deref())
}
}
-impl Drop for BigNum {
- fn drop(&mut self) {
- unsafe {
- if !self.raw().is_null() {
- ffi::BN_clear_free(self.raw());
- }
- }
+impl<'a> PartialOrd<BigNumRef<'a>> for BigNum {
+ fn partial_cmp(&self, oth: &BigNumRef) -> Option<Ordering> {
+ self.deref().partial_cmp(oth)
}
}
-#[doc(hidden)] // This module only contains impls, so it's empty when generating docs
-pub mod unchecked {
- use std::ops::{Add, Div, Mul, Neg, Rem, Shl, Shr, Sub};
- use ffi;
- use super::BigNum;
+impl Ord for BigNum {
+ fn cmp(&self, oth: &BigNum) -> Ordering {
+ self.deref().cmp(oth.deref())
+ }
+}
- impl<'a> Add<&'a BigNum> for &'a BigNum {
- type Output = BigNum;
+impl<'a, 'b> Add<&'b BigNumRef<'b>> for &'a BigNumRef<'a> {
+ type Output = BigNum;
- fn add(self, oth: &'a BigNum) -> BigNum {
- self.checked_add(oth).unwrap()
- }
+ fn add(self, oth: &BigNumRef) -> BigNum {
+ self.checked_add(oth).unwrap()
}
+}
- impl<'a> Sub<&'a BigNum> for &'a BigNum {
- type Output = BigNum;
+impl<'a, 'b> Sub<&'b BigNumRef<'b>> for &'a BigNumRef<'a> {
+ type Output = BigNum;
- fn sub(self, oth: &'a BigNum) -> BigNum {
- self.checked_sub(oth).unwrap()
- }
+ fn sub(self, oth: &BigNumRef) -> BigNum {
+ self.checked_sub(oth).unwrap()
}
+}
- impl<'a> Mul<&'a BigNum> for &'a BigNum {
- type Output = BigNum;
+impl<'a, 'b> Sub<&'b BigNum> for &'a BigNumRef<'a> {
+ type Output = BigNum;
- fn mul(self, oth: &'a BigNum) -> BigNum {
- self.checked_mul(oth).unwrap()
- }
+ fn sub(self, oth: &BigNum) -> BigNum {
+ self.checked_sub(oth).unwrap()
}
+}
- impl<'a> Div<&'a BigNum> for &'a BigNum {
- type Output = BigNum;
+impl<'a, 'b> Sub<&'b BigNum> for &'a BigNum {
+ type Output = BigNum;
- fn div(self, oth: &'a BigNum) -> BigNum {
- self.checked_div(oth).unwrap()
- }
+ fn sub(self, oth: &BigNum) -> BigNum {
+ self.checked_sub(oth).unwrap()
}
+}
- impl<'a> Rem<&'a BigNum> for &'a BigNum {
- type Output = BigNum;
+impl<'a, 'b> Sub<&'b BigNumRef<'b>> for &'a BigNum {
+ type Output = BigNum;
- fn rem(self, oth: &'a BigNum) -> BigNum {
- self.checked_mod(oth).unwrap()
- }
+ fn sub(self, oth: &BigNumRef) -> BigNum {
+ self.checked_sub(oth).unwrap()
}
+}
- impl<'a> Shl<i32> for &'a BigNum {
- type Output = BigNum;
+impl<'a, 'b> Mul<&'b BigNumRef<'b>> for &'a BigNumRef<'a> {
+ type Output = BigNum;
- fn shl(self, n: i32) -> BigNum {
- self.checked_shl(&n).unwrap()
- }
+ fn mul(self, oth: &BigNumRef) -> BigNum {
+ self.checked_mul(oth).unwrap()
}
+}
- impl<'a> Shr<i32> for &'a BigNum {
- type Output = BigNum;
+impl<'a, 'b> Mul<&'b BigNum> for &'a BigNumRef<'a> {
+ type Output = BigNum;
- fn shr(self, n: i32) -> BigNum {
- self.checked_shr(&n).unwrap()
- }
+ fn mul(self, oth: &BigNum) -> BigNum {
+ self.checked_mul(oth).unwrap()
}
+}
- impl Clone for BigNum {
- fn clone(&self) -> BigNum {
- unsafe {
- let r = ffi::BN_dup(self.raw());
- if r.is_null() {
- panic!("Unexpected null pointer from BN_dup(..)")
- } else {
- BigNum(r)
- }
- }
- }
+impl<'a, 'b> Mul<&'b BigNum> for &'a BigNum {
+ type Output = BigNum;
+
+ fn mul(self, oth: &BigNum) -> BigNum {
+ self.checked_mul(oth).unwrap()
}
+}
- impl Neg for BigNum {
- type Output = BigNum;
+impl<'a, 'b> Mul<&'b BigNumRef<'b>> for &'a BigNum {
+ type Output = BigNum;
- fn neg(self) -> BigNum {
- let mut n = self.clone();
- n.negate();
- n
- }
+ fn mul(self, oth: &BigNumRef) -> BigNum {
+ self.checked_mul(oth).unwrap()
+ }
+}
+
+impl<'a, 'b> Div<&'b BigNumRef<'b>> for &'a BigNumRef<'a> {
+ type Output = BigNum;
+
+ fn div(self, oth: &'b BigNumRef<'b>) -> BigNum {
+ self.checked_div(oth).unwrap()
+ }
+}
+
+impl<'a, 'b> Div<&'b BigNum> for &'a BigNumRef<'a> {
+ type Output = BigNum;
+
+ fn div(self, oth: &'b BigNum) -> BigNum {
+ self.checked_div(oth).unwrap()
+ }
+}
+
+impl<'a, 'b> Div<&'b BigNum> for &'a BigNum {
+ type Output = BigNum;
+
+ fn div(self, oth: &'b BigNum) -> BigNum {
+ self.checked_div(oth).unwrap()
+ }
+}
+
+impl<'a, 'b> Div<&'b BigNumRef<'b>> for &'a BigNum {
+ type Output = BigNum;
+
+ fn div(self, oth: &'b BigNumRef<'b>) -> BigNum {
+ self.checked_div(oth).unwrap()
+ }
+}
+
+impl<'a, 'b> Rem<&'b BigNumRef<'b>> for &'a BigNumRef<'a> {
+ type Output = BigNum;
+
+ fn rem(self, oth: &'b BigNumRef<'b>) -> BigNum {
+ self.checked_mod(oth).unwrap()
+ }
+}
+
+impl<'a, 'b> Rem<&'b BigNum> for &'a BigNumRef<'a> {
+ type Output = BigNum;
+
+ fn rem(self, oth: &'b BigNum) -> BigNum {
+ self.checked_mod(oth).unwrap()
+ }
+}
+
+impl<'a, 'b> Rem<&'b BigNumRef<'b>> for &'a BigNum {
+ type Output = BigNum;
+
+ fn rem(self, oth: &'b BigNumRef<'b>) -> BigNum {
+ self.checked_mod(oth).unwrap()
+ }
+}
+
+impl<'a, 'b> Rem<&'b BigNum> for &'a BigNum {
+ type Output = BigNum;
+
+ fn rem(self, oth: &'b BigNum) -> BigNum {
+ self.checked_mod(oth).unwrap()
+ }
+}
+
+impl<'a> Shl<i32> for &'a BigNumRef<'a> {
+ type Output = BigNum;
+
+ fn shl(self, n: i32) -> BigNum {
+ self.checked_shl(&n).unwrap()
+ }
+}
+
+impl<'a> Shl<i32> for &'a BigNum {
+ type Output = BigNum;
+
+ fn shl(self, n: i32) -> BigNum {
+ self.checked_shl(&n).unwrap()
+ }
+}
+
+impl<'a> Shr<i32> for &'a BigNumRef<'a> {
+ type Output = BigNum;
+
+ fn shr(self, n: i32) -> BigNum {
+ self.checked_shr(&n).unwrap()
+ }
+}
+
+impl<'a> Shr<i32> for &'a BigNum {
+ type Output = BigNum;
+
+ fn shr(self, n: i32) -> BigNum {
+ self.checked_shr(&n).unwrap()
+ }
+}
+
+impl<'a> Neg for &'a BigNumRef<'a> {
+ type Output = BigNum;
+
+ fn neg(self) -> BigNum {
+ let mut n = self.to_owned().unwrap();
+ n.negate();
+ n
+ }
+}
+
+impl<'a> Neg for &'a BigNum {
+ type Output = BigNum;
+
+ fn neg(self) -> BigNum {
+ let mut n = self.deref().to_owned().unwrap();
+ n.negate();
+ n
+ }
+}
+
+impl Neg for BigNum {
+ type Output = BigNum;
+
+ fn neg(mut self) -> BigNum {
+ self.negate();
+ self
}
}
@@ -816,7 +996,7 @@ mod tests {
#[test]
fn test_to_from_slice() {
- let v0 = BigNum::new_from(10203004_u64).unwrap();
+ let v0 = BigNum::new_from(10203004).unwrap();
let vec = v0.to_vec();
let v1 = BigNum::new_from_slice(&vec).unwrap();
@@ -825,7 +1005,7 @@ mod tests {
#[test]
fn test_negation() {
- let a = BigNum::new_from(909829283_u64).unwrap();
+ let a = BigNum::new_from(909829283).unwrap();
assert!(!a.is_negative());
assert!((-a).is_negative());
@@ -834,7 +1014,7 @@ mod tests {
#[test]
fn test_prime_numbers() {
- let a = BigNum::new_from(19029017_u64).unwrap();
+ let a = BigNum::new_from(19029017).unwrap();
let p = BigNum::checked_generate_prime(128, true, None, Some(&a)).unwrap();
assert!(p.is_prime(100).unwrap());
diff --git a/openssl/src/c_helpers.c b/openssl/src/c_helpers.c
index e884bebd..13041956 100644
--- a/openssl/src/c_helpers.c
+++ b/openssl/src/c_helpers.c
@@ -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
diff --git a/openssl/src/c_helpers.rs b/openssl/src/c_helpers.rs
new file mode 100644
index 00000000..90fcf877
--- /dev/null
+++ b/openssl/src/c_helpers.rs
@@ -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;
+}
diff --git a/openssl/src/crypto/dsa.rs b/openssl/src/crypto/dsa.rs
new file mode 100644
index 00000000..97ba7a97
--- /dev/null
+++ b/openssl/src/crypto/dsa.rs
@@ -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);
+ }
+}
diff --git a/openssl/src/crypto/hash.rs b/openssl/src/crypto/hash.rs
index 69d3a350..207a55f5 100644
--- a/openssl/src/crypto/hash.rs
+++ b/openssl/src/crypto/hash.rs
@@ -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());
}
- unsafe {
- let r = ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), data.len() as c_uint);
- assert_eq!(r, 1);
+ while !data.is_empty() {
+ let len = cmp::min(data.len(), c_uint::max_value() as usize);
+ unsafe {
+ try_ssl!(ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), len as c_uint));
+ }
+ data = &data[len..];
}
self.state = Updated;
+ Ok(())
}
- #[inline]
- fn finalize(&mut self) -> Vec<u8> {
+ /// Returns the hash of the data written since creation or
+ /// the last `finish` and resets the hasher.
+ pub fn finish(&mut self) -> Result<Vec<u8>, ErrorStack> {
if self.state == Finalized {
- self.init();
+ try!(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);
+ 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;
- assert_eq!(len as usize, md_len);
- assert_eq!(r, 1);
+ Ok(res)
}
- res
- }
-
- /// 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()
}
}
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);
}
diff --git a/openssl/src/crypto/hmac.rs b/openssl/src/crypto/hmac.rs
index 143c7b75..857be339 100644
--- a/openssl/src/crypto/hmac.rs
+++ b/openssl/src/crypto/hmac.rs
@@ -14,13 +14,15 @@
//
use libc::{c_int, c_uint};
-use std::iter::repeat;
use std::io;
use std::io::prelude::*;
+use std::cmp;
+use ffi;
+use HashTypeInternals;
use crypto::hash::Type;
-use ffi;
-use ffi_extras;
+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(),
- key.len() as c_int,
- md,
- 0 as *const _);
- assert_eq!(r, 1);
+ try_ssl!(c_helpers::rust_HMAC_Init_ex(&mut self.ctx,
+ key.as_ptr() as *const _,
+ key.len() as c_int,
+ md,
+ 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,
- 0 as *const _,
- 0,
- 0 as *const _,
- 0 as *const _);
- assert_eq!(r, 1);
+ try_ssl!(c_helpers::rust_HMAC_Init_ex(&mut self.ctx,
+ 0 as *const _,
+ 0,
+ 0 as *const _,
+ 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());
}
- unsafe {
- let r = ffi_extras::HMAC_Update(&mut self.ctx, data.as_ptr(), data.len() as c_uint);
- assert_eq!(r, 1);
+ while !data.is_empty() {
+ let len = cmp::min(data.len(), c_uint::max_value() as usize);
+ unsafe {
+ try_ssl!(c_helpers::rust_HMAC_Update(&mut self.ctx, data.as_ptr(), len as c_uint));
+ }
+ data = &data[len..];
}
self.state = Updated;
+ Ok(())
}
- #[inline]
- fn finalize(&mut self) -> Vec<u8> {
+ /// Returns the hash of the data written since creation or
+ /// the last `finish` and resets the hasher.
+ pub fn finish(&mut self) -> Result<Vec<u8>, ErrorStack> {
if self.state == Finalized {
- self.init();
+ try!(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);
+ 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;
- assert_eq!(len as usize, md_len);
- assert_eq!(r, 1);
+ Ok(res)
}
- res
- }
-
- /// 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()
}
}
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());
diff --git a/openssl/src/crypto/mod.rs b/openssl/src/crypto/mod.rs
index 95b27022..93aba9eb 100644
--- a/openssl/src/crypto/mod.rs
+++ b/openssl/src/crypto/mod.rs
@@ -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;
diff --git a/openssl/src/crypto/pkcs5.rs b/openssl/src/crypto/pkcs5.rs
index 0ba005cc..ef84fbe1 100644
--- a/openssl/src/crypto/pkcs5.rs
+++ b/openssl/src/crypto/pkcs5.rs
@@ -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 {
@@ -16,125 +17,102 @@ pub struct KeyIvPair {
///
/// If specified `salt` must be 8 bytes in length.
///
-/// If the total key and IV length is less than 16 bytes and MD5 is used then
-/// the algorithm is compatible with the key derivation algorithm from PKCS#5
+/// If the total key and IV length is less than 16 bytes and MD5 is used then
+/// the algorithm is compatible with the key derivation algorithm from PKCS#5
/// v1.5 or PBKDF1 from PKCS#5 v2.0.
///
-/// New applications should not use this and instead use `pbkdf2_hmac_sha1` or
+/// New applications should not use this and instead use `pbkdf2_hmac_sha1` or
/// another more modern key derivation algorithm.
pub fn evp_bytes_to_key_pbkdf1_compatible(typ: symm::Type,
message_digest_type: hash::Type,
data: &[u8],
salt: Option<&[u8]>,
count: u32)
- -> 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 message_digest = message_digest_type.evp_md();
-
- let mut key = vec![0; keylen as usize];
- let mut iv = vec![0; keylen as usize];
+ let typ = typ.as_ptr();
+ let message_digest_type = message_digest_type.evp_md();
+
+ let len = ffi::EVP_BytesToKey(typ,
+ message_digest_type,
+ salt_ptr,
+ data.as_ptr(),
+ data.len() as c_int,
+ count as c_int,
+ ptr::null_mut(),
+ ptr::null_mut());
+ if len == 0 {
+ return Err(ErrorStack::get());
+ }
+ let mut key = vec![0; len as usize];
+ let mut iv = vec![0; len as usize];
- let ret: c_int = ffi::EVP_BytesToKey(evp,
- message_digest,
- 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);
+ 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()));
- 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(),
- 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.set_len(keylen);
-
- out
+ try_ssl!(ffi::PKCS5_PBKDF2_HMAC_SHA1(pass.as_ptr(),
+ pass.len() as c_int,
+ salt.as_ptr(),
+ salt.len() as c_int,
+ iter as c_int,
+ keylen as c_int,
+ out.as_mut_ptr()));
+ Ok(out)
}
}
-/// Derives a key from a password and salt using the PBKDF2-HMAC-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(),
- pass.len() as c_int,
- salt.as_ptr(),
- salt.len() as c_int,
- iter as c_int,
- digest,
- keylen as c_int,
- out.as_mut_ptr());
-
- if r != 1 {
- panic!();
- }
-
- out.set_len(keylen);
-
- out
+ try_ssl!(ffi::PKCS5_PBKDF2_HMAC(pass.as_ptr(),
+ pass.len() as c_int,
+ salt.as_ptr(),
+ salt.len() as c_int,
+ iter as c_int,
+ hash.evp_md(),
+ keylen as c_int,
+ out.as_mut_ptr()));
+ Ok(out)
}
}
@@ -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(),
- 50,
- 64),
+ assert_eq!(super::pbkdf2_hmac(b"passwordPASSWORDpassword",
+ b"salt\0\0\0",
+ 50,
+ hash::Type::SHA512,
+ 64).unwrap(),
vec![0x01_u8, 0x68_u8, 0x71_u8, 0xa4_u8, 0xc4_u8, 0xb7_u8, 0x5f_u8, 0x96_u8,
0x85_u8, 0x7f_u8, 0xd2_u8, 0xb9_u8, 0xf8_u8, 0xca_u8, 0x28_u8, 0x02_u8,
0x3b_u8, 0x30_u8, 0xee_u8, 0x2a_u8, 0x39_u8, 0xf5_u8, 0xad_u8, 0xca_u8,
@@ -257,7 +236,7 @@ mod tests {
hash::Type::SHA1,
&data,
Some(&salt),
- 1),
+ 1).unwrap(),
super::KeyIvPair {
key: expected_key,
iv: expected_iv,
diff --git a/openssl/src/crypto/pkey.rs b/openssl/src/crypto/pkey.rs
index c4111860..a2a6f9c1 100644
--- a/openssl/src/crypto/pkey.rs
+++ b/openssl/src/crypto/pkey.rs
@@ -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 crypto::rsa::RSA;
-
-#[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,
- }
-}
+use bio::{MemBio, MemBioSlice};
+use crypto::rsa::RSA;
+use error::ErrorStack;
+use crypto::util::{CallbackState, invoke_passwd_cb};
-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,
- })
- }
- }
-
- /// 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));
-
- unsafe {
- let evp = try_ssl_null!(ffi::PEM_read_bio_PUBKEY(mem_bio.get_handle(),
- 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,
- })
+ Ok(PKey::from_ptr(evp))
}
}
- /// 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
+ /// 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
{
- 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 {
+ ffi::init();
+ let mut cb = CallbackState::new(pass_cb);
+ let mem_bio = try!(MemBioSlice::new(buf));
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
- }
+ 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))
}
}
- pub fn gen(&mut self, keysz: usize) {
+ /// Reads public key from PEM, takes ownership of handle
+ pub fn public_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
+ ffi::init();
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
- let 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;
+ let evp = try_ssl_null!(ffi::PEM_read_bio_PUBKEY(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ None,
+ ptr::null_mut()));
+ Ok(PKey::from_ptr(evp))
}
}
/// assign RSA key to this pkey
- pub fn set_rsa(&mut self, rsa: &RSA) {
+ 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)
- }
-
- /**
- * 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 fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
+ unsafe { try_ssl!(ffi::PEM_write_bio_PUBKEY(mem_bio.as_ptr(), self.0)) }
+ Ok(mem_bio.get_buf().to_owned())
}
- pub 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);
- }
- }
-}
-
-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 => {}
+ ffi::EVP_PKEY_free(self.0);
}
- 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 = super::PKey::private_key_from_pem(&mut file).unwrap();
+ let key = include_bytes!("../../test/key.pem");
+ let key = super::PKey::private_key_from_pem(key).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());
- }
}
diff --git a/openssl/src/crypto/rand.rs b/openssl/src/crypto/rand.rs
index ba57a8a1..519449e9 100644
--- a/openssl/src/crypto/rand.rs
+++ b/openssl/src/crypto/rand.rs
@@ -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();
}
}
diff --git a/openssl/src/crypto/rsa.rs b/openssl/src/crypto/rsa.rs
index 52b8590e..feb66a6f 100644
--- a/openssl/src/crypto/rsa.rs
+++ b/openssl/src/crypto/rsa.rs
@@ -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,53 @@ 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)
}
- /// 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
- {
- let mut mem_bio = try!(MemBio::new());
- try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
+ /// Generates a public/private key pair with the specified size.
+ ///
+ /// The public exponent will be 65537.
+ pub fn generate(bits: u32) -> Result<RSA, ErrorStack> {
+ unsafe {
+ let rsa = try_ssl_null!(ffi::RSA_new());
+ let rsa = RSA(rsa);
+ let e = try!(BigNum::new_from(ffi::RSA_F4 as c_ulong));
+
+ try_ssl!(ffi::RSA_generate_key_ex(rsa.0, bits as c_int, e.as_ptr(), ptr::null_mut()));
+ Ok(rsa)
+ }
+ }
+
+ /// Reads an RSA private key from PEM formatted data.
+ pub fn private_key_from_pem(buf: &[u8]) -> Result<RSA, ErrorStack> {
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
- let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.get_handle(),
+ let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(),
ptr::null_mut(),
None,
ptr::null_mut()));
@@ -76,40 +97,29 @@ 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
+ /// Reads an RSA private key from PEM formatted data and supplies a password callback.
+ pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<RSA, ErrorStack>
+ where F: FnOnce(&mut [c_char]) -> usize
{
- let mut mem_bio = try!(MemBio::new());
+ let mut cb = CallbackState::new(pass_cb);
+ let mem_bio = try!(MemBioSlice::new(buf));
- let result = unsafe {
- ffi::PEM_write_bio_RSAPrivateKey(mem_bio.get_handle(),
- 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));
+ unsafe {
+ let cb_ptr = &mut cb as *mut _ as *mut c_void;
+ let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ Some(invoke_passwd_cb::<F>),
+ cb_ptr));
- Ok(())
- } else {
- Err(SslError::OpenSslErrors(vec![]))
+ Ok(RSA(rsa))
}
}
/// 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));
-
+ 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.get_handle(),
+ let rsa = try_ssl_null!(ffi::PEM_read_bio_RSA_PUBKEY(mem_bio.as_ptr(),
ptr::null_mut(),
None,
ptr::null_mut()));
@@ -117,97 +127,127 @@ impl RSA {
}
}
- /// 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());
+ /// Writes an RSA private key as unencrypted PEM formatted data
+ pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
+
+ unsafe {
+ try_ssl!(ffi::PEM_write_bio_RSAPrivateKey(mem_bio.as_ptr(),
+ self.0,
+ ptr::null(),
+ ptr::null_mut(),
+ 0,
+ None,
+ ptr::null_mut()));
+ }
+ Ok(mem_bio.get_buf().to_owned())
+ }
- let result = unsafe { ffi::PEM_write_bio_RSA_PUBKEY(mem_bio.get_handle(), self.0) };
+ /// Writes an RSA public key as PEM formatted data
+ pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
- if result == 1 {
- try!(io::copy(&mut mem_bio, writer).map_err(StreamError));
+ unsafe {
+ try_ssl!(ffi::PEM_write_bio_RSA_PUBKEY(mem_bio.as_ptr(), self.0))
+ };
- Ok(())
- } else {
- Err(SslError::OpenSslErrors(vec![]))
- }
+ Ok(mem_bio.get_buf().to_owned())
}
- pub fn size(&self) -> Result<u32, SslError> {
- if self.has_n() {
- unsafe { Ok(ffi::RSA_size(self.0) as u32) }
+ 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 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,
- message.as_ptr(),
- message.len() as u32,
- sig.as_mut_ptr(),
- &mut sig_len,
- self.0);
+ try_ssl!(ffi::RSA_sign(hash.as_nid() as c_int,
+ message.as_ptr(),
+ message.len() as u32,
+ sig.as_mut_ptr(),
+ &mut sig_len,
+ self.0));
assert!(sig_len == k_len);
-
- if result == 1 {
- Ok(sig)
- } else {
- Err(SslError::OpenSslErrors(vec![]))
- }
+ Ok(sig)
}
}
- 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,
- message.as_ptr(),
- message.len() as u32,
- sig.as_ptr(),
- sig.len() as u32,
- self.0);
-
- Ok(result == 1)
+ try_ssl!(ffi::RSA_verify(hash.as_nid() as c_int,
+ message.as_ptr(),
+ message.len() as u32,
+ sig.as_ptr(),
+ sig.len() as u32,
+ self.0));
}
+ Ok(())
}
pub fn as_ptr(&self) -> *mut ffi::RSA {
self.0
}
- // 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 has_n(&self) -> bool {
- unsafe { !(*self.0).n.is_null() }
- }
-
- pub fn d(&self) -> Result<BigNum, SslError> {
- unsafe { BigNum::new_from_ffi((*self.0).d) }
+ 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 e(&self) -> Result<BigNum, SslError> {
- unsafe { BigNum::new_from_ffi((*self.0).e) }
+ 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 has_e(&self) -> bool {
- unsafe { !(*self.0).e.is_null() }
+ pub fn e<'a>(&'a self) -> Option<BigNumRef<'a>> {
+ unsafe {
+ let e = (*self.0).e;
+ if e.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr(e))
+ }
+ }
}
- pub fn p(&self) -> Result<BigNum, SslError> {
- unsafe { BigNum::new_from_ffi((*self.0).p) }
+ pub fn p<'a>(&'a self) -> Option<BigNumRef<'a>> {
+ unsafe {
+ let p = (*self.0).p;
+ if p.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr(p))
+ }
+ }
}
- pub fn q(&self) -> Result<BigNum, SslError> {
- unsafe { BigNum::new_from_ffi((*self.0).q) }
+ 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))
+ }
+ }
}
}
@@ -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);
}
}
diff --git a/openssl/src/crypto/symm.rs b/openssl/src/crypto/symm.rs
index 935980f3..93764e4d 100644
--- a/openssl/src/crypto/symm.rs
+++ b/openssl/src/crypto/symm.rs
@@ -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,
- 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
- };
- ffi::EVP_CIPHER_CTX_set_padding(self.ctx, v);
- }
- }
- }
-
- /**
- * Initializes this crypter.
- */
- pub fn init(&self, mode: Mode, key: &[u8], iv: &[u8]) {
unsafe {
+ let ctx = try_ssl_null!(ffi::EVP_CIPHER_CTX_new());
+ let crypter = Crypter {
+ ctx: ctx,
+ block_size: t.block_size(),
+ };
+
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;
-
- ffi::EVP_CipherUpdate(self.ctx,
- res.as_mut_ptr(),
- &mut reslen,
- data.as_ptr(),
- data.len() as c_int);
-
- res.truncate(reslen as usize);
- res
+ 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;
+
+ try_ssl!(ffi::EVP_CipherUpdate(self.ctx,
+ output.as_mut_ptr(),
+ &mut outl,
+ input.as_ptr(),
+ inl));
+
+ 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());
diff --git a/openssl/src/crypto/symm_internal.rs b/openssl/src/crypto/symm_internal.rs
deleted file mode 100644
index ba01e1c1..00000000
--- a/openssl/src/crypto/symm_internal.rs
+++ /dev/null
@@ -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),
- }
- }
-}
diff --git a/openssl/src/crypto/util.rs b/openssl/src/crypto/util.rs
new file mode 100644
index 00000000..be72aa59
--- /dev/null
+++ b/openssl/src/crypto/util.rs
@@ -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;
+ }
+}
diff --git a/openssl/src/dh/mod.rs b/openssl/src/dh/mod.rs
index d2f26c3f..78dcb778 100644
--- a/openssl/src/dh/mod.rs
+++ b/openssl/src/dh/mod.rs
@@ -1,78 +1,71 @@
use ffi;
-use std::io;
-use std::io::prelude::*;
-use ssl::error::{SslError, StreamError};
-use bio::MemBio;
+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;
-use std::ptr;
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();
}
}
diff --git a/openssl/src/error.rs b/openssl/src/error.rs
new file mode 100644
index 00000000..5fa542c2
--- /dev/null
+++ b/openssl/src/error.rs
@@ -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()
+ }
+}
+
diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs
index 690ab32b..d7e69b0c 100644
--- a/openssl/src/lib.rs
+++ b/openssl/src/lib.rs
@@ -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;
+}
diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs
index 3e4bb429..35221f1c 100644
--- a/openssl/src/macros.rs
+++ b/openssl/src/macros.rs
@@ -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(())
}
diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs
index b6f20cf2..c5663eb1 100644
--- a/openssl/src/ssl/bio.rs
+++ b/openssl/src/ssl/bio.rs
@@ -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 {
diff --git a/openssl/src/ssl/error.rs b/openssl/src/ssl/error.rs
index 2459a473..95213361 100644
--- a/openssl/src/ssl/error.rs
+++ b/openssl/src/ssl/error.rs
@@ -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,30 +20,16 @@ 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;
- } else {
- try!(fmt.write_str(", "));
- }
- try!(fmt.write_str(&err.reason()))
- }
- Ok(())
- }
- _ => Ok(()),
+ if let Some(err) = self.cause() {
+ write!(fmt, ": {}", err)
+ } else {
+ 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 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",
- }
+impl From<ErrorStack> for Error {
+ fn from(e: ErrorStack) -> Error {
+ Error::Ssl(e)
}
-
- 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");
}
diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs
index d0954bc7..82ee3127 100644
--- a/openssl/src/ssl/mod.rs
+++ b/openssl/src/ssl/mod.rs
@@ -1,34 +1,31 @@
use libc::{c_int, c_void, c_long};
+use std::any::Any;
use std::any::TypeId;
+use std::cmp;
use std::collections::HashMap;
+use std::error as stderror;
use std::ffi::{CStr, CString};
use std::fmt;
use std::io;
use std::io::prelude::*;
use std::mem;
-use std::str;
-use std::net;
+use std::ops::{Deref, DerefMut};
use std::path::Path;
use std::ptr;
-use std::sync::{Once, ONCE_INIT, Mutex, Arc};
-use std::cmp;
-use std::any::Any;
+use std::str;
+use std::sync::{Mutex, Arc};
#[cfg(any(feature = "npn", feature = "alpn"))]
use libc::{c_uchar, c_uint};
#[cfg(any(feature = "npn", feature = "alpn"))]
use std::slice;
use std::marker::PhantomData;
-#[cfg(unix)]
-use std::os::unix::io::{AsRawFd, RawFd};
-#[cfg(windows)]
-use std::os::windows::io::{AsRawSocket, RawSocket};
-
use ffi;
-use ffi_extras;
+
+use init;
use dh::DH;
-use ssl::error::{NonblockingSslError, SslError, OpenSslError, OpensslError};
-use x509::{X509StoreContext, X509FileType, X509};
+use x509::{X509StoreContext, X509FileType, X509, X509Ref};
use crypto::pkey::PKey;
+use error::ErrorStack;
pub mod error;
mod bio;
@@ -40,81 +37,35 @@ use self::bio::BioMethod;
#[doc(inline)]
pub use ssl::error::Error;
-extern "C" {
- fn rust_SSL_clone(ssl: *mut ffi::SSL);
- fn rust_SSL_CTX_clone(cxt: *mut ffi::SSL_CTX);
-}
-
-static mut VERIFY_IDX: c_int = -1;
-static mut SNI_IDX: c_int = -1;
-
-/// Manually initialize SSL.
-/// It is optional to call this function and safe to do so more than once.
-pub fn init() {
- static mut INIT: Once = ONCE_INIT;
-
- unsafe {
- INIT.call_once(|| {
- ffi::init();
-
- let verify_idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, None);
- assert!(verify_idx >= 0);
- VERIFY_IDX = verify_idx;
-
- let sni_idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, None);
- assert!(sni_idx >= 0);
- SNI_IDX = sni_idx;
- });
- }
-}
-
bitflags! {
- pub flags SslContextOptions: u64 {
- const SSL_OP_MICROSOFT_SESS_ID_BUG = ::ffi_extras::SSL_OP_MICROSOFT_SESS_ID_BUG,
- const SSL_OP_NETSCAPE_CHALLENGE_BUG = ::ffi_extras::SSL_OP_NETSCAPE_CHALLENGE_BUG,
- const SSL_OP_LEGACY_SERVER_CONNECT = ::ffi_extras::SSL_OP_LEGACY_SERVER_CONNECT,
- const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = ::ffi_extras::SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG,
- const SSL_OP_TLSEXT_PADDING = ::ffi_extras::SSL_OP_TLSEXT_PADDING,
- const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = ::ffi_extras::SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER,
- const SSL_OP_SAFARI_ECDHE_ECDSA_BUG = ::ffi_extras::SSL_OP_SAFARI_ECDHE_ECDSA_BUG,
- const SSL_OP_SSLEAY_080_CLIENT_DH_BUG = ::ffi_extras::SSL_OP_SSLEAY_080_CLIENT_DH_BUG,
- const SSL_OP_TLS_D5_BUG = ::ffi_extras::SSL_OP_TLS_D5_BUG,
- const SSL_OP_TLS_BLOCK_PADDING_BUG = ::ffi_extras::SSL_OP_TLS_BLOCK_PADDING_BUG,
- const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = ::ffi_extras::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS,
- const SSL_OP_NO_QUERY_MTU = ::ffi_extras::SSL_OP_NO_QUERY_MTU,
- const SSL_OP_COOKIE_EXCHANGE = ::ffi_extras::SSL_OP_COOKIE_EXCHANGE,
- const SSL_OP_NO_TICKET = ::ffi_extras::SSL_OP_NO_TICKET,
- const SSL_OP_CISCO_ANYCONNECT = ::ffi_extras::SSL_OP_CISCO_ANYCONNECT,
- const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = ::ffi_extras::SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION,
- const SSL_OP_NO_COMPRESSION = ::ffi_extras::SSL_OP_NO_COMPRESSION,
- const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = ::ffi_extras::SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION,
- const SSL_OP_SINGLE_ECDH_USE = ::ffi_extras::SSL_OP_SINGLE_ECDH_USE,
- const SSL_OP_SINGLE_DH_USE = ::ffi_extras::SSL_OP_SINGLE_DH_USE,
- const SSL_OP_CIPHER_SERVER_PREFERENCE = ::ffi_extras::SSL_OP_CIPHER_SERVER_PREFERENCE,
- const SSL_OP_TLS_ROLLBACK_BUG = ::ffi_extras::SSL_OP_TLS_ROLLBACK_BUG,
- const SSL_OP_NO_SSLV2 = ::ffi_extras::SSL_OP_NO_SSLv2,
- const SSL_OP_NO_SSLV3 = ::ffi_extras::SSL_OP_NO_SSLv3,
- const SSL_OP_NO_DTLSV1 = ::ffi_extras::SSL_OP_NO_DTLSv1,
- const SSL_OP_NO_TLSV1 = ::ffi_extras::SSL_OP_NO_TLSv1,
- const SSL_OP_NO_DTLSV1_2 = ::ffi_extras::SSL_OP_NO_DTLSv1_2,
- const SSL_OP_NO_TLSV1_2 = ::ffi_extras::SSL_OP_NO_TLSv1_2,
- const SSL_OP_NO_TLSV1_1 = ::ffi_extras::SSL_OP_NO_TLSv1_1,
- const SSL_OP_NETSCAPE_CA_DN_BUG = ::ffi_extras::SSL_OP_NETSCAPE_CA_DN_BUG,
- const SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG = ::ffi_extras::SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG,
- const SSL_OP_CRYPTOPRO_TLSEXT_BUG = ::ffi_extras::SSL_OP_CRYPTOPRO_TLSEXT_BUG,
- const SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG = ::ffi_extras::SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG,
- const SSL_OP_MSIE_SSLV2_RSA_PADDING = ::ffi_extras::SSL_OP_MSIE_SSLV2_RSA_PADDING,
- const SSL_OP_PKCS1_CHECK_1 = ::ffi_extras::SSL_OP_PKCS1_CHECK_1,
- const SSL_OP_PKCS1_CHECK_2 = ::ffi_extras::SSL_OP_PKCS1_CHECK_2,
- const SSL_OP_EPHEMERAL_RSA = ::ffi_extras::SSL_OP_EPHEMERAL_RSA,
- const SSL_OP_ALL = SSL_OP_MICROSOFT_SESS_ID_BUG.bits|SSL_OP_NETSCAPE_CHALLENGE_BUG.bits
- |SSL_OP_LEGACY_SERVER_CONNECT.bits|SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG.bits
- |SSL_OP_TLSEXT_PADDING.bits|SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER.bits
- |SSL_OP_SAFARI_ECDHE_ECDSA_BUG.bits|SSL_OP_SSLEAY_080_CLIENT_DH_BUG.bits
- |SSL_OP_TLS_D5_BUG.bits|SSL_OP_TLS_BLOCK_PADDING_BUG.bits
- |SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS.bits|SSL_OP_CRYPTOPRO_TLSEXT_BUG.bits,
- const SSL_OP_NO_SSL_MASK = SSL_OP_NO_SSLV2.bits|SSL_OP_NO_SSLV3.bits|SSL_OP_NO_TLSV1.bits
- |SSL_OP_NO_TLSV1_1.bits|SSL_OP_NO_TLSV1_2.bits,
+ pub flags SslContextOptions: c_long {
+ const SSL_OP_MICROSOFT_SESS_ID_BUG = ffi::SSL_OP_MICROSOFT_SESS_ID_BUG,
+ const SSL_OP_NETSCAPE_CHALLENGE_BUG = ffi::SSL_OP_NETSCAPE_CHALLENGE_BUG,
+ const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG =
+ ffi::SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG,
+ const SSL_OP_TLSEXT_PADDING = ffi::SSL_OP_TLSEXT_PADDING,
+ const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = ffi::SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER,
+ const SSL_OP_SSLEAY_080_CLIENT_DH_BUG = ffi::SSL_OP_SSLEAY_080_CLIENT_DH_BUG,
+ const SSL_OP_TLS_D5_BUG = ffi::SSL_OP_TLS_D5_BUG,
+ const SSL_OP_TLS_BLOCK_PADDING_BUG = ffi::SSL_OP_TLS_BLOCK_PADDING_BUG,
+ const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = ffi::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS,
+ const SSL_OP_ALL = ffi::SSL_OP_ALL,
+ const SSL_OP_NO_QUERY_MTU = ffi::SSL_OP_NO_QUERY_MTU,
+ const SSL_OP_COOKIE_EXCHANGE = ffi::SSL_OP_COOKIE_EXCHANGE,
+ const SSL_OP_NO_TICKET = ffi::SSL_OP_NO_TICKET,
+ const SSL_OP_CISCO_ANYCONNECT = ffi::SSL_OP_CISCO_ANYCONNECT,
+ const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION =
+ ffi::SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION,
+ const SSL_OP_NO_COMPRESSION = ffi::SSL_OP_NO_COMPRESSION,
+ const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION =
+ ffi::SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION,
+ const SSL_OP_SINGLE_ECDH_USE = ffi::SSL_OP_SINGLE_ECDH_USE,
+ const SSL_OP_SINGLE_DH_USE = ffi::SSL_OP_SINGLE_DH_USE,
+ const SSL_OP_CIPHER_SERVER_PREFERENCE = ffi::SSL_OP_CIPHER_SERVER_PREFERENCE,
+ const SSL_OP_TLS_ROLLBACK_BUG = ffi::SSL_OP_TLS_ROLLBACK_BUG,
+ const SSL_OP_NO_SSLV2 = ffi::SSL_OP_NO_SSLv2,
+ const SSL_OP_NO_SSLV3 = ffi::SSL_OP_NO_SSLv3,
+ const SSL_OP_NO_TLSV1 = ffi::SSL_OP_NO_TLSv1,
}
}
@@ -148,68 +99,48 @@ pub enum SslMethod {
}
impl SslMethod {
- unsafe fn to_raw(&self) -> *const ffi::SSL_METHOD {
- match *self {
- #[cfg(feature = "sslv2")]
- SslMethod::Sslv2 => ffi::SSLv2_method(),
- #[cfg(feature = "sslv3")]
- SslMethod::Sslv3 => ffi::SSLv3_method(),
- SslMethod::Tlsv1 => ffi::TLSv1_method(),
- SslMethod::Sslv23 => ffi::SSLv23_method(),
- #[cfg(feature = "tlsv1_1")]
- SslMethod::Tlsv1_1 => ffi::TLSv1_1_method(),
- #[cfg(feature = "tlsv1_2")]
- SslMethod::Tlsv1_2 => ffi::TLSv1_2_method(),
- #[cfg(feature = "dtlsv1")]
- SslMethod::Dtlsv1 => ffi::DTLSv1_method(),
- #[cfg(feature = "dtlsv1_2")]
- SslMethod::Dtlsv1_2 => ffi::DTLSv1_2_method(),
+ fn to_raw(&self) -> *const ffi::SSL_METHOD {
+ unsafe {
+ match *self {
+ #[cfg(feature = "sslv2")]
+ SslMethod::Sslv2 => ffi::SSLv2_method(),
+ #[cfg(feature = "sslv3")]
+ SslMethod::Sslv3 => ffi::SSLv3_method(),
+ SslMethod::Tlsv1 => ffi::TLSv1_method(),
+ SslMethod::Sslv23 => ffi::SSLv23_method(),
+ #[cfg(feature = "tlsv1_1")]
+ SslMethod::Tlsv1_1 => ffi::TLSv1_1_method(),
+ #[cfg(feature = "tlsv1_2")]
+ SslMethod::Tlsv1_2 => ffi::TLSv1_2_method(),
+ #[cfg(feature = "dtlsv1")]
+ SslMethod::Dtlsv1 => ffi::DTLSv1_method(),
+ #[cfg(feature = "dtlsv1_2")]
+ SslMethod::Dtlsv1_2 => ffi::DTLSv1_2_method(),
+ }
}
}
- unsafe fn from_raw(method: *const ffi::SSL_METHOD) -> Option<SslMethod> {
- match method {
- #[cfg(feature = "sslv2")]
- x if x == ffi::SSLv2_method() => Some(SslMethod::Sslv2),
- #[cfg(feature = "sslv3")]
- x if x == ffi::SSLv3_method() => Some(SslMethod::Sslv3),
- x if x == ffi::TLSv1_method() => Some(SslMethod::Tlsv1),
- x if x == ffi::SSLv23_method() => Some(SslMethod::Sslv23),
- #[cfg(feature = "tlsv1_1")]
- x if x == ffi::TLSv1_1_method() => Some(SslMethod::Tlsv1_1),
- #[cfg(feature = "tlsv1_2")]
- x if x == ffi::TLSv1_2_method() => Some(SslMethod::Tlsv1_2),
- #[cfg(feature = "dtlsv1")]
- x if x == ffi::DTLSv1_method() => Some(SslMethod::Dtlsv1),
- #[cfg(feature = "dtlsv1_2")]
- x if x == ffi::DTLSv1_2_method() => Some(SslMethod::Dtlsv1_2),
- _ => None,
+ fn from_raw(method: *const ffi::SSL_METHOD) -> Option<SslMethod> {
+ unsafe {
+ match method {
+ #[cfg(feature = "sslv2")]
+ x if x == ffi::SSLv2_method() => Some(SslMethod::Sslv2),
+ #[cfg(feature = "sslv3")]
+ x if x == ffi::SSLv3_method() => Some(SslMethod::Sslv3),
+ x if x == ffi::TLSv1_method() => Some(SslMethod::Tlsv1),
+ x if x == ffi::SSLv23_method() => Some(SslMethod::Sslv23),
+ #[cfg(feature = "tlsv1_1")]
+ x if x == ffi::TLSv1_1_method() => Some(SslMethod::Tlsv1_1),
+ #[cfg(feature = "tlsv1_2")]
+ x if x == ffi::TLSv1_2_method() => Some(SslMethod::Tlsv1_2),
+ #[cfg(feature = "dtlsv1")]
+ x if x == ffi::DTLSv1_method() => Some(SslMethod::Dtlsv1),
+ #[cfg(feature = "dtlsv1_2")]
+ x if x == ffi::DTLSv1_2_method() => Some(SslMethod::Dtlsv1_2),
+ _ => None,
+ }
}
}
-
- #[cfg(feature = "dtlsv1")]
- pub fn is_dtlsv1(&self) -> bool {
- *self == SslMethod::Dtlsv1
- }
-
- #[cfg(feature = "dtlsv1_2")]
- pub fn is_dtlsv1_2(&self) -> bool {
- *self == SslMethod::Dtlsv1_2
- }
-
- pub fn is_dtls(&self) -> bool {
- self.is_dtlsv1() || self.is_dtlsv1_2()
- }
-
- #[cfg(not(feature = "dtlsv1"))]
- pub fn is_dtlsv1(&self) -> bool {
- false
- }
-
- #[cfg(not(feature = "dtlsv1_2"))]
- pub fn is_dtlsv1_2(&self) -> bool {
- false
- }
}
/// Determines the type of certificate verification used
@@ -292,47 +223,19 @@ fn get_new_ssl_idx<T>() -> c_int {
}
}
-extern "C" fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int {
- unsafe {
- let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx();
- let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx);
- let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
- let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, VERIFY_IDX);
- let verify: Option<VerifyCallback> = mem::transmute(verify);
-
- let ctx = X509StoreContext::new(x509_ctx);
-
- match verify {
- None => preverify_ok,
- Some(verify) => verify(preverify_ok != 0, &ctx) as c_int,
- }
- }
-}
-
-extern "C" fn raw_verify_with_data<T>(preverify_ok: c_int,
- x509_ctx: *mut ffi::X509_STORE_CTX)
- -> c_int
- where T: Any + 'static
+extern "C" fn raw_verify<F>(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int
+ where F: Fn(bool, &X509StoreContext) -> bool + Any + 'static + Sync + Send
{
unsafe {
let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx();
let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx);
let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
-
- let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, VERIFY_IDX);
- let verify: Option<VerifyCallbackData<T>> = mem::transmute(verify);
-
- let data = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::<T>());
- let data: &T = mem::transmute(data);
+ let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::<F>());
+ let verify: &F = mem::transmute(verify);
let ctx = X509StoreContext::new(x509_ctx);
- let res = match verify {
- None => preverify_ok,
- Some(verify) => verify(preverify_ok != 0, &ctx, data) as c_int,
- };
-
- res
+ verify(preverify_ok != 0, &ctx) as c_int
}
}
@@ -351,50 +254,30 @@ extern "C" fn ssl_raw_verify<F>(preverify_ok: c_int, x509_ctx: *mut ffi::X509_ST
}
}
-extern "C" fn raw_sni(ssl: *mut ffi::SSL, ad: &mut c_int, _arg: *mut c_void) -> c_int {
- unsafe {
- let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
- let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, SNI_IDX);
- let callback: Option<ServerNameCallback> = mem::transmute(callback);
- rust_SSL_clone(ssl);
- let mut s = Ssl { ssl: ssl };
-
- let res = match callback {
- None => ffi::SSL_TLSEXT_ERR_ALERT_FATAL,
- Some(callback) => callback(&mut s, ad),
- };
-
- res
- }
-}
-
-extern "C" fn raw_sni_with_data<T>(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_void) -> c_int
- where T: Any + 'static
+extern "C" fn raw_sni<F>(ssl: *mut ffi::SSL, al: *mut c_int, _arg: *mut c_void) -> c_int
+ where F: Fn(&mut SslRef) -> Result<(), SniError> + Any + 'static + Sync + Send
{
unsafe {
let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
-
- let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, SNI_IDX);
- let callback: Option<ServerNameCallbackData<T>> = mem::transmute(callback);
- rust_SSL_clone(ssl);
- let mut s = Ssl { ssl: ssl };
-
- let data: &T = mem::transmute(arg);
-
- let res = match callback {
- None => ffi::SSL_TLSEXT_ERR_ALERT_FATAL,
- Some(callback) => callback(&mut s, ad, &*data),
- };
-
- // Since data might be required on the next verification
- // it is time to forget about it and avoid dropping
- // data will be freed once OpenSSL considers it is time
- // to free all context data
- res
+ let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::<F>());
+ let callback: &F = mem::transmute(callback);
+ let mut ssl = SslRef::from_ptr(ssl);
+
+ match callback(&mut ssl) {
+ Ok(()) => ffi::SSL_TLSEXT_ERR_OK,
+ Err(SniError::Fatal(e)) => {
+ *al = e;
+ ffi::SSL_TLSEXT_ERR_ALERT_FATAL
+ }
+ Err(SniError::Warning(e)) => {
+ *al = e;
+ ffi::SSL_TLSEXT_ERR_ALERT_WARNING
+ }
+ Err(SniError::NoAck) => ffi::SSL_TLSEXT_ERR_NOACK,
+ }
}
}
-
#[cfg(any(feature = "npn", feature = "alpn"))]
unsafe fn select_proto_using(ssl: *mut ffi::SSL,
out: *mut *mut c_uchar,
@@ -499,164 +382,91 @@ fn ssl_encode_byte_strings(strings: &[&[u8]]) -> Vec<u8> {
enc
}
-/// The signature of functions that can be used to manually verify certificates
-pub type VerifyCallback = fn(preverify_ok: bool, x509_ctx: &X509StoreContext) -> bool;
-
-/// The signature of functions that can be used to manually verify certificates
-/// when user-data should be carried for all verification process
-pub type VerifyCallbackData<T> = fn(preverify_ok: bool, x509_ctx: &X509StoreContext, data: &T)
- -> bool;
-
-/// The signature of functions that can be used to choose the context depending on the server name
-pub type ServerNameCallback = fn(ssl: &mut Ssl, ad: &mut i32) -> i32;
-
-pub type ServerNameCallbackData<T> = fn(ssl: &mut Ssl, ad: &mut i32, data: &T) -> i32;
+/// An error returned from an SNI callback.
+pub enum SniError {
+ Fatal(c_int),
+ Warning(c_int),
+ NoAck,
+}
// FIXME: macro may be instead of inlining?
#[inline]
-fn wrap_ssl_result(res: c_int) -> Result<(), SslError> {
+fn wrap_ssl_result(res: c_int) -> Result<(), ErrorStack> {
if res == 0 {
- Err(SslError::get())
+ Err(ErrorStack::get())
} else {
Ok(())
}
}
-/// An SSL context object
-///
-/// Internally ref-counted, use `.clone()` in the same way as Rc and Arc.
-pub struct SslContext {
- ctx: *mut ffi::SSL_CTX,
-}
+/// A borrowed SSL context object.
+pub struct SslContextRef<'a>(*mut ffi::SSL_CTX, PhantomData<&'a ()>);
-unsafe impl Send for SslContext {}
-unsafe impl Sync for SslContext {}
-
-impl Clone for SslContext {
- fn clone(&self) -> Self {
- unsafe { SslContext::new_ref(self.ctx) }
+impl<'a> SslContextRef<'a> {
+ pub unsafe fn from_ptr(ctx: *mut ffi::SSL_CTX) -> SslContextRef<'a> {
+ SslContextRef(ctx, PhantomData)
}
-}
-// TODO: add useful info here
-impl fmt::Debug for SslContext {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- write!(fmt, "SslContext")
- }
-}
-
-impl Drop for SslContext {
- fn drop(&mut self) {
- unsafe { ffi::SSL_CTX_free(self.ctx) }
- }
-}
-
-impl SslContext {
- // Create a new SslContext given an existing ref, and incriment ref-count appropriately.
- unsafe fn new_ref(ctx: *mut ffi::SSL_CTX) -> SslContext {
- rust_SSL_CTX_clone(ctx);
- SslContext { ctx: ctx }
- }
-
- /// Creates a new SSL context.
- pub fn new(method: SslMethod) -> Result<SslContext, SslError> {
- init();
-
- let ctx = try_ssl_null!(unsafe { ffi::SSL_CTX_new(method.to_raw()) });
-
- let ctx = SslContext { ctx: ctx };
-
- // this is a bit dubious (?)
- try!(ctx.set_mode(ffi::SSL_MODE_AUTO_RETRY));
-
- if method.is_dtls() {
- ctx.set_read_ahead(1);
- }
-
- Ok(ctx)
+ pub fn as_ptr(&self) -> *mut ffi::SSL_CTX {
+ self.0
}
/// Configures the certificate verification method for new connections.
- pub fn set_verify(&mut self, mode: SslVerifyMode, verify: Option<VerifyCallback>) {
+ pub fn set_verify(&mut self, mode: SslVerifyMode) {
unsafe {
- ffi::SSL_CTX_set_ex_data(self.ctx, VERIFY_IDX, mem::transmute(verify));
- let f: extern "C" fn(c_int, *mut ffi::X509_STORE_CTX) -> c_int = raw_verify;
-
- ffi::SSL_CTX_set_verify(self.ctx, mode.bits as c_int, Some(f));
+ ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, None);
}
}
- /// Configures the certificate verification method for new connections also
- /// carrying supplied data.
- // Note: no option because there is no point to set data without providing
- // a function handling it
- pub fn set_verify_with_data<T>(&mut self,
- mode: SslVerifyMode,
- verify: VerifyCallbackData<T>,
- data: T)
- where T: Any + 'static
+ /// Configures the certificate verification method for new connections and
+ /// registers a verification callback.
+ pub fn set_verify_callback<F>(&mut self, mode: SslVerifyMode, verify: F)
+ where F: Fn(bool, &X509StoreContext) -> bool + Any + 'static + Sync + Send
{
- let data = Box::new(data);
unsafe {
- ffi::SSL_CTX_set_ex_data(self.ctx, VERIFY_IDX, mem::transmute(Some(verify)));
- ffi::SSL_CTX_set_ex_data(self.ctx, get_verify_data_idx::<T>(), mem::transmute(data));
- let f: extern "C" fn(c_int, *mut ffi::X509_STORE_CTX) -> c_int =
- raw_verify_with_data::<T>;
-
- ffi::SSL_CTX_set_verify(self.ctx, mode.bits as c_int, Some(f));
+ let verify = Box::new(verify);
+ ffi::SSL_CTX_set_ex_data(self.as_ptr(), get_verify_data_idx::<F>(), mem::transmute(verify));
+ ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, Some(raw_verify::<F>));
}
}
/// Configures the server name indication (SNI) callback for new connections
///
- /// obtain the server name with `get_servername` then set the corresponding context
+ /// Obtain the server name with `servername` then set the corresponding context
/// with `set_ssl_context`
- pub fn set_servername_callback(&mut self, callback: Option<ServerNameCallback>) {
- unsafe {
- ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX, mem::transmute(callback));
- let f: extern "C" fn(_, _, _) -> _ = raw_sni;
- let f: extern "C" fn() = mem::transmute(f);
- ffi_extras::SSL_CTX_set_tlsext_servername_callback(self.ctx, Some(f));
- }
- }
-
- /// Configures the server name indication (SNI) callback for new connections
- /// carrying supplied data
- pub fn set_servername_callback_with_data<T>(&mut self,
- callback: ServerNameCallbackData<T>,
- data: T)
- where T: Any + 'static
+ pub fn set_servername_callback<F>(&mut self, callback: F)
+ where F: Fn(&mut SslRef) -> Result<(), SniError> + Any + 'static + Sync + Send
{
- let data = Box::new(data);
unsafe {
- ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX, mem::transmute(Some(callback)));
-
- ffi_extras::SSL_CTX_set_tlsext_servername_arg(self.ctx, mem::transmute(data));
- let f: extern "C" fn(_, _, _) -> _ = raw_sni_with_data::<T>;
+ let callback = Box::new(callback);
+ ffi::SSL_CTX_set_ex_data(self.as_ptr(),
+ get_verify_data_idx::<F>(),
+ mem::transmute(callback));
+ let f: extern "C" fn(_, _, _) -> _ = raw_sni::<F>;
let f: extern "C" fn() = mem::transmute(f);
- ffi_extras::SSL_CTX_set_tlsext_servername_callback(self.ctx, Some(f));
+ ffi::SSL_CTX_set_tlsext_servername_callback(self.as_ptr(), Some(f));
}
}
/// Sets verification depth
pub fn set_verify_depth(&mut self, depth: u32) {
unsafe {
- ffi::SSL_CTX_set_verify_depth(self.ctx, depth as c_int);
+ ffi::SSL_CTX_set_verify_depth(self.as_ptr(), depth as c_int);
}
}
- pub fn set_read_ahead(&self, m: u32) {
+ pub fn set_read_ahead(&mut self, m: u32) {
unsafe {
- ffi_extras::SSL_CTX_set_read_ahead(self.ctx, m as c_long);
+ ffi::SSL_CTX_set_read_ahead(self.as_ptr(), m as c_long);
}
}
- fn set_mode(&self, mode: c_long) -> Result<(), SslError> {
- wrap_ssl_result(unsafe { ffi_extras::SSL_CTX_set_mode(self.ctx, mode) as c_int })
+ fn set_mode(&mut self, mode: c_long) -> Result<(), ErrorStack> {
+ wrap_ssl_result(unsafe { ffi::SSL_CTX_set_mode(self.as_ptr(), mode) as c_int })
}
- pub fn set_tmp_dh(&self, dh: DH) -> Result<(), SslError> {
- wrap_ssl_result(unsafe { ffi_extras::SSL_CTX_set_tmp_dh(self.ctx, dh.raw()) as c_int })
+ pub fn set_tmp_dh(&mut self, dh: &DH) -> Result<(), ErrorStack> {
+ wrap_ssl_result(unsafe { ffi::SSL_CTX_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as i32 })
}
/// Use the default locations of trusted certificates for verification.
@@ -664,16 +474,16 @@ impl SslContext {
/// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR`
/// environment variables if present, or defaults specified at OpenSSL
/// build time otherwise.
- pub fn set_default_verify_paths(&mut self) -> Result<(), SslError> {
- wrap_ssl_result(unsafe { ffi::SSL_CTX_set_default_verify_paths(self.ctx) })
+ pub fn set_default_verify_paths(&mut self) -> Result<(), ErrorStack> {
+ wrap_ssl_result(unsafe { ffi::SSL_CTX_set_default_verify_paths(self.as_ptr()) })
}
#[allow(non_snake_case)]
/// Specifies the file that contains trusted CA certificates.
- pub fn set_CA_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(), SslError> {
+ pub fn set_CA_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(), ErrorStack> {
let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
wrap_ssl_result(unsafe {
- ffi::SSL_CTX_load_verify_locations(self.ctx, file.as_ptr() as *const _, ptr::null())
+ ffi::SSL_CTX_load_verify_locations(self.as_ptr(), file.as_ptr() as *const _, ptr::null())
})
}
@@ -685,9 +495,9 @@ impl SslContext {
///
/// This value should be set when using client certificates, or each request will fail
/// handshake and need to be restarted.
- pub fn set_session_id_context(&mut self, sid_ctx: &[u8]) -> Result<(), SslError> {
+ pub fn set_session_id_context(&mut self, sid_ctx: &[u8]) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe {
- ffi::SSL_CTX_set_session_id_context(self.ctx, sid_ctx.as_ptr(), sid_ctx.len() as u32)
+ ffi::SSL_CTX_set_session_id_context(self.as_ptr(), sid_ctx.as_ptr(), sid_ctx.len() as u32)
})
}
@@ -695,10 +505,10 @@ impl SslContext {
pub fn set_certificate_file<P: AsRef<Path>>(&mut self,
file: P,
file_type: X509FileType)
- -> Result<(), SslError> {
+ -> Result<(), ErrorStack> {
let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
wrap_ssl_result(unsafe {
- ffi::SSL_CTX_use_certificate_file(self.ctx,
+ ffi::SSL_CTX_use_certificate_file(self.as_ptr(),
file.as_ptr() as *const _,
file_type as c_int)
})
@@ -708,25 +518,25 @@ impl SslContext {
pub fn set_certificate_chain_file<P: AsRef<Path>>(&mut self,
file: P,
file_type: X509FileType)
- -> Result<(), SslError> {
+ -> Result<(), ErrorStack> {
let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
wrap_ssl_result(unsafe {
- ffi::SSL_CTX_use_certificate_chain_file(self.ctx,
+ ffi::SSL_CTX_use_certificate_chain_file(self.as_ptr(),
file.as_ptr() as *const _,
file_type as c_int)
})
}
/// Specifies the certificate
- pub fn set_certificate(&mut self, cert: &X509) -> Result<(), SslError> {
- wrap_ssl_result(unsafe { ffi::SSL_CTX_use_certificate(self.ctx, cert.get_handle()) })
+ pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
+ wrap_ssl_result(unsafe { ffi::SSL_CTX_use_certificate(self.as_ptr(), cert.as_ptr()) })
}
/// Adds a certificate to the certificate chain presented together with the
/// certificate specified using set_certificate()
- pub fn add_extra_chain_cert(&mut self, cert: &X509) -> Result<(), SslError> {
+ pub fn add_extra_chain_cert(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe {
- ffi_extras::SSL_CTX_add_extra_chain_cert(self.ctx, cert.get_handle()) as c_int
+ ffi::SSL_CTX_add_extra_chain_cert(self.as_ptr(), cert.as_ptr()) as c_int
})
}
@@ -734,29 +544,29 @@ impl SslContext {
pub fn set_private_key_file<P: AsRef<Path>>(&mut self,
file: P,
file_type: X509FileType)
- -> Result<(), SslError> {
+ -> Result<(), ErrorStack> {
let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
wrap_ssl_result(unsafe {
- ffi::SSL_CTX_use_PrivateKey_file(self.ctx,
+ ffi::SSL_CTX_use_PrivateKey_file(self.as_ptr(),
file.as_ptr() as *const _,
file_type as c_int)
})
}
/// Specifies the private key
- pub fn set_private_key(&mut self, key: &PKey) -> Result<(), SslError> {
- wrap_ssl_result(unsafe { ffi::SSL_CTX_use_PrivateKey(self.ctx, key.get_handle()) })
+ pub fn set_private_key(&mut self, key: &PKey) -> Result<(), ErrorStack> {
+ wrap_ssl_result(unsafe { ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr()) })
}
/// Check consistency of private key and certificate
- pub fn check_private_key(&mut self) -> Result<(), SslError> {
- wrap_ssl_result(unsafe { ffi::SSL_CTX_check_private_key(self.ctx) })
+ pub fn check_private_key(&mut self) -> Result<(), ErrorStack> {
+ wrap_ssl_result(unsafe { ffi::SSL_CTX_check_private_key(self.as_ptr()) })
}
- pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), SslError> {
+ pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe {
let cipher_list = CString::new(cipher_list).unwrap();
- ffi::SSL_CTX_set_cipher_list(self.ctx, cipher_list.as_ptr() as *const _)
+ ffi::SSL_CTX_set_cipher_list(self.as_ptr(), cipher_list.as_ptr() as *const _)
})
}
@@ -765,24 +575,22 @@ impl SslContext {
///
/// This method requires OpenSSL >= 1.0.2 or LibreSSL and the `ecdh_auto` feature.
#[cfg(feature = "ecdh_auto")]
- pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), SslError> {
- wrap_ssl_result(unsafe { ffi_extras::SSL_CTX_set_ecdh_auto(self.ctx, onoff as c_int) })
+ pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
+ wrap_ssl_result(unsafe { ffi::SSL_CTX_set_ecdh_auto(self.as_ptr(), onoff as c_long) as c_int })
}
pub fn set_options(&mut self, option: SslContextOptions) -> SslContextOptions {
- let raw_bits = option.bits();
- let ret = unsafe { ffi_extras::SSL_CTX_set_options(self.ctx, raw_bits) };
+ let ret = unsafe { ffi::SSL_CTX_set_options(self.as_ptr(), option.bits()) };
SslContextOptions::from_bits(ret).unwrap()
}
- pub fn get_options(&mut self) -> SslContextOptions {
- let ret = unsafe { ffi_extras::SSL_CTX_get_options(self.ctx) };
+ pub fn options(&self) -> SslContextOptions {
+ let ret = unsafe { ffi::SSL_CTX_get_options(self.as_ptr()) };
SslContextOptions::from_bits(ret).unwrap()
}
pub fn clear_options(&mut self, option: SslContextOptions) -> SslContextOptions {
- let raw_bits = option.bits();
- let ret = unsafe { ffi_extras::SSL_CTX_clear_options(self.ctx, raw_bits) };
+ let ret = unsafe { ffi::SSL_CTX_clear_options(self.as_ptr(), option.bits()) };
SslContextOptions::from_bits(ret).unwrap()
}
@@ -799,16 +607,16 @@ impl SslContext {
unsafe {
// Attach the protocol list to the OpenSSL context structure,
// so that we can refer to it within the callback.
- ffi::SSL_CTX_set_ex_data(self.ctx, *NPN_PROTOS_IDX, mem::transmute(protocols));
+ ffi::SSL_CTX_set_ex_data(self.as_ptr(), *NPN_PROTOS_IDX, mem::transmute(protocols));
// Now register the callback that performs the default protocol
// matching based on the client-supported list of protocols that
// has been saved.
- ffi::SSL_CTX_set_next_proto_select_cb(self.ctx,
+ ffi::SSL_CTX_set_next_proto_select_cb(self.as_ptr(),
raw_next_proto_select_cb,
ptr::null_mut());
// Also register the callback to advertise these protocols, if a server socket is
// created with the context.
- ffi::SSL_CTX_set_next_protos_advertised_cb(self.ctx,
+ ffi::SSL_CTX_set_next_protos_advertised_cb(self.as_ptr(),
raw_next_protos_advertise_cb,
ptr::null_mut());
}
@@ -827,28 +635,105 @@ impl SslContext {
let protocols: Box<Vec<u8>> = Box::new(ssl_encode_byte_strings(protocols));
unsafe {
// Set the context's internal protocol list for use if we are a server
- ffi::SSL_CTX_set_alpn_protos(self.ctx, protocols.as_ptr(), protocols.len() as c_uint);
+ ffi::SSL_CTX_set_alpn_protos(self.as_ptr(), protocols.as_ptr(), protocols.len() as c_uint);
// Rather than use the argument to the callback to contain our data, store it in the
// ssl ctx's ex_data so that we can configure a function to free it later. In the
// future, it might make sense to pull this into our internal struct Ssl instead of
// leaning on openssl and using function pointers.
- ffi::SSL_CTX_set_ex_data(self.ctx, *ALPN_PROTOS_IDX, mem::transmute(protocols));
+ ffi::SSL_CTX_set_ex_data(self.as_ptr(), *ALPN_PROTOS_IDX, mem::transmute(protocols));
// Now register the callback that performs the default protocol
// matching based on the client-supported list of protocols that
// has been saved.
- ffi::SSL_CTX_set_alpn_select_cb(self.ctx, raw_alpn_select_cb, ptr::null_mut());
+ ffi::SSL_CTX_set_alpn_select_cb(self.as_ptr(), raw_alpn_select_cb, ptr::null_mut());
+ }
+ }
+}
+
+/// An owned SSL context object.
+pub struct SslContext(SslContextRef<'static>);
+
+unsafe impl Send for SslContext {}
+unsafe impl Sync for SslContext {}
+
+#[cfg(feature = "ssl_context_clone")]
+impl Clone for SslContext {
+ /// Requires the `ssl_context_clone` feature.
+ fn clone(&self) -> Self {
+ unsafe {
+ ::c_helpers::rust_SSL_CTX_clone(self.as_ptr());
+ SslContext::from_ptr(self.as_ptr())
}
}
}
+// TODO: add useful info here
+impl fmt::Debug for SslContext {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "SslContext")
+ }
+}
+
+impl Drop for SslContext {
+ fn drop(&mut self) {
+ unsafe { ffi::SSL_CTX_free(self.as_ptr()) }
+ }
+}
+
+impl Deref for SslContext {
+ type Target = SslContextRef<'static>;
+
+ fn deref(&self) -> &SslContextRef<'static> {
+ &self.0
+ }
+}
+
+impl DerefMut for SslContext {
+ fn deref_mut(&mut self) -> &mut SslContextRef<'static> {
+ &mut self.0
+ }
+}
+
+impl SslContext {
+ /// Creates a new SSL context.
+ pub fn new(method: SslMethod) -> Result<SslContext, ErrorStack> {
+ init();
+
+ let mut ctx = unsafe {
+ let ctx = try_ssl_null!(ffi::SSL_CTX_new(method.to_raw()));
+ SslContext::from_ptr(ctx)
+ };
+
+ match method {
+ #[cfg(feature = "dtlsv1")]
+ SslMethod::Dtlsv1 => ctx.set_read_ahead(1),
+ #[cfg(feature = "dtlsv1_2")]
+ SslMethod::Dtlsv1_2 => ctx.set_read_ahead(1),
+ _ => {}
+ }
+ // this is a bit dubious (?)
+ try!(ctx.set_mode(ffi::SSL_MODE_AUTO_RETRY | ffi::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER));
+
+ Ok(ctx)
+ }
+
+ pub unsafe fn from_ptr(ctx: *mut ffi::SSL_CTX) -> SslContext {
+ SslContext(SslContextRef::from_ptr(ctx))
+ }
+
+ pub fn as_ptr(&self) -> *mut ffi::SSL_CTX {
+ (**self).as_ptr()
+ }
+}
+
pub struct CipherBits {
/// The number of secret bits used for the cipher.
pub secret: i32,
/// The number of bits processed by the chosen algorithm, if not None.
pub algorithm: Option<i32>,
+ _p: (),
}
@@ -887,11 +772,13 @@ impl<'a> SslCipher<'a> {
CipherBits {
secret: secret_bits,
algorithm: Some(*algo_bits),
+ _p: (),
}
} else {
CipherBits {
secret: secret_bits,
algorithm: None,
+ _p: (),
}
}
}
@@ -913,79 +800,63 @@ impl<'a> SslCipher<'a> {
}
}
+pub struct SslRef<'a>(*mut ffi::SSL, PhantomData<&'a ()>);
-pub struct Ssl {
- ssl: *mut ffi::SSL,
-}
+unsafe impl<'a> Send for SslRef<'a> {}
+unsafe impl<'a> Sync for SslRef<'a> {}
-unsafe impl Send for Ssl {}
-unsafe impl Sync for Ssl {}
-
-impl fmt::Debug for Ssl {
+impl<'a> fmt::Debug for SslRef<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- fmt.debug_struct("Ssl")
+ fmt.debug_struct("SslRef")
.field("state", &self.state_string_long())
.finish()
}
}
-impl Drop for Ssl {
- fn drop(&mut self) {
- unsafe { ffi::SSL_free(self.ssl) }
+impl<'a> SslRef<'a> {
+ pub unsafe fn from_ptr(ssl: *mut ffi::SSL) -> SslRef<'a> {
+ SslRef(ssl, PhantomData)
}
-}
-
-impl Clone for Ssl {
- /// # Deprecated
- fn clone(&self) -> Ssl {
- unsafe { rust_SSL_clone(self.ssl) };
- Ssl { ssl: self.ssl }
+ pub fn as_ptr(&self) -> *mut ffi::SSL {
+ self.0
}
-}
-impl Ssl {
- pub fn new(ctx: &SslContext) -> Result<Ssl, SslError> {
- let ssl = try_ssl_null!(unsafe { ffi::SSL_new(ctx.ctx) });
- let ssl = Ssl { ssl: ssl };
- Ok(ssl)
+ fn get_raw_rbio(&self) -> *mut ffi::BIO {
+ unsafe { ffi::SSL_get_rbio(self.as_ptr()) }
}
- fn get_raw_rbio(&self) -> *mut ffi::BIO {
- unsafe { ffi::SSL_get_rbio(self.ssl) }
+ fn connect(&mut self) -> c_int {
+ unsafe { ffi::SSL_connect(self.as_ptr()) }
}
- fn connect(&self) -> c_int {
- unsafe { ffi::SSL_connect(self.ssl) }
+ fn accept(&mut self) -> c_int {
+ unsafe { ffi::SSL_accept(self.as_ptr()) }
}
- fn accept(&self) -> c_int {
- unsafe { ffi::SSL_accept(self.ssl) }
+ fn handshake(&mut self) -> c_int {
+ unsafe { ffi::SSL_do_handshake(self.as_ptr()) }
}
- fn read(&self, buf: &mut [u8]) -> c_int {
+ fn read(&mut self, buf: &mut [u8]) -> c_int {
let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
- unsafe { ffi::SSL_read(self.ssl, buf.as_ptr() as *mut c_void, len) }
+ unsafe { ffi::SSL_read(self.as_ptr(), buf.as_ptr() as *mut c_void, len) }
}
- fn write(&self, buf: &[u8]) -> c_int {
+ fn write(&mut self, buf: &[u8]) -> c_int {
let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
- unsafe { ffi::SSL_write(self.ssl, buf.as_ptr() as *const c_void, len) }
+ unsafe { ffi::SSL_write(self.as_ptr(), buf.as_ptr() as *const c_void, len) }
}
- fn get_error(&self, ret: c_int) -> LibSslError {
- let err = unsafe { ffi::SSL_get_error(self.ssl, ret) };
- match LibSslError::from_i32(err as i32) {
- Some(err) => err,
- None => unreachable!(),
- }
+ fn get_error(&self, ret: c_int) -> c_int {
+ unsafe { ffi::SSL_get_error(self.as_ptr(), ret) }
}
/// Sets the verification mode to be used during the handshake process.
///
/// Use `set_verify_callback` to additionally add a callback.
pub fn set_verify(&mut self, mode: SslVerifyMode) {
- unsafe { ffi::SSL_set_verify(self.ssl, mode.bits as c_int, None) }
+ unsafe { ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, None) }
}
/// Sets the certificate verification callback to be used during the
@@ -1000,16 +871,16 @@ impl Ssl {
{
unsafe {
let verify = Box::new(verify);
- ffi::SSL_set_ex_data(self.ssl,
+ ffi::SSL_set_ex_data(self.as_ptr(),
get_ssl_verify_data_idx::<F>(),
mem::transmute(verify));
- ffi::SSL_set_verify(self.ssl, mode.bits as c_int, Some(ssl_raw_verify::<F>));
+ ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, Some(ssl_raw_verify::<F>));
}
}
- pub fn get_current_cipher<'a>(&'a self) -> Option<SslCipher<'a>> {
+ pub fn current_cipher(&self) -> Option<SslCipher<'a>> {
unsafe {
- let ptr = ffi::SSL_get_current_cipher(self.ssl);
+ let ptr = ffi::SSL_get_current_cipher(self.as_ptr());
if ptr.is_null() {
None
@@ -1024,7 +895,7 @@ impl Ssl {
pub fn state_string(&self) -> &'static str {
let state = unsafe {
- let ptr = ffi::SSL_state_string(self.ssl);
+ let ptr = ffi::SSL_state_string(self.as_ptr());
CStr::from_ptr(ptr as *const _)
};
@@ -1033,7 +904,7 @@ impl Ssl {
pub fn state_string_long(&self) -> &'static str {
let state = unsafe {
- let ptr = ffi::SSL_state_string_long(self.ssl);
+ let ptr = ffi::SSL_state_string_long(self.as_ptr());
CStr::from_ptr(ptr as *const _)
};
@@ -1041,15 +912,15 @@ impl Ssl {
}
/// Sets the host name to be used with SNI (Server Name Indication).
- pub fn set_hostname(&self, hostname: &str) -> Result<(), SslError> {
+ pub fn set_hostname(&mut self, hostname: &str) -> Result<(), ErrorStack> {
let cstr = CString::new(hostname).unwrap();
let ret = unsafe {
- ffi_extras::SSL_set_tlsext_host_name(self.ssl, cstr.as_ptr() as *const _)
+ ffi::SSL_set_tlsext_host_name(self.as_ptr(), cstr.as_ptr() as *mut _)
};
// For this case, 0 indicates failure.
if ret == 0 {
- Err(SslError::get())
+ Err(ErrorStack::get())
} else {
Ok(())
}
@@ -1058,11 +929,11 @@ impl Ssl {
/// Returns the certificate of the peer, if present.
pub fn peer_certificate(&self) -> Option<X509> {
unsafe {
- let ptr = ffi::SSL_get_peer_certificate(self.ssl);
+ let ptr = ffi::SSL_get_peer_certificate(self.as_ptr());
if ptr.is_null() {
None
} else {
- Some(X509::new(ptr, true))
+ Some(X509::new(ptr))
}
}
}
@@ -1070,7 +941,7 @@ impl Ssl {
/// Returns the name of the protocol used for the connection, e.g. "TLSv1.2", "SSLv3", etc.
pub fn version(&self) -> &'static str {
let version = unsafe {
- let ptr = ffi::SSL_get_version(self.ssl);
+ let ptr = ffi::SSL_get_version(self.as_ptr());
CStr::from_ptr(ptr as *const _)
};
@@ -1090,7 +961,7 @@ impl Ssl {
let mut len: c_uint = 0;
// Get the negotiated protocol from the SSL instance.
// `data` will point at a `c_uchar` array; `len` will contain the length of this array.
- ffi::SSL_get0_next_proto_negotiated(self.ssl, &mut data, &mut len);
+ ffi::SSL_get0_next_proto_negotiated(self.as_ptr(), &mut data, &mut len);
if data.is_null() {
None
@@ -1113,7 +984,7 @@ impl Ssl {
let mut len: c_uint = 0;
// Get the negotiated protocol from the SSL instance.
// `data` will point at a `c_uchar` array; `len` will contain the length of this array.
- ffi::SSL_get0_alpn_selected(self.ssl, &mut data, &mut len);
+ ffi::SSL_get0_alpn_selected(self.as_ptr(), &mut data, &mut len);
if data.is_null() {
None
@@ -1126,7 +997,7 @@ impl Ssl {
/// Returns the number of bytes remaining in the currently processed TLS
/// record.
pub fn pending(&self) -> usize {
- unsafe { ffi::SSL_pending(self.ssl) as usize }
+ unsafe { ffi::SSL_pending(self.as_ptr()) as usize }
}
/// Returns the compression currently in use.
@@ -1134,7 +1005,7 @@ impl Ssl {
/// The result will be either None, indicating no compression is in use, or
/// a string with the compression name.
pub fn compression(&self) -> Option<String> {
- let ptr = unsafe { ffi::SSL_get_current_compression(self.ssl) };
+ let ptr = unsafe { ffi::SSL_get_current_compression(self.as_ptr()) };
if ptr == ptr::null() {
return None;
}
@@ -1147,16 +1018,16 @@ impl Ssl {
Some(s)
}
- pub fn get_ssl_method(&self) -> Option<SslMethod> {
+ pub fn ssl_method(&self) -> SslMethod {
unsafe {
- let method = ffi::SSL_get_ssl_method(self.ssl);
- SslMethod::from_raw(method)
+ let method = ffi::SSL_get_ssl_method(self.as_ptr());
+ SslMethod::from_raw(method).unwrap()
}
}
/// Returns the server's name for the current connection
- pub fn get_servername(&self) -> Option<String> {
- let name = unsafe { ffi::SSL_get_servername(self.ssl, ffi::TLSEXT_NAMETYPE_host_name) };
+ pub fn servername(&self) -> Option<String> {
+ let name = unsafe { ffi::SSL_get_servername(self.as_ptr(), ffi::TLSEXT_NAMETYPE_host_name) };
if name == ptr::null() {
return None;
}
@@ -1164,61 +1035,64 @@ impl Ssl {
unsafe { String::from_utf8(CStr::from_ptr(name as *const _).to_bytes().to_vec()).ok() }
}
- /// change the context corresponding to the current connection
- ///
- /// Returns a clone of the SslContext @ctx (ie: the new context). The old context is freed.
- pub fn set_ssl_context(&self, ctx: &SslContext) -> SslContext {
- // If duplication of @ctx's cert fails, this returns NULL. This _appears_ to only occur on
- // allocation failures (meaning panicing is probably appropriate), but it might be nice to
- // propogate the error.
- assert!(unsafe { ffi::SSL_set_SSL_CTX(self.ssl, ctx.ctx) } != ptr::null_mut());
-
- // FIXME: we return this reference here for compatibility, but it isn't actually required.
- // This should be removed when a api-incompatabile version is to be released.
- //
- // ffi:SSL_set_SSL_CTX() returns copy of the ctx pointer passed to it, so it's easier for
- // us to do the clone directly.
- ctx.clone()
- }
-
- /// obtain the context corresponding to the current connection
- pub fn get_ssl_context(&self) -> SslContext {
+ /// Changes the context corresponding to the current connection.
+ pub fn set_ssl_context(&mut self, ctx: &SslContextRef) -> Result<(), ErrorStack> {
unsafe {
- let ssl_ctx = ffi::SSL_get_SSL_CTX(self.ssl);
- SslContext::new_ref(ssl_ctx)
+ try_ssl_null!(ffi::SSL_set_SSL_CTX(self.as_ptr(), ctx.as_ptr()));
}
+ Ok(())
}
-}
-macro_rules! make_LibSslError {
- ($($variant:ident = $value:ident),+) => {
- #[derive(Debug)]
- #[repr(i32)]
- enum LibSslError {
- $($variant = ffi::$value),+
+ /// Returns the context corresponding to the current connection
+ pub fn ssl_context(&self) -> SslContextRef<'a> {
+ unsafe {
+ let ssl_ctx = ffi::SSL_get_SSL_CTX(self.as_ptr());
+ SslContextRef::from_ptr(ssl_ctx)
}
+ }
+}
- impl LibSslError {
- fn from_i32(val: i32) -> Option<LibSslError> {
- match val {
- $(ffi::$value => Some(LibSslError::$variant),)+
- _ => None
- }
- }
- }
+pub struct Ssl(SslRef<'static>);
+
+impl fmt::Debug for Ssl {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("Ssl")
+ .field("state", &self.state_string_long())
+ .finish()
}
}
-make_LibSslError! {
- ErrorNone = SSL_ERROR_NONE,
- ErrorSsl = SSL_ERROR_SSL,
- ErrorWantRead = SSL_ERROR_WANT_READ,
- ErrorWantWrite = SSL_ERROR_WANT_WRITE,
- ErrorWantX509Lookup = SSL_ERROR_WANT_X509_LOOKUP,
- ErrorSyscall = SSL_ERROR_SYSCALL,
- ErrorZeroReturn = SSL_ERROR_ZERO_RETURN,
- ErrorWantConnect = SSL_ERROR_WANT_CONNECT,
- ErrorWantAccept = SSL_ERROR_WANT_ACCEPT
+impl Drop for Ssl {
+ fn drop(&mut self) {
+ unsafe { ffi::SSL_free(self.as_ptr()) }
+ }
+}
+
+impl Deref for Ssl {
+ type Target = SslRef<'static>;
+
+ fn deref(&self) -> &SslRef<'static> {
+ &self.0
+ }
+}
+
+impl DerefMut for Ssl {
+ fn deref_mut(&mut self) -> &mut SslRef<'static> {
+ &mut self.0
+ }
+}
+
+impl Ssl {
+ pub fn new(ctx: &SslContext) -> Result<Ssl, ErrorStack> {
+ unsafe {
+ let ssl = try_ssl_null!(ffi::SSL_new(ctx.as_ptr()));
+ Ok(Ssl::from_ptr(ssl))
+ }
+ }
+
+ pub unsafe fn from_ptr(ssl: *mut ffi::SSL) -> Ssl {
+ Ssl(SslRef::from_ptr(ssl))
+ }
}
/// A stream wrapper which handles SSL encryption for an underlying stream.
@@ -1228,19 +1102,7 @@ pub struct SslStream<S> {
_p: PhantomData<S>,
}
-/// # Deprecated
-///
-/// This method does not behave as expected and will be removed in a future
-/// release.
-impl<S: Clone + Read + Write> Clone for SslStream<S> {
- fn clone(&self) -> SslStream<S> {
- SslStream {
- ssl: self.ssl.clone(),
- _method: self._method.clone(),
- _p: PhantomData,
- }
- }
-}
+unsafe impl<S: Send> Send for SslStream<S> {}
impl<S> fmt::Debug for SslStream<S>
where S: fmt::Debug
@@ -1253,25 +1115,11 @@ impl<S> fmt::Debug for SslStream<S>
}
}
-#[cfg(unix)]
-impl<S: AsRawFd> AsRawFd for SslStream<S> {
- fn as_raw_fd(&self) -> RawFd {
- self.get_ref().as_raw_fd()
- }
-}
-
-#[cfg(windows)]
-impl<S: AsRawSocket> AsRawSocket for SslStream<S> {
- fn as_raw_socket(&self) -> RawSocket {
- self.get_ref().as_raw_socket()
- }
-}
-
impl<S: Read + Write> SslStream<S> {
fn new_base(ssl: Ssl, stream: S) -> Self {
unsafe {
let (bio, method) = bio::new(stream).unwrap();
- ffi::SSL_set_bio(ssl.ssl, bio, bio);
+ ffi::SSL_set_bio(ssl.as_ptr(), bio, bio);
SslStream {
ssl: ssl,
@@ -1282,49 +1130,53 @@ impl<S: Read + Write> SslStream<S> {
}
/// Creates an SSL/TLS client operating over the provided stream.
- pub fn connect<T: IntoSsl>(ssl: T, stream: S) -> Result<Self, SslError> {
- let ssl = try!(ssl.into_ssl());
+ pub fn connect<T: IntoSsl>(ssl: T, stream: S)
+ -> Result<Self, HandshakeError<S>>{
+ let ssl = try!(ssl.into_ssl().map_err(|e| {
+ HandshakeError::Failure(Error::Ssl(e))
+ }));
let mut stream = Self::new_base(ssl, stream);
let ret = stream.ssl.connect();
if ret > 0 {
Ok(stream)
} else {
- match stream.make_old_error(ret) {
- Some(err) => Err(err),
- None => Ok(stream),
+ match stream.make_error(ret) {
+ e @ Error::WantWrite(_) |
+ e @ Error::WantRead(_) => {
+ Err(HandshakeError::Interrupted(MidHandshakeSslStream {
+ stream: stream,
+ error: e,
+ }))
+ }
+ err => Err(HandshakeError::Failure(err)),
}
}
}
/// Creates an SSL/TLS server operating over the provided stream.
- pub fn accept<T: IntoSsl>(ssl: T, stream: S) -> Result<Self, SslError> {
- let ssl = try!(ssl.into_ssl());
+ pub fn accept<T: IntoSsl>(ssl: T, stream: S)
+ -> Result<Self, HandshakeError<S>> {
+ let ssl = try!(ssl.into_ssl().map_err(|e| {
+ HandshakeError::Failure(Error::Ssl(e))
+ }));
let mut stream = Self::new_base(ssl, stream);
let ret = stream.ssl.accept();
if ret > 0 {
Ok(stream)
} else {
- match stream.make_old_error(ret) {
- Some(err) => Err(err),
- None => Ok(stream),
+ match stream.make_error(ret) {
+ e @ Error::WantWrite(_) |
+ e @ Error::WantRead(_) => {
+ Err(HandshakeError::Interrupted(MidHandshakeSslStream {
+ stream: stream,
+ error: e,
+ }))
+ }
+ err => Err(HandshakeError::Failure(err)),
}
}
}
- /// ### Deprecated
- ///
- /// Use `connect`.
- pub fn connect_generic<T: IntoSsl>(ssl: T, stream: S) -> Result<SslStream<S>, SslError> {
- Self::connect(ssl, stream)
- }
-
- /// ### Deprecated
- ///
- /// Use `accept`.
- pub fn accept_generic<T: IntoSsl>(ssl: T, stream: S) -> Result<SslStream<S>, SslError> {
- Self::accept(ssl, stream)
- }
-
/// Like `read`, but returns an `ssl::Error` rather than an `io::Error`.
///
/// This is particularly useful with a nonblocking socket, where the error
@@ -1352,63 +1204,112 @@ impl<S: Read + Write> SslStream<S> {
}
}
-impl<S> SslStream<S> {
- fn make_error(&mut self, ret: c_int) -> Error {
- self.check_panic();
+/// An error or intermediate state after a TLS handshake attempt.
+#[derive(Debug)]
+pub enum HandshakeError<S> {
+ /// The handshake failed.
+ Failure(Error),
+ /// The handshake was interrupted midway through.
+ Interrupted(MidHandshakeSslStream<S>),
+}
- match self.ssl.get_error(ret) {
- LibSslError::ErrorSsl => Error::Ssl(OpenSslError::get_stack()),
- LibSslError::ErrorSyscall => {
- let errs = OpenSslError::get_stack();
- if errs.is_empty() {
- if ret == 0 {
- Error::Stream(io::Error::new(io::ErrorKind::ConnectionAborted,
- "unexpected EOF observed"))
- } else {
- Error::Stream(self.get_bio_error())
- }
- } else {
- Error::Ssl(errs)
+impl<S: Any + fmt::Debug> stderror::Error for HandshakeError<S> {
+ fn description(&self) -> &str {
+ match *self {
+ HandshakeError::Failure(ref e) => e.description(),
+ HandshakeError::Interrupted(ref e) => e.error.description(),
+ }
+ }
+
+ fn cause(&self) -> Option<&stderror::Error> {
+ match *self {
+ HandshakeError::Failure(ref e) => Some(e),
+ HandshakeError::Interrupted(ref e) => Some(&e.error),
+ }
+ }
+}
+
+impl<S: Any + fmt::Debug> fmt::Display for HandshakeError<S> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ try!(f.write_str(stderror::Error::description(self)));
+ if let Some(e) = stderror::Error::cause(self) {
+ try!(write!(f, ": {}", e));
+ }
+ Ok(())
+ }
+}
+
+/// An SSL stream midway through the handshake process.
+#[derive(Debug)]
+pub struct MidHandshakeSslStream<S> {
+ stream: SslStream<S>,
+ error: Error,
+}
+
+impl<S> MidHandshakeSslStream<S> {
+ /// Returns a shared reference to the inner stream.
+ pub fn get_ref(&self) -> &S {
+ self.stream.get_ref()
+ }
+
+ /// Returns a mutable reference to the inner stream.
+ pub fn get_mut(&mut self) -> &mut S {
+ self.stream.get_mut()
+ }
+
+ /// Returns a shared reference to the `Ssl` of the stream.
+ pub fn ssl(&self) -> &Ssl {
+ self.stream.ssl()
+ }
+
+ /// Returns the underlying error which interrupted this handshake.
+ pub fn error(&self) -> &Error {
+ &self.error
+ }
+
+ /// Restarts the handshake process.
+ pub fn handshake(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
+ let ret = self.stream.ssl.handshake();
+ if ret > 0 {
+ Ok(self.stream)
+ } else {
+ match self.stream.make_error(ret) {
+ e @ Error::WantWrite(_) |
+ e @ Error::WantRead(_) => {
+ self.error = e;
+ Err(HandshakeError::Interrupted(self))
}
- }
- LibSslError::ErrorZeroReturn => Error::ZeroReturn,
- LibSslError::ErrorWantWrite => Error::WantWrite(self.get_bio_error()),
- LibSslError::ErrorWantRead => Error::WantRead(self.get_bio_error()),
- err => {
- Error::Stream(io::Error::new(io::ErrorKind::Other,
- format!("unexpected error {:?}", err)))
+ err => Err(HandshakeError::Failure(err)),
}
}
}
+}
- fn make_old_error(&mut self, ret: c_int) -> Option<SslError> {
+impl<S> SslStream<S> {
+ fn make_error(&mut self, ret: c_int) -> Error {
self.check_panic();
match self.ssl.get_error(ret) {
- LibSslError::ErrorSsl => Some(SslError::get()),
- LibSslError::ErrorSyscall => {
- let err = SslError::get();
- let count = match err {
- SslError::OpenSslErrors(ref v) => v.len(),
- _ => unreachable!(),
- };
- if count == 0 {
+ ffi::SSL_ERROR_SSL => Error::Ssl(ErrorStack::get()),
+ ffi::SSL_ERROR_SYSCALL => {
+ let errs = ErrorStack::get();
+ if errs.errors().is_empty() {
if ret == 0 {
- Some(SslError::StreamError(io::Error::new(io::ErrorKind::ConnectionAborted,
- "unexpected EOF observed")))
+ Error::Stream(io::Error::new(io::ErrorKind::ConnectionAborted,
+ "unexpected EOF observed"))
} else {
- Some(SslError::StreamError(self.get_bio_error()))
+ Error::Stream(self.get_bio_error())
}
} else {
- Some(err)
+ Error::Ssl(errs)
}
}
- LibSslError::ErrorZeroReturn => Some(SslError::SslSessionClosed),
- LibSslError::ErrorWantWrite |
- LibSslError::ErrorWantRead => None,
+ ffi::SSL_ERROR_ZERO_RETURN => Error::ZeroReturn,
+ ffi::SSL_ERROR_WANT_WRITE => Error::WantWrite(self.get_bio_error()),
+ ffi::SSL_ERROR_WANT_READ => Error::WantRead(self.get_bio_error()),
err => {
- Some(SslError::StreamError(io::Error::new(io::ErrorKind::Other,
- format!("unexpected error {:?}", err))))
+ Error::Stream(io::Error::new(io::ErrorKind::InvalidData,
+ format!("unexpected error {}", err)))
}
}
}
@@ -1461,20 +1362,6 @@ impl<S> SslStream<S> {
}
}
-impl SslStream<::std::net::TcpStream> {
- /// # Deprecated
- ///
- /// This method does not behave as expected and will be removed in a future
- /// release.
- pub fn try_clone(&self) -> io::Result<SslStream<::std::net::TcpStream>> {
- Ok(SslStream {
- ssl: self.ssl.clone(),
- _method: self._method.clone(),
- _p: PhantomData,
- })
- }
-}
-
impl<S: Read + Write> Read for SslStream<S> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self.ssl_read(buf) {
@@ -1506,222 +1393,17 @@ impl<S: Read + Write> Write for SslStream<S> {
}
pub trait IntoSsl {
- fn into_ssl(self) -> Result<Ssl, SslError>;
+ fn into_ssl(self) -> Result<Ssl, ErrorStack>;
}
impl IntoSsl for Ssl {
- fn into_ssl(self) -> Result<Ssl, SslError> {
+ fn into_ssl(self) -> Result<Ssl, ErrorStack> {
Ok(self)
}
}
impl<'a> IntoSsl for &'a SslContext {
- fn into_ssl(self) -> Result<Ssl, SslError> {
+ fn into_ssl(self) -> Result<Ssl, ErrorStack> {
Ssl::new(self)
}
}
-
-/// A utility type to help in cases where the use of SSL is decided at runtime.
-#[derive(Debug)]
-pub enum MaybeSslStream<S>
- where S: Read + Write
-{
- /// A connection using SSL
- Ssl(SslStream<S>),
- /// A connection not using SSL
- Normal(S),
-}
-
-impl<S> Read for MaybeSslStream<S>
- where S: Read + Write
-{
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- match *self {
- MaybeSslStream::Ssl(ref mut s) => s.read(buf),
- MaybeSslStream::Normal(ref mut s) => s.read(buf),
- }
- }
-}
-
-impl<S> Write for MaybeSslStream<S>
- where S: Read + Write
-{
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- match *self {
- MaybeSslStream::Ssl(ref mut s) => s.write(buf),
- MaybeSslStream::Normal(ref mut s) => s.write(buf),
- }
- }
-
- fn flush(&mut self) -> io::Result<()> {
- match *self {
- MaybeSslStream::Ssl(ref mut s) => s.flush(),
- MaybeSslStream::Normal(ref mut s) => s.flush(),
- }
- }
-}
-
-impl<S> MaybeSslStream<S>
- where S: Read + Write
-{
- /// Returns a reference to the underlying stream.
- pub fn get_ref(&self) -> &S {
- match *self {
- MaybeSslStream::Ssl(ref s) => s.get_ref(),
- MaybeSslStream::Normal(ref s) => s,
- }
- }
-
- /// Returns a mutable reference to the underlying stream.
- ///
- /// ## Warning
- ///
- /// It is inadvisable to read from or write to the underlying stream.
- pub fn get_mut(&mut self) -> &mut S {
- match *self {
- MaybeSslStream::Ssl(ref mut s) => s.get_mut(),
- MaybeSslStream::Normal(ref mut s) => s,
- }
- }
-}
-
-impl MaybeSslStream<net::TcpStream> {
- /// Like `TcpStream::try_clone`.
- pub fn try_clone(&self) -> io::Result<MaybeSslStream<net::TcpStream>> {
- match *self {
- MaybeSslStream::Ssl(ref s) => s.try_clone().map(MaybeSslStream::Ssl),
- MaybeSslStream::Normal(ref s) => s.try_clone().map(MaybeSslStream::Normal),
- }
- }
-}
-
-/// # Deprecated
-///
-/// Use `SslStream` with `ssl_read` and `ssl_write`.
-pub struct NonblockingSslStream<S>(SslStream<S>);
-
-impl<S: Clone + Read + Write> Clone for NonblockingSslStream<S> {
- fn clone(&self) -> Self {
- NonblockingSslStream(self.0.clone())
- }
-}
-
-#[cfg(unix)]
-impl<S: AsRawFd> AsRawFd for NonblockingSslStream<S> {
- fn as_raw_fd(&self) -> RawFd {
- self.0.as_raw_fd()
- }
-}
-
-#[cfg(windows)]
-impl<S: AsRawSocket> AsRawSocket for NonblockingSslStream<S> {
- fn as_raw_socket(&self) -> RawSocket {
- self.0.as_raw_socket()
- }
-}
-
-impl NonblockingSslStream<net::TcpStream> {
- pub fn try_clone(&self) -> io::Result<NonblockingSslStream<net::TcpStream>> {
- self.0.try_clone().map(NonblockingSslStream)
- }
-}
-
-impl<S> NonblockingSslStream<S> {
- /// Returns a reference to the underlying stream.
- pub fn get_ref(&self) -> &S {
- self.0.get_ref()
- }
-
- /// Returns a mutable reference to the underlying stream.
- ///
- /// ## Warning
- ///
- /// It is inadvisable to read from or write to the underlying stream as it
- /// will most likely corrupt the SSL session.
- pub fn get_mut(&mut self) -> &mut S {
- self.0.get_mut()
- }
-
- /// Returns a reference to the Ssl.
- pub fn ssl(&self) -> &Ssl {
- self.0.ssl()
- }
-}
-
-impl<S: Read + Write> NonblockingSslStream<S> {
- /// Create a new nonblocking client ssl connection on wrapped `stream`.
- ///
- /// Note that this method will most likely not actually complete the SSL
- /// handshake because doing so requires several round trips; the handshake will
- /// be completed in subsequent read/write calls managed by your event loop.
- pub fn connect<T: IntoSsl>(ssl: T, stream: S) -> Result<NonblockingSslStream<S>, SslError> {
- SslStream::connect(ssl, stream).map(NonblockingSslStream)
- }
-
- /// Create a new nonblocking server ssl connection on wrapped `stream`.
- ///
- /// Note that this method will most likely not actually complete the SSL
- /// handshake because doing so requires several round trips; the handshake will
- /// be completed in subsequent read/write calls managed by your event loop.
- pub fn accept<T: IntoSsl>(ssl: T, stream: S) -> Result<NonblockingSslStream<S>, SslError> {
- SslStream::accept(ssl, stream).map(NonblockingSslStream)
- }
-
- fn convert_err(&self, err: Error) -> NonblockingSslError {
- match err {
- Error::ZeroReturn => SslError::SslSessionClosed.into(),
- Error::WantRead(_) => NonblockingSslError::WantRead,
- Error::WantWrite(_) => NonblockingSslError::WantWrite,
- Error::WantX509Lookup => unreachable!(),
- Error::Stream(e) => SslError::StreamError(e).into(),
- Error::Ssl(e) => {
- SslError::OpenSslErrors(e.iter()
- .map(|e| OpensslError::from_error_code(e.error_code()))
- .collect())
- .into()
- }
- }
- }
-
- /// Read bytes from the SSL stream into `buf`.
- ///
- /// Given the SSL state machine, this method may return either `WantWrite`
- /// or `WantRead` to indicate that your event loop should respectively wait
- /// for write or read readiness on the underlying stream. Upon readiness,
- /// repeat your `read()` call with the same arguments each time until you
- /// receive an `Ok(count)`.
- ///
- /// An `SslError` return value, is terminal; do not re-attempt your read.
- ///
- /// As expected of a nonblocking API, this method will never block your
- /// thread on I/O.
- ///
- /// On a return value of `Ok(count)`, count is the number of decrypted
- /// plaintext bytes copied into the `buf` slice.
- pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, NonblockingSslError> {
- match self.0.ssl_read(buf) {
- Ok(n) => Ok(n),
- Err(Error::ZeroReturn) => Ok(0),
- Err(e) => Err(self.convert_err(e)),
- }
- }
-
- /// Write bytes from `buf` to the SSL stream.
- ///
- /// Given the SSL state machine, this method may return either `WantWrite`
- /// or `WantRead` to indicate that your event loop should respectively wait
- /// for write or read readiness on the underlying stream. Upon readiness,
- /// repeat your `write()` call with the same arguments each time until you
- /// receive an `Ok(count)`.
- ///
- /// An `SslError` return value, is terminal; do not re-attempt your write.
- ///
- /// As expected of a nonblocking API, this method will never block your
- /// thread on I/O.
- ///
- /// Given a return value of `Ok(count)`, count is the number of plaintext bytes
- /// from the `buf` slice that were encrypted and written onto the stream.
- pub fn write(&mut self, buf: &[u8]) -> Result<usize, NonblockingSslError> {
- self.0.ssl_write(buf).map_err(|e| self.convert_err(e))
- }
-}
diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs
index 5339f27e..bfcaa5e4 100644
--- a/openssl/src/ssl/tests/mod.rs
+++ b/openssl/src/ssl/tests/mod.rs
@@ -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()
}
@@ -980,14 +963,6 @@ fn test_read_nonblocking() {
}
#[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")]
fn write_panic() {
@@ -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();
diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs
index 3150cc6e..4cb4458a 100644
--- a/openssl/src/x509/mod.rs
+++ b/openssl/src/x509/mod.rs
@@ -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,
- })
+ if ptr.is_null() {
+ None
+ } else {
+ 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,
- }
- }
-
- /// 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,
- }
+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)
}
- /// 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 as_ptr(&self) -> *mut ffi::X509 {
+ self.0
}
- 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>> {
- 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!"),
- }
- }
+ pub fn fingerprint(&self, hash_type: hash::Type) -> Result<Vec<u8>, ErrorStack> {
+ unsafe {
+ let evp = hash_type.evp_md();
+ 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 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> 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 Deref for X509 {
+ type Target = X509Ref<'static>;
+
+ fn deref(&self) -> &X509Ref<'static> {
+ &self.0
}
}
-impl<'ctx> Drop for X509<'ctx> {
- fn drop(&mut self) {
- if self.owned {
- unsafe { ffi::X509_free(self.handle) };
+#[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())
}
}
}
-#[allow(dead_code)]
-pub struct X509Name<'x> {
- x509: &'x X509<'x>,
- name: *mut ffi::X509_NAME,
+impl Drop for X509 {
+ fn drop(&mut self) {
+ unsafe { ffi::X509_free(self.as_ptr()) };
+ }
}
-#[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)
}
- /// 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 as_ptr(&self) -> *mut ffi::X509_REQ {
+ self.0
+ }
+ /// Reads CSR from PEM
+ 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());
+ 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());
+ }
+ 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 {
- try_ssl!(ffi::PEM_write_bio_X509_REQ(mem_bio.get_handle(), self.handle));
+ ffi::i2d_X509_REQ_bio(mem_bio.as_ptr(), self.0);
}
- io::copy(&mut mem_bio, writer).map_err(StreamError).map(|_| ())
+ 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");
}
}
diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs
index f547a982..c09b31cd 100644
--- a/openssl/src/x509/tests.rs
+++ b/openssl/src/x509/tests.rs
@@ -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 der = cert.to_der().unwrap();
+ assert!(!der.is_empty());
+}
- let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM");
+#[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();
diff --git a/openssl/test/dsa-encrypted.pem b/openssl/test/dsa-encrypted.pem
new file mode 100644
index 00000000..9b1984eb
--- /dev/null
+++ b/openssl/test/dsa-encrypted.pem
@@ -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-----
diff --git a/openssl/test/dsa.pem b/openssl/test/dsa.pem
new file mode 100644
index 00000000..9b550184
--- /dev/null
+++ b/openssl/test/dsa.pem
@@ -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-----
diff --git a/openssl/test/dsa.pem.pub b/openssl/test/dsa.pem.pub
new file mode 100644
index 00000000..ae298d09
--- /dev/null
+++ b/openssl/test/dsa.pem.pub
@@ -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-----
diff --git a/openssl/test/dsaparam.pem b/openssl/test/dsaparam.pem
new file mode 100644
index 00000000..53bda543
--- /dev/null
+++ b/openssl/test/dsaparam.pem
@@ -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-----
diff --git a/openssl/test/rsa-encrypted.pem b/openssl/test/rsa-encrypted.pem
new file mode 100644
index 00000000..a6249997
--- /dev/null
+++ b/openssl/test/rsa-encrypted.pem
@@ -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-----
diff --git a/openssl/test/run.sh b/openssl/test/run.sh
index 829f11e9..b9481837 100755
--- a/openssl/test/run.sh
+++ b/openssl/test/run.sh
@@ -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")