Merge branch 'release-v0.7.6' into release

This commit is contained in:
Steven Fackler 2016-02-10 09:36:44 -08:00
commit 7540471ce0
19 changed files with 325 additions and 52 deletions

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)
[Documentation](https://sfackler.github.io/rust-openssl/doc/v0.7.5/openssl).
[Documentation](https://sfackler.github.io/rust-openssl/doc/v0.7.6/openssl).
## Building
@ -19,6 +19,8 @@ something like `openssl-devel` or `libssl-dev`.
sudo apt-get install libssl-dev
# On Arch Linux
sudo pacman -S openssl
# On Fedora
sudo dnf install openssl-devel
```
### OSX

View File

@ -8,8 +8,8 @@ environment:
- TARGET: x86_64-pc-windows-msvc
BITS: 64
install:
- ps: Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-1_0_2e.exe"
- Win%BITS%OpenSSL-1_0_2e.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL"
- ps: Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-1_0_2f.exe"
- Win%BITS%OpenSSL-1_0_2f.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL"
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.5.0-${env:TARGET}.exe"
- rust-1.5.0-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin

View File

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

View File

@ -1,5 +1,5 @@
#![allow(non_upper_case_globals, non_snake_case)]
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.5")]
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.6")]
extern crate openssl_sys;
extern crate libc;

View File

@ -1,12 +1,12 @@
[package]
name = "openssl-sys"
version = "0.7.5"
version = "0.7.6"
authors = ["Alex Crichton <alex@alexcrichton.com>",
"Steven Fackler <sfackler@gmail.com>"]
license = "MIT"
description = "FFI bindings to OpenSSL"
repository = "https://github.com/sfackler/rust-openssl"
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.5/openssl_sys"
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.6/openssl_sys"
links = "openssl"
build = "build.rs"

View File

@ -1,6 +1,6 @@
#![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)]
#![allow(dead_code)]
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.5")]
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.6")]
extern crate libc;
@ -22,9 +22,7 @@ pub type ENGINE = c_void;
pub type EVP_CIPHER = c_void;
pub type EVP_CIPHER_CTX = c_void;
pub type EVP_MD = c_void;
pub type EVP_PKEY = c_void;
pub type EVP_PKEY_CTX = c_void;
pub type RSA = c_void;
pub type SSL = c_void;
pub type SSL_CTX = c_void;
pub type SSL_METHOD = c_void;
@ -64,6 +62,47 @@ pub struct BIO_METHOD {
// so we can create static BIO_METHODs
unsafe impl Sync for BIO_METHOD {}
#[repr(C)]
pub struct RSA {
pub pad: c_int,
pub version: c_long,
pub meth: *const c_void,
pub engine: *mut c_void,
pub n: *mut BIGNUM,
pub e: *mut BIGNUM,
pub d: *mut BIGNUM,
pub p: *mut BIGNUM,
pub q: *mut BIGNUM,
pub dmp1: *mut BIGNUM,
pub dmq1: *mut BIGNUM,
pub iqmp: *mut BIGNUM,
pub ex_data: *mut c_void,
pub references: c_int,
pub flags: c_int,
pub _method_mod_n: *mut c_void,
pub _method_mod_p: *mut c_void,
pub _method_mod_q: *mut c_void,
pub bignum_data: *mut c_char,
pub blinding: *mut c_void,
pub mt_blinding: *mut c_void,
}
#[repr(C)]
pub struct EVP_PKEY {
pub type_: c_int,
pub save_type: c_int,
pub references: c_int,
pub ameth: *const c_void,
pub engine: *mut ENGINE,
pub pkey: *mut c_void,
pub save_parameters: c_int,
pub attributes: *mut c_void,
}
#[repr(C)]
pub struct BIO {
pub method: *mut BIO_METHOD,

View File

@ -1,14 +1,15 @@
[package]
name = "openssl"
version = "0.7.5"
version = "0.7.6"
authors = ["Steven Fackler <sfackler@gmail.com>"]
license = "Apache-2.0"
description = "OpenSSL bindings"
repository = "https://github.com/sfackler/rust-openssl"
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.5/openssl"
documentation = "https://sfackler.github.io/rust-openssl/doc/v0.7.6/openssl"
readme = "../README.md"
keywords = ["crypto", "tls", "ssl", "dtls"]
build = "build.rs"
exclude = ["test/*"]
[features]
tlsv1_2 = ["openssl-sys/tlsv1_2"]
@ -31,8 +32,8 @@ nightly = []
bitflags = ">= 0.2, < 0.4"
lazy_static = "0.1"
libc = "0.2"
openssl-sys = { version = "0.7.5", path = "../openssl-sys" }
openssl-sys-extras = { version = "0.7.5", path = "../openssl-sys-extras" }
openssl-sys = { version = "0.7.6", path = "../openssl-sys" }
openssl-sys-extras = { version = "0.7.6", path = "../openssl-sys-extras" }
[build-dependencies]
gcc = "0.3"

View File

@ -102,6 +102,18 @@ impl BigNum {
})
}
pub unsafe fn new_from_ffi(orig: *mut ffi::BIGNUM) -> Result<BigNum, SslError> {
if orig.is_null() {
panic!("Null Pointer was supplied to BigNum::new_from_ffi");
}
let r = ffi::BN_dup(orig);
if r.is_null() {
Err(SslError::get())
} else {
Ok(BigNum(r))
}
}
pub fn new_from_slice(n: &[u8]) -> Result<BigNum, SslError> {
BigNum::new().and_then(|v| unsafe {
try_ssl_null!(ffi::BN_bin2bn(n.as_ptr(), n.len() as c_int, v.raw()));

View File

@ -21,5 +21,6 @@ pub mod pkey;
pub mod rand;
pub mod symm;
pub mod memcmp;
pub mod rsa;
mod symm_internal;

View File

@ -9,6 +9,7 @@ use crypto::hash;
use crypto::hash::Type as HashType;
use ffi;
use ssl::error::{SslError, StreamError};
use crypto::rsa::RSA;
#[derive(Copy, Clone)]
pub enum Parts {
@ -100,7 +101,7 @@ impl PKey {
None,
ptr::null_mut()));
Ok(PKey {
evp: evp,
evp: evp as *mut ffi::EVP_PKEY,
parts: Parts::Both,
})
}
@ -119,7 +120,7 @@ impl PKey {
None,
ptr::null_mut()));
Ok(PKey {
evp: evp,
evp: evp as *mut ffi::EVP_PKEY,
parts: Parts::Public,
})
}
@ -129,18 +130,10 @@ impl PKey {
pub fn private_rsa_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError>
where R: Read
{
let mut mem_bio = try!(MemBio::new());
try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
let rsa = try!(RSA::private_key_from_pem(reader));
unsafe {
let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.get_handle(),
ptr::null_mut(),
None,
ptr::null_mut()));
let evp = ffi::EVP_PKEY_new();
if ffi::EVP_PKEY_set1_RSA(evp, rsa) == 0 {
return Err(SslError::get());
}
let evp = try_ssl_null!(ffi::EVP_PKEY_new());
try_ssl!(ffi::EVP_PKEY_set1_RSA(evp, rsa.as_ptr()));
Ok(PKey {
evp: evp,
@ -153,18 +146,10 @@ impl PKey {
pub fn public_rsa_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError>
where R: Read
{
let mut mem_bio = try!(MemBio::new());
try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
let rsa = try!(RSA::public_key_from_pem(reader));
unsafe {
let rsa = try_ssl_null!(ffi::PEM_read_bio_RSA_PUBKEY(mem_bio.get_handle(),
ptr::null_mut(),
None,
ptr::null_mut()));
let evp = ffi::EVP_PKEY_new();
if ffi::EVP_PKEY_set1_RSA(evp, rsa) == 0 {
return Err(SslError::get());
}
let evp = try_ssl_null!(ffi::EVP_PKEY_new());
try_ssl!(ffi::EVP_PKEY_set1_RSA(evp, rsa.as_ptr()));
Ok(PKey {
evp: evp,

93
openssl/src/crypto/rsa.rs Normal file
View File

@ -0,0 +1,93 @@
use ffi;
use std::fmt;
use ssl::error::{SslError, StreamError};
use std::ptr;
use std::io::{self, Read};
use bn::BigNum;
use bio::MemBio;
pub struct RSA(*mut ffi::RSA);
impl Drop for RSA {
fn drop(&mut self) {
unsafe {
ffi::RSA_free(self.0);
}
}
}
impl RSA {
/// Reads an RSA private key from PEM formatted data.
pub fn private_key_from_pem<R>(reader: &mut R) -> Result<RSA, SslError>
where R: Read
{
let mut mem_bio = try!(MemBio::new());
try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
unsafe {
let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.get_handle(),
ptr::null_mut(),
None,
ptr::null_mut()));
Ok(RSA(rsa))
}
}
/// Reads an RSA public key from PEM formatted data.
pub fn public_key_from_pem<R>(reader: &mut R) -> Result<RSA, SslError>
where R: Read
{
let mut mem_bio = try!(MemBio::new());
try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
unsafe {
let rsa = try_ssl_null!(ffi::PEM_read_bio_RSA_PUBKEY(mem_bio.get_handle(),
ptr::null_mut(),
None,
ptr::null_mut()));
Ok(RSA(rsa))
}
}
pub fn as_ptr(&self) -> *mut ffi::RSA {
self.0
}
// The following getters are unsafe, since BigNum::new_from_ffi fails upon null pointers
pub fn n(&self) -> Result<BigNum, SslError> {
unsafe {
BigNum::new_from_ffi((*self.0).n)
}
}
pub fn d(&self) -> Result<BigNum, SslError> {
unsafe {
BigNum::new_from_ffi((*self.0).d)
}
}
pub fn e(&self) -> Result<BigNum, SslError> {
unsafe {
BigNum::new_from_ffi((*self.0).e)
}
}
pub fn p(&self) -> Result<BigNum, SslError> {
unsafe {
BigNum::new_from_ffi((*self.0).p)
}
}
pub fn q(&self) -> Result<BigNum, SslError> {
unsafe {
BigNum::new_from_ffi((*self.0).q)
}
}
}
impl fmt::Debug for RSA {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "RSA")
}
}

View File

@ -1,4 +1,4 @@
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.5")]
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.6")]
#![cfg_attr(feature = "nightly", feature(const_fn, recover, panic_propagate))]
#[macro_use]

View File

@ -104,6 +104,7 @@ pub enum Nid {
G,
S,
I,
/// uniqueIdentifier
UID,
CrlDistributionPoints,
RSA_NP_MD5,
@ -170,4 +171,6 @@ pub enum Nid {
ID_QT_UNOTICE,
RC2_64_CBC,
SMIMECaps,
/// Shown as UID in cert subject
UserId = 458
}

View File

@ -9,6 +9,7 @@ use std::net::{TcpStream, TcpListener, SocketAddr};
use std::path::Path;
use std::process::{Command, Child, Stdio, ChildStdin};
use std::thread;
use std::time::Duration;
use net2::TcpStreamExt;
@ -79,7 +80,7 @@ impl Server {
match TcpStream::connect(&addr) {
Ok(s) => return (server, s),
Err(ref e) if e.kind() == io::ErrorKind::ConnectionRefused => {
thread::sleep_ms(100);
thread::sleep(Duration::from_millis(100));
}
Err(e) => panic!("wut: {}", e),
}
@ -117,7 +118,7 @@ impl Server {
// Need to wait for the UDP socket to get bound in our child process,
// but don't currently have a great way to do that so just wait for a
// bit.
thread::sleep_ms(100);
thread::sleep(Duration::from_millis(100));
let socket = UdpSocket::bind(next_addr()).unwrap();
socket.connect(&addr).unwrap();
(s, UdpConnected(socket))

View File

@ -146,8 +146,7 @@ pub struct X509Generator {
bits: u32,
days: u32,
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>,
extensions: Extensions,
hash_type: HashType,
}
@ -166,7 +165,7 @@ impl X509Generator {
bits: 1024,
days: 365,
names: vec![],
extensions: HashMap::new(),
extensions: Extensions::new(),
hash_type: HashType::SHA1,
}
}
@ -219,7 +218,7 @@ impl X509Generator {
/// 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.extensions.add(ext);
self
}
@ -237,7 +236,10 @@ impl X509Generator {
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)));
for ext in exts {
self.extensions.add(ext);
}
self
}
@ -372,7 +374,7 @@ impl X509Generator {
ffi::X509_set_issuer_name(x509.handle, name);
for (exttype, ext) in self.extensions.iter() {
try!(X509Generator::add_extension_internal(x509.handle, exttype, &ext.to_string()));
try!(X509Generator::add_extension_internal(x509.handle, &exttype, &ext.to_string()));
}
let hash_fn = self.hash_type.evp_md();
@ -618,6 +620,75 @@ impl Drop for X509Req {
}
}
/// A collection of X.509 extensions.
///
/// Upholds the invariant that a certificate MUST NOT include more than one
/// instance of a particular extension, according to RFC 3280 §4.2. Also
/// ensures that extensions are added to the certificate during signing
/// in the order they were inserted, which is required for certain
/// extensions like SubjectKeyIdentifier and AuthorityKeyIdentifier.
struct Extensions {
/// The extensions contained in the collection.
extensions: Vec<Extension>,
/// A map of used to keep track of added extensions and their indexes in `self.extensions`.
indexes: HashMap<ExtensionType, usize>,
}
impl Extensions {
/// Creates a new `Extensions`.
pub fn new() -> Extensions {
Extensions {
extensions: vec![],
indexes: HashMap::new(),
}
}
/// Adds a new `Extension`, replacing any existing one of the same
/// `ExtensionType`.
pub fn add(&mut self, ext: Extension) {
let ext_type = ext.get_type();
if let Some(index) = self.indexes.get(&ext_type) {
self.extensions[*index] = ext;
return;
}
self.extensions.push(ext);
self.indexes.insert(ext_type, self.extensions.len() - 1);
}
/// Returns an `ExtensionsIter` for the collection.
pub fn iter(&self) -> ExtensionsIter {
ExtensionsIter {
current: 0,
extensions: &self.extensions,
}
}
}
/// An iterator that iterates over `(ExtensionType, Extension)` for each
/// extension in the collection.
struct ExtensionsIter<'a> {
current: usize,
extensions: &'a Vec<Extension>
}
impl<'a> Iterator for ExtensionsIter<'a> {
type Item = (ExtensionType, &'a Extension);
fn next(&mut self) -> Option<Self::Item> {
if self.current < self.extensions.len() {
let ext = &self.extensions[self.current];
self.current += 1;
Some((ext.get_type(), ext))
} else {
None
}
}
}
macro_rules! make_validation_error(
($ok_val:ident, $($name:ident = $val:ident,)+) => (
#[derive(Copy, Clone)]

View File

@ -39,6 +39,30 @@ fn test_cert_gen() {
assert_eq!(pkey.save_pub(), cert.public_key().save_pub());
}
/// SubjectKeyIdentifier must be added before AuthorityKeyIdentifier or OpenSSL
/// is "unable to get issuer keyid." This test ensures the order of insertion
/// for extensions is preserved when the cert is signed.
#[test]
fn test_cert_gen_extension_ordering() {
get_generator()
.add_extension(OtherNid(Nid::SubjectKeyIdentifier, "hash".to_owned()))
.add_extension(OtherNid(Nid::AuthorityKeyIdentifier, "keyid:always".to_owned()))
.generate()
.expect("Failed to generate cert with order-dependent extensions");
}
/// Proves that a passing result from `test_cert_gen_extension_ordering` is
/// deterministic by reversing the order of extensions and asserting failure.
#[test]
fn test_cert_gen_extension_bad_ordering() {
let result = get_generator()
.add_extension(OtherNid(Nid::AuthorityKeyIdentifier, "keyid:always".to_owned()))
.add_extension(OtherNid(Nid::SubjectKeyIdentifier, "hash".to_owned()))
.generate();
assert!(result.is_err());
}
#[test]
fn test_req_gen() {
let mut pkey = PKey::new();
@ -116,3 +140,20 @@ fn test_nid_values() {
};
assert_eq!(&friendly as &str, "Example");
}
#[test]
fn test_nid_uid_value() {
let cert_path = Path::new("test/nid_uid_test_cert.pem");
let mut file = File::open(&cert_path)
.ok()
.expect("Failed to open `test/nid_uid_test_cert.pem`");
let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM");
let subject = cert.subject_name();
let cn = match subject.text_by_nid(Nid::UserId) {
Some(x) => x,
None => panic!("Failed to read UID from cert"),
};
assert_eq!(&cn as &str, "this is the userId");
}

View File

@ -15,7 +15,7 @@ fi
mkdir /tmp/openssl
cd /tmp/openssl
curl https://openssl.org/source/openssl-1.0.2e.tar.gz | tar --strip-components=1 -xzf -
curl https://openssl.org/source/openssl-1.0.2f.tar.gz | tar --strip-components=1 -xzf -
./Configure --prefix=$HOME/openssl shared --cross-compile-prefix=$CROSS $OS_COMPILER
make
make install

View File

@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIIEGTCCAwGgAwIBAgIJAItKTzcGfL1lMA0GCSqGSIb3DQEBCwUAMIGiMSIwIAYK
CZImiZPyLGQBAQwSdGhpcyBpcyB0aGUgdXNlcklkMQswCQYDVQQGEwJVUzETMBEG
A1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxlMRUwEwYDVQQKDAxS
dXN0IE9wZW5TU0wxDDAKBgNVBAsMA09TUzEhMB8GA1UEAwwYcnVzdC1vcGVuc3Ns
LmV4YW1wbGUuY29tMB4XDTE2MDIwMjE3MjIwMVoXDTE2MDMwMzE3MjIwMVowgaIx
IjAgBgoJkiaJk/IsZAEBDBJ0aGlzIGlzIHRoZSB1c2VySWQxCzAJBgNVBAYTAlVT
MRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlTdW5ueXZhbGUxFTATBgNV
BAoMDFJ1c3QgT3BlblNTTDEMMAoGA1UECwwDT1NTMSEwHwYDVQQDDBhydXN0LW9w
ZW5zc2wuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
AQDa3Gc+IE5DOhTv1m5DZW8qKiyNLd7v4DaAYLXSsDuLs+9wJ+Bs+wlBfrg+PT0t
EJlPaLL9IfD5eR3WpFu62TUexYhnJh+3vhCGsFHOXcTjtM+wy/dzZtOVh2wTzvqE
/FHBGw1eG3Ww+RkSFbwYmtm8JhIN8ffYxGn2O0yQpxypf5hNPYrC81zX+52X2w1h
jDYLpYt55w+e6q+iRRFk0tKiWHEqqh/r6UQQRpj2EeS+xTloZlO6h0nl2NPkVF3r
CXBoT8Ittxr7sqcYqf8TAA0I4qZRYXKYehFmv/VkSt85CcURJ/zXeoJ1TpxSvQie
2R9cRDkYROrIOAFbB/0mmHLBAgMBAAGjUDBOMB0GA1UdDgQWBBRKfPqtgrbdbTmH
XR6RC/p8t/65GjAfBgNVHSMEGDAWgBRKfPqtgrbdbTmHXR6RC/p8t/65GjAMBgNV
HRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCKfeGRduGsIwKNiGcDUNkNrc7Z
f8SWAmb/R6xiDfgjbhrtfBDowIZ5natEkTgf6kQPMJKyjg2NEM2uJWBc55rLOHIv
es1wQOlYjfEUmFD3lTIt2TM/IUgXn2j+zV1CRkJthQLVFChXsidd0Bqq2fBjd3ad
Yjzrxf3uOTBAs27koh2INNHfcUZCRsx8hP739zz2kw/r5NB/9iyENEyJKQvxo0jb
oN0JK2joGZrWetDukQrqf032TsdkboW5JresYybbAD3326Ljp+hlT/3WINc+3nZJ
Dn+pPMdpuZ5BUZ+u+XyNEPum3k3P3K19AF+zWYGooX0J1cmuCBrrqce20Lwy
-----END CERTIFICATE-----