Merge branch 'release-v0.6.5' into release

This commit is contained in:
Steven Fackler 2015-08-31 19:11:10 -07:00
commit abde5382c9
21 changed files with 849 additions and 216 deletions

View File

@ -8,7 +8,7 @@ os:
- linux - linux
env: env:
global: global:
- FEATURES="tlsv1_2 tlsv1_1 dtlsv1 dtlsv1_2 sslv2 aes_xts npn alpn" - FEATURES="tlsv1_2 tlsv1_1 dtlsv1 dtlsv1_2 sslv2 aes_xts npn alpn aes_ctr"
before_install: before_install:
- (test $TRAVIS_OS_NAME == "osx" || ./openssl/test/build.sh) - (test $TRAVIS_OS_NAME == "osx" || ./openssl/test/build.sh)
before_script: before_script:

View File

@ -2,7 +2,7 @@
[![Build Status](https://travis-ci.org/sfackler/rust-openssl.svg?branch=master)](https://travis-ci.org/sfackler/rust-openssl) [![Build Status](https://travis-ci.org/sfackler/rust-openssl.svg?branch=master)](https://travis-ci.org/sfackler/rust-openssl)
[Documentation](https://sfackler.github.io/rust-openssl/doc/v0.6.4/openssl). [Documentation](https://sfackler.github.io/rust-openssl/doc/v0.6.5/openssl).
## Building ## Building

View File

@ -1,12 +1,12 @@
[package] [package]
name = "openssl-sys" name = "openssl-sys"
version = "0.6.4" version = "0.6.5"
authors = ["Alex Crichton <alex@alexcrichton.com>", authors = ["Alex Crichton <alex@alexcrichton.com>",
"Steven Fackler <sfackler@gmail.com>"] "Steven Fackler <sfackler@gmail.com>"]
license = "MIT" license = "MIT"
description = "FFI bindings to OpenSSL" description = "FFI bindings to OpenSSL"
repository = "https://github.com/sfackler/rust-openssl" repository = "https://github.com/sfackler/rust-openssl"
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.6.4/openssl_sys" documentation = "https://sfackler.github.io/rust-openssl/doc/v0.6.5/openssl_sys"
links = "openssl" links = "openssl"
build = "build.rs" build = "build.rs"
@ -18,6 +18,7 @@ dtlsv1 = []
dtlsv1_2 = [] dtlsv1_2 = []
sslv2 = [] sslv2 = []
aes_xts = [] aes_xts = []
aes_ctr = []
npn = [] npn = []
alpn = [] alpn = []

View File

@ -2,7 +2,10 @@ extern crate pkg_config;
extern crate gcc; extern crate gcc;
use std::env; use std::env;
use std::fmt::Write as FmtWrite;
use std::path::PathBuf; use std::path::PathBuf;
use std::fs::File;
use std::io::Write;
fn main() { fn main() {
let target = env::var("TARGET").unwrap(); let target = env::var("TARGET").unwrap();
@ -65,7 +68,63 @@ fn main() {
build_openssl_shim(&include_dirs); build_openssl_shim(&include_dirs);
} }
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
}
fn build_openssl_shim(include_paths: &[PathBuf]) { fn build_openssl_shim(include_paths: &[PathBuf]) {
let options_shim_file = generate_options_shim();
let mut config = gcc::Config::new(); let mut config = gcc::Config::new();
for path in include_paths { for path in include_paths {
@ -73,6 +132,7 @@ fn build_openssl_shim(include_paths: &[PathBuf]) {
} }
config.file("src/openssl_shim.c") config.file("src/openssl_shim.c")
.file(options_shim_file)
.compile("libopenssl_shim.a"); .compile("libopenssl_shim.a");
} }

View File

@ -1,6 +1,6 @@
#![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] #![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)]
#![allow(dead_code)] #![allow(dead_code)]
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.6.4")] #![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.6.5")]
extern crate libc; extern crate libc;
@ -37,6 +37,7 @@ pub type X509_NAME = c_void;
pub type X509_NAME_ENTRY = c_void; pub type X509_NAME_ENTRY = c_void;
pub type X509_REQ = c_void; pub type X509_REQ = c_void;
pub type X509_STORE_CTX = c_void; pub type X509_STORE_CTX = c_void;
pub type stack_st_X509_EXTENSION = c_void;
#[repr(C)] #[repr(C)]
pub struct EVP_MD_CTX { pub struct EVP_MD_CTX {
@ -128,6 +129,8 @@ pub const MBSTRING_UTF8: c_int = MBSTRING_FLAG;
pub const NID_ext_key_usage: c_int = 126; pub const NID_ext_key_usage: c_int = 126;
pub const NID_key_usage: c_int = 83; pub const NID_key_usage: c_int = 83;
pub const PKCS5_SALT_LEN: c_int = 8;
pub const SSL_CTRL_OPTIONS: c_int = 32; pub const SSL_CTRL_OPTIONS: c_int = 32;
pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77;
@ -155,6 +158,14 @@ pub const SSL_TLSEXT_ERR_ALERT_WARNING: c_int = 1;
pub const SSL_TLSEXT_ERR_ALERT_FATAL: c_int = 2; pub const SSL_TLSEXT_ERR_ALERT_FATAL: c_int = 2;
pub const SSL_TLSEXT_ERR_NOACK: c_int = 3; pub const SSL_TLSEXT_ERR_NOACK: c_int = 3;
macro_rules! import_options {
( $( $name:ident $val:expr )* ) => {
$( pub const $name: u64 = $val; )*
};
}
include!("ssl_options.rs");
#[cfg(feature = "npn")] #[cfg(feature = "npn")]
pub const OPENSSL_NPN_UNSUPPORTED: c_int = 0; pub const OPENSSL_NPN_UNSUPPORTED: c_int = 0;
#[cfg(feature = "npn")] #[cfg(feature = "npn")]
@ -262,8 +273,23 @@ pub fn init() {
} }
} }
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)))
}
// True functions // True functions
extern "C" { extern "C" {
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;
pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int;
pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING;
pub fn ASN1_TIME_free(tm: *mut ASN1_TIME); pub fn ASN1_TIME_free(tm: *mut ASN1_TIME);
@ -374,16 +400,22 @@ extern "C" {
pub fn EVP_aes_128_ecb() -> *const EVP_CIPHER; pub fn EVP_aes_128_ecb() -> *const EVP_CIPHER;
#[cfg(feature = "aes_xts")] #[cfg(feature = "aes_xts")]
pub fn EVP_aes_128_xts() -> *const EVP_CIPHER; pub fn EVP_aes_128_xts() -> *const EVP_CIPHER;
// fn EVP_aes_128_ctr() -> EVP_CIPHER; #[cfg(feature = "aes_ctr")]
pub fn EVP_aes_128_ctr() -> *const EVP_CIPHER;
// fn EVP_aes_128_gcm() -> EVP_CIPHER; // fn EVP_aes_128_gcm() -> EVP_CIPHER;
pub fn EVP_aes_256_cbc() -> *const EVP_CIPHER; pub fn EVP_aes_256_cbc() -> *const EVP_CIPHER;
pub fn EVP_aes_256_ecb() -> *const EVP_CIPHER; pub fn EVP_aes_256_ecb() -> *const EVP_CIPHER;
#[cfg(feature = "aes_xts")] #[cfg(feature = "aes_xts")]
pub fn EVP_aes_256_xts() -> *const EVP_CIPHER; pub fn EVP_aes_256_xts() -> *const EVP_CIPHER;
// fn EVP_aes_256_ctr() -> EVP_CIPHER; #[cfg(feature = "aes_ctr")]
pub fn EVP_aes_256_ctr() -> *const EVP_CIPHER;
// fn EVP_aes_256_gcm() -> EVP_CIPHER; // fn EVP_aes_256_gcm() -> EVP_CIPHER;
pub fn EVP_rc4() -> *const EVP_CIPHER; pub fn EVP_rc4() -> *const EVP_CIPHER;
pub fn EVP_BytesToKey(typ: *const EVP_CIPHER, md: *const EVP_MD,
salt: *const u8, data: *const u8, datalen: c_int,
count: c_int, key: *mut u8, iv: *mut u8) -> c_int;
pub fn EVP_CIPHER_CTX_new() -> *mut EVP_CIPHER_CTX; pub fn EVP_CIPHER_CTX_new() -> *mut EVP_CIPHER_CTX;
pub fn EVP_CIPHER_CTX_set_padding(ctx: *mut EVP_CIPHER_CTX, padding: c_int) -> c_int; pub fn EVP_CIPHER_CTX_set_padding(ctx: *mut EVP_CIPHER_CTX, padding: c_int) -> c_int;
pub fn EVP_CIPHER_CTX_free(ctx: *mut EVP_CIPHER_CTX); pub fn EVP_CIPHER_CTX_free(ctx: *mut EVP_CIPHER_CTX);
@ -445,6 +477,7 @@ extern "C" {
kstr: *mut c_char, klen: c_int, kstr: *mut c_char, klen: c_int,
callback: Option<PasswordCallback>, callback: Option<PasswordCallback>,
user_data: *mut c_void) -> c_int; user_data: *mut c_void) -> c_int;
pub fn PEM_write_bio_PUBKEY(bp: *mut BIO, x: *mut EVP_PKEY) -> c_int;
pub fn PEM_write_bio_X509(bio: *mut BIO, x509: *mut X509) -> c_int; pub fn PEM_write_bio_X509(bio: *mut BIO, x509: *mut X509) -> c_int;
pub fn PEM_write_bio_X509_REQ(bio: *mut BIO, x509: *mut X509_REQ) -> c_int; pub fn PEM_write_bio_X509_REQ(bio: *mut BIO, x509: *mut X509_REQ) -> c_int;
@ -502,6 +535,9 @@ extern "C" {
pub fn SSL_get_SSL_CTX(ssl: *mut SSL) -> *mut SSL_CTX; pub fn SSL_get_SSL_CTX(ssl: *mut SSL) -> *mut SSL_CTX;
pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const COMP_METHOD; pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const COMP_METHOD;
pub fn SSL_get_peer_certificate(ssl: *mut SSL) -> *mut X509; pub fn SSL_get_peer_certificate(ssl: *mut SSL) -> *mut X509;
pub fn SSL_get_ssl_method(ssl: *mut SSL) -> *const SSL_METHOD;
pub fn SSL_state_string(ssl: *mut SSL) -> *const c_char;
pub fn SSL_state_string_long(ssl: *mut SSL) -> *const c_char;
pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char; pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char;
@ -603,8 +639,12 @@ extern "C" {
pub fn X509_STORE_CTX_get_ex_data(ctx: *mut X509_STORE_CTX, idx: c_int) -> *mut c_void; pub fn X509_STORE_CTX_get_ex_data(ctx: *mut X509_STORE_CTX, idx: c_int) -> *mut c_void;
pub fn X509V3_EXT_conf_nid(conf: *mut c_void, ctx: *mut X509V3_CTX, ext_nid: c_int, value: *mut c_char) -> *mut X509_EXTENSION; pub fn X509V3_EXT_conf_nid(conf: *mut c_void, ctx: *mut X509V3_CTX, ext_nid: c_int, value: *mut c_char) -> *mut X509_EXTENSION;
pub fn X509V3_EXT_conf(conf: *mut c_void, ctx: *mut X509V3_CTX, name: *mut c_char, value: *mut c_char) -> *mut X509_EXTENSION;
pub fn X509V3_set_ctx(ctx: *mut X509V3_CTX, issuer: *mut X509, subject: *mut X509, req: *mut X509_REQ, crl: *mut X509_CRL, flags: c_int); pub fn X509V3_set_ctx(ctx: *mut X509V3_CTX, issuer: *mut X509, subject: *mut X509, req: *mut X509_REQ, crl: *mut X509_CRL, flags: c_int);
pub fn X509_REQ_add_extensions(req: *mut X509_REQ, exts: *mut stack_st_X509_EXTENSION) -> c_int;
pub fn X509_REQ_sign(x: *mut X509_REQ, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int;
pub fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *const *mut u8) -> c_int; pub fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *const *mut u8) -> c_int;
pub fn d2i_RSA_PUBKEY(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA; pub fn d2i_RSA_PUBKEY(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA;
pub fn i2d_RSAPrivateKey(k: *mut RSA, buf: *const *mut u8) -> c_int; pub fn i2d_RSAPrivateKey(k: *mut RSA, buf: *const *mut u8) -> c_int;
@ -615,18 +655,17 @@ extern "C" {
pub fn BIO_eof(b: *mut BIO) -> c_int; pub fn BIO_eof(b: *mut BIO) -> c_int;
#[link_name = "BIO_set_mem_eof_return_shim"] #[link_name = "BIO_set_mem_eof_return_shim"]
pub fn BIO_set_mem_eof_return(b: *mut BIO, v: c_int); pub fn BIO_set_mem_eof_return(b: *mut BIO, v: c_int);
#[link_name = "SSL_CTX_set_options_shim"] pub fn SSL_CTX_set_options_shim(ctx: *mut SSL_CTX, options: c_long) -> c_long;
pub fn SSL_CTX_set_options(ctx: *mut SSL_CTX, options: c_long) -> c_long; pub fn SSL_CTX_get_options_shim(ctx: *mut SSL_CTX) -> c_long;
#[link_name = "SSL_CTX_get_options_shim"] pub fn SSL_CTX_clear_options_shim(ctx: *mut SSL_CTX, options: c_long) -> c_long;
pub fn SSL_CTX_get_options(ctx: *mut SSL_CTX) -> c_long;
#[link_name = "SSL_CTX_clear_options_shim"]
pub fn SSL_CTX_clear_options(ctx: *mut SSL_CTX, options: c_long) -> c_long;
#[link_name = "SSL_CTX_add_extra_chain_cert_shim"] #[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; 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"] #[link_name = "SSL_CTX_set_read_ahead_shim"]
pub fn SSL_CTX_set_read_ahead(ctx: *mut SSL_CTX, m: c_long) -> c_long; pub fn SSL_CTX_set_read_ahead(ctx: *mut SSL_CTX, m: c_long) -> c_long;
#[link_name = "SSL_set_tlsext_host_name_shim"] #[link_name = "SSL_set_tlsext_host_name_shim"]
pub fn SSL_set_tlsext_host_name(s: *mut SSL, name: *const c_char) -> c_long; pub fn SSL_set_tlsext_host_name(s: *mut SSL, name: *const c_char) -> c_long;
#[link_name = "X509_get_extensions_shim"]
pub fn X509_get_extensions(x: *mut X509) -> *mut stack_st_X509_EXTENSION;
} }
pub mod probe; pub mod probe;

View File

@ -82,3 +82,7 @@ long SSL_CTX_set_read_ahead_shim(SSL_CTX *ctx, long m) {
long SSL_set_tlsext_host_name_shim(SSL *s, char *name) { long SSL_set_tlsext_host_name_shim(SSL *s, char *name) {
return SSL_set_tlsext_host_name(s, name); return SSL_set_tlsext_host_name(s, name);
} }
STACK_OF(X509_EXTENSION) *X509_get_extensions_shim(X509 *x) {
return x->cert_info ? x->cert_info->extensions : NULL;
}

View File

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

View File

@ -1,11 +1,11 @@
[package] [package]
name = "openssl" name = "openssl"
version = "0.6.4" version = "0.6.5"
authors = ["Steven Fackler <sfackler@gmail.com>"] authors = ["Steven Fackler <sfackler@gmail.com>"]
license = "Apache-2.0" license = "Apache-2.0"
description = "OpenSSL bindings" description = "OpenSSL bindings"
repository = "https://github.com/sfackler/rust-openssl" repository = "https://github.com/sfackler/rust-openssl"
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.6.4/openssl" documentation = "https://sfackler.github.io/rust-openssl/doc/v0.6.5/openssl"
readme = "../README.md" readme = "../README.md"
keywords = ["crypto", "tls", "ssl", "dtls"] keywords = ["crypto", "tls", "ssl", "dtls"]
@ -16,6 +16,7 @@ dtlsv1 = ["openssl-sys/dtlsv1"]
dtlsv1_2 = ["openssl-sys/dtlsv1_2"] dtlsv1_2 = ["openssl-sys/dtlsv1_2"]
sslv2 = ["openssl-sys/sslv2"] sslv2 = ["openssl-sys/sslv2"]
aes_xts = ["openssl-sys/aes_xts"] aes_xts = ["openssl-sys/aes_xts"]
aes_ctr = ["openssl-sys/aes_ctr"]
npn = ["openssl-sys/npn"] npn = ["openssl-sys/npn"]
alpn = ["openssl-sys/alpn"] alpn = ["openssl-sys/alpn"]

View File

@ -22,3 +22,5 @@ pub mod pkey;
pub mod rand; pub mod rand;
pub mod symm; pub mod symm;
pub mod memcmp; pub mod memcmp;
mod symm_internal;

View File

@ -1,6 +1,69 @@
use libc::c_int; use libc::c_int;
use std::ptr::null;
use crypto::symm_internal::evpc;
use crypto::hash;
use crypto::symm;
use ffi; use ffi;
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct KeyIvPair
{
pub key: Vec<u8>,
pub iv: Vec<u8>
}
/// Derives a key and an IV from various parameters.
///
/// 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
/// v1.5 or PBKDF1 from PKCS#5 v2.0.
///
/// 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 {
unsafe {
let salt_ptr = match salt {
Some(salt) => {
assert_eq!(salt.len(), ffi::PKCS5_SALT_LEN as usize);
salt.as_ptr()
},
None => 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 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);
KeyIvPair {
key: key,
iv: iv
}
}
}
/// Derives a key from a password and salt using the PBKDF2-HMAC-SHA1 algorithm. /// Derives a key from a password and salt using the PBKDF2-HMAC-SHA1 algorithm.
pub fn pbkdf2_hmac_sha1(pass: &str, salt: &[u8], iter: usize, keylen: usize) -> Vec<u8> { pub fn pbkdf2_hmac_sha1(pass: &str, salt: &[u8], iter: usize, keylen: usize) -> Vec<u8> {
unsafe { unsafe {
@ -27,6 +90,9 @@ pub fn pbkdf2_hmac_sha1(pass: &str, salt: &[u8], iter: usize, keylen: usize) ->
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crypto::hash;
use crypto::symm;
// Test vectors from // Test vectors from
// http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06 // http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06
#[test] #[test]
@ -116,4 +182,47 @@ mod tests {
) )
); );
} }
#[test]
fn test_evp_bytes_to_key_pbkdf1_compatible() {
let salt = [
16_u8, 34_u8, 19_u8, 23_u8, 141_u8, 4_u8, 207_u8, 221_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, 65_u8, 207_u8
];
let expected_key = vec![
249_u8, 115_u8, 114_u8, 97_u8, 32_u8, 213_u8, 165_u8, 146_u8, 58_u8,
87_u8, 234_u8, 3_u8, 43_u8, 250_u8, 97_u8, 114_u8, 26_u8, 98_u8,
245_u8, 246_u8, 238_u8, 177_u8, 229_u8, 161_u8, 183_u8, 224_u8,
174_u8, 3_u8, 6_u8, 244_u8, 236_u8, 255_u8
];
let expected_iv = vec![
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
];
assert_eq!(
super::evp_bytes_to_key_pbkdf1_compatible(
symm::Type::AES_256_CBC,
hash::Type::SHA1,
&data,
Some(&salt),
1
),
super::KeyIvPair {
key: expected_key,
iv: expected_iv
}
);
}
} }

View File

@ -182,6 +182,17 @@ impl PKey {
writer.write_all(&buf).map_err(StreamError) writer.write_all(&buf).map_err(StreamError)
} }
/// 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. * Returns the size of the public key modulus.
*/ */
@ -500,4 +511,25 @@ mod tests {
assert!(!k0.public_eq(&p1)); assert!(!k0.public_eq(&p1));
assert!(!p0.public_eq(&k1)); assert!(!p0.public_eq(&k1));
} }
#[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 mut priv_key = Vec::new();
let mut pub_key = Vec::new();
key.write_pem(&mut priv_key).unwrap();
key.write_pub_pem(&mut pub_key).unwrap();
// As a super-simple verification, just check that the buffers contain
// 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"));
}
} }

