Merge branch 'release-v0.6.5' into release
This commit is contained in:
commit
abde5382c9
|
|
@ -8,7 +8,7 @@ os:
|
|||
- linux
|
||||
env:
|
||||
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:
|
||||
- (test $TRAVIS_OS_NAME == "osx" || ./openssl/test/build.sh)
|
||||
before_script:
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[](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
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
[package]
|
||||
name = "openssl-sys"
|
||||
version = "0.6.4"
|
||||
version = "0.6.5"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>",
|
||||
"Steven Fackler <sfackler@gmail.com>"]
|
||||
license = "MIT"
|
||||
description = "FFI bindings to OpenSSL"
|
||||
repository = "https://github.com/sfackler/rust-openssl"
|
||||
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.6.4/openssl_sys"
|
||||
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.6.5/openssl_sys"
|
||||
|
||||
links = "openssl"
|
||||
build = "build.rs"
|
||||
|
|
@ -18,6 +18,7 @@ dtlsv1 = []
|
|||
dtlsv1_2 = []
|
||||
sslv2 = []
|
||||
aes_xts = []
|
||||
aes_ctr = []
|
||||
npn = []
|
||||
alpn = []
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@ extern crate pkg_config;
|
|||
extern crate gcc;
|
||||
|
||||
use std::env;
|
||||
use std::fmt::Write as FmtWrite;
|
||||
use std::path::PathBuf;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
|
@ -65,7 +68,63 @@ fn main() {
|
|||
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©_MASK;").unwrap();
|
||||
for &(name,_) in options {
|
||||
writeln!(shim," if (rustval&RUST_{0}) cval|={0};",name).unwrap();
|
||||
}
|
||||
writeln!(shim," return cval;").unwrap();
|
||||
writeln!(shim,"}}").unwrap();
|
||||
|
||||
writeln!(shim,"uint64_t rust_openssl_ssl_ctx_options_c_to_rust(long cval) {{").unwrap();
|
||||
writeln!(shim," uint64_t rustval=cval©_MASK;").unwrap();
|
||||
for &(name,_) in options {
|
||||
writeln!(shim," if (cval&{0}) rustval|=RUST_{0};",name).unwrap();
|
||||
}
|
||||
writeln!(shim," return rustval;").unwrap();
|
||||
writeln!(shim,"}}").unwrap();
|
||||
|
||||
let out_dir = env::var("OUT_DIR").unwrap();
|
||||
let dest_file = PathBuf::from(&out_dir).join("ssl_ctx_options_shim.c");
|
||||
let mut f = File::create(&dest_file).unwrap();
|
||||
|
||||
f.write_all(shim.as_bytes()).unwrap();
|
||||
|
||||
dest_file
|
||||
}
|
||||
|
||||
fn build_openssl_shim(include_paths: &[PathBuf]) {
|
||||
let options_shim_file = generate_options_shim();
|
||||
let mut config = gcc::Config::new();
|
||||
|
||||
for path in include_paths {
|
||||
|
|
@ -73,6 +132,7 @@ fn build_openssl_shim(include_paths: &[PathBuf]) {
|
|||
}
|
||||
|
||||
config.file("src/openssl_shim.c")
|
||||
.file(options_shim_file)
|
||||
.compile("libopenssl_shim.a");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.6.4")]
|
||||
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.6.5")]
|
||||
|
||||
extern crate libc;
|
||||
|
||||
|
|
@ -37,6 +37,7 @@ pub type X509_NAME = c_void;
|
|||
pub type X509_NAME_ENTRY = c_void;
|
||||
pub type X509_REQ = c_void;
|
||||
pub type X509_STORE_CTX = c_void;
|
||||
pub type stack_st_X509_EXTENSION = c_void;
|
||||
|
||||
#[repr(C)]
|
||||
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_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;
|
||||
|
||||
|
|
@ -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_NOACK: c_int = 3;
|
||||
|
||||
macro_rules! import_options {
|
||||
( $( $name:ident $val:expr )* ) => {
|
||||
$( pub const $name: u64 = $val; )*
|
||||
};
|
||||
}
|
||||
|
||||
include!("ssl_options.rs");
|
||||
|
||||
#[cfg(feature = "npn")]
|
||||
pub const OPENSSL_NPN_UNSUPPORTED: c_int = 0;
|
||||
#[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
|
||||
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_STRING_type_new(ty: c_int) -> *mut ASN1_STRING;
|
||||
pub fn ASN1_TIME_free(tm: *mut ASN1_TIME);
|
||||
|
|
@ -374,16 +400,22 @@ extern "C" {
|
|||
pub fn EVP_aes_128_ecb() -> *const EVP_CIPHER;
|
||||
#[cfg(feature = "aes_xts")]
|
||||
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;
|
||||
pub fn EVP_aes_256_cbc() -> *const EVP_CIPHER;
|
||||
pub fn EVP_aes_256_ecb() -> *const EVP_CIPHER;
|
||||
#[cfg(feature = "aes_xts")]
|
||||
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;
|
||||
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_set_padding(ctx: *mut EVP_CIPHER_CTX, padding: c_int) -> c_int;
|
||||
pub fn EVP_CIPHER_CTX_free(ctx: *mut EVP_CIPHER_CTX);
|
||||
|
|
@ -445,6 +477,7 @@ extern "C" {
|
|||
kstr: *mut c_char, klen: c_int,
|
||||
callback: Option<PasswordCallback>,
|
||||
user_data: *mut c_void) -> c_int;
|
||||
pub fn PEM_write_bio_PUBKEY(bp: *mut BIO, x: *mut EVP_PKEY) -> c_int;
|
||||
pub fn PEM_write_bio_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;
|
||||
|
||||
|
|
@ -502,6 +535,9 @@ extern "C" {
|
|||
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_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;
|
||||
|
||||
|
|
@ -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 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 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 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;
|
||||
|
|
@ -615,18 +655,17 @@ extern "C" {
|
|||
pub fn BIO_eof(b: *mut BIO) -> c_int;
|
||||
#[link_name = "BIO_set_mem_eof_return_shim"]
|
||||
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(ctx: *mut SSL_CTX, options: c_long) -> c_long;
|
||||
#[link_name = "SSL_CTX_get_options_shim"]
|
||||
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;
|
||||
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_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;
|
||||
#[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 = "X509_get_extensions_shim"]
|
||||
pub fn X509_get_extensions(x: *mut X509) -> *mut stack_st_X509_EXTENSION;
|
||||
}
|
||||
|
||||
pub mod probe;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
[package]
|
||||
name = "openssl"
|
||||
version = "0.6.4"
|
||||
version = "0.6.5"
|
||||
authors = ["Steven Fackler <sfackler@gmail.com>"]
|
||||
license = "Apache-2.0"
|
||||
description = "OpenSSL bindings"
|
||||
repository = "https://github.com/sfackler/rust-openssl"
|
||||
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.6.4/openssl"
|
||||
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.6.5/openssl"
|
||||
readme = "../README.md"
|
||||
keywords = ["crypto", "tls", "ssl", "dtls"]
|
||||
|
||||
|
|
@ -16,6 +16,7 @@ dtlsv1 = ["openssl-sys/dtlsv1"]
|
|||
dtlsv1_2 = ["openssl-sys/dtlsv1_2"]
|
||||
sslv2 = ["openssl-sys/sslv2"]
|
||||
aes_xts = ["openssl-sys/aes_xts"]
|
||||
aes_ctr = ["openssl-sys/aes_ctr"]
|
||||
npn = ["openssl-sys/npn"]
|
||||
alpn = ["openssl-sys/alpn"]
|
||||
|
||||
|
|
|
|||
|
|
@ -22,3 +22,5 @@ pub mod pkey;
|
|||
pub mod rand;
|
||||
pub mod symm;
|
||||
pub mod memcmp;
|
||||
|
||||
mod symm_internal;
|
||||
|
|
@ -1,6 +1,69 @@
|
|||
use libc::c_int;
|
||||
use std::ptr::null;
|
||||
|
||||
use crypto::symm_internal::evpc;
|
||||
use crypto::hash;
|
||||
use crypto::symm;
|
||||
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.
|
||||
pub fn pbkdf2_hmac_sha1(pass: &str, salt: &[u8], iter: usize, keylen: usize) -> Vec<u8> {
|
||||
unsafe {
|
||||
|
|
@ -27,6 +90,9 @@ pub fn pbkdf2_hmac_sha1(pass: &str, salt: &[u8], iter: usize, keylen: usize) ->
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crypto::hash;
|
||||
use crypto::symm;
|
||||
|
||||
// Test vectors from
|
||||
// http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06
|
||||
#[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
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,6 +182,17 @@ impl PKey {
|
|||
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.
|
||||
*/
|
||||
|
|
@ -500,4 +511,25 @@ mod tests {
|
|||
assert!(!k0.public_eq(&p1));
|
||||
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"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use std::iter::repeat;
|
|||
use std::convert::AsRef;
|
||||
use libc::{c_int};
|
||||
|
||||
use crypto::symm_internal::evpc;
|
||||
use ffi;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
|
@ -18,7 +19,8 @@ pub enum Type {
|
|||
/// Requires the `aes_xts` feature
|
||||
#[cfg(feature = "aes_xts")]
|
||||
AES_128_XTS,
|
||||
// AES_128_CTR,
|
||||
#[cfg(feature = "aes_ctr")]
|
||||
AES_128_CTR,
|
||||
//AES_128_GCM,
|
||||
|
||||
AES_256_ECB,
|
||||
|
|
@ -26,33 +28,13 @@ pub enum Type {
|
|||
/// Requires the `aes_xts` feature
|
||||
#[cfg(feature = "aes_xts")]
|
||||
AES_256_XTS,
|
||||
// AES_256_CTR,
|
||||
#[cfg(feature = "aes_ctr")]
|
||||
AES_256_CTR,
|
||||
//AES_256_GCM,
|
||||
|
||||
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.
|
||||
pub struct Crypter {
|
||||
|
|
@ -288,16 +270,17 @@ mod tests {
|
|||
cipher_test(super::Type::AES_256_XTS, pt, ct, key, iv);
|
||||
}
|
||||
|
||||
/*#[test]
|
||||
#[test]
|
||||
#[cfg(feature = "aes_ctr")]
|
||||
fn test_aes128_ctr() {
|
||||
|
||||
let pt = ~"6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710";
|
||||
let ct = ~"874D6191B620E3261BEF6864990DB6CE9806F66B7970FDFF8617187BB9FFFDFF5AE4DF3EDBD5D35E5B4F09020DB03EAB1E031DDA2FBE03D1792170A0F3009CEE";
|
||||
let key = ~"2B7E151628AED2A6ABF7158809CF4F3C";
|
||||
let iv = ~"F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF";
|
||||
let pt = "6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710";
|
||||
let ct = "874D6191B620E3261BEF6864990DB6CE9806F66B7970FDFF8617187BB9FFFDFF5AE4DF3EDBD5D35E5B4F09020DB03EAB1E031DDA2FBE03D1792170A0F3009CEE";
|
||||
let key = "2B7E151628AED2A6ABF7158809CF4F3C";
|
||||
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]
|
||||
fn test_aes128_gcm() {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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]
|
||||
extern crate bitflags;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#[allow(non_camel_case_types)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
|
||||
#[repr(usize)]
|
||||
pub enum Nid {
|
||||
Undefined,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use std::fmt;
|
|||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::mem;
|
||||
use std::str;
|
||||
use std::net;
|
||||
use std::path::Path;
|
||||
use std::ptr;
|
||||
|
|
@ -30,7 +31,9 @@ mod tests;
|
|||
|
||||
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;
|
||||
|
||||
unsafe {
|
||||
|
|
@ -46,35 +49,52 @@ fn init() {
|
|||
}
|
||||
|
||||
bitflags! {
|
||||
flags SslContextOptions: c_long {
|
||||
const SSL_OP_LEGACY_SERVER_CONNECT = 0x00000004,
|
||||
const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = 0x00000008,
|
||||
const SSL_OP_TLSEXT_PADDING = 0x00000010,
|
||||
const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = 0x00000020,
|
||||
const SSL_OP_SAFARI_ECDHE_ECDSA_BUG = 0x00000040,
|
||||
const SSL_OP_SSLEAY_080_CLIENT_DH_BUG = 0x00000080,
|
||||
const SSL_OP_TLS_D5_BUG = 0x00000100,
|
||||
const SSL_OP_TLS_BLOCK_PADDING_BUG = 0x00000200,
|
||||
const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 0x00000800,
|
||||
const SSL_OP_ALL = 0x80000BFF,
|
||||
const SSL_OP_NO_QUERY_MTU = 0x00001000,
|
||||
const SSL_OP_COOKIE_EXCHANGE = 0x00002000,
|
||||
const SSL_OP_NO_TICKET = 0x00004000,
|
||||
const SSL_OP_CISCO_ANYCONNECT = 0x00008000,
|
||||
const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 0x00010000,
|
||||
const SSL_OP_NO_COMPRESSION = 0x00020000,
|
||||
const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = 0x00040000,
|
||||
const SSL_OP_SINGLE_ECDH_USE = 0x00080000,
|
||||
const SSL_OP_SINGLE_DH_USE = 0x00100000,
|
||||
const SSL_OP_CIPHER_SERVER_PREFERENCE = 0x00400000,
|
||||
const SSL_OP_TLS_ROLLBACK_BUG = 0x00800000,
|
||||
const SSL_OP_NO_SSLV2 = 0x00000000,
|
||||
const SSL_OP_NO_SSLV3 = 0x02000000,
|
||||
const SSL_OP_NO_TLSV1 = 0x04000000,
|
||||
const SSL_OP_NO_TLSV1_2 = 0x08000000,
|
||||
const SSL_OP_NO_TLSV1_1 = 0x10000000,
|
||||
const SSL_OP_NO_DTLSV1 = 0x04000000,
|
||||
const SSL_OP_NO_DTLSV1_2 = 0x08000000
|
||||
flags SslContextOptions: u64 {
|
||||
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_LEGACY_SERVER_CONNECT = ffi::SSL_OP_LEGACY_SERVER_CONNECT,
|
||||
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_SAFARI_ECDHE_ECDSA_BUG = ffi::SSL_OP_SAFARI_ECDHE_ECDSA_BUG,
|
||||
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_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_DTLSV1 = ffi::SSL_OP_NO_DTLSv1,
|
||||
const SSL_OP_NO_TLSV1 = ffi::SSL_OP_NO_TLSv1,
|
||||
const SSL_OP_NO_DTLSV1_2 = ffi::SSL_OP_NO_DTLSv1_2,
|
||||
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")]
|
||||
pub fn is_dtlsv1(&self) -> bool {
|
||||
*self == SslMethod::Dtlsv1
|
||||
|
|
@ -652,6 +691,24 @@ impl 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> {
|
||||
unsafe { self.wrap_bio(ffi::SSL_get_rbio(self.ssl)) }
|
||||
}
|
||||
|
|
@ -770,6 +827,13 @@ impl Ssl {
|
|||
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 {
|
||||
|
|
@ -871,8 +935,16 @@ impl<S: Read+Write> IndirectStream<S> {
|
|||
LibSslError::ErrorWantRead => {
|
||||
try_ssl_stream!(self.flush());
|
||||
let len = try_ssl_stream!(self.stream.read(&mut self.buf[..]));
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
try_ssl_stream!(self.ssl.get_rbio().write_all(&self.buf[..len]));
|
||||
}
|
||||
|
|
@ -993,6 +1065,9 @@ impl<S> DirectStream<S> {
|
|||
err
|
||||
}
|
||||
}
|
||||
LibSslError::ErrorWantWrite | LibSslError::ErrorWantRead => {
|
||||
SslError::StreamError(io::Error::last_os_error())
|
||||
}
|
||||
err => panic!("unexpected error {:?} with ret {}", err, ret),
|
||||
}
|
||||
}
|
||||
|
|
@ -1260,6 +1335,14 @@ impl<S: Read+Write> SslStream<S> {
|
|||
pub fn pending(&self) -> usize {
|
||||
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> {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ macro_rules! run_test(
|
|||
use std::net::TcpStream;
|
||||
use ssl;
|
||||
use ssl::SslMethod;
|
||||
use ssl::{SslContext, SslStream, VerifyCallback};
|
||||
use ssl::{SslContext, Ssl, SslStream, VerifyCallback};
|
||||
use ssl::SSL_VERIFY_PEER;
|
||||
use crypto::hash::Type::SHA256;
|
||||
use x509::X509StoreContext;
|
||||
|
|
@ -86,6 +86,11 @@ run_test!(new_sslstream, |method, stream| {
|
|||
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| {
|
||||
let mut ctx = SslContext::new(method).unwrap();
|
||||
ctx.set_verify(SSL_VERIFY_PEER, None);
|
||||
|
|
@ -390,6 +395,14 @@ fn test_pending() {
|
|||
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
|
||||
/// break the existing connection behavior.
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ use std::ptr;
|
|||
use std::ops::Deref;
|
||||
use std::fmt;
|
||||
use std::str;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use asn1::{Asn1Time};
|
||||
use bio::{MemBio};
|
||||
|
|
@ -20,6 +21,9 @@ use ffi;
|
|||
use ssl::error::{SslError, StreamError};
|
||||
use nid;
|
||||
|
||||
pub mod extension;
|
||||
|
||||
use self::extension::{ExtensionType,Extension};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
@ -98,92 +102,9 @@ impl X509StoreContext {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
trait AsStr<'a> {
|
||||
fn as_str(&self) -> &'a str;
|
||||
}
|
||||
|
||||
#[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
|
||||
})
|
||||
}
|
||||
}
|
||||
// Backwards-compatibility
|
||||
pub use self::extension::KeyUsageOption as KeyUsage;
|
||||
pub use self::extension::ExtKeyUsageOption as ExtKeyUsage;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
/// Generator of private key/certificate pairs
|
||||
|
|
@ -224,9 +145,9 @@ impl<'a, T: AsStr<'a>> ToStr for Vec<T> {
|
|||
pub struct X509Generator {
|
||||
bits: u32,
|
||||
days: u32,
|
||||
CN: String,
|
||||
key_usage: Vec<KeyUsage>,
|
||||
ext_key_usage: Vec<ExtKeyUsage>,
|
||||
names: Vec<(String,String)>,
|
||||
// RFC 3280 §4.2: A certificate MUST NOT include more than one instance of a particular extension.
|
||||
extensions: HashMap<ExtensionType,Extension>,
|
||||
hash_type: HashType,
|
||||
}
|
||||
|
||||
|
|
@ -244,9 +165,8 @@ impl X509Generator {
|
|||
X509Generator {
|
||||
bits: 1024,
|
||||
days: 365,
|
||||
CN: "rust-openssl".to_string(),
|
||||
key_usage: Vec::new(),
|
||||
ext_key_usage: Vec::new(),
|
||||
names: vec![],
|
||||
extensions: HashMap::new(),
|
||||
hash_type: HashType::SHA1
|
||||
}
|
||||
}
|
||||
|
|
@ -264,21 +184,88 @@ impl X509Generator {
|
|||
}
|
||||
|
||||
#[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 {
|
||||
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
|
||||
}
|
||||
|
||||
/// Sets what for certificate could be used
|
||||
pub fn set_usage(mut self, purposes: &[KeyUsage]) -> X509Generator {
|
||||
self.key_usage = purposes.to_vec();
|
||||
/// Add attribute to the name of the certificate
|
||||
///
|
||||
/// ```
|
||||
/// # 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
|
||||
}
|
||||
|
||||
/// Sets allowed extended usage of certificate
|
||||
pub fn set_ext_usage(mut self, purposes: &[ExtKeyUsage]) -> X509Generator {
|
||||
self.ext_key_usage = purposes.to_vec();
|
||||
/// Add multiple attributes to the name of the certificate
|
||||
///
|
||||
/// ```
|
||||
/// # 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
|
||||
}
|
||||
|
||||
|
|
@ -287,17 +274,25 @@ impl X509Generator {
|
|||
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 {
|
||||
let mut ctx: ffi::X509V3_CTX = mem::zeroed();
|
||||
ffi::X509V3_set_ctx(&mut ctx, x509, x509,
|
||||
ptr::null_mut(), ptr::null_mut(), 0);
|
||||
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),
|
||||
extension,
|
||||
value.as_ptr() as *mut c_char);
|
||||
|
||||
nid as c_int,
|
||||
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;
|
||||
if ext != ptr::null_mut() {
|
||||
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;
|
||||
lift_ssl!(unsafe {
|
||||
let key = CString::new(key.as_bytes()).unwrap();
|
||||
|
|
@ -373,17 +368,19 @@ impl X509Generator {
|
|||
let name = ffi::X509_get_subject_name(x509.handle);
|
||||
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);
|
||||
|
||||
if self.key_usage.len() > 0 {
|
||||
try!(X509Generator::add_extension(x509.handle, ffi::NID_key_usage,
|
||||
&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()));
|
||||
for (exttype,ext) in self.extensions.iter() {
|
||||
try!(X509Generator::add_extension_internal(x509.handle, exttype, &ext.to_string()));
|
||||
}
|
||||
|
||||
let hash_fn = self.hash_type.evp_md();
|
||||
|
|
@ -399,12 +396,21 @@ impl X509Generator {
|
|||
Err(x) => return Err(x)
|
||||
};
|
||||
|
||||
let hash_fn = self.hash_type.evp_md();
|
||||
let req = unsafe { ffi::X509_to_X509_REQ(cert.handle, p_key.get_handle(), hash_fn) };
|
||||
unsafe {
|
||||
let req = ffi::X509_to_X509_REQ(cert.handle, ptr::null_mut(), ptr::null());
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,28 +4,32 @@ use std::path::Path;
|
|||
use std::fs::File;
|
||||
|
||||
use crypto::hash::Type::{SHA256};
|
||||
use crypto::pkey::PKey;
|
||||
use x509::{X509, X509Generator};
|
||||
use x509::KeyUsage::{DigitalSignature, KeyEncipherment};
|
||||
use x509::ExtKeyUsage::{ClientAuth, ServerAuth};
|
||||
use x509::extension::Extension::{KeyUsage,ExtKeyUsage,SubjectAltName,OtherNid,OtherStr};
|
||||
use x509::extension::AltNameOption as SAN;
|
||||
use x509::extension::KeyUsageOption::{DigitalSignature, KeyEncipherment};
|
||||
use x509::extension::ExtKeyUsageOption::{self, ClientAuth, ServerAuth};
|
||||
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]
|
||||
fn test_cert_gen() {
|
||||
let gen = X509Generator::new()
|
||||
.set_bitlength(2048)
|
||||
.set_valid_period(365*2)
|
||||
.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());
|
||||
let (cert, pkey) = get_generator().generate().unwrap();
|
||||
cert.write_pem(&mut io::sink()).unwrap();
|
||||
pkey.write_pem(&mut io::sink()).unwrap();
|
||||
|
||||
// FIXME: check data in result to be correct, needs implementation
|
||||
// of X509 getters
|
||||
|
|
@ -33,6 +37,18 @@ fn test_cert_gen() {
|
|||
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]
|
||||
fn test_cert_loading() {
|
||||
let cert_path = Path::new("test/cert.pem");
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ set -e
|
|||
mkdir /tmp/openssl
|
||||
cd /tmp/openssl
|
||||
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
|
||||
make
|
||||
sudo make install
|
||||
|
|
|
|||
Loading…
Reference in New Issue