View File

@ -2,6 +2,7 @@ use std::iter::repeat;
use std::convert::AsRef; use std::convert::AsRef;
use libc::{c_int}; use libc::{c_int};
use crypto::symm_internal::evpc;
use ffi; use ffi;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -18,7 +19,8 @@ pub enum Type {
/// Requires the `aes_xts` feature /// Requires the `aes_xts` feature
#[cfg(feature = "aes_xts")] #[cfg(feature = "aes_xts")]
AES_128_XTS, AES_128_XTS,
// AES_128_CTR, #[cfg(feature = "aes_ctr")]
AES_128_CTR,
//AES_128_GCM, //AES_128_GCM,
AES_256_ECB, AES_256_ECB,
@ -26,33 +28,13 @@ pub enum Type {
/// Requires the `aes_xts` feature /// Requires the `aes_xts` feature
#[cfg(feature = "aes_xts")] #[cfg(feature = "aes_xts")]
AES_256_XTS, AES_256_XTS,
// AES_256_CTR, #[cfg(feature = "aes_ctr")]
AES_256_CTR,
//AES_256_GCM, //AES_256_GCM,
RC4_128, RC4_128,
} }
fn evpc(t: Type) -> (*const ffi::EVP_CIPHER, u32, u32) {
unsafe {
match t {
Type::AES_128_ECB => (ffi::EVP_aes_128_ecb(), 16, 16),
Type::AES_128_CBC => (ffi::EVP_aes_128_cbc(), 16, 16),
#[cfg(feature = "aes_xts")]
Type::AES_128_XTS => (ffi::EVP_aes_128_xts(), 32, 16),
// AES_128_CTR => (EVP_aes_128_ctr(), 16, 0),
//AES_128_GCM => (EVP_aes_128_gcm(), 16, 16),
Type::AES_256_ECB => (ffi::EVP_aes_256_ecb(), 32, 16),
Type::AES_256_CBC => (ffi::EVP_aes_256_cbc(), 32, 16),
#[cfg(feature = "aes_xts")]
Type::AES_256_XTS => (ffi::EVP_aes_256_xts(), 64, 16),
// AES_256_CTR => (EVP_aes_256_ctr(), 32, 0),
//AES_256_GCM => (EVP_aes_256_gcm(), 32, 16),
Type::RC4_128 => (ffi::EVP_rc4(), 16, 0),
}
}
}
/// Represents a symmetric cipher context. /// Represents a symmetric cipher context.
pub struct Crypter { pub struct Crypter {
@ -288,16 +270,17 @@ mod tests {
cipher_test(super::Type::AES_256_XTS, pt, ct, key, iv); cipher_test(super::Type::AES_256_XTS, pt, ct, key, iv);
} }
/*#[test] #[test]
#[cfg(feature = "aes_ctr")]
fn test_aes128_ctr() { fn test_aes128_ctr() {
let pt = ~"6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710"; let pt = "6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710";
let ct = ~"874D6191B620E3261BEF6864990DB6CE9806F66B7970FDFF8617187BB9FFFDFF5AE4DF3EDBD5D35E5B4F09020DB03EAB1E031DDA2FBE03D1792170A0F3009CEE"; let ct = "874D6191B620E3261BEF6864990DB6CE9806F66B7970FDFF8617187BB9FFFDFF5AE4DF3EDBD5D35E5B4F09020DB03EAB1E031DDA2FBE03D1792170A0F3009CEE";
let key = ~"2B7E151628AED2A6ABF7158809CF4F3C"; let key = "2B7E151628AED2A6ABF7158809CF4F3C";
let iv = ~"F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"; let iv = "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF";
cipher_test(super::AES_128_CTR, pt, ct, key, iv); cipher_test(super::Type::AES_128_CTR, pt, ct, key, iv);
}*/ }
/*#[test] /*#[test]
fn test_aes128_gcm() { fn test_aes128_gcm() {

View File

@ -0,0 +1,26 @@
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_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::RC4_128 => (ffi::EVP_rc4(), 16, 0),
}
}
}

View File

@ -1,4 +1,4 @@
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.6.4")] #![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.6.5")]
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;

View File

@ -1,5 +1,5 @@
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Copy, Clone)] #[derive(Copy, Clone, Hash, PartialEq, Eq)]
#[repr(usize)] #[repr(usize)]
pub enum Nid { pub enum Nid {
Undefined, Undefined,

View File

@ -6,6 +6,7 @@ use std::fmt;
use std::io; use std::io;
use std::io::prelude::*; use std::io::prelude::*;
use std::mem; use std::mem;
use std::str;
use std::net; use std::net;
use std::path::Path; use std::path::Path;
use std::ptr; use std::ptr;
@ -30,7 +31,9 @@ mod tests;
static mut VERIFY_IDX: c_int = -1; static mut VERIFY_IDX: c_int = -1;
fn init() { /// 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; static mut INIT: Once = ONCE_INIT;
unsafe { unsafe {
@ -46,35 +49,52 @@ fn init() {
} }
bitflags! { bitflags! {
flags SslContextOptions: c_long { flags SslContextOptions: u64 {
const SSL_OP_LEGACY_SERVER_CONNECT = 0x00000004, const SSL_OP_MICROSOFT_SESS_ID_BUG = ffi::SSL_OP_MICROSOFT_SESS_ID_BUG,
const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = 0x00000008, const SSL_OP_NETSCAPE_CHALLENGE_BUG = ffi::SSL_OP_NETSCAPE_CHALLENGE_BUG,
const SSL_OP_TLSEXT_PADDING = 0x00000010, const SSL_OP_LEGACY_SERVER_CONNECT = ffi::SSL_OP_LEGACY_SERVER_CONNECT,
const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = 0x00000020, const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = ffi::SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG,
const SSL_OP_SAFARI_ECDHE_ECDSA_BUG = 0x00000040, const SSL_OP_TLSEXT_PADDING = ffi::SSL_OP_TLSEXT_PADDING,
const SSL_OP_SSLEAY_080_CLIENT_DH_BUG = 0x00000080, const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = ffi::SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER,
const SSL_OP_TLS_D5_BUG = 0x00000100, const SSL_OP_SAFARI_ECDHE_ECDSA_BUG = ffi::SSL_OP_SAFARI_ECDHE_ECDSA_BUG,
const SSL_OP_TLS_BLOCK_PADDING_BUG = 0x00000200, const SSL_OP_SSLEAY_080_CLIENT_DH_BUG = ffi::SSL_OP_SSLEAY_080_CLIENT_DH_BUG,
const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 0x00000800, const SSL_OP_TLS_D5_BUG = ffi::SSL_OP_TLS_D5_BUG,
const SSL_OP_ALL = 0x80000BFF, const SSL_OP_TLS_BLOCK_PADDING_BUG = ffi::SSL_OP_TLS_BLOCK_PADDING_BUG,
const SSL_OP_NO_QUERY_MTU = 0x00001000, const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = ffi::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS,
const SSL_OP_COOKIE_EXCHANGE = 0x00002000, const SSL_OP_NO_QUERY_MTU = ffi::SSL_OP_NO_QUERY_MTU,
const SSL_OP_NO_TICKET = 0x00004000, const SSL_OP_COOKIE_EXCHANGE = ffi::SSL_OP_COOKIE_EXCHANGE,
const SSL_OP_CISCO_ANYCONNECT = 0x00008000, const SSL_OP_NO_TICKET = ffi::SSL_OP_NO_TICKET,
const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 0x00010000, const SSL_OP_CISCO_ANYCONNECT = ffi::SSL_OP_CISCO_ANYCONNECT,
const SSL_OP_NO_COMPRESSION = 0x00020000, const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = ffi::SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION,
const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = 0x00040000, const SSL_OP_NO_COMPRESSION = ffi::SSL_OP_NO_COMPRESSION,
const SSL_OP_SINGLE_ECDH_USE = 0x00080000, const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = ffi::SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION,
const SSL_OP_SINGLE_DH_USE = 0x00100000, const SSL_OP_SINGLE_ECDH_USE = ffi::SSL_OP_SINGLE_ECDH_USE,
const SSL_OP_CIPHER_SERVER_PREFERENCE = 0x00400000, const SSL_OP_SINGLE_DH_USE = ffi::SSL_OP_SINGLE_DH_USE,
const SSL_OP_TLS_ROLLBACK_BUG = 0x00800000, const SSL_OP_CIPHER_SERVER_PREFERENCE = ffi::SSL_OP_CIPHER_SERVER_PREFERENCE,
const SSL_OP_NO_SSLV2 = 0x00000000, const SSL_OP_TLS_ROLLBACK_BUG = ffi::SSL_OP_TLS_ROLLBACK_BUG,
const SSL_OP_NO_SSLV3 = 0x02000000, const SSL_OP_NO_SSLV2 = ffi::SSL_OP_NO_SSLv2,
const SSL_OP_NO_TLSV1 = 0x04000000, const SSL_OP_NO_SSLV3 = ffi::SSL_OP_NO_SSLv3,
const SSL_OP_NO_TLSV1_2 = 0x08000000, const SSL_OP_NO_DTLSV1 = ffi::SSL_OP_NO_DTLSv1,
const SSL_OP_NO_TLSV1_1 = 0x10000000, const SSL_OP_NO_TLSV1 = ffi::SSL_OP_NO_TLSv1,
const SSL_OP_NO_DTLSV1 = 0x04000000, const SSL_OP_NO_DTLSV1_2 = ffi::SSL_OP_NO_DTLSv1_2,
const SSL_OP_NO_DTLSV1_2 = 0x08000000 const SSL_OP_NO_TLSV1_2 = ffi::SSL_OP_NO_TLSv1_2,
const SSL_OP_NO_TLSV1_1 = ffi::SSL_OP_NO_TLSv1_1,
const SSL_OP_NETSCAPE_CA_DN_BUG = ffi::SSL_OP_NETSCAPE_CA_DN_BUG,
const SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG = ffi::SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG,
const SSL_OP_CRYPTOPRO_TLSEXT_BUG = ffi::SSL_OP_CRYPTOPRO_TLSEXT_BUG,
const SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG = ffi::SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG,
const SSL_OP_MSIE_SSLV2_RSA_PADDING = ffi::SSL_OP_MSIE_SSLV2_RSA_PADDING,
const SSL_OP_PKCS1_CHECK_1 = ffi::SSL_OP_PKCS1_CHECK_1,
const SSL_OP_PKCS1_CHECK_2 = ffi::SSL_OP_PKCS1_CHECK_2,
const SSL_OP_EPHEMERAL_RSA = ffi::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,
} }
} }
@ -124,6 +144,25 @@ impl SslMethod {
} }
} }
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),
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")] #[cfg(feature = "dtlsv1")]
pub fn is_dtlsv1(&self) -> bool { pub fn is_dtlsv1(&self) -> bool {
*self == SslMethod::Dtlsv1 *self == SslMethod::Dtlsv1
@ -652,6 +691,24 @@ impl Ssl {
Ok(ssl) Ok(ssl)
} }
pub fn get_state_string(&self) -> &'static str {
let state = unsafe {
let ptr = ffi::SSL_state_string(self.ssl);
CStr::from_ptr(ptr)
};
str::from_utf8(state.to_bytes()).unwrap()
}
pub fn get_state_string_long(&self) -> &'static str {
let state = unsafe {
let ptr = ffi::SSL_state_string_long(self.ssl);
CStr::from_ptr(ptr)
};
str::from_utf8(state.to_bytes()).unwrap()
}
fn get_rbio<'a>(&'a self) -> MemBioRef<'a> { fn get_rbio<'a>(&'a self) -> MemBioRef<'a> {
unsafe { self.wrap_bio(ffi::SSL_get_rbio(self.ssl)) } unsafe { self.wrap_bio(ffi::SSL_get_rbio(self.ssl)) }
} }
@ -770,6 +827,13 @@ impl Ssl {
ffi::SSL_pending(self.ssl) as usize ffi::SSL_pending(self.ssl) as usize
} }
} }
pub fn get_ssl_method(&self) -> Option<SslMethod> {
unsafe {
let method = ffi::SSL_get_ssl_method(self.ssl);
SslMethod::from_raw(method)
}
}
} }
macro_rules! make_LibSslError { macro_rules! make_LibSslError {
@ -871,8 +935,16 @@ impl<S: Read+Write> IndirectStream<S> {
LibSslError::ErrorWantRead => { LibSslError::ErrorWantRead => {
try_ssl_stream!(self.flush()); try_ssl_stream!(self.flush());
let len = try_ssl_stream!(self.stream.read(&mut self.buf[..])); let len = try_ssl_stream!(self.stream.read(&mut self.buf[..]));
if len == 0 { if len == 0 {
let method = self.ssl.get_ssl_method();
if method.map(|m| m.is_dtls()).unwrap_or(false) {
return Ok(0);
} else {
self.ssl.get_rbio().set_eof(true); self.ssl.get_rbio().set_eof(true);
}
} else { } else {
try_ssl_stream!(self.ssl.get_rbio().write_all(&self.buf[..len])); try_ssl_stream!(self.ssl.get_rbio().write_all(&self.buf[..len]));
} }
@ -993,6 +1065,9 @@ impl<S> DirectStream<S> {
err err
} }
} }
LibSslError::ErrorWantWrite | LibSslError::ErrorWantRead => {
SslError::StreamError(io::Error::last_os_error())
}
err => panic!("unexpected error {:?} with ret {}", err, ret), err => panic!("unexpected error {:?} with ret {}", err, ret),
} }
} }
@ -1260,6 +1335,14 @@ impl<S: Read+Write> SslStream<S> {
pub fn pending(&self) -> usize { pub fn pending(&self) -> usize {
self.kind.ssl().pending() self.kind.ssl().pending()
} }
pub fn get_state_string(&self) -> &'static str {
self.kind.ssl().get_state_string()
}
pub fn get_state_string_long(&self) -> &'static str {
self.kind.ssl().get_state_string_long()
}
} }
impl<S: Read+Write> Read for SslStream<S> { impl<S: Read+Write> Read for SslStream<S> {

View File

@ -51,7 +51,7 @@ macro_rules! run_test(
use std::net::TcpStream; use std::net::TcpStream;
use ssl; use ssl;
use ssl::SslMethod; use ssl::SslMethod;
use ssl::{SslContext, SslStream, VerifyCallback}; use ssl::{SslContext, Ssl, SslStream, VerifyCallback};
use ssl::SSL_VERIFY_PEER; use ssl::SSL_VERIFY_PEER;
use crypto::hash::Type::SHA256; use crypto::hash::Type::SHA256;
use x509::X509StoreContext; use x509::X509StoreContext;
@ -86,6 +86,11 @@ run_test!(new_sslstream, |method, stream| {
SslStream::connect_generic(&SslContext::new(method).unwrap(), stream).unwrap(); SslStream::connect_generic(&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));
});
run_test!(verify_untrusted, |method, stream| { run_test!(verify_untrusted, |method, stream| {
let mut ctx = SslContext::new(method).unwrap(); let mut ctx = SslContext::new(method).unwrap();
ctx.set_verify(SSL_VERIFY_PEER, None); ctx.set_verify(SSL_VERIFY_PEER, None);
@ -390,6 +395,14 @@ fn test_pending() {
assert_eq!(pending, len); assert_eq!(pending, len);
} }
#[test]
fn test_state() {
let tcp = TcpStream::connect("127.0.0.1:15418").unwrap();
let stream = SslStream::connect_generic(&SslContext::new(Sslv23).unwrap(), tcp).unwrap();
assert_eq!(stream.get_state_string(), "SSLOK ");
assert_eq!(stream.get_state_string_long(), "SSL negotiation finished successfully");
}
/// Tests that connecting with the client using NPN, but the server not does not /// Tests that connecting with the client using NPN, but the server not does not
/// break the existing connection behavior. /// break the existing connection behavior.
#[test] #[test]

View File

@ -0,0 +1,212 @@
use std::fmt;
use nid::Nid;
/// Type-only version of the `Extension` enum.
///
/// See the `Extension` documentation for more information on the different
/// variants.
#[derive(Clone,Hash,PartialEq,Eq)]
pub enum ExtensionType {
KeyUsage,
ExtKeyUsage,
SubjectAltName,
IssuerAltName,
OtherNid(Nid),
OtherStr(String),
}
/// A X.509 v3 certificate extension.
///
/// Only one extension of each type is allow in a certificate.
/// See RFC 3280 for more information about extensions.
#[derive(Clone)]
pub enum Extension {
/// The purposes of the key contained in the certificate
KeyUsage(Vec<KeyUsageOption>),
/// The extended purposes of the key contained in the certificate
ExtKeyUsage(Vec<ExtKeyUsageOption>),
/// Subject Alternative Names
SubjectAltName(Vec<(AltNameOption,String)>),
/// Issuer Alternative Names
IssuerAltName(Vec<(AltNameOption,String)>),
/// Arbitrary extensions by NID. See `man x509v3_config` for value syntax.
///
/// You must not use this to add extensions which this enum can express directly.
///
/// ```
/// use openssl::x509::extension::Extension::*;
/// use openssl::nid::Nid;
///
/// # let generator = openssl::x509::X509Generator::new();
/// generator.add_extension(OtherNid(Nid::BasicConstraints,"critical,CA:TRUE".to_owned()));
/// ```
OtherNid(Nid,String),
/// Arbitrary extensions by OID string. See `man ASN1_generate_nconf` for value syntax.
///
/// You must not use this to add extensions which this enum can express directly.
///
/// ```
/// use openssl::x509::extension::Extension::*;
///
/// # let generator = openssl::x509::X509Generator::new();
/// generator.add_extension(OtherStr("2.999.2".to_owned(),"ASN1:UTF8:example value".to_owned()));
/// ```
OtherStr(String,String),
}
impl Extension {
pub fn get_type(&self) -> ExtensionType {
match self {
&Extension::KeyUsage(_) => ExtensionType::KeyUsage,
&Extension::ExtKeyUsage(_) => ExtensionType::ExtKeyUsage,
&Extension::SubjectAltName(_) => ExtensionType::SubjectAltName,
&Extension::IssuerAltName(_) => ExtensionType::IssuerAltName,
&Extension::OtherNid(nid,_) => ExtensionType::OtherNid(nid),
&Extension::OtherStr(ref s,_) => ExtensionType::OtherStr(s.clone()),
}
}
}
impl ExtensionType {
pub fn get_nid(&self) -> Option<Nid> {
match self {
&ExtensionType::KeyUsage => Some(Nid::KeyUsage),
&ExtensionType::ExtKeyUsage => Some(Nid::ExtendedKeyUsage),
&ExtensionType::SubjectAltName => Some(Nid::SubjectAltName),
&ExtensionType::IssuerAltName => Some(Nid::IssuerAltName),
&ExtensionType::OtherNid(nid) => Some(nid),
&ExtensionType::OtherStr(_) => None,
}
}
pub fn get_name<'a>(&'a self) -> Option<&'a str> {
match self {
&ExtensionType::OtherStr(ref s) => Some(s),
_ => None,
}
}
}
// FIXME: This would be nicer as a method on Iterator<Item=ToString>. This can
// eventually be replaced by the successor to std::slice::SliceConcatExt.connect
fn join<I: Iterator<Item=T>,T: ToString>(iter: I, sep: &str) -> String {
iter.enumerate().fold(String::new(), |mut acc, (idx, v)| {
if idx > 0 { acc.push_str(sep) };
acc.push_str(&v.to_string());
acc
})
}
impl ToString for Extension {
fn to_string(&self) -> String {
match self {
&Extension::KeyUsage(ref purposes) => join(purposes.iter(),","),
&Extension::ExtKeyUsage(ref purposes) => join(purposes.iter(),","),
&Extension::SubjectAltName(ref names) => join(names.iter().map(|&(ref opt,ref val)|opt.to_string()+":"+&val),","),
&Extension::IssuerAltName(ref names) => join(names.iter().map(|&(ref opt,ref val)|opt.to_string()+":"+&val),","),
&Extension::OtherNid(_,ref value) => value.clone(),
&Extension::OtherStr(_,ref value) => value.clone(),
}
}
}
#[derive(Clone,Copy)]
pub enum KeyUsageOption {
DigitalSignature,
NonRepudiation,
KeyEncipherment,
DataEncipherment,
KeyAgreement,
KeyCertSign,
CRLSign,
EncipherOnly,
DecipherOnly,
}
impl fmt::Display for KeyUsageOption {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.pad(match self {
&KeyUsageOption::DigitalSignature => "digitalSignature",
&KeyUsageOption::NonRepudiation => "nonRepudiation",
&KeyUsageOption::KeyEncipherment => "keyEncipherment",
&KeyUsageOption::DataEncipherment => "dataEncipherment",
&KeyUsageOption::KeyAgreement => "keyAgreement",
&KeyUsageOption::KeyCertSign => "keyCertSign",
&KeyUsageOption::CRLSign => "cRLSign",
&KeyUsageOption::EncipherOnly => "encipherOnly",
&KeyUsageOption::DecipherOnly => "decipherOnly",
})
}
}
#[derive(Clone)]
pub enum ExtKeyUsageOption {
ServerAuth,
ClientAuth,
CodeSigning,
EmailProtection,
TimeStamping,
MsCodeInd,
MsCodeCom,
MsCtlSign,
MsSgc,
MsEfs,
NsSgc,
/// An arbitrary key usage by OID.
Other(String),
}
impl fmt::Display for ExtKeyUsageOption {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.pad(match self {
&ExtKeyUsageOption::ServerAuth => "serverAuth",
&ExtKeyUsageOption::ClientAuth => "clientAuth",
&ExtKeyUsageOption::CodeSigning => "codeSigning",
&ExtKeyUsageOption::EmailProtection => "emailProtection",
&ExtKeyUsageOption::TimeStamping => "timeStamping",
&ExtKeyUsageOption::MsCodeInd => "msCodeInd",
&ExtKeyUsageOption::MsCodeCom => "msCodeCom",
&ExtKeyUsageOption::MsCtlSign => "msCTLSign",
&ExtKeyUsageOption::MsSgc => "msSGC",
&ExtKeyUsageOption::MsEfs => "msEFS",
&ExtKeyUsageOption::NsSgc =>"nsSGC",
&ExtKeyUsageOption::Other(ref s) => &s[..],
})
}
}
#[derive(Clone, Copy)]
pub enum AltNameOption {
/// The value is specified as OID;content. See `man ASN1_generate_nconf` for more information on the content syntax.
///
/// ```
/// use openssl::x509::extension::Extension::*;
/// use openssl::x509::extension::AltNameOption::Other as OtherName;
///
/// # let generator = openssl::x509::X509Generator::new();
/// generator.add_extension(SubjectAltName(vec![(OtherName,"2.999.3;ASN1:UTF8:some other name".to_owned())]));
/// ```
Other,
Email,
DNS,
//X400, // Not supported by OpenSSL
Directory,
//EDIParty, // Not supported by OpenSSL
URI,
IPAddress,
RegisteredID,
}
impl fmt::Display for AltNameOption {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.pad(match self {
&AltNameOption::Other => "otherName",
&AltNameOption::Email => "email",
&AltNameOption::DNS => "DNS",
&AltNameOption::Directory => "dirName",
&AltNameOption::URI => "URI",
&AltNameOption::IPAddress => "IP",
&AltNameOption::RegisteredID => "RID",
})
}
}

View File

@ -9,6 +9,7 @@ use std::ptr;
use std::ops::Deref; use std::ops::Deref;
use std::fmt; use std::fmt;
use std::str; use std::str;
use std::collections::HashMap;
use asn1::{Asn1Time}; use asn1::{Asn1Time};
use bio::{MemBio}; use bio::{MemBio};
@ -20,6 +21,9 @@ use ffi;
use ssl::error::{SslError, StreamError}; use ssl::error::{SslError, StreamError};
use nid; use nid;
pub mod extension;
use self::extension::{ExtensionType,Extension};
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
@ -98,92 +102,9 @@ impl X509StoreContext {
} }
} }
#[doc(hidden)] // Backwards-compatibility
trait AsStr<'a> { pub use self::extension::KeyUsageOption as KeyUsage;
fn as_str(&self) -> &'a str; pub use self::extension::ExtKeyUsageOption as ExtKeyUsage;
}
#[derive(Clone, Copy)]
pub enum KeyUsage {
DigitalSignature,
NonRepudiation,
KeyEncipherment,
DataEncipherment,
KeyAgreement,
KeyCertSign,
CRLSign,
EncipherOnly,
DecipherOnly
}
impl AsStr<'static> for KeyUsage {
fn as_str(&self) -> &'static str {
match self {
&KeyUsage::DigitalSignature => "digitalSignature",
&KeyUsage::NonRepudiation => "nonRepudiation",
&KeyUsage::KeyEncipherment => "keyEncipherment",
&KeyUsage::DataEncipherment => "dataEncipherment",
&KeyUsage::KeyAgreement => "keyAgreement",
&KeyUsage::KeyCertSign => "keyCertSign",
&KeyUsage::CRLSign => "cRLSign",
&KeyUsage::EncipherOnly => "encipherOnly",
&KeyUsage::DecipherOnly => "decipherOnly"
}
}
}
#[derive(Clone, Copy)]
pub enum ExtKeyUsage {
ServerAuth,
ClientAuth,
CodeSigning,
EmailProtection,
TimeStamping,
MsCodeInd,
MsCodeCom,
MsCtlSign,
MsSgc,
MsEfs,
NsSgc
}
impl AsStr<'static> for ExtKeyUsage {
fn as_str(&self) -> &'static str {
match self {
&ExtKeyUsage::ServerAuth => "serverAuth",
&ExtKeyUsage::ClientAuth => "clientAuth",
&ExtKeyUsage::CodeSigning => "codeSigning",
&ExtKeyUsage::EmailProtection => "emailProtection",
&ExtKeyUsage::TimeStamping => "timeStamping",
&ExtKeyUsage::MsCodeInd => "msCodeInd",
&ExtKeyUsage::MsCodeCom => "msCodeCom",
&ExtKeyUsage::MsCtlSign => "msCTLSign",
&ExtKeyUsage::MsSgc => "msSGC",
&ExtKeyUsage::MsEfs => "msEFS",
&ExtKeyUsage::NsSgc =>"nsSGC"
}
}
}
// FIXME: a dirty hack as there is no way to
// implement ToString for Vec as both are defined
// in another crate
#[doc(hidden)]
trait ToStr {
fn to_str(&self) -> String;
}
impl<'a, T: AsStr<'a>> ToStr for Vec<T> {
fn to_str(&self) -> String {
self.iter().enumerate().fold(String::new(), |mut acc, (idx, v)| {
if idx > 0 { acc.push(',') };
acc.push_str(v.as_str());
acc
})
}
}
#[allow(non_snake_case)] #[allow(non_snake_case)]
/// Generator of private key/certificate pairs /// Generator of private key/certificate pairs
@ -224,9 +145,9 @@ impl<'a, T: AsStr<'a>> ToStr for Vec<T> {
pub struct X509Generator { pub struct X509Generator {
bits: u32, bits: u32,
days: u32, days: u32,
CN: String, names: Vec<(String,String)>,
key_usage: Vec<KeyUsage>, // RFC 3280 §4.2: A certificate MUST NOT include more than one instance of a particular extension.
ext_key_usage: Vec<ExtKeyUsage>, extensions: HashMap<ExtensionType,Extension>,
hash_type: HashType, hash_type: HashType,
} }
@ -244,9 +165,8 @@ impl X509Generator {
X509Generator { X509Generator {
bits: 1024, bits: 1024,
days: 365, days: 365,
CN: "rust-openssl".to_string(), names: vec![],
key_usage: Vec::new(), extensions: HashMap::new(),
ext_key_usage: Vec::new(),
hash_type: HashType::SHA1 hash_type: HashType::SHA1
} }
} }
@ -264,21 +184,88 @@ impl X509Generator {
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
/// Sets Common Name of certificate /// (deprecated) Sets Common Name of certificate
///
/// This function is deprecated, use `X509Generator.add_name` instead.
/// Don't use this function AND the `add_name` method
pub fn set_CN(mut self, CN: &str) -> X509Generator { pub fn set_CN(mut self, CN: &str) -> X509Generator {
self.CN = CN.to_string(); match self.names.get_mut(0) {
Some(&mut(_,ref mut val)) => *val=CN.to_string(),
_ => {} /* would move push here, but borrow checker won't let me */
}
if self.names.len()==0 {
self.names.push(("CN".to_string(),CN.to_string()));
}
self self
} }
/// Sets what for certificate could be used /// Add attribute to the name of the certificate
pub fn set_usage(mut self, purposes: &[KeyUsage]) -> X509Generator { ///
self.key_usage = purposes.to_vec(); /// ```
/// # let generator = openssl::x509::X509Generator::new();
/// generator.add_name("CN".to_string(),"example.com".to_string());
/// ```
pub fn add_name(mut self, attr_type: String, attr_value: String) -> X509Generator {
self.names.push((attr_type,attr_value));
self self
} }
/// Sets allowed extended usage of certificate /// Add multiple attributes to the name of the certificate
pub fn set_ext_usage(mut self, purposes: &[ExtKeyUsage]) -> X509Generator { ///
self.ext_key_usage = purposes.to_vec(); /// ```
/// # let generator = openssl::x509::X509Generator::new();
/// generator.add_names(vec![("CN".to_string(),"example.com".to_string())]);
/// ```
pub fn add_names<I>(mut self, attrs: I) -> X509Generator
where I: IntoIterator<Item=(String,String)> {
self.names.extend(attrs);
self
}
/// (deprecated) Sets what for certificate could be used
///
/// This function is deprecated, use `X509Generator.add_extension` instead.
pub fn set_usage(self, purposes: &[KeyUsage]) -> X509Generator {
self.add_extension(Extension::KeyUsage(purposes.to_owned()))
}
/// (deprecated) Sets allowed extended usage of certificate
///
/// This function is deprecated, use `X509Generator.add_extension` instead.
pub fn set_ext_usage(self, purposes: &[ExtKeyUsage]) -> X509Generator {
self.add_extension(Extension::ExtKeyUsage(purposes.to_owned()))
}
/// Add an extension to a certificate
///
/// If the extension already exists, it will be replaced.
///
/// ```
/// use openssl::x509::extension::Extension::*;
/// use openssl::x509::extension::KeyUsageOption::*;
///
/// # let generator = openssl::x509::X509Generator::new();
/// generator.add_extension(KeyUsage(vec![DigitalSignature, KeyEncipherment]));
/// ```
pub fn add_extension(mut self, ext: extension::Extension) -> X509Generator {
self.extensions.insert(ext.get_type(),ext);
self
}
/// Add multiple extensions to a certificate
///
/// If any of the extensions already exist, they will be replaced.
///
/// ```
/// use openssl::x509::extension::Extension::*;
/// use openssl::x509::extension::KeyUsageOption::*;
///
/// # let generator = openssl::x509::X509Generator::new();
/// generator.add_extensions(vec![KeyUsage(vec![DigitalSignature, KeyEncipherment])]);
/// ```
pub fn add_extensions<I>(mut self, exts: I) -> X509Generator
where I: IntoIterator<Item=extension::Extension> {
self.extensions.extend(exts.into_iter().map(|ext|(ext.get_type(),ext)));
self self
} }
@ -287,17 +274,25 @@ impl X509Generator {
self self
} }
fn add_extension(x509: *mut ffi::X509, extension: c_int, value: &str) -> Result<(), SslError> { fn add_extension_internal(x509: *mut ffi::X509, exttype: &extension::ExtensionType, value: &str) -> Result<(), SslError> {
unsafe { unsafe {
let mut ctx: ffi::X509V3_CTX = mem::zeroed(); let mut ctx: ffi::X509V3_CTX = mem::zeroed();
ffi::X509V3_set_ctx(&mut ctx, x509, x509, ffi::X509V3_set_ctx(&mut ctx, x509, x509,
ptr::null_mut(), ptr::null_mut(), 0); ptr::null_mut(), ptr::null_mut(), 0);
let value = CString::new(value.as_bytes()).unwrap(); let value = CString::new(value.as_bytes()).unwrap();
let ext = ffi::X509V3_EXT_conf_nid(ptr::null_mut(), let ext=match exttype.get_nid() {
Some(nid) => ffi::X509V3_EXT_conf_nid(ptr::null_mut(),
mem::transmute(&ctx), mem::transmute(&ctx),
extension, nid as c_int,
value.as_ptr() as *mut c_char); value.as_ptr() as *mut c_char),
None => {
let name=CString::new(exttype.get_name().unwrap().as_bytes()).unwrap();
ffi::X509V3_EXT_conf(ptr::null_mut(),
mem::transmute(&ctx),
name.as_ptr() as *mut c_char,
value.as_ptr() as *mut c_char)
}
};
let mut success = false; let mut success = false;
if ext != ptr::null_mut() { if ext != ptr::null_mut() {
success = ffi::X509_add_ext(x509, ext, -1) != 0; success = ffi::X509_add_ext(x509, ext, -1) != 0;
@ -307,7 +302,7 @@ impl X509Generator {
} }
} }
fn add_name(name: *mut ffi::X509_NAME, key: &str, value: &str) -> Result<(), SslError> { fn add_name_internal(name: *mut ffi::X509_NAME, key: &str, value: &str) -> Result<(), SslError> {
let value_len = value.len() as c_int; let value_len = value.len() as c_int;
lift_ssl!(unsafe { lift_ssl!(unsafe {
let key = CString::new(key.as_bytes()).unwrap(); let key = CString::new(key.as_bytes()).unwrap();
@ -373,17 +368,19 @@ impl X509Generator {
let name = ffi::X509_get_subject_name(x509.handle); let name = ffi::X509_get_subject_name(x509.handle);
try_ssl_null!(name); try_ssl_null!(name);
try!(X509Generator::add_name(name, "CN", &self.CN)); let default=[("CN","rust-openssl")];
let default_iter=&mut default.iter().map(|&(k,v)|(k,v));
let arg_iter=&mut self.names.iter().map(|&(ref k,ref v)|(&k[..],&v[..]));
let iter: &mut Iterator<Item=(&str,&str)> =
if self.names.len()==0 { default_iter } else { arg_iter };
for (key,val) in iter {
try!(X509Generator::add_name_internal(name, &key, &val));
}
ffi::X509_set_issuer_name(x509.handle, name); ffi::X509_set_issuer_name(x509.handle, name);
if self.key_usage.len() > 0 { for (exttype,ext) in self.extensions.iter() {
try!(X509Generator::add_extension(x509.handle, ffi::NID_key_usage, try!(X509Generator::add_extension_internal(x509.handle, exttype, &ext.to_string()));
&self.key_usage.to_str()));
}
if self.ext_key_usage.len() > 0 {
try!(X509Generator::add_extension(x509.handle, ffi::NID_ext_key_usage,
&self.ext_key_usage.to_str()));
} }
let hash_fn = self.hash_type.evp_md(); let hash_fn = self.hash_type.evp_md();
@ -399,13 +396,22 @@ impl X509Generator {
Err(x) => return Err(x) Err(x) => return Err(x)
}; };
let hash_fn = self.hash_type.evp_md(); unsafe {
let req = unsafe { ffi::X509_to_X509_REQ(cert.handle, p_key.get_handle(), hash_fn) }; let req = ffi::X509_to_X509_REQ(cert.handle, ptr::null_mut(), ptr::null());
try_ssl_null!(req); try_ssl_null!(req);
let exts = ffi::X509_get_extensions(cert.handle);
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));
Ok(X509Req::new(req)) Ok(X509Req::new(req))
} }
} }
}
#[allow(dead_code)] #[allow(dead_code)]

View File

@ -4,28 +4,32 @@ use std::path::Path;
use std::fs::File; use std::fs::File;
use crypto::hash::Type::{SHA256}; use crypto::hash::Type::{SHA256};
use crypto::pkey::PKey;
use x509::{X509, X509Generator}; use x509::{X509, X509Generator};
use x509::KeyUsage::{DigitalSignature, KeyEncipherment}; use x509::extension::Extension::{KeyUsage,ExtKeyUsage,SubjectAltName,OtherNid,OtherStr};
use x509::ExtKeyUsage::{ClientAuth, ServerAuth}; use x509::extension::AltNameOption as SAN;
use x509::extension::KeyUsageOption::{DigitalSignature, KeyEncipherment};
use x509::extension::ExtKeyUsageOption::{self, ClientAuth, ServerAuth};
use nid::Nid; 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(SHA256)
.add_extension(KeyUsage(vec![DigitalSignature, KeyEncipherment]))
.add_extension(ExtKeyUsage(vec![ClientAuth, ServerAuth, ExtKeyUsageOption::Other("2.999.1".to_owned())]))
.add_extension(SubjectAltName(vec![(SAN::DNS,"example.com".to_owned())]))
.add_extension(OtherNid(Nid::BasicConstraints,"critical,CA:TRUE".to_owned()))
.add_extension(OtherStr("2.999.2".to_owned(),"ASN1:UTF8:example value".to_owned()))
}
#[test] #[test]
fn test_cert_gen() { fn test_cert_gen() {
let gen = X509Generator::new() let (cert, pkey) = get_generator().generate().unwrap();
.set_bitlength(2048) cert.write_pem(&mut io::sink()).unwrap();
.set_valid_period(365*2) pkey.write_pem(&mut io::sink()).unwrap();
.set_CN("test_me")
.set_sign_hash(SHA256)
.set_usage(&[DigitalSignature, KeyEncipherment])
.set_ext_usage(&[ClientAuth, ServerAuth]);
let res = gen.generate();
assert!(res.is_ok());
let (cert, pkey) = res.unwrap();
assert!(cert.write_pem(&mut io::sink()).is_ok());
assert!(pkey.write_pem(&mut io::sink()).is_ok());
// FIXME: check data in result to be correct, needs implementation // FIXME: check data in result to be correct, needs implementation
// of X509 getters // of X509 getters
@ -33,6 +37,18 @@ fn test_cert_gen() {
assert_eq!(pkey.save_pub(), cert.public_key().save_pub()); assert_eq!(pkey.save_pub(), cert.public_key().save_pub());
} }
#[test]
fn test_req_gen() {
let mut pkey = PKey::new();
pkey.gen(512);
let req = get_generator().request(&pkey).unwrap();
req.write_pem(&mut io::sink()).unwrap();
// FIXME: check data in result to be correct, needs implementation
// of X509_REQ getters
}
#[test] #[test]
fn test_cert_loading() { fn test_cert_loading() {
let cert_path = Path::new("test/cert.pem"); let cert_path = Path::new("test/cert.pem");

View File

@ -4,7 +4,7 @@ set -e
mkdir /tmp/openssl mkdir /tmp/openssl
cd /tmp/openssl cd /tmp/openssl
sudo apt-get install gcc make sudo apt-get install gcc make
curl https://openssl.org/source/openssl-1.0.2-latest.tar.gz | tar --strip-components=1 -xzf - curl https://openssl.org/source/openssl-1.0.2d.tar.gz | tar --strip-components=1 -xzf -
./config --prefix=/usr/ shared ./config --prefix=/usr/ shared
make make
sudo make install sudo make install