aboutsummaryrefslogtreecommitdiff
path: root/openssl/src
diff options
context:
space:
mode:
authorSteven Fackler <[email protected]>2016-08-02 20:52:07 -0700
committerSteven Fackler <[email protected]>2016-08-02 20:52:07 -0700
commitc5b2ede2829869915852b30bf9600bc3cb1fbdc9 (patch)
treedb723196c8a5d63fa569721de26be59ec559f8d9 /openssl/src
parentMerge pull request #433 from tmiasko/binop-different-lifetimes (diff)
parentRestructure PEM input/output methods (diff)
downloadrust-openssl-c5b2ede2829869915852b30bf9600bc3cb1fbdc9.tar.xz
rust-openssl-c5b2ede2829869915852b30bf9600bc3cb1fbdc9.zip
Merge remote-tracking branch 'origin/breaks'
Diffstat (limited to 'openssl/src')
-rw-r--r--openssl/src/asn1/mod.rs7
-rw-r--r--openssl/src/bio.rs67
-rw-r--r--openssl/src/bio/mod.rs107
-rw-r--r--openssl/src/bn/mod.rs108
-rw-r--r--openssl/src/crypto/dsa.rs128
-rw-r--r--openssl/src/crypto/mod.rs1
-rw-r--r--openssl/src/crypto/pkey.rs132
-rw-r--r--openssl/src/crypto/rsa.rs132
-rw-r--r--openssl/src/dh/mod.rs36
-rw-r--r--openssl/src/error.rs137
-rw-r--r--openssl/src/lib.rs8
-rw-r--r--openssl/src/macros.rs4
-rw-r--r--openssl/src/ssl/bio.rs4
-rw-r--r--openssl/src/ssl/error.rs274
-rw-r--r--openssl/src/ssl/mod.rs796
-rw-r--r--openssl/src/ssl/tests/mod.rs241
-rw-r--r--openssl/src/x509/mod.rs88
-rw-r--r--openssl/src/x509/tests.rs57
18 files changed, 814 insertions, 1513 deletions
diff --git a/openssl/src/asn1/mod.rs b/openssl/src/asn1/mod.rs
index d5561b62..202909ec 100644
--- a/openssl/src/asn1/mod.rs
+++ b/openssl/src/asn1/mod.rs
@@ -2,8 +2,7 @@ use libc::c_long;
use std::ptr;
use ffi;
-use ssl::error::SslError;
-
+use error::ErrorStack;
pub struct Asn1Time {
handle: *mut ffi::ASN1_TIME,
@@ -19,7 +18,7 @@ impl Asn1Time {
}
}
- fn new_with_period(period: u64) -> Result<Asn1Time, SslError> {
+ fn new_with_period(period: u64) -> Result<Asn1Time, ErrorStack> {
ffi::init();
let handle = unsafe {
@@ -29,7 +28,7 @@ impl Asn1Time {
}
/// Creates a new time on specified interval in days from now
- pub fn days_from_now(days: u32) -> Result<Asn1Time, SslError> {
+ pub fn days_from_now(days: u32) -> Result<Asn1Time, ErrorStack> {
Asn1Time::new_with_period(days as u64 * 60 * 60 * 24)
}
diff --git a/openssl/src/bio.rs b/openssl/src/bio.rs
new file mode 100644
index 00000000..841aca0e
--- /dev/null
+++ b/openssl/src/bio.rs
@@ -0,0 +1,67 @@
+use std::marker::PhantomData;
+use std::ptr;
+use std::slice;
+use libc::c_int;
+use ffi;
+
+use error::ErrorStack;
+
+pub struct MemBioSlice<'a>(*mut ffi::BIO, PhantomData<&'a [u8]>);
+
+impl<'a> Drop for MemBioSlice<'a> {
+ fn drop(&mut self) {
+ unsafe {
+ ffi::BIO_free_all(self.0);
+ }
+ }
+}
+
+impl<'a> MemBioSlice<'a> {
+ pub fn new(buf: &'a [u8]) -> Result<MemBioSlice<'a>, ErrorStack> {
+ ffi::init();
+
+ assert!(buf.len() <= c_int::max_value() as usize);
+ let bio = unsafe {
+ try_ssl_null!(ffi::BIO_new_mem_buf(buf.as_ptr() as *const _, buf.len() as c_int))
+ };
+
+ Ok(MemBioSlice(bio, PhantomData))
+ }
+
+ pub fn get_handle(&self) -> *mut ffi::BIO {
+ self.0
+ }
+}
+
+pub struct MemBio(*mut ffi::BIO);
+
+impl Drop for MemBio {
+ fn drop(&mut self) {
+ unsafe {
+ ffi::BIO_free_all(self.0);
+ }
+ }
+}
+
+impl MemBio {
+ pub fn new() -> Result<MemBio, ErrorStack> {
+ ffi::init();
+
+ let bio = unsafe {
+ try_ssl_null!(ffi::BIO_new(ffi::BIO_s_mem()))
+ };
+ Ok(MemBio(bio))
+ }
+
+ pub fn get_handle(&self) -> *mut ffi::BIO {
+ self.0
+ }
+
+ pub fn get_buf(&self) -> &[u8] {
+ unsafe {
+ let mut ptr = ptr::null_mut();
+ let len = ffi::BIO_get_mem_data(self.0, &mut ptr);
+ slice::from_raw_parts(ptr as *const _ as *const _, len as usize)
+ }
+ }
+}
diff --git a/openssl/src/bio/mod.rs b/openssl/src/bio/mod.rs
deleted file mode 100644
index 4c9b20b0..00000000
--- a/openssl/src/bio/mod.rs
+++ /dev/null
@@ -1,107 +0,0 @@
-use libc::{c_void, c_int};
-use std::io;
-use std::io::prelude::*;
-use std::ptr;
-use std::cmp;
-
-use ffi;
-use ffi_extras;
-use ssl::error::SslError;
-
-pub struct MemBio {
- bio: *mut ffi::BIO,
- owned: bool,
-}
-
-impl Drop for MemBio {
- fn drop(&mut self) {
- if self.owned {
- unsafe {
- ffi::BIO_free_all(self.bio);
- }
- }
- }
-}
-
-impl MemBio {
- /// Creates a new owned memory based BIO
- pub fn new() -> Result<MemBio, SslError> {
- ffi::init();
-
- let bio = unsafe { ffi::BIO_new(ffi::BIO_s_mem()) };
- try_ssl_null!(bio);
-
- Ok(MemBio {
- bio: bio,
- owned: true,
- })
- }
-
- /// Returns a "borrow", i.e. it has no ownership
- pub fn borrowed(bio: *mut ffi::BIO) -> MemBio {
- MemBio {
- bio: bio,
- owned: false,
- }
- }
-
- /// Consumes current bio and returns wrapped value
- /// Note that data ownership is lost and
- /// should be managed manually
- pub unsafe fn unwrap(mut self) -> *mut ffi::BIO {
- self.owned = false;
- self.bio
- }
-
- /// Temporarily gets wrapped value
- pub unsafe fn get_handle(&self) -> *mut ffi::BIO {
- self.bio
- }
-
- /// Sets the BIO's EOF state.
- pub fn set_eof(&self, eof: bool) {
- let v = if eof {
- 0
- } else {
- -1
- };
- unsafe {
- ffi_extras::BIO_set_mem_eof_return(self.bio, v);
- }
- }
-}
-
-impl Read for MemBio {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
- let ret = unsafe { ffi::BIO_read(self.bio, buf.as_ptr() as *mut c_void, len) };
-
- if ret <= 0 {
- let is_eof = unsafe { ffi_extras::BIO_eof(self.bio) };
- if is_eof != 0 {
- Ok(0)
- } else {
- Err(io::Error::new(io::ErrorKind::Other, SslError::get()))
- }
- } else {
- Ok(ret as usize)
- }
- }
-}
-
-impl Write for MemBio {
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
- let ret = unsafe { ffi::BIO_write(self.bio, buf.as_ptr() as *const c_void, len) };
-
- if ret < 0 {
- Err(io::Error::new(io::ErrorKind::Other, SslError::get()))
- } else {
- Ok(ret as usize)
- }
- }
-
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
-}
diff --git a/openssl/src/bn/mod.rs b/openssl/src/bn/mod.rs
index ab0e0f2e..d6febe51 100644
--- a/openssl/src/bn/mod.rs
+++ b/openssl/src/bn/mod.rs
@@ -4,7 +4,7 @@ use std::cmp::Ordering;
use std::{fmt, ptr, mem};
use ffi;
-use ssl::error::SslError;
+use error::ErrorStack;
/// A signed arbitrary-precision integer.
///
@@ -30,7 +30,7 @@ macro_rules! with_ctx(
($name:ident, $action:block) => ({
let $name = ffi::BN_CTX_new();
if ($name).is_null() {
- Err(SslError::get())
+ Err(ErrorStack::get())
} else {
let r = $action;
ffi::BN_CTX_free($name);
@@ -47,7 +47,7 @@ macro_rules! with_bn(
if $action {
Ok($name)
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
},
Err(err) => Err(err),
@@ -62,13 +62,13 @@ macro_rules! with_bn_in_ctx(
Ok($name) => {
let $ctx_name = ffi::BN_CTX_new();
if ($ctx_name).is_null() {
- Err(SslError::get())
+ Err(ErrorStack::get())
} else {
let r =
if $action {
Ok($name)
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
};
ffi::BN_CTX_free($ctx_name);
r
@@ -81,7 +81,7 @@ macro_rules! with_bn_in_ctx(
impl BigNum {
/// Creates a new `BigNum` with the value 0.
- pub fn new() -> Result<BigNum, SslError> {
+ pub fn new() -> Result<BigNum, ErrorStack> {
unsafe {
ffi::init();
@@ -91,7 +91,7 @@ impl BigNum {
}
/// Creates a new `BigNum` with the given value.
- pub fn new_from(n: u64) -> Result<BigNum, SslError> {
+ pub fn new_from(n: u64) -> Result<BigNum, ErrorStack> {
BigNum::new().and_then(|v| unsafe {
try_ssl!(ffi::BN_set_word(v.raw(), n as c_ulong));
Ok(v)
@@ -99,7 +99,7 @@ impl BigNum {
}
/// Creates a `BigNum` from a decimal string.
- pub fn from_dec_str(s: &str) -> Result<BigNum, SslError> {
+ pub fn from_dec_str(s: &str) -> Result<BigNum, ErrorStack> {
BigNum::new().and_then(|v| unsafe {
let c_str = CString::new(s.as_bytes()).unwrap();
try_ssl!(ffi::BN_dec2bn(v.raw_ptr(), c_str.as_ptr() as *const _));
@@ -108,7 +108,7 @@ impl BigNum {
}
/// Creates a `BigNum` from a hexadecimal string.
- pub fn from_hex_str(s: &str) -> Result<BigNum, SslError> {
+ pub fn from_hex_str(s: &str) -> Result<BigNum, ErrorStack> {
BigNum::new().and_then(|v| unsafe {
let c_str = CString::new(s.as_bytes()).unwrap();
try_ssl!(ffi::BN_hex2bn(v.raw_ptr(), c_str.as_ptr() as *const _));
@@ -116,13 +116,13 @@ impl BigNum {
})
}
- pub unsafe fn new_from_ffi(orig: *mut ffi::BIGNUM) -> Result<BigNum, SslError> {
+ pub unsafe fn new_from_ffi(orig: *mut ffi::BIGNUM) -> Result<BigNum, ErrorStack> {
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())
+ Err(ErrorStack::get())
} else {
Ok(BigNum(r))
}
@@ -136,7 +136,7 @@ impl BigNum {
///
/// assert_eq!(bignum, BigNum::new_from(0x120034).unwrap());
/// ```
- pub fn new_from_slice(n: &[u8]) -> Result<BigNum, SslError> {
+ pub fn new_from_slice(n: &[u8]) -> Result<BigNum, ErrorStack> {
BigNum::new().and_then(|v| unsafe {
try_ssl_null!(ffi::BN_bin2bn(n.as_ptr(), n.len() as c_int, v.raw()));
Ok(v)
@@ -153,7 +153,7 @@ impl BigNum {
/// assert_eq!(n.checked_sqr().unwrap(), squared);
/// assert_eq!(n * n, squared);
/// ```
- pub fn checked_sqr(&self) -> Result<BigNum, SslError> {
+ pub fn checked_sqr(&self) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
ffi::BN_sqr(r.raw(), self.raw(), ctx) == 1
@@ -162,7 +162,7 @@ impl BigNum {
}
/// Returns the unsigned remainder of the division `self / n`.
- pub fn checked_nnmod(&self, n: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_nnmod(&self, n: &BigNum) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
ffi::BN_nnmod(r.raw(), self.raw(), n.raw(), ctx) == 1
@@ -181,7 +181,7 @@ impl BigNum {
///
/// assert_eq!(s.checked_mod_add(a, n).unwrap(), result);
/// ```
- pub fn checked_mod_add(&self, a: &BigNum, n: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_mod_add(&self, a: &BigNum, n: &BigNum) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
ffi::BN_mod_add(r.raw(), self.raw(), a.raw(), n.raw(), ctx) == 1
@@ -190,7 +190,7 @@ impl BigNum {
}
/// Equivalent to `(self - a) mod n`.
- pub fn checked_mod_sub(&self, a: &BigNum, n: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_mod_sub(&self, a: &BigNum, n: &BigNum) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
ffi::BN_mod_sub(r.raw(), self.raw(), a.raw(), n.raw(), ctx) == 1
@@ -199,7 +199,7 @@ impl BigNum {
}
/// Equivalent to `(self * a) mod n`.
- pub fn checked_mod_mul(&self, a: &BigNum, n: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_mod_mul(&self, a: &BigNum, n: &BigNum) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
ffi::BN_mod_mul(r.raw(), self.raw(), a.raw(), n.raw(), ctx) == 1
@@ -208,7 +208,7 @@ impl BigNum {
}
/// Equivalent to `self² mod n`.
- pub fn checked_mod_sqr(&self, n: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_mod_sqr(&self, n: &BigNum) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
ffi::BN_mod_sqr(r.raw(), self.raw(), n.raw(), ctx) == 1
@@ -217,7 +217,7 @@ impl BigNum {
}
/// Raises `self` to the `p`th power.
- pub fn checked_exp(&self, p: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_exp(&self, p: &BigNum) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
ffi::BN_exp(r.raw(), self.raw(), p.raw(), ctx) == 1
@@ -226,7 +226,7 @@ impl BigNum {
}
/// Equivalent to `self.checked_exp(p) mod n`.
- pub fn checked_mod_exp(&self, p: &BigNum, n: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_mod_exp(&self, p: &BigNum, n: &BigNum) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
ffi::BN_mod_exp(r.raw(), self.raw(), p.raw(), n.raw(), ctx) == 1
@@ -236,7 +236,7 @@ impl BigNum {
/// Calculates the modular multiplicative inverse of `self` modulo `n`, that is, an integer `r`
/// such that `(self * r) % n == 1`.
- pub fn checked_mod_inv(&self, n: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_mod_inv(&self, n: &BigNum) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
!ffi::BN_mod_inverse(r.raw(), self.raw(), n.raw(), ctx).is_null()
@@ -245,60 +245,60 @@ impl BigNum {
}
/// Add an `unsigned long` to `self`. This is more efficient than adding a `BigNum`.
- pub fn add_word(&mut self, w: c_ulong) -> Result<(), SslError> {
+ pub fn add_word(&mut self, w: c_ulong) -> Result<(), ErrorStack> {
unsafe {
if ffi::BN_add_word(self.raw(), w) == 1 {
Ok(())
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
}
}
- pub fn sub_word(&mut self, w: c_ulong) -> Result<(), SslError> {
+ pub fn sub_word(&mut self, w: c_ulong) -> Result<(), ErrorStack> {
unsafe {
if ffi::BN_sub_word(self.raw(), w) == 1 {
Ok(())
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
}
}
- pub fn mul_word(&mut self, w: c_ulong) -> Result<(), SslError> {
+ pub fn mul_word(&mut self, w: c_ulong) -> Result<(), ErrorStack> {
unsafe {
if ffi::BN_mul_word(self.raw(), w) == 1 {
Ok(())
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
}
}
- pub fn div_word(&mut self, w: c_ulong) -> Result<c_ulong, SslError> {
+ pub fn div_word(&mut self, w: c_ulong) -> Result<c_ulong, ErrorStack> {
unsafe {
let result = ffi::BN_div_word(self.raw(), w);
if result != !0 as c_ulong {
Ok(result)
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
}
}
- pub fn mod_word(&self, w: c_ulong) -> Result<c_ulong, SslError> {
+ pub fn mod_word(&self, w: c_ulong) -> Result<c_ulong, ErrorStack> {
unsafe {
let result = ffi::BN_mod_word(self.raw(), w);
if result != !0 as c_ulong {
Ok(result)
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
}
}
/// Computes the greatest common denominator of `self` and `a`.
- pub fn checked_gcd(&self, a: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_gcd(&self, a: &BigNum) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
ffi::BN_gcd(r.raw(), self.raw(), a.raw(), ctx) == 1
@@ -318,7 +318,7 @@ impl BigNum {
safe: bool,
add: Option<&BigNum>,
rem: Option<&BigNum>)
- -> Result<BigNum, SslError> {
+ -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
let add_arg = add.map(|a| a.raw()).unwrap_or(ptr::null_mut());
@@ -341,7 +341,7 @@ impl BigNum {
/// # Return Value
///
/// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`.
- pub fn is_prime(&self, checks: i32) -> Result<bool, SslError> {
+ pub fn is_prime(&self, checks: i32) -> Result<bool, ErrorStack> {
unsafe {
with_ctx!(ctx, {
Ok(ffi::BN_is_prime_ex(self.raw(), checks as c_int, ctx, ptr::null()) == 1)
@@ -358,7 +358,7 @@ impl BigNum {
/// # Return Value
///
/// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`.
- pub fn is_prime_fast(&self, checks: i32, do_trial_division: bool) -> Result<bool, SslError> {
+ pub fn is_prime_fast(&self, checks: i32, do_trial_division: bool) -> Result<bool, ErrorStack> {
unsafe {
with_ctx!(ctx, {
Ok(ffi::BN_is_prime_fasttest_ex(self.raw(),
@@ -377,7 +377,7 @@ impl BigNum {
/// * `bits`: Length of the number in bits.
/// * `prop`: The desired properties of the number.
/// * `odd`: If `true`, the generated number will be odd.
- pub fn checked_new_random(bits: i32, prop: RNGProperty, odd: bool) -> Result<BigNum, SslError> {
+ pub fn checked_new_random(bits: i32, prop: RNGProperty, odd: bool) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
ffi::BN_rand(r.raw(), bits as c_int, prop as c_int, odd as c_int) == 1
@@ -389,7 +389,7 @@ impl BigNum {
pub fn checked_new_pseudo_random(bits: i32,
prop: RNGProperty,
odd: bool)
- -> Result<BigNum, SslError> {
+ -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
ffi::BN_pseudo_rand(r.raw(), bits as c_int, prop as c_int, odd as c_int) == 1
@@ -399,7 +399,7 @@ impl BigNum {
/// Generates a cryptographically strong pseudo-random `BigNum` `r` in the range
/// `0 <= r < self`.
- pub fn checked_rand_in_range(&self) -> Result<BigNum, SslError> {
+ pub fn checked_rand_in_range(&self) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
ffi::BN_rand_range(r.raw(), self.raw()) == 1
@@ -408,7 +408,7 @@ impl BigNum {
}
/// The cryptographically weak counterpart to `checked_rand_in_range`.
- pub fn checked_pseudo_rand_in_range(&self) -> Result<BigNum, SslError> {
+ pub fn checked_pseudo_rand_in_range(&self) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
ffi::BN_pseudo_rand_range(r.raw(), self.raw()) == 1
@@ -419,12 +419,12 @@ impl BigNum {
/// Sets bit `n`. Equivalent to `self |= (1 << n)`.
///
/// When setting a bit outside of `self`, it is expanded.
- pub fn set_bit(&mut self, n: i32) -> Result<(), SslError> {
+ pub fn set_bit(&mut self, n: i32) -> Result<(), ErrorStack> {
unsafe {
if ffi::BN_set_bit(self.raw(), n as c_int) == 1 {
Ok(())
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
}
}
@@ -432,12 +432,12 @@ impl BigNum {
/// Clears bit `n`, setting it to 0. Equivalent to `self &= ~(1 << n)`.
///
/// When clearing a bit outside of `self`, an error is returned.
- pub fn clear_bit(&mut self, n: i32) -> Result<(), SslError> {
+ pub fn clear_bit(&mut self, n: i32) -> Result<(), ErrorStack> {
unsafe {
if ffi::BN_clear_bit(self.raw(), n as c_int) == 1 {
Ok(())
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
}
}
@@ -450,12 +450,12 @@ impl BigNum {
/// Truncates `self` to the lowest `n` bits.
///
/// An error occurs if `self` is already shorter than `n` bits.
- pub fn mask_bits(&mut self, n: i32) -> Result<(), SslError> {
+ pub fn mask_bits(&mut self, n: i32) -> Result<(), ErrorStack> {
unsafe {
if ffi::BN_mask_bits(self.raw(), n as c_int) == 1 {
Ok(())
} else {
- Err(SslError::get())
+ Err(ErrorStack::get())
}
}
}
@@ -478,7 +478,7 @@ impl BigNum {
/// // (-8) << 1 == -16
/// assert_eq!(s.checked_shl1().unwrap(), result);
/// ```
- pub fn checked_shl1(&self) -> Result<BigNum, SslError> {
+ pub fn checked_shl1(&self) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn!(r, {
ffi::BN_lshift1(r.raw(), self.raw()) == 1
@@ -487,7 +487,7 @@ impl BigNum {
}
/// Returns `self`, shifted right by 1 bit. `self` may be negative.
- pub fn checked_shr1(&self) -> Result<BigNum, SslError> {
+ pub fn checked_shr1(&self) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn!(r, {
ffi::BN_rshift1(r.raw(), self.raw()) == 1
@@ -495,7 +495,7 @@ impl BigNum {
}
}
- pub fn checked_add(&self, a: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_add(&self, a: &BigNum) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn!(r, {
ffi::BN_add(r.raw(), self.raw(), a.raw()) == 1
@@ -503,7 +503,7 @@ impl BigNum {
}
}
- pub fn checked_sub(&self, a: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_sub(&self, a: &BigNum) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn!(r, {
ffi::BN_sub(r.raw(), self.raw(), a.raw()) == 1
@@ -511,7 +511,7 @@ impl BigNum {
}
}
- pub fn checked_mul(&self, a: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_mul(&self, a: &BigNum) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
ffi::BN_mul(r.raw(), self.raw(), a.raw(), ctx) == 1
@@ -519,7 +519,7 @@ impl BigNum {
}
}
- pub fn checked_div(&self, a: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_div(&self, a: &BigNum) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
ffi::BN_div(r.raw(), ptr::null_mut(), self.raw(), a.raw(), ctx) == 1
@@ -527,7 +527,7 @@ impl BigNum {
}
}
- pub fn checked_mod(&self, a: &BigNum) -> Result<BigNum, SslError> {
+ pub fn checked_mod(&self, a: &BigNum) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn_in_ctx!(r, ctx, {
ffi::BN_div(ptr::null_mut(), r.raw(), self.raw(), a.raw(), ctx) == 1
@@ -535,7 +535,7 @@ impl BigNum {
}
}
- pub fn checked_shl(&self, a: &i32) -> Result<BigNum, SslError> {
+ pub fn checked_shl(&self, a: &i32) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn!(r, {
ffi::BN_lshift(r.raw(), self.raw(), *a as c_int) == 1
@@ -543,7 +543,7 @@ impl BigNum {
}
}
- pub fn checked_shr(&self, a: &i32) -> Result<BigNum, SslError> {
+ pub fn checked_shr(&self, a: &i32) -> Result<BigNum, ErrorStack> {
unsafe {
with_bn!(r, {
ffi::BN_rshift(r.raw(), self.raw(), *a as c_int) == 1
diff --git a/openssl/src/crypto/dsa.rs b/openssl/src/crypto/dsa.rs
index 7e384ae3..de35893b 100644
--- a/openssl/src/crypto/dsa.rs
+++ b/openssl/src/crypto/dsa.rs
@@ -1,25 +1,21 @@
use ffi;
use std::fmt;
-use ssl::error::{SslError, StreamError};
+use error::ErrorStack;
use std::ptr;
-use std::io::{self, Read, Write};
-use libc::{c_uint, c_int};
+use libc::{c_uint, c_int, c_char, c_void};
use bn::BigNum;
-use bio::MemBio;
+use bio::{MemBio, MemBioSlice};
use crypto::hash;
use crypto::HashTypeInternals;
-
-#[cfg(feature = "catch_unwind")]
-use libc::{c_char, c_void};
-#[cfg(feature = "catch_unwind")]
use crypto::util::{CallbackState, invoke_passwd_cb};
+
/// Builder for upfront DSA parameter generateration
pub struct DSAParams(*mut ffi::DSA);
impl DSAParams {
- pub fn with_size(size: usize) -> Result<DSAParams, SslError> {
+ pub fn with_size(size: usize) -> Result<DSAParams, ErrorStack> {
unsafe {
// Wrap it so that if we panic we'll call the dtor
let dsa = DSAParams(try_ssl_null!(ffi::DSA_new()));
@@ -30,7 +26,7 @@ impl DSAParams {
}
/// Generate a key pair from the initialized parameters
- pub fn generate(self) -> Result<DSA, SslError> {
+ pub fn generate(self) -> Result<DSA, ErrorStack> {
unsafe {
try_ssl!(ffi::DSA_generate_key(self.0));
let dsa = DSA(self.0);
@@ -66,17 +62,15 @@ impl DSA {
/// Generate a DSA key pair
/// For more complicated key generation scenarios see the `DSAParams` type
- pub fn generate(size: usize) -> Result<DSA, SslError> {
+ pub fn generate(size: usize) -> Result<DSA, ErrorStack> {
let params = try!(DSAParams::with_size(size));
params.generate()
}
/// Reads a DSA private key from PEM formatted data.
- pub fn private_key_from_pem<R>(reader: &mut R) -> Result<DSA, SslError>
- where R: Read
- {
- let mut mem_bio = try!(MemBio::new());
- try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
+ pub fn private_key_from_pem(buf: &[u8]) -> Result<DSA, ErrorStack> {
+ ffi::init();
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let dsa = try_ssl_null!(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.get_handle(),
@@ -94,15 +88,12 @@ impl DSA {
///
/// The callback will be passed the password buffer and should return the number of characters
/// placed into the buffer.
- ///
- /// Requires the `catch_unwind` feature.
- #[cfg(feature = "catch_unwind")]
- pub fn private_key_from_pem_cb<R, F>(reader: &mut R, pass_cb: F) -> Result<DSA, SslError>
- where R: Read, F: FnOnce(&mut [c_char]) -> usize
+ pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<DSA, ErrorStack>
+ where F: FnOnce(&mut [c_char]) -> usize
{
+ ffi::init();
let mut cb = CallbackState::new(pass_cb);
- let mut mem_bio = try!(MemBio::new());
- try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let cb_ptr = &mut cb as *mut _ as *mut c_void;
@@ -117,11 +108,10 @@ impl DSA {
}
/// Writes an DSA private key as unencrypted PEM formatted data
- pub fn private_key_to_pem<W>(&self, writer: &mut W) -> Result<(), SslError>
- where W: Write
+ pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack>
{
assert!(self.has_private_key());
- let mut mem_bio = try!(MemBio::new());
+ let mem_bio = try!(MemBio::new());
unsafe {
try_ssl!(ffi::PEM_write_bio_DSAPrivateKey(mem_bio.get_handle(), self.0,
@@ -129,18 +119,15 @@ impl DSA {
None, ptr::null_mut()))
};
-
- try!(io::copy(&mut mem_bio, writer).map_err(StreamError));
- Ok(())
+ Ok(mem_bio.get_buf().to_owned())
}
/// Reads an DSA public key from PEM formatted data.
- pub fn public_key_from_pem<R>(reader: &mut R) -> Result<DSA, SslError>
- where R: Read
+ pub fn public_key_from_pem(buf: &[u8]) -> Result<DSA, ErrorStack>
{
- let mut mem_bio = try!(MemBio::new());
- try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
+ ffi::init();
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let dsa = try_ssl_null!(ffi::PEM_read_bio_DSA_PUBKEY(mem_bio.get_handle(),
ptr::null_mut(),
@@ -151,28 +138,23 @@ impl DSA {
}
/// Writes an DSA public key as PEM formatted data
- pub fn public_key_to_pem<W>(&self, writer: &mut W) -> Result<(), SslError>
- where W: Write
- {
- let mut mem_bio = try!(MemBio::new());
-
+ pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
unsafe { try_ssl!(ffi::PEM_write_bio_DSA_PUBKEY(mem_bio.get_handle(), self.0)) };
-
- try!(io::copy(&mut mem_bio, writer).map_err(StreamError));
- Ok(())
+ Ok(mem_bio.get_buf().to_owned())
}
- pub fn size(&self) -> Result<isize, SslError> {
+ pub fn size(&self) -> Option<u32> {
if self.has_q() {
- unsafe { Ok(ffi::DSA_size(self.0) as isize) }
+ unsafe { Some(ffi::DSA_size(self.0) as u32) }
} else {
- Err(SslError::OpenSslErrors(vec![]))
+ None
}
}
- pub fn sign(&self, hash: hash::Type, message: &[u8]) -> Result<Vec<u8>, SslError> {
- let k_len = try!(self.size()) as c_uint;
- let mut sig = vec![0;k_len as usize];
+ pub fn sign(&self, hash: hash::Type, message: &[u8]) -> Result<Vec<u8>, ErrorStack> {
+ let k_len = self.size().expect("DSA missing a q") as c_uint;
+ let mut sig = vec![0; k_len as usize];
let mut sig_len = k_len;
assert!(self.has_private_key());
@@ -189,7 +171,7 @@ impl DSA {
}
}
- pub fn verify(&self, hash: hash::Type, message: &[u8], sig: &[u8]) -> Result<bool, SslError> {
+ pub fn verify(&self, hash: hash::Type, message: &[u8], sig: &[u8]) -> Result<bool, ErrorStack> {
unsafe {
let result = ffi::DSA_verify(hash.as_nid() as c_int,
message.as_ptr(),
@@ -208,7 +190,7 @@ impl DSA {
}
// The following getters are unsafe, since BigNum::new_from_ffi fails upon null pointers
- pub fn p(&self) -> Result<BigNum, SslError> {
+ pub fn p(&self) -> Result<BigNum, ErrorStack> {
unsafe { BigNum::new_from_ffi((*self.0).p) }
}
@@ -216,7 +198,7 @@ impl DSA {
unsafe { !(*self.0).p.is_null() }
}
- pub fn q(&self) -> Result<BigNum, SslError> {
+ pub fn q(&self) -> Result<BigNum, ErrorStack> {
unsafe { BigNum::new_from_ffi((*self.0).q) }
}
@@ -224,7 +206,7 @@ impl DSA {
unsafe { !(*self.0).q.is_null() }
}
- pub fn g(&self) -> Result<BigNum, SslError> {
+ pub fn g(&self) -> Result<BigNum, ErrorStack> {
unsafe { BigNum::new_from_ffi((*self.0).g) }
}
@@ -249,19 +231,18 @@ impl fmt::Debug for DSA {
#[cfg(test)]
mod test {
- use std::fs::File;
- use std::io::{Write, Cursor};
+ use std::io::Write;
+ use libc::c_char;
+
use super::*;
use crypto::hash::*;
#[test]
pub fn test_generate() {
let key = DSA::generate(1024).unwrap();
- let mut priv_buf = Cursor::new(vec![]);
- let mut pub_buf = Cursor::new(vec![]);
- key.public_key_to_pem(&mut pub_buf).unwrap();
- key.private_key_to_pem(&mut priv_buf).unwrap();
+ key.public_key_to_pem().unwrap();
+ key.private_key_to_pem().unwrap();
let input: Vec<u8> = (0..25).cycle().take(1024).collect();
@@ -281,13 +262,13 @@ mod test {
let input: Vec<u8> = (0..25).cycle().take(1024).collect();
let private_key = {
- let mut buffer = File::open("test/dsa.pem").unwrap();
- DSA::private_key_from_pem(&mut buffer).unwrap()
+ let key = include_bytes!("../../test/dsa.pem");
+ DSA::private_key_from_pem(key).unwrap()
};
let public_key = {
- let mut buffer = File::open("test/dsa.pem.pub").unwrap();
- DSA::public_key_from_pem(&mut buffer).unwrap()
+ let key = include_bytes!("../../test/dsa.pem.pub");
+ DSA::public_key_from_pem(key).unwrap()
};
let digest = {
@@ -305,13 +286,13 @@ mod test {
pub fn test_sign_verify_fail() {
let input: Vec<u8> = (0..25).cycle().take(128).collect();
let private_key = {
- let mut buffer = File::open("test/dsa.pem").unwrap();
- DSA::private_key_from_pem(&mut buffer).unwrap()
+ let key = include_bytes!("../../test/dsa.pem");
+ DSA::private_key_from_pem(key).unwrap()
};
let public_key = {
- let mut buffer = File::open("test/dsa.pem.pub").unwrap();
- DSA::public_key_from_pem(&mut buffer).unwrap()
+ let key = include_bytes!("../../test/dsa.pem.pub");
+ DSA::public_key_from_pem(key).unwrap()
};
let digest = {
@@ -331,18 +312,17 @@ mod test {
}
#[test]
- #[cfg(feature = "catch_unwind")]
pub fn test_password() {
let mut password_queried = false;
- let mut buffer = File::open("test/dsa-encrypted.pem").unwrap();
- DSA::private_key_from_pem_cb(&mut buffer, |password| {
+ let key = include_bytes!("../../test/dsa-encrypted.pem");
+ DSA::private_key_from_pem_cb(key, |password| {
password_queried = true;
- password[0] = b'm' as _;
- password[1] = b'y' as _;
- password[2] = b'p' as _;
- password[3] = b'a' as _;
- password[4] = b's' as _;
- password[5] = b's' as _;
+ password[0] = b'm' as c_char;
+ password[1] = b'y' as c_char;
+ password[2] = b'p' as c_char;
+ password[3] = b'a' as c_char;
+ password[4] = b's' as c_char;
+ password[5] = b's' as c_char;
6
}).unwrap();
diff --git a/openssl/src/crypto/mod.rs b/openssl/src/crypto/mod.rs
index 6a34bd59..5b891ce7 100644
--- a/openssl/src/crypto/mod.rs
+++ b/openssl/src/crypto/mod.rs
@@ -25,7 +25,6 @@ pub mod symm;
pub mod memcmp;
pub mod rsa;
pub mod dsa;
-#[cfg(feature = "catch_unwind")]
mod util;
mod symm_internal;
diff --git a/openssl/src/crypto/pkey.rs b/openssl/src/crypto/pkey.rs
index 15744047..ab9a4a95 100644
--- a/openssl/src/crypto/pkey.rs
+++ b/openssl/src/crypto/pkey.rs
@@ -1,21 +1,15 @@
-use libc::{c_int, c_uint, c_ulong};
-use std::io;
-use std::io::prelude::*;
+use libc::{c_int, c_uint, c_ulong, c_void, c_char};
use std::iter::repeat;
use std::mem;
use std::ptr;
-use bio::MemBio;
+use bio::{MemBio, MemBioSlice};
use crypto::HashTypeInternals;
use crypto::hash;
use crypto::hash::Type as HashType;
use ffi;
-use ssl::error::{SslError, StreamError};
use crypto::rsa::RSA;
-
-#[cfg(feature = "catch_unwind")]
-use libc::{c_void, c_char};
-#[cfg(feature = "catch_unwind")]
+use error::ErrorStack;
use crypto::util::{CallbackState, invoke_passwd_cb};
#[derive(Copy, Clone)]
@@ -80,17 +74,14 @@ impl PKey {
}
/// Reads private key from PEM, takes ownership of handle
- pub fn private_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError>
- where R: Read
- {
- let mut mem_bio = try!(MemBio::new());
- try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
-
+ pub fn private_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.get_handle(),
ptr::null_mut(),
None,
ptr::null_mut()));
+
Ok(PKey {
evp: evp as *mut ffi::EVP_PKEY,
parts: Parts::Both,
@@ -103,17 +94,11 @@ impl PKey {
///
/// The callback will be passed the password buffer and should return the number of characters
/// placed into the buffer.
- ///
- /// Requires the `catch_unwind` feature.
- #[cfg(feature = "catch_unwind")]
- pub fn private_key_from_pem_cb<R, F>(reader: &mut R, pass_cb: F) -> Result<PKey, SslError>
- where R: Read, F: FnOnce(&mut [c_char]) -> usize
+ pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<PKey, ErrorStack>
+ where F: FnOnce(&mut [c_char]) -> usize
{
let mut cb = CallbackState::new(pass_cb);
-
- let mut mem_bio = try!(MemBio::new());
- try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
-
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.get_handle(),
ptr::null_mut(),
@@ -128,12 +113,8 @@ impl PKey {
}
/// Reads public key from PEM, takes ownership of handle
- pub fn public_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError>
- where R: Read
- {
- let mut mem_bio = try!(MemBio::new());
- try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
-
+ pub fn public_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let evp = try_ssl_null!(ffi::PEM_read_bio_PUBKEY(mem_bio.get_handle(),
ptr::null_mut(),
@@ -147,13 +128,13 @@ impl PKey {
}
/// Reads an RSA private key from PEM, takes ownership of handle
- pub fn private_rsa_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError>
- where R: Read
- {
- let rsa = try!(RSA::private_key_from_pem(reader));
+ pub fn private_rsa_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
+ let rsa = try!(RSA::private_key_from_pem(buf));
unsafe {
let evp = try_ssl_null!(ffi::EVP_PKEY_new());
- try_ssl!(ffi::EVP_PKEY_set1_RSA(evp, rsa.as_ptr()));
+ if ffi::EVP_PKEY_set1_RSA(evp, rsa.as_ptr()) == 0 {
+ return Err(ErrorStack::get());
+ }
Ok(PKey {
evp: evp,
@@ -163,13 +144,13 @@ impl PKey {
}
/// Reads an RSA public key from PEM, takes ownership of handle
- pub fn public_rsa_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError>
- where R: Read
- {
- let rsa = try!(RSA::public_key_from_pem(reader));
+ pub fn public_rsa_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
+ let rsa = try!(RSA::public_key_from_pem(buf));
unsafe {
let evp = try_ssl_null!(ffi::EVP_PKEY_new());
- try_ssl!(ffi::EVP_PKEY_set1_RSA(evp, rsa.as_ptr()));
+ if ffi::EVP_PKEY_set1_RSA(evp, rsa.as_ptr()) == 0 {
+ return Err(ErrorStack::get());
+ }
Ok(PKey {
evp: evp,
@@ -282,10 +263,8 @@ impl PKey {
/// Stores private key as a PEM
// FIXME: also add password and encryption
- pub fn write_pem<W: Write>(&self,
- writer: &mut W /* , password: Option<String> */)
- -> Result<(), SslError> {
- let mut mem_bio = try!(MemBio::new());
+ pub fn write_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
unsafe {
try_ssl!(ffi::PEM_write_bio_PrivateKey(mem_bio.get_handle(),
self.evp,
@@ -296,20 +275,14 @@ impl PKey {
ptr::null_mut()));
}
- let mut buf = vec![];
- try!(mem_bio.read_to_end(&mut buf).map_err(StreamError));
- writer.write_all(&buf).map_err(StreamError)
+ Ok(mem_bio.get_buf().to_owned())
}
/// Stores public key as a PEM
- pub fn write_pub_pem<W: Write>(&self,
- writer: &mut W /* , password: Option<String> */)
- -> Result<(), SslError> {
- let mut mem_bio = try!(MemBio::new());
+ pub fn write_pub_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let 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)
+ Ok(mem_bio.get_buf().to_owned())
}
/**
@@ -394,7 +367,7 @@ impl PKey {
openssl_padding_code(padding));
if rv < 0 as c_int {
- // println!("{:?}", SslError::get());
+ // println!("{:?}", ErrorStack::get());
vec![]
} else {
r.truncate(rv as usize);
@@ -650,8 +623,6 @@ impl Clone for PKey {
#[cfg(test)]
mod tests {
- use std::path::Path;
- use std::fs::File;
use crypto::hash::Type::{MD5, SHA1};
use crypto::rsa::RSA;
@@ -695,42 +666,26 @@ mod tests {
#[test]
fn test_private_key_from_pem() {
- let key_path = Path::new("test/key.pem");
- let mut file = File::open(&key_path)
- .ok()
- .expect("Failed to open `test/key.pem`");
-
- super::PKey::private_key_from_pem(&mut file).unwrap();
+ let key = include_bytes!("../../test/key.pem");
+ super::PKey::private_key_from_pem(key).unwrap();
}
#[test]
fn test_public_key_from_pem() {
- let key_path = Path::new("test/key.pem.pub");
- let mut file = File::open(&key_path)
- .ok()
- .expect("Failed to open `test/key.pem.pub`");
-
- super::PKey::public_key_from_pem(&mut file).unwrap();
+ let key = include_bytes!("../../test/key.pem.pub");
+ super::PKey::public_key_from_pem(key).unwrap();
}
#[test]
fn test_private_rsa_key_from_pem() {
- let key_path = Path::new("test/key.pem");
- let mut file = File::open(&key_path)
- .ok()
- .expect("Failed to open `test/key.pem`");
-
- super::PKey::private_rsa_key_from_pem(&mut file).unwrap();
+ let key = include_bytes!("../../test/key.pem");
+ super::PKey::private_rsa_key_from_pem(key).unwrap();
}
#[test]
fn test_public_rsa_key_from_pem() {
- let key_path = Path::new("test/key.pem.pub");
- let mut file = File::open(&key_path)
- .ok()
- .expect("Failed to open `test/key.pem.pub`");
-
- super::PKey::public_rsa_key_from_pem(&mut file).unwrap();
+ let key = include_bytes!("../../test/key.pem.pub");
+ super::PKey::public_rsa_key_from_pem(key).unwrap();
}
#[test]
@@ -821,18 +776,11 @@ mod tests {
#[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();
+ let key = include_bytes!("../../test/key.pem");
+ let key = super::PKey::private_key_from_pem(key).unwrap();
- key.write_pem(&mut priv_key).unwrap();
- key.write_pub_pem(&mut pub_key).unwrap();
+ let priv_key = key.write_pem().unwrap();
+ let pub_key = key.write_pub_pem().unwrap();
// As a super-simple verification, just check that the buffers contain
// the `PRIVATE KEY` or `PUBLIC KEY` strings.
diff --git a/openssl/src/crypto/rsa.rs b/openssl/src/crypto/rsa.rs
index 2b563a7a..226b2aab 100644
--- a/openssl/src/crypto/rsa.rs
+++ b/openssl/src/crypto/rsa.rs
@@ -1,18 +1,13 @@
use ffi;
use std::fmt;
-use ssl::error::{SslError, StreamError};
use std::ptr;
-use std::io::{self, Read, Write};
-use libc::c_int;
+use libc::{c_int, c_void, c_char};
use bn::BigNum;
-use bio::MemBio;
+use bio::{MemBio, MemBioSlice};
+use error::ErrorStack;
use crypto::HashTypeInternals;
use crypto::hash;
-
-#[cfg(feature = "catch_unwind")]
-use libc::{c_void, c_char};
-#[cfg(feature = "catch_unwind")]
use crypto::util::{CallbackState, invoke_passwd_cb};
pub struct RSA(*mut ffi::RSA);
@@ -28,7 +23,7 @@ impl Drop for RSA {
impl RSA {
/// only useful for associating the key material directly with the key, it's safer to use
/// the supplied load and save methods for DER formatted keys.
- pub fn from_public_components(n: BigNum, e: BigNum) -> Result<RSA, SslError> {
+ pub fn from_public_components(n: BigNum, e: BigNum) -> Result<RSA, ErrorStack> {
unsafe {
let rsa = try_ssl_null!(ffi::RSA_new());
(*rsa).n = n.into_raw();
@@ -45,7 +40,7 @@ impl RSA {
dp: BigNum,
dq: BigNum,
qi: BigNum)
- -> Result<RSA, SslError> {
+ -> Result<RSA, ErrorStack> {
unsafe {
let rsa = try_ssl_null!(ffi::RSA_new());
(*rsa).n = n.into_raw();
@@ -66,12 +61,8 @@ 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));
-
+ pub fn private_key_from_pem(buf: &[u8]) -> Result<RSA, ErrorStack> {
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.get_handle(),
ptr::null_mut(),
@@ -82,16 +73,11 @@ impl RSA {
}
/// Reads an RSA private key from PEM formatted data and supplies a password callback.
- ///
- /// Requires the `catch_unwind` feature.
- #[cfg(feature = "catch_unwind")]
- pub fn private_key_from_pem_cb<R, F>(reader: &mut R, pass_cb: F) -> Result<RSA, SslError>
- where R: Read, F: FnOnce(&mut [c_char]) -> usize
+ pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<RSA, ErrorStack>
+ where F: FnOnce(&mut [c_char]) -> usize
{
let mut cb = CallbackState::new(pass_cb);
-
- let mut mem_bio = try!(MemBio::new());
- try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let cb_ptr = &mut cb as *mut _ as *mut c_void;
@@ -105,10 +91,8 @@ impl RSA {
}
/// Writes an RSA private key as unencrypted PEM formatted data
- pub fn private_key_to_pem<W>(&self, writer: &mut W) -> Result<(), SslError>
- where W: Write
- {
- let mut mem_bio = try!(MemBio::new());
+ pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
unsafe {
try_ssl!(ffi::PEM_write_bio_RSAPrivateKey(mem_bio.get_handle(),
@@ -119,17 +103,12 @@ impl RSA {
None,
ptr::null_mut()));
}
- try!(io::copy(&mut mem_bio, writer).map_err(StreamError));
- Ok(())
+ Ok(mem_bio.get_buf().to_owned())
}
/// Reads an RSA public key from PEM formatted data.
- pub fn public_key_from_pem<R>(reader: &mut R) -> Result<RSA, SslError>
- where R: Read
- {
- let mut mem_bio = try!(MemBio::new());
- try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
-
+ pub fn public_key_from_pem(buf: &[u8]) -> Result<RSA, ErrorStack> {
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let rsa = try_ssl_null!(ffi::PEM_read_bio_RSA_PUBKEY(mem_bio.get_handle(),
ptr::null_mut(),
@@ -140,30 +119,27 @@ impl RSA {
}
/// Writes an RSA public key as PEM formatted data
- pub fn public_key_to_pem<W>(&self, writer: &mut W) -> Result<(), SslError>
- where W: Write
- {
- let mut mem_bio = try!(MemBio::new());
+ pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
unsafe {
try_ssl!(ffi::PEM_write_bio_RSA_PUBKEY(mem_bio.get_handle(), self.0))
};
- try!(io::copy(&mut mem_bio, writer).map_err(StreamError));
- Ok(())
+ Ok(mem_bio.get_buf().to_owned())
}
- pub fn size(&self) -> Result<u32, SslError> {
+ pub fn size(&self) -> Option<u32> {
if self.has_n() {
- unsafe { Ok(ffi::RSA_size(self.0) as u32) }
+ unsafe { Some(ffi::RSA_size(self.0) as u32) }
} else {
- Err(SslError::OpenSslErrors(vec![]))
+ None
}
}
- pub fn sign(&self, hash: hash::Type, message: &[u8]) -> Result<Vec<u8>, SslError> {
- let k_len = try!(self.size());
- let mut sig = vec![0;k_len as usize];
+ pub fn sign(&self, hash: hash::Type, message: &[u8]) -> Result<Vec<u8>, ErrorStack> {
+ let k_len = self.size().expect("RSA missing an n");
+ let mut sig = vec![0; k_len as usize];
let mut sig_len = k_len;
unsafe {
@@ -178,7 +154,7 @@ impl RSA {
}
}
- pub fn verify(&self, hash: hash::Type, message: &[u8], sig: &[u8]) -> Result<bool, SslError> {
+ pub fn verify(&self, hash: hash::Type, message: &[u8], sig: &[u8]) -> Result<bool, ErrorStack> {
unsafe {
let result = ffi::RSA_verify(hash.as_nid() as c_int,
message.as_ptr(),
@@ -196,32 +172,42 @@ impl RSA {
}
// The following getters are unsafe, since BigNum::new_from_ffi fails upon null pointers
- pub fn n(&self) -> Result<BigNum, SslError> {
- unsafe { BigNum::new_from_ffi((*self.0).n) }
+ pub fn n(&self) -> Result<BigNum, ErrorStack> {
+ unsafe {
+ BigNum::new_from_ffi((*self.0).n)
+ }
}
pub fn has_n(&self) -> bool {
unsafe { !(*self.0).n.is_null() }
}
- pub fn d(&self) -> Result<BigNum, SslError> {
- unsafe { BigNum::new_from_ffi((*self.0).d) }
+ pub fn d(&self) -> Result<BigNum, ErrorStack> {
+ 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 e(&self) -> Result<BigNum, ErrorStack> {
+ unsafe {
+ BigNum::new_from_ffi((*self.0).e)
+ }
}
pub fn has_e(&self) -> bool {
unsafe { !(*self.0).e.is_null() }
}
- pub fn p(&self) -> Result<BigNum, SslError> {
- unsafe { BigNum::new_from_ffi((*self.0).p) }
+ pub fn p(&self) -> Result<BigNum, ErrorStack> {
+ unsafe {
+ BigNum::new_from_ffi((*self.0).p)
+ }
}
- pub fn q(&self) -> Result<BigNum, SslError> {
- unsafe { BigNum::new_from_ffi((*self.0).q) }
+ pub fn q(&self) -> Result<BigNum, ErrorStack> {
+ unsafe {
+ BigNum::new_from_ffi((*self.0).q)
+ }
}
}
@@ -233,8 +219,9 @@ impl fmt::Debug for RSA {
#[cfg(test)]
mod test {
- use std::fs::File;
use std::io::Write;
+ use libc::c_char;
+
use super::*;
use crypto::hash::*;
@@ -266,8 +253,8 @@ mod test {
#[test]
pub fn test_sign() {
- let mut buffer = File::open("test/rsa.pem").unwrap();
- let private_key = RSA::private_key_from_pem(&mut buffer).unwrap();
+ let key = include_bytes!("../../test/rsa.pem");
+ let private_key = RSA::private_key_from_pem(key).unwrap();
let mut sha = Hasher::new(Type::SHA256);
sha.write_all(&signing_input_rs256()).unwrap();
@@ -280,8 +267,8 @@ mod test {
#[test]
pub fn test_verify() {
- let mut buffer = File::open("test/rsa.pem.pub").unwrap();
- let public_key = RSA::public_key_from_pem(&mut buffer).unwrap();
+ let key = include_bytes!("../../test/rsa.pem.pub");
+ let public_key = RSA::public_key_from_pem(key).unwrap();
let mut sha = Hasher::new(Type::SHA256);
sha.write_all(&signing_input_rs256()).unwrap();
@@ -293,18 +280,17 @@ mod test {
}
#[test]
- #[cfg(feature = "catch_unwind")]
pub fn test_password() {
let mut password_queried = false;
- let mut buffer = File::open("test/rsa-encrypted.pem").unwrap();
- RSA::private_key_from_pem_cb(&mut buffer, |password| {
+ let key = include_bytes!("../../test/rsa-encrypted.pem");
+ RSA::private_key_from_pem_cb(key, |password| {
password_queried = true;
- password[0] = b'm' as _;
- password[1] = b'y' as _;
- password[2] = b'p' as _;
- password[3] = b'a' as _;
- password[4] = b's' as _;
- password[5] = b's' as _;
+ password[0] = b'm' as c_char;
+ password[1] = b'y' as c_char;
+ password[2] = b'p' as c_char;
+ password[3] = b'a' as c_char;
+ password[4] = b's' as c_char;
+ password[5] = b's' as c_char;
6
}).unwrap();
diff --git a/openssl/src/dh/mod.rs b/openssl/src/dh/mod.rs
index d2f26c3f..df6f1b0a 100644
--- a/openssl/src/dh/mod.rs
+++ b/openssl/src/dh/mod.rs
@@ -1,8 +1,6 @@
use ffi;
-use std::io;
-use std::io::prelude::*;
-use ssl::error::{SslError, StreamError};
-use bio::MemBio;
+use error::ErrorStack;
+use bio::MemBioSlice;
use bn::BigNum;
use std::mem;
use std::ptr;
@@ -10,7 +8,7 @@ use std::ptr;
pub struct DH(*mut ffi::DH);
impl DH {
- pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result<DH, SslError> {
+ pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result<DH, ErrorStack> {
let dh = try_ssl_null!(unsafe { ffi::DH_new_from_params(p.raw(), g.raw(), q.raw()) });
mem::forget(p);
mem::forget(g);
@@ -18,11 +16,8 @@ impl DH {
Ok(DH(dh))
}
- pub fn from_pem<R>(reader: &mut R) -> Result<DH, SslError>
- where R: Read
- {
- let mut mem_bio = try!(MemBio::new());
- try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
+ pub fn from_pem(buf: &[u8]) -> Result<DH, ErrorStack> {
+ let mem_bio = try!(MemBioSlice::new(buf));
let dh = unsafe {
ffi::PEM_read_bio_DHparams(mem_bio.get_handle(), ptr::null_mut(), None, ptr::null_mut())
};
@@ -31,19 +26,19 @@ impl DH {
}
#[cfg(feature = "rfc5114")]
- pub fn get_1024_160() -> Result<DH, SslError> {
+ pub fn get_1024_160() -> Result<DH, ErrorStack> {
let dh = try_ssl_null!(unsafe { ffi::DH_get_1024_160() });
Ok(DH(dh))
}
#[cfg(feature = "rfc5114")]
- pub fn get_2048_224() -> Result<DH, SslError> {
+ pub fn get_2048_224() -> Result<DH, ErrorStack> {
let dh = try_ssl_null!(unsafe { ffi::DH_get_2048_224() });
Ok(DH(dh))
}
#[cfg(feature = "rfc5114")]
- pub fn get_2048_256() -> Result<DH, SslError> {
+ pub fn get_2048_256() -> Result<DH, ErrorStack> {
let dh = try_ssl_null!(unsafe { ffi::DH_get_2048_256() });
Ok(DH(dh))
}
@@ -71,8 +66,6 @@ impl Drop for DH {
#[cfg(test)]
mod tests {
- use std::fs::File;
- use std::path::Path;
use super::DH;
use bn::BigNum;
use ssl::SslContext;
@@ -81,7 +74,7 @@ mod tests {
#[test]
#[cfg(feature = "rfc5114")]
fn test_dh_rfc5114() {
- let ctx = SslContext::new(Sslv23).unwrap();
+ let mut ctx = SslContext::new(Sslv23).unwrap();
let dh1 = DH::get_1024_160().unwrap();
ctx.set_tmp_dh(dh1).unwrap();
let dh2 = DH::get_2048_224().unwrap();
@@ -92,7 +85,7 @@ mod tests {
#[test]
fn test_dh() {
- let ctx = SslContext::new(Sslv23).unwrap();
+ let mut ctx = SslContext::new(Sslv23).unwrap();
let p = BigNum::from_hex_str("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435\
E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF429\
6D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C02\
@@ -122,12 +115,9 @@ mod tests {
#[test]
fn test_dh_from_pem() {
- let ctx = SslContext::new(Sslv23).unwrap();
- let pem_path = Path::new("test/dhparams.pem");
- let mut file = File::open(&pem_path)
- .ok()
- .expect("Failed to open `test/dhparams.pem`");
- let dh = DH::from_pem(&mut file).ok().expect("Failed to load PEM");
+ let mut ctx = SslContext::new(Sslv23).unwrap();
+ let params = include_bytes!("../../test/dhparams.pem");
+ let dh = DH::from_pem(params).ok().expect("Failed to load PEM");
ctx.set_tmp_dh(dh).unwrap();
}
}
diff --git a/openssl/src/error.rs b/openssl/src/error.rs
new file mode 100644
index 00000000..5fa542c2
--- /dev/null
+++ b/openssl/src/error.rs
@@ -0,0 +1,137 @@
+use libc::c_ulong;
+use std::fmt;
+use std::error;
+use std::ffi::CStr;
+use std::io;
+use std::str;
+
+use ffi;
+
+#[derive(Debug)]
+pub struct ErrorStack(Vec<Error>);
+
+impl ErrorStack {
+ /// Returns the contents of the OpenSSL error stack.
+ pub fn get() -> ErrorStack {
+ let mut vec = vec![];
+ while let Some(err) = Error::get() {
+ vec.push(err);
+ }
+ ErrorStack(vec)
+ }
+}
+
+impl ErrorStack {
+ /// Returns the errors in the stack.
+ pub fn errors(&self) -> &[Error] {
+ &self.0
+ }
+}
+
+impl fmt::Display for ErrorStack {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let mut first = true;
+ for err in &self.0 {
+ if first {
+ try!(fmt.write_str(", "));
+ first = false;
+ }
+ try!(write!(fmt, "{}", err));
+ }
+ Ok(())
+ }
+}
+
+impl error::Error for ErrorStack {
+ fn description(&self) -> &str {
+ "An OpenSSL error stack"
+ }
+}
+
+impl From<ErrorStack> for io::Error {
+ fn from(e: ErrorStack) -> io::Error {
+ io::Error::new(io::ErrorKind::Other, e)
+ }
+}
+
+/// An error reported from OpenSSL.
+pub struct Error(c_ulong);
+
+impl Error {
+ /// Returns the first error on the OpenSSL error stack.
+ pub fn get() -> Option<Error> {
+ ffi::init();
+
+ match unsafe { ffi::ERR_get_error() } {
+ 0 => None,
+ err => Some((Error(err))),
+ }
+ }
+
+ /// Returns the raw OpenSSL error code for this error.
+ pub fn error_code(&self) -> c_ulong {
+ self.0
+ }
+
+ /// Returns the name of the library reporting the error.
+ pub fn library(&self) -> &'static str {
+ get_lib(self.0)
+ }
+
+ /// Returns the name of the function reporting the error.
+ pub fn function(&self) -> &'static str {
+ get_func(self.0)
+ }
+
+ /// Returns the reason for the error.
+ pub fn reason(&self) -> &'static str {
+ get_reason(self.0)
+ }
+}
+
+impl fmt::Debug for Error {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("Error")
+ .field("library", &self.library())
+ .field("function", &self.function())
+ .field("reason", &self.reason())
+ .finish()
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.write_str(&self.reason())
+ }
+}
+
+impl error::Error for Error {
+ fn description(&self) -> &str {
+ "An OpenSSL error"
+ }
+}
+
+fn get_lib(err: c_ulong) -> &'static str {
+ unsafe {
+ let cstr = ffi::ERR_lib_error_string(err);
+ let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
+ str::from_utf8(bytes).unwrap()
+ }
+}
+
+fn get_func(err: c_ulong) -> &'static str {
+ unsafe {
+ let cstr = ffi::ERR_func_error_string(err);
+ let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
+ str::from_utf8(bytes).unwrap()
+ }
+}
+
+fn get_reason(err: c_ulong) -> &'static str {
+ unsafe {
+ let cstr = ffi::ERR_reason_error_string(err);
+ let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
+ str::from_utf8(bytes).unwrap()
+ }
+}
+
diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs
index 690ab32b..4cd76613 100644
--- a/openssl/src/lib.rs
+++ b/openssl/src/lib.rs
@@ -1,5 +1,4 @@
#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.7.14")]
-#![cfg_attr(feature = "nightly", feature(const_fn))]
#[macro_use]
extern crate bitflags;
@@ -18,11 +17,12 @@ extern crate net2;
mod macros;
pub mod asn1;
+mod bio;
pub mod bn;
-pub mod bio;
pub mod crypto;
pub mod dh;
-pub mod ssl;
-pub mod x509;
+pub mod error;
pub mod nid;
+pub mod ssl;
pub mod version;
+pub mod x509;
diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs
index 3e4bb429..35221f1c 100644
--- a/openssl/src/macros.rs
+++ b/openssl/src/macros.rs
@@ -13,7 +13,7 @@ macro_rules! try_ssl_stream {
macro_rules! try_ssl_if {
($e:expr) => (
if $e {
- return Err(SslError::get())
+ return Err(::error::ErrorStack::get().into())
}
)
}
@@ -45,7 +45,7 @@ macro_rules! try_ssl_null{
macro_rules! lift_ssl_if{
($e:expr) => ( {
if $e {
- Err(SslError::get())
+ Err(::error::ErrorStack::get().into())
} else {
Ok(())
}
diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs
index b6f20cf2..3ced1c95 100644
--- a/openssl/src/ssl/bio.rs
+++ b/openssl/src/ssl/bio.rs
@@ -9,7 +9,7 @@ use std::ptr;
use std::slice;
use std::sync::Arc;
-use ssl::error::SslError;
+use error::ErrorStack;
pub struct StreamState<S> {
pub stream: S,
@@ -39,7 +39,7 @@ impl BioMethod {
unsafe impl Send for BioMethod {}
-pub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, Arc<BioMethod>), SslError> {
+pub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, Arc<BioMethod>), ErrorStack> {
let method = Arc::new(BioMethod::new::<S>());
let state = Box::new(StreamState {
diff --git a/openssl/src/ssl/error.rs b/openssl/src/ssl/error.rs
index 2459a473..95213361 100644
--- a/openssl/src/ssl/error.rs
+++ b/openssl/src/ssl/error.rs
@@ -1,15 +1,8 @@
-pub use self::SslError::*;
-pub use self::OpensslError::*;
-
-use libc::c_ulong;
use std::error;
use std::error::Error as StdError;
use std::fmt;
-use std::ffi::CStr;
use std::io;
-use std::str;
-
-use ffi;
+use error::ErrorStack;
/// An SSL error.
#[derive(Debug)]
@@ -27,30 +20,16 @@ pub enum Error {
/// An error reported by the underlying stream.
Stream(io::Error),
/// An error in the OpenSSL library.
- Ssl(Vec<OpenSslError>),
+ Ssl(ErrorStack),
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
try!(fmt.write_str(self.description()));
- match *self {
- Error::Stream(ref err) => write!(fmt, ": {}", err),
- Error::WantRead(ref err) => write!(fmt, ": {}", err),
- Error::WantWrite(ref err) => write!(fmt, ": {}", err),
- Error::Ssl(ref errs) => {
- let mut first = true;
- for err in errs {
- if first {
- try!(fmt.write_str(": "));
- first = false;
- } else {
- try!(fmt.write_str(", "));
- }
- try!(fmt.write_str(&err.reason()))
- }
- Ok(())
- }
- _ => Ok(()),
+ if let Some(err) = self.cause() {
+ write!(fmt, ": {}", err)
+ } else {
+ Ok(())
}
}
}
@@ -72,247 +51,14 @@ impl error::Error for Error {
Error::WantRead(ref err) => Some(err),
Error::WantWrite(ref err) => Some(err),
Error::Stream(ref err) => Some(err),
+ Error::Ssl(ref err) => Some(err),
_ => None,
}
}
}
-/// An error reported from OpenSSL.
-pub struct OpenSslError(c_ulong);
-
-impl OpenSslError {
- /// Returns the contents of the OpenSSL error stack.
- pub fn get_stack() -> Vec<OpenSslError> {
- ffi::init();
-
- let mut errs = vec![];
- loop {
- match unsafe { ffi::ERR_get_error() } {
- 0 => break,
- err => errs.push(OpenSslError(err)),
- }
- }
- errs
- }
-
- /// Returns the raw OpenSSL error code for this error.
- pub fn error_code(&self) -> c_ulong {
- self.0
- }
-
- /// Returns the name of the library reporting the error.
- pub fn library(&self) -> &'static str {
- get_lib(self.0)
- }
-
- /// Returns the name of the function reporting the error.
- pub fn function(&self) -> &'static str {
- get_func(self.0)
- }
-
- /// Returns the reason for the error.
- pub fn reason(&self) -> &'static str {
- get_reason(self.0)
- }
-}
-
-impl fmt::Debug for OpenSslError {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- fmt.debug_struct("OpenSslError")
- .field("library", &self.library())
- .field("function", &self.function())
- .field("reason", &self.reason())
- .finish()
- }
-}
-
-impl fmt::Display for OpenSslError {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- fmt.write_str(&self.reason())
- }
-}
-
-impl error::Error for OpenSslError {
- fn description(&self) -> &str {
- "An OpenSSL error"
- }
-}
-
-/// An SSL error
-#[derive(Debug)]
-pub enum SslError {
- /// The underlying stream reported an error
- StreamError(io::Error),
- /// The SSL session has been closed by the other end
- SslSessionClosed,
- /// An error in the OpenSSL library
- OpenSslErrors(Vec<OpensslError>),
-}
-
-/// An error on a nonblocking stream.
-#[derive(Debug)]
-pub enum NonblockingSslError {
- /// A standard SSL error occurred.
- SslError(SslError),
- /// The OpenSSL library wants data from the remote socket;
- /// the caller should wait for read readiness.
- WantRead,
- /// The OpenSSL library wants to send data to the remote socket;
- /// the caller should wait for write readiness.
- WantWrite,
-}
-
-impl fmt::Display for SslError {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- try!(fmt.write_str(error::Error::description(self)));
- if let OpenSslErrors(ref errs) = *self {
- let mut first = true;
- for err in errs {
- if first {
- try!(fmt.write_str(": "));
- first = false;
- } else {
- try!(fmt.write_str(", "));
- }
- match *err {
- UnknownError { ref reason, .. } => try!(fmt.write_str(reason)),
- }
- }
- }
-
- Ok(())
- }
-}
-
-impl error::Error for SslError {
- fn description(&self) -> &str {
- match *self {
- StreamError(_) => "The underlying stream reported an error",
- SslSessionClosed => "The SSL session has been closed by the other end",
- OpenSslErrors(_) => "An error in the OpenSSL library",
- }
+impl From<ErrorStack> for Error {
+ fn from(e: ErrorStack) -> Error {
+ Error::Ssl(e)
}
-
- fn cause(&self) -> Option<&error::Error> {
- match *self {
- StreamError(ref err) => Some(err as &error::Error),
- _ => None,
- }
- }
-}
-
-impl fmt::Display for NonblockingSslError {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- fmt.write_str(error::Error::description(self))
- }
-}
-
-impl error::Error for NonblockingSslError {
- fn description(&self) -> &str {
- match *self {
- NonblockingSslError::SslError(ref e) => e.description(),
- NonblockingSslError::WantRead => {
- "The OpenSSL library wants data from the remote socket"
- }
- NonblockingSslError::WantWrite => {
- "The OpenSSL library want to send data to the remote socket"
- }
- }
- }
-
- fn cause(&self) -> Option<&error::Error> {
- match *self {
- NonblockingSslError::SslError(ref e) => e.cause(),
- _ => None,
- }
- }
-}
-
-impl From<SslError> for NonblockingSslError {
- fn from(e: SslError) -> NonblockingSslError {
- NonblockingSslError::SslError(e)
- }
-}
-
-/// An error from the OpenSSL library
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum OpensslError {
- /// An unknown error
- UnknownError {
- /// The library reporting the error
- library: String,
- /// The function reporting the error
- function: String,
- /// The reason for the error
- reason: String,
- },
-}
-
-impl OpensslError {
- pub fn from_error_code(err: c_ulong) -> OpensslError {
- ffi::init();
- UnknownError {
- library: get_lib(err).to_owned(),
- function: get_func(err).to_owned(),
- reason: get_reason(err).to_owned(),
- }
- }
-}
-
-fn get_lib(err: c_ulong) -> &'static str {
- unsafe {
- let cstr = ffi::ERR_lib_error_string(err);
- let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
- str::from_utf8(bytes).unwrap()
- }
-}
-
-fn get_func(err: c_ulong) -> &'static str {
- unsafe {
- let cstr = ffi::ERR_func_error_string(err);
- let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
- str::from_utf8(bytes).unwrap()
- }
-}
-
-fn get_reason(err: c_ulong) -> &'static str {
- unsafe {
- let cstr = ffi::ERR_reason_error_string(err);
- let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
- str::from_utf8(bytes).unwrap()
- }
-}
-
-impl SslError {
- /// Creates a new `OpenSslErrors` with the current contents of the error
- /// stack.
- pub fn get() -> SslError {
- let mut errs = vec![];
- loop {
- match unsafe { ffi::ERR_get_error() } {
- 0 => break,
- err => errs.push(OpensslError::from_error_code(err)),
- }
- }
- OpenSslErrors(errs)
- }
-
- /// Creates an `SslError` from the raw numeric error code.
- pub fn from_error(err: c_ulong) -> SslError {
- OpenSslErrors(vec![OpensslError::from_error_code(err)])
- }
-}
-
-#[test]
-fn test_uknown_error_should_have_correct_messages() {
- let errs = match SslError::from_error(336032784) {
- OpenSslErrors(errs) => errs,
- _ => panic!("This should always be an `OpenSslErrors` variant."),
- };
-
- let UnknownError { ref library, ref function, ref reason } = errs[0];
-
- assert_eq!(&library[..], "SSL routines");
- assert_eq!(&function[..], "SSL23_GET_SERVER_HELLO");
- assert_eq!(&reason[..], "sslv3 alert handshake failure");
}
diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs
index 0252b114..3d1ec6e5 100644
--- a/openssl/src/ssl/mod.rs
+++ b/openssl/src/ssl/mod.rs
@@ -5,9 +5,9 @@ use std::ffi::{CStr, CString};
use std::fmt;
use std::io;
use std::io::prelude::*;
+use std::error as stderror;
use std::mem;
use std::str;
-use std::net;
use std::path::Path;
use std::ptr;
use std::sync::{Once, ONCE_INIT, Mutex, Arc};
@@ -18,17 +18,13 @@ use libc::{c_uchar, c_uint};
#[cfg(any(feature = "npn", feature = "alpn"))]
use std::slice;
use std::marker::PhantomData;
-#[cfg(unix)]
-use std::os::unix::io::{AsRawFd, RawFd};
-#[cfg(windows)]
-use std::os::windows::io::{AsRawSocket, RawSocket};
use ffi;
use ffi_extras;
use dh::DH;
-use ssl::error::{NonblockingSslError, SslError, OpenSslError, OpensslError};
use x509::{X509StoreContext, X509FileType, X509};
use crypto::pkey::PKey;
+use error::ErrorStack;
pub mod error;
mod bio;
@@ -45,27 +41,11 @@ extern "C" {
fn rust_SSL_CTX_clone(cxt: *mut ffi::SSL_CTX);
}
-static mut VERIFY_IDX: c_int = -1;
-static mut SNI_IDX: c_int = -1;
-
/// Manually initialize SSL.
/// It is optional to call this function and safe to do so more than once.
pub fn init() {
static mut INIT: Once = ONCE_INIT;
-
- unsafe {
- INIT.call_once(|| {
- ffi::init();
-
- let verify_idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, None);
- assert!(verify_idx >= 0);
- VERIFY_IDX = verify_idx;
-
- let sni_idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, None);
- assert!(sni_idx >= 0);
- SNI_IDX = sni_idx;
- });
- }
+ unsafe { INIT.call_once(|| ffi::init()); }
}
bitflags! {
@@ -186,30 +166,6 @@ impl SslMethod {
_ => None,
}
}
-
- #[cfg(feature = "dtlsv1")]
- pub fn is_dtlsv1(&self) -> bool {
- *self == SslMethod::Dtlsv1
- }
-
- #[cfg(feature = "dtlsv1_2")]
- pub fn is_dtlsv1_2(&self) -> bool {
- *self == SslMethod::Dtlsv1_2
- }
-
- pub fn is_dtls(&self) -> bool {
- self.is_dtlsv1() || self.is_dtlsv1_2()
- }
-
- #[cfg(not(feature = "dtlsv1"))]
- pub fn is_dtlsv1(&self) -> bool {
- false
- }
-
- #[cfg(not(feature = "dtlsv1_2"))]
- pub fn is_dtlsv1_2(&self) -> bool {
- false
- }
}
/// Determines the type of certificate verification used
@@ -292,47 +248,19 @@ fn get_new_ssl_idx<T>() -> c_int {
}
}
-extern "C" fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int {
- unsafe {
- let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx();
- let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx);
- let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
- let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, VERIFY_IDX);
- let verify: Option<VerifyCallback> = mem::transmute(verify);
-
- let ctx = X509StoreContext::new(x509_ctx);
-
- match verify {
- None => preverify_ok,
- Some(verify) => verify(preverify_ok != 0, &ctx) as c_int,
- }
- }
-}
-
-extern "C" fn raw_verify_with_data<T>(preverify_ok: c_int,
- x509_ctx: *mut ffi::X509_STORE_CTX)
- -> c_int
- where T: Any + 'static
+extern "C" fn raw_verify<F>(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int
+ where F: Fn(bool, &X509StoreContext) -> bool + Any + 'static + Sync + Send
{
unsafe {
let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx();
let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx);
let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
-
- let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, VERIFY_IDX);
- let verify: Option<VerifyCallbackData<T>> = mem::transmute(verify);
-
- let data = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::<T>());
- let data: &T = mem::transmute(data);
+ let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::<F>());
+ let verify: &F = mem::transmute(verify);
let ctx = X509StoreContext::new(x509_ctx);
- let res = match verify {
- None => preverify_ok,
- Some(verify) => verify(preverify_ok != 0, &ctx, data) as c_int,
- };
-
- res
+ verify(preverify_ok != 0, &ctx) as c_int
}
}
@@ -351,50 +279,31 @@ extern "C" fn ssl_raw_verify<F>(preverify_ok: c_int, x509_ctx: *mut ffi::X509_ST
}
}
-extern "C" fn raw_sni(ssl: *mut ffi::SSL, ad: &mut c_int, _arg: *mut c_void) -> c_int {
- unsafe {
- let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
- let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, SNI_IDX);
- let callback: Option<ServerNameCallback> = mem::transmute(callback);
- rust_SSL_clone(ssl);
- let mut s = Ssl { ssl: ssl };
-
- let res = match callback {
- None => ffi::SSL_TLSEXT_ERR_ALERT_FATAL,
- Some(callback) => callback(&mut s, ad),
- };
-
- res
- }
-}
-
-extern "C" fn raw_sni_with_data<T>(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_void) -> c_int
- where T: Any + 'static
+extern "C" fn raw_sni<F>(ssl: *mut ffi::SSL, al: *mut c_int, _arg: *mut c_void) -> c_int
+ where F: Fn(&mut Ssl) -> Result<(), SniError> + Any + 'static + Sync + Send
{
unsafe {
let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
-
- let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, SNI_IDX);
- let callback: Option<ServerNameCallbackData<T>> = mem::transmute(callback);
+ let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::<F>());
+ let callback: &F = mem::transmute(callback);
rust_SSL_clone(ssl);
- let mut s = Ssl { ssl: ssl };
-
- let data: &T = mem::transmute(arg);
-
- let res = match callback {
- None => ffi::SSL_TLSEXT_ERR_ALERT_FATAL,
- Some(callback) => callback(&mut s, ad, &*data),
- };
+ let mut ssl = Ssl { ssl: ssl };
- // Since data might be required on the next verification
- // it is time to forget about it and avoid dropping
- // data will be freed once OpenSSL considers it is time
- // to free all context data
- res
+ match callback(&mut ssl) {
+ Ok(()) => ffi::SSL_TLSEXT_ERR_OK,
+ Err(SniError::Fatal(e)) => {
+ *al = e;
+ ffi::SSL_TLSEXT_ERR_ALERT_FATAL
+ }
+ Err(SniError::Warning(e)) => {
+ *al = e;
+ ffi::SSL_TLSEXT_ERR_ALERT_WARNING
+ }
+ Err(SniError::NoAck) => ffi::SSL_TLSEXT_ERR_NOACK,
+ }
}
}
-
#[cfg(any(feature = "npn", feature = "alpn"))]
unsafe fn select_proto_using(ssl: *mut ffi::SSL,
out: *mut *mut c_uchar,
@@ -499,24 +408,18 @@ fn ssl_encode_byte_strings(strings: &[&[u8]]) -> Vec<u8> {
enc
}
-/// The signature of functions that can be used to manually verify certificates
-pub type VerifyCallback = fn(preverify_ok: bool, x509_ctx: &X509StoreContext) -> bool;
-
-/// The signature of functions that can be used to manually verify certificates
-/// when user-data should be carried for all verification process
-pub type VerifyCallbackData<T> = fn(preverify_ok: bool, x509_ctx: &X509StoreContext, data: &T)
- -> bool;
-
-/// The signature of functions that can be used to choose the context depending on the server name
-pub type ServerNameCallback = fn(ssl: &mut Ssl, ad: &mut i32) -> i32;
-
-pub type ServerNameCallbackData<T> = fn(ssl: &mut Ssl, ad: &mut i32, data: &T) -> i32;
+/// An error returned from an SNI callback.
+pub enum SniError {
+ Fatal(c_int),
+ Warning(c_int),
+ NoAck,
+}
// FIXME: macro may be instead of inlining?
#[inline]
-fn wrap_ssl_result(res: c_int) -> Result<(), SslError> {
+fn wrap_ssl_result(res: c_int) -> Result<(), ErrorStack> {
if res == 0 {
- Err(SslError::get())
+ Err(ErrorStack::get())
} else {
Ok(())
}
@@ -559,80 +462,56 @@ impl SslContext {
}
/// Creates a new SSL context.
- pub fn new(method: SslMethod) -> Result<SslContext, SslError> {
+ pub fn new(method: SslMethod) -> Result<SslContext, ErrorStack> {
init();
let ctx = try_ssl_null!(unsafe { ffi::SSL_CTX_new(method.to_raw()) });
- let ctx = SslContext { ctx: ctx };
+ let mut ctx = SslContext { ctx: ctx };
+ match method {
+ #[cfg(feature = "dtlsv1")]
+ SslMethod::Dtlsv1 => ctx.set_read_ahead(1),
+ #[cfg(feature = "dtlsv1_2")]
+ SslMethod::Dtlsv1_2 => ctx.set_read_ahead(1),
+ _ => {}
+ }
// this is a bit dubious (?)
try!(ctx.set_mode(ffi::SSL_MODE_AUTO_RETRY | ffi::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER));
- if method.is_dtls() {
- ctx.set_read_ahead(1);
- }
-
Ok(ctx)
}
/// Configures the certificate verification method for new connections.
- pub fn set_verify(&mut self, mode: SslVerifyMode, verify: Option<VerifyCallback>) {
+ pub fn set_verify(&mut self, mode: SslVerifyMode) {
unsafe {
- ffi::SSL_CTX_set_ex_data(self.ctx, VERIFY_IDX, mem::transmute(verify));
- let f: extern "C" fn(c_int, *mut ffi::X509_STORE_CTX) -> c_int = raw_verify;
-
- ffi::SSL_CTX_set_verify(self.ctx, mode.bits as c_int, Some(f));
+ ffi::SSL_CTX_set_verify(self.ctx, mode.bits as c_int, None);
}
}
- /// Configures the certificate verification method for new connections also
- /// carrying supplied data.
- // Note: no option because there is no point to set data without providing
- // a function handling it
- pub fn set_verify_with_data<T>(&mut self,
- mode: SslVerifyMode,
- verify: VerifyCallbackData<T>,
- data: T)
- where T: Any + 'static
+ /// Configures the certificate verification method for new connections and
+ /// registers a verification callback.
+ pub fn set_verify_callback<F>(&mut self, mode: SslVerifyMode, verify: F)
+ where F: Fn(bool, &X509StoreContext) -> bool + Any + 'static + Sync + Send
{
- let data = Box::new(data);
unsafe {
- ffi::SSL_CTX_set_ex_data(self.ctx, VERIFY_IDX, mem::transmute(Some(verify)));
- ffi::SSL_CTX_set_ex_data(self.ctx, get_verify_data_idx::<T>(), mem::transmute(data));
- let f: extern "C" fn(c_int, *mut ffi::X509_STORE_CTX) -> c_int =
- raw_verify_with_data::<T>;
-
- ffi::SSL_CTX_set_verify(self.ctx, mode.bits as c_int, Some(f));
+ let verify = Box::new(verify);
+ ffi::SSL_CTX_set_ex_data(self.ctx, get_verify_data_idx::<F>(), mem::transmute(verify));
+ ffi::SSL_CTX_set_verify(self.ctx, mode.bits as c_int, Some(raw_verify::<F>));
}
}
/// Configures the server name indication (SNI) callback for new connections
///
- /// obtain the server name with `get_servername` then set the corresponding context
+ /// Obtain the server name with `servername` then set the corresponding context
/// with `set_ssl_context`
- pub fn set_servername_callback(&mut self, callback: Option<ServerNameCallback>) {
- unsafe {
- ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX, mem::transmute(callback));
- let f: extern "C" fn(_, _, _) -> _ = raw_sni;
- let f: extern "C" fn() = mem::transmute(f);
- ffi_extras::SSL_CTX_set_tlsext_servername_callback(self.ctx, Some(f));
- }
- }
-
- /// Configures the server name indication (SNI) callback for new connections
- /// carrying supplied data
- pub fn set_servername_callback_with_data<T>(&mut self,
- callback: ServerNameCallbackData<T>,
- data: T)
- where T: Any + 'static
+ pub fn set_servername_callback<F>(&mut self, callback: F)
+ where F: Fn(&mut Ssl) -> Result<(), SniError> + Any + 'static + Sync + Send
{
- let data = Box::new(data);
unsafe {
- ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX, mem::transmute(Some(callback)));
-
- ffi_extras::SSL_CTX_set_tlsext_servername_arg(self.ctx, mem::transmute(data));
- let f: extern "C" fn(_, _, _) -> _ = raw_sni_with_data::<T>;
+ let callback = Box::new(callback);
+ ffi::SSL_CTX_set_ex_data(self.ctx, get_verify_data_idx::<F>(), mem::transmute(callback));
+ let f: extern "C" fn(_, _, _) -> _ = raw_sni::<F>;
let f: extern "C" fn() = mem::transmute(f);
ffi_extras::SSL_CTX_set_tlsext_servername_callback(self.ctx, Some(f));
}
@@ -645,18 +524,18 @@ impl SslContext {
}
}
- pub fn set_read_ahead(&self, m: u32) {
+ pub fn set_read_ahead(&mut self, m: u32) {
unsafe {
ffi_extras::SSL_CTX_set_read_ahead(self.ctx, m as c_long);
}
}
- fn set_mode(&self, mode: c_long) -> Result<(), SslError> {
+ fn set_mode(&mut self, mode: c_long) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe { ffi_extras::SSL_CTX_set_mode(self.ctx, mode) as c_int })
}
- pub fn set_tmp_dh(&self, dh: DH) -> Result<(), SslError> {
- wrap_ssl_result(unsafe { ffi_extras::SSL_CTX_set_tmp_dh(self.ctx, dh.raw()) as c_int })
+ pub fn set_tmp_dh(&mut self, dh: DH) -> Result<(), ErrorStack> {
+ wrap_ssl_result(unsafe { ffi_extras::SSL_CTX_set_tmp_dh(self.ctx, dh.raw()) as i32 })
}
/// Use the default locations of trusted certificates for verification.
@@ -664,13 +543,13 @@ impl SslContext {
/// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR`
/// environment variables if present, or defaults specified at OpenSSL
/// build time otherwise.
- pub fn set_default_verify_paths(&mut self) -> Result<(), SslError> {
+ pub fn set_default_verify_paths(&mut self) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe { ffi::SSL_CTX_set_default_verify_paths(self.ctx) })
}
#[allow(non_snake_case)]
/// Specifies the file that contains trusted CA certificates.
- pub fn set_CA_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(), SslError> {
+ pub fn set_CA_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(), ErrorStack> {
let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
wrap_ssl_result(unsafe {
ffi::SSL_CTX_load_verify_locations(self.ctx, file.as_ptr() as *const _, ptr::null())
@@ -685,7 +564,7 @@ impl SslContext {
///
/// This value should be set when using client certificates, or each request will fail
/// handshake and need to be restarted.
- pub fn set_session_id_context(&mut self, sid_ctx: &[u8]) -> Result<(), SslError> {
+ pub fn set_session_id_context(&mut self, sid_ctx: &[u8]) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe {
ffi::SSL_CTX_set_session_id_context(self.ctx, sid_ctx.as_ptr(), sid_ctx.len() as u32)
})
@@ -695,7 +574,7 @@ impl SslContext {
pub fn set_certificate_file<P: AsRef<Path>>(&mut self,
file: P,
file_type: X509FileType)
- -> Result<(), SslError> {
+ -> Result<(), ErrorStack> {
let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
wrap_ssl_result(unsafe {
ffi::SSL_CTX_use_certificate_file(self.ctx,
@@ -708,7 +587,7 @@ impl SslContext {
pub fn set_certificate_chain_file<P: AsRef<Path>>(&mut self,
file: P,
file_type: X509FileType)
- -> Result<(), SslError> {
+ -> Result<(), ErrorStack> {
let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
wrap_ssl_result(unsafe {
ffi::SSL_CTX_use_certificate_chain_file(self.ctx,
@@ -718,13 +597,13 @@ impl SslContext {
}
/// Specifies the certificate
- pub fn set_certificate(&mut self, cert: &X509) -> Result<(), SslError> {
+ pub fn set_certificate(&mut self, cert: &X509) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe { ffi::SSL_CTX_use_certificate(self.ctx, cert.get_handle()) })
}
/// Adds a certificate to the certificate chain presented together with the
/// certificate specified using set_certificate()
- pub fn add_extra_chain_cert(&mut self, cert: &X509) -> Result<(), SslError> {
+ pub fn add_extra_chain_cert(&mut self, cert: &X509) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe {
ffi_extras::SSL_CTX_add_extra_chain_cert(self.ctx, cert.get_handle()) as c_int
})
@@ -734,7 +613,7 @@ impl SslContext {
pub fn set_private_key_file<P: AsRef<Path>>(&mut self,
file: P,
file_type: X509FileType)
- -> Result<(), SslError> {
+ -> Result<(), ErrorStack> {
let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
wrap_ssl_result(unsafe {
ffi::SSL_CTX_use_PrivateKey_file(self.ctx,
@@ -744,16 +623,16 @@ impl SslContext {
}
/// Specifies the private key
- pub fn set_private_key(&mut self, key: &PKey) -> Result<(), SslError> {
+ pub fn set_private_key(&mut self, key: &PKey) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe { ffi::SSL_CTX_use_PrivateKey(self.ctx, key.get_handle()) })
}
/// Check consistency of private key and certificate
- pub fn check_private_key(&mut self) -> Result<(), SslError> {
+ pub fn check_private_key(&mut self) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe { ffi::SSL_CTX_check_private_key(self.ctx) })
}
- pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), SslError> {
+ pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe {
let cipher_list = CString::new(cipher_list).unwrap();
ffi::SSL_CTX_set_cipher_list(self.ctx, cipher_list.as_ptr() as *const _)
@@ -765,7 +644,7 @@ impl SslContext {
///
/// This method requires OpenSSL >= 1.0.2 or LibreSSL and the `ecdh_auto` feature.
#[cfg(feature = "ecdh_auto")]
- pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), SslError> {
+ pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe { ffi_extras::SSL_CTX_set_ecdh_auto(self.ctx, onoff as c_int) })
}
@@ -775,7 +654,7 @@ impl SslContext {
SslContextOptions::from_bits(ret).unwrap()
}
- pub fn get_options(&mut self) -> SslContextOptions {
+ pub fn options(&self) -> SslContextOptions {
let ret = unsafe { ffi_extras::SSL_CTX_get_options(self.ctx) };
SslContextOptions::from_bits(ret).unwrap()
}
@@ -935,17 +814,8 @@ impl Drop for Ssl {
}
}
-impl Clone for Ssl {
- /// # Deprecated
- fn clone(&self) -> Ssl {
- unsafe { rust_SSL_clone(self.ssl) };
- Ssl { ssl: self.ssl }
-
- }
-}
-
impl Ssl {
- pub fn new(ctx: &SslContext) -> Result<Ssl, SslError> {
+ pub fn new(ctx: &SslContext) -> Result<Ssl, ErrorStack> {
let ssl = try_ssl_null!(unsafe { ffi::SSL_new(ctx.ctx) });
let ssl = Ssl { ssl: ssl };
Ok(ssl)
@@ -963,6 +833,10 @@ impl Ssl {
unsafe { ffi::SSL_accept(self.ssl) }
}
+ fn handshake(&self) -> c_int {
+ unsafe { ffi::SSL_do_handshake(self.ssl) }
+ }
+
fn read(&self, buf: &mut [u8]) -> c_int {
let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
unsafe { ffi::SSL_read(self.ssl, buf.as_ptr() as *mut c_void, len) }
@@ -973,12 +847,8 @@ impl Ssl {
unsafe { ffi::SSL_write(self.ssl, buf.as_ptr() as *const c_void, len) }
}
- fn get_error(&self, ret: c_int) -> LibSslError {
- let err = unsafe { ffi::SSL_get_error(self.ssl, ret) };
- match LibSslError::from_i32(err as i32) {
- Some(err) => err,
- None => unreachable!(),
- }
+ fn get_error(&self, ret: c_int) -> c_int {
+ unsafe { ffi::SSL_get_error(self.ssl, ret) }
}
/// Sets the verification mode to be used during the handshake process.
@@ -1007,7 +877,7 @@ impl Ssl {
}
}
- pub fn get_current_cipher<'a>(&'a self) -> Option<SslCipher<'a>> {
+ pub fn current_cipher<'a>(&'a self) -> Option<SslCipher<'a>> {
unsafe {
let ptr = ffi::SSL_get_current_cipher(self.ssl);
@@ -1041,7 +911,7 @@ impl Ssl {
}
/// Sets the host name to be used with SNI (Server Name Indication).
- pub fn set_hostname(&self, hostname: &str) -> Result<(), SslError> {
+ pub fn set_hostname(&self, hostname: &str) -> Result<(), ErrorStack> {
let cstr = CString::new(hostname).unwrap();
let ret = unsafe {
ffi_extras::SSL_set_tlsext_host_name(self.ssl, cstr.as_ptr() as *const _)
@@ -1049,7 +919,7 @@ impl Ssl {
// For this case, 0 indicates failure.
if ret == 0 {
- Err(SslError::get())
+ Err(ErrorStack::get())
} else {
Ok(())
}
@@ -1147,7 +1017,7 @@ impl Ssl {
Some(s)
}
- pub fn get_ssl_method(&self) -> Option<SslMethod> {
+ pub fn ssl_method(&self) -> Option<SslMethod> {
unsafe {
let method = ffi::SSL_get_ssl_method(self.ssl);
SslMethod::from_raw(method)
@@ -1155,7 +1025,7 @@ impl Ssl {
}
/// Returns the server's name for the current connection
- pub fn get_servername(&self) -> Option<String> {
+ pub fn servername(&self) -> Option<String> {
let name = unsafe { ffi::SSL_get_servername(self.ssl, ffi::TLSEXT_NAMETYPE_host_name) };
if name == ptr::null() {
return None;
@@ -1164,63 +1034,23 @@ impl Ssl {
unsafe { String::from_utf8(CStr::from_ptr(name as *const _).to_bytes().to_vec()).ok() }
}
- /// change the context corresponding to the current connection
- ///
- /// Returns a clone of the SslContext @ctx (ie: the new context). The old context is freed.
- pub fn set_ssl_context(&self, ctx: &SslContext) -> SslContext {
- // If duplication of @ctx's cert fails, this returns NULL. This _appears_ to only occur on
- // allocation failures (meaning panicing is probably appropriate), but it might be nice to
- // propogate the error.
- assert!(unsafe { ffi::SSL_set_SSL_CTX(self.ssl, ctx.ctx) } != ptr::null_mut());
-
- // FIXME: we return this reference here for compatibility, but it isn't actually required.
- // This should be removed when a api-incompatabile version is to be released.
- //
- // ffi:SSL_set_SSL_CTX() returns copy of the ctx pointer passed to it, so it's easier for
- // us to do the clone directly.
- ctx.clone()
- }
-
- /// obtain the context corresponding to the current connection
- pub fn get_ssl_context(&self) -> SslContext {
+ /// Changes the context corresponding to the current connection.
+ pub fn set_ssl_context(&self, ctx: &SslContext) -> Result<(), ErrorStack> {
unsafe {
- let ssl_ctx = ffi::SSL_get_SSL_CTX(self.ssl);
- SslContext::new_ref(ssl_ctx)
+ try_ssl_null!(ffi::SSL_set_SSL_CTX(self.ssl, ctx.ctx));
}
+ Ok(())
}
-}
-macro_rules! make_LibSslError {
- ($($variant:ident = $value:ident),+) => {
- #[derive(Debug)]
- #[repr(i32)]
- enum LibSslError {
- $($variant = ffi::$value),+
- }
-
- impl LibSslError {
- fn from_i32(val: i32) -> Option<LibSslError> {
- match val {
- $(ffi::$value => Some(LibSslError::$variant),)+
- _ => None
- }
- }
+ /// Returns the context corresponding to the current connection
+ pub fn ssl_context(&self) -> SslContext {
+ unsafe {
+ let ssl_ctx = ffi::SSL_get_SSL_CTX(self.ssl);
+ SslContext::new_ref(ssl_ctx)
}
}
}
-make_LibSslError! {
- ErrorNone = SSL_ERROR_NONE,
- ErrorSsl = SSL_ERROR_SSL,
- ErrorWantRead = SSL_ERROR_WANT_READ,
- ErrorWantWrite = SSL_ERROR_WANT_WRITE,
- ErrorWantX509Lookup = SSL_ERROR_WANT_X509_LOOKUP,
- ErrorSyscall = SSL_ERROR_SYSCALL,
- ErrorZeroReturn = SSL_ERROR_ZERO_RETURN,
- ErrorWantConnect = SSL_ERROR_WANT_CONNECT,
- ErrorWantAccept = SSL_ERROR_WANT_ACCEPT
-}
-
/// A stream wrapper which handles SSL encryption for an underlying stream.
pub struct SslStream<S> {
ssl: Ssl,
@@ -1228,19 +1058,7 @@ pub struct SslStream<S> {
_p: PhantomData<S>,
}
-/// # Deprecated
-///
-/// This method does not behave as expected and will be removed in a future
-/// release.
-impl<S: Clone + Read + Write> Clone for SslStream<S> {
- fn clone(&self) -> SslStream<S> {
- SslStream {
- ssl: self.ssl.clone(),
- _method: self._method.clone(),
- _p: PhantomData,
- }
- }
-}
+unsafe impl<S: Send> Send for SslStream<S> {}
impl<S> fmt::Debug for SslStream<S>
where S: fmt::Debug
@@ -1253,20 +1071,6 @@ impl<S> fmt::Debug for SslStream<S>
}
}
-#[cfg(unix)]
-impl<S: AsRawFd> AsRawFd for SslStream<S> {
- fn as_raw_fd(&self) -> RawFd {
- self.get_ref().as_raw_fd()
- }
-}
-
-#[cfg(windows)]
-impl<S: AsRawSocket> AsRawSocket for SslStream<S> {
- fn as_raw_socket(&self) -> RawSocket {
- self.get_ref().as_raw_socket()
- }
-}
-
impl<S: Read + Write> SslStream<S> {
fn new_base(ssl: Ssl, stream: S) -> Self {
unsafe {
@@ -1282,49 +1086,53 @@ impl<S: Read + Write> SslStream<S> {
}
/// Creates an SSL/TLS client operating over the provided stream.
- pub fn connect<T: IntoSsl>(ssl: T, stream: S) -> Result<Self, SslError> {
- let ssl = try!(ssl.into_ssl());
+ pub fn connect<T: IntoSsl>(ssl: T, stream: S)
+ -> Result<Self, HandshakeError<S>>{
+ let ssl = try!(ssl.into_ssl().map_err(|e| {
+ HandshakeError::Failure(Error::Ssl(e))
+ }));
let mut stream = Self::new_base(ssl, stream);
let ret = stream.ssl.connect();
if ret > 0 {
Ok(stream)
} else {
- match stream.make_old_error(ret) {
- Some(err) => Err(err),
- None => Ok(stream),
+ match stream.make_error(ret) {
+ e @ Error::WantWrite(_) |
+ e @ Error::WantRead(_) => {
+ Err(HandshakeError::Interrupted(MidHandshakeSslStream {
+ stream: stream,
+ error: e,
+ }))
+ }
+ err => Err(HandshakeError::Failure(err)),
}
}
}
/// Creates an SSL/TLS server operating over the provided stream.
- pub fn accept<T: IntoSsl>(ssl: T, stream: S) -> Result<Self, SslError> {
- let ssl = try!(ssl.into_ssl());
+ pub fn accept<T: IntoSsl>(ssl: T, stream: S)
+ -> Result<Self, HandshakeError<S>> {
+ let ssl = try!(ssl.into_ssl().map_err(|e| {
+ HandshakeError::Failure(Error::Ssl(e))
+ }));
let mut stream = Self::new_base(ssl, stream);
let ret = stream.ssl.accept();
if ret > 0 {
Ok(stream)
} else {
- match stream.make_old_error(ret) {
- Some(err) => Err(err),
- None => Ok(stream),
+ match stream.make_error(ret) {
+ e @ Error::WantWrite(_) |
+ e @ Error::WantRead(_) => {
+ Err(HandshakeError::Interrupted(MidHandshakeSslStream {
+ stream: stream,
+ error: e,
+ }))
+ }
+ err => Err(HandshakeError::Failure(err)),
}
}
}
- /// ### Deprecated
- ///
- /// Use `connect`.
- pub fn connect_generic<T: IntoSsl>(ssl: T, stream: S) -> Result<SslStream<S>, SslError> {
- Self::connect(ssl, stream)
- }
-
- /// ### Deprecated
- ///
- /// Use `accept`.
- pub fn accept_generic<T: IntoSsl>(ssl: T, stream: S) -> Result<SslStream<S>, SslError> {
- Self::accept(ssl, stream)
- }
-
/// Like `read`, but returns an `ssl::Error` rather than an `io::Error`.
///
/// This is particularly useful with a nonblocking socket, where the error
@@ -1352,63 +1160,112 @@ impl<S: Read + Write> SslStream<S> {
}
}
-impl<S> SslStream<S> {
- fn make_error(&mut self, ret: c_int) -> Error {
- self.check_panic();
+/// An error or intermediate state after a TLS handshake attempt.
+#[derive(Debug)]
+pub enum HandshakeError<S> {
+ /// The handshake failed.
+ Failure(Error),
+ /// The handshake was interrupted midway through.
+ Interrupted(MidHandshakeSslStream<S>),
+}
- match self.ssl.get_error(ret) {
- LibSslError::ErrorSsl => Error::Ssl(OpenSslError::get_stack()),
- LibSslError::ErrorSyscall => {
- let errs = OpenSslError::get_stack();
- if errs.is_empty() {
- if ret == 0 {
- Error::Stream(io::Error::new(io::ErrorKind::ConnectionAborted,
- "unexpected EOF observed"))
- } else {
- Error::Stream(self.get_bio_error())
- }
- } else {
- Error::Ssl(errs)
+impl<S: Any + fmt::Debug> stderror::Error for HandshakeError<S> {
+ fn description(&self) -> &str {
+ match *self {
+ HandshakeError::Failure(ref e) => e.description(),
+ HandshakeError::Interrupted(ref e) => e.error.description(),
+ }
+ }
+
+ fn cause(&self) -> Option<&stderror::Error> {
+ match *self {
+ HandshakeError::Failure(ref e) => Some(e),
+ HandshakeError::Interrupted(ref e) => Some(&e.error),
+ }
+ }
+}
+
+impl<S: Any + fmt::Debug> fmt::Display for HandshakeError<S> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ try!(f.write_str(stderror::Error::description(self)));
+ if let Some(e) = stderror::Error::cause(self) {
+ try!(write!(f, ": {}", e));
+ }
+ Ok(())
+ }
+}
+
+/// An SSL stream midway through the handshake process.
+#[derive(Debug)]
+pub struct MidHandshakeSslStream<S> {
+ stream: SslStream<S>,
+ error: Error,
+}
+
+impl<S> MidHandshakeSslStream<S> {
+ /// Returns a shared reference to the inner stream.
+ pub fn get_ref(&self) -> &S {
+ self.stream.get_ref()
+ }
+
+ /// Returns a mutable reference to the inner stream.
+ pub fn get_mut(&mut self) -> &mut S {
+ self.stream.get_mut()
+ }
+
+ /// Returns a shared reference to the `SslContext` of the stream.
+ pub fn ssl(&self) -> &Ssl {
+ self.stream.ssl()
+ }
+
+ /// Returns the underlying error which interrupted this handshake.
+ pub fn error(&self) -> &Error {
+ &self.error
+ }
+
+ /// Restarts the handshake process.
+ pub fn handshake(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
+ let ret = self.stream.ssl.handshake();
+ if ret > 0 {
+ Ok(self.stream)
+ } else {
+ match self.stream.make_error(ret) {
+ e @ Error::WantWrite(_) |
+ e @ Error::WantRead(_) => {
+ self.error = e;
+ Err(HandshakeError::Interrupted(self))
}
- }
- LibSslError::ErrorZeroReturn => Error::ZeroReturn,
- LibSslError::ErrorWantWrite => Error::WantWrite(self.get_bio_error()),
- LibSslError::ErrorWantRead => Error::WantRead(self.get_bio_error()),
- err => {
- Error::Stream(io::Error::new(io::ErrorKind::Other,
- format!("unexpected error {:?}", err)))
+ err => Err(HandshakeError::Failure(err)),
}
}
}
+}
- fn make_old_error(&mut self, ret: c_int) -> Option<SslError> {
+impl<S> SslStream<S> {
+ fn make_error(&mut self, ret: c_int) -> Error {
self.check_panic();
match self.ssl.get_error(ret) {
- LibSslError::ErrorSsl => Some(SslError::get()),
- LibSslError::ErrorSyscall => {
- let err = SslError::get();
- let count = match err {
- SslError::OpenSslErrors(ref v) => v.len(),
- _ => unreachable!(),
- };
- if count == 0 {
+ ffi::SSL_ERROR_SSL => Error::Ssl(ErrorStack::get()),
+ ffi::SSL_ERROR_SYSCALL => {
+ let errs = ErrorStack::get();
+ if errs.errors().is_empty() {
if ret == 0 {
- Some(SslError::StreamError(io::Error::new(io::ErrorKind::ConnectionAborted,
- "unexpected EOF observed")))
+ Error::Stream(io::Error::new(io::ErrorKind::ConnectionAborted,
+ "unexpected EOF observed"))
} else {
- Some(SslError::StreamError(self.get_bio_error()))
+ Error::Stream(self.get_bio_error())
}
} else {
- Some(err)
+ Error::Ssl(errs)
}
}
- LibSslError::ErrorZeroReturn => Some(SslError::SslSessionClosed),
- LibSslError::ErrorWantWrite |
- LibSslError::ErrorWantRead => None,
+ ffi::SSL_ERROR_ZERO_RETURN => Error::ZeroReturn,
+ ffi::SSL_ERROR_WANT_WRITE => Error::WantWrite(self.get_bio_error()),
+ ffi::SSL_ERROR_WANT_READ => Error::WantRead(self.get_bio_error()),
err => {
- Some(SslError::StreamError(io::Error::new(io::ErrorKind::Other,
- format!("unexpected error {:?}", err))))
+ Error::Stream(io::Error::new(io::ErrorKind::InvalidData,
+ format!("unexpected error {}", err)))
}
}
}
@@ -1461,20 +1318,6 @@ impl<S> SslStream<S> {
}
}
-impl SslStream<::std::net::TcpStream> {
- /// # Deprecated
- ///
- /// This method does not behave as expected and will be removed in a future
- /// release.
- pub fn try_clone(&self) -> io::Result<SslStream<::std::net::TcpStream>> {
- Ok(SslStream {
- ssl: self.ssl.clone(),
- _method: self._method.clone(),
- _p: PhantomData,
- })
- }
-}
-
impl<S: Read + Write> Read for SslStream<S> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self.ssl_read(buf) {
@@ -1506,222 +1349,17 @@ impl<S: Read + Write> Write for SslStream<S> {
}
pub trait IntoSsl {
- fn into_ssl(self) -> Result<Ssl, SslError>;
+ fn into_ssl(self) -> Result<Ssl, ErrorStack>;
}
impl IntoSsl for Ssl {
- fn into_ssl(self) -> Result<Ssl, SslError> {
+ fn into_ssl(self) -> Result<Ssl, ErrorStack> {
Ok(self)
}
}
impl<'a> IntoSsl for &'a SslContext {
- fn into_ssl(self) -> Result<Ssl, SslError> {
+ fn into_ssl(self) -> Result<Ssl, ErrorStack> {
Ssl::new(self)
}
}
-
-/// A utility type to help in cases where the use of SSL is decided at runtime.
-#[derive(Debug)]
-pub enum MaybeSslStream<S>
- where S: Read + Write
-{
- /// A connection using SSL
- Ssl(SslStream<S>),
- /// A connection not using SSL
- Normal(S),
-}
-
-impl<S> Read for MaybeSslStream<S>
- where S: Read + Write
-{
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- match *self {
- MaybeSslStream::Ssl(ref mut s) => s.read(buf),
- MaybeSslStream::Normal(ref mut s) => s.read(buf),
- }
- }
-}
-
-impl<S> Write for MaybeSslStream<S>
- where S: Read + Write
-{
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- match *self {
- MaybeSslStream::Ssl(ref mut s) => s.write(buf),
- MaybeSslStream::Normal(ref mut s) => s.write(buf),
- }
- }
-
- fn flush(&mut self) -> io::Result<()> {
- match *self {
- MaybeSslStream::Ssl(ref mut s) => s.flush(),
- MaybeSslStream::Normal(ref mut s) => s.flush(),
- }
- }
-}
-
-impl<S> MaybeSslStream<S>
- where S: Read + Write
-{
- /// Returns a reference to the underlying stream.
- pub fn get_ref(&self) -> &S {
- match *self {
- MaybeSslStream::Ssl(ref s) => s.get_ref(),
- MaybeSslStream::Normal(ref s) => s,
- }
- }
-
- /// Returns a mutable reference to the underlying stream.
- ///
- /// ## Warning
- ///
- /// It is inadvisable to read from or write to the underlying stream.
- pub fn get_mut(&mut self) -> &mut S {
- match *self {
- MaybeSslStream::Ssl(ref mut s) => s.get_mut(),
- MaybeSslStream::Normal(ref mut s) => s,
- }
- }
-}
-
-impl MaybeSslStream<net::TcpStream> {
- /// Like `TcpStream::try_clone`.
- pub fn try_clone(&self) -> io::Result<MaybeSslStream<net::TcpStream>> {
- match *self {
- MaybeSslStream::Ssl(ref s) => s.try_clone().map(MaybeSslStream::Ssl),
- MaybeSslStream::Normal(ref s) => s.try_clone().map(MaybeSslStream::Normal),
- }
- }
-}
-
-/// # Deprecated
-///
-/// Use `SslStream` with `ssl_read` and `ssl_write`.
-pub struct NonblockingSslStream<S>(SslStream<S>);
-
-impl<S: Clone + Read + Write> Clone for NonblockingSslStream<S> {
- fn clone(&self) -> Self {
- NonblockingSslStream(self.0.clone())
- }
-}
-
-#[cfg(unix)]
-impl<S: AsRawFd> AsRawFd for NonblockingSslStream<S> {
- fn as_raw_fd(&self) -> RawFd {
- self.0.as_raw_fd()
- }
-}
-
-#[cfg(windows)]
-impl<S: AsRawSocket> AsRawSocket for NonblockingSslStream<S> {
- fn as_raw_socket(&self) -> RawSocket {
- self.0.as_raw_socket()
- }
-}
-
-impl NonblockingSslStream<net::TcpStream> {
- pub fn try_clone(&self) -> io::Result<NonblockingSslStream<net::TcpStream>> {
- self.0.try_clone().map(NonblockingSslStream)
- }
-}
-
-impl<S> NonblockingSslStream<S> {
- /// Returns a reference to the underlying stream.
- pub fn get_ref(&self) -> &S {
- self.0.get_ref()
- }
-
- /// Returns a mutable reference to the underlying stream.
- ///
- /// ## Warning
- ///
- /// It is inadvisable to read from or write to the underlying stream as it
- /// will most likely corrupt the SSL session.
- pub fn get_mut(&mut self) -> &mut S {
- self.0.get_mut()
- }
-
- /// Returns a reference to the Ssl.
- pub fn ssl(&self) -> &Ssl {
- self.0.ssl()
- }
-}
-
-impl<S: Read + Write> NonblockingSslStream<S> {
- /// Create a new nonblocking client ssl connection on wrapped `stream`.
- ///
- /// Note that this method will most likely not actually complete the SSL
- /// handshake because doing so requires several round trips; the handshake will
- /// be completed in subsequent read/write calls managed by your event loop.
- pub fn connect<T: IntoSsl>(ssl: T, stream: S) -> Result<NonblockingSslStream<S>, SslError> {
- SslStream::connect(ssl, stream).map(NonblockingSslStream)
- }
-
- /// Create a new nonblocking server ssl connection on wrapped `stream`.
- ///
- /// Note that this method will most likely not actually complete the SSL
- /// handshake because doing so requires several round trips; the handshake will
- /// be completed in subsequent read/write calls managed by your event loop.
- pub fn accept<T: IntoSsl>(ssl: T, stream: S) -> Result<NonblockingSslStream<S>, SslError> {
- SslStream::accept(ssl, stream).map(NonblockingSslStream)
- }
-
- fn convert_err(&self, err: Error) -> NonblockingSslError {
- match err {
- Error::ZeroReturn => SslError::SslSessionClosed.into(),
- Error::WantRead(_) => NonblockingSslError::WantRead,
- Error::WantWrite(_) => NonblockingSslError::WantWrite,
- Error::WantX509Lookup => unreachable!(),
- Error::Stream(e) => SslError::StreamError(e).into(),
- Error::Ssl(e) => {
- SslError::OpenSslErrors(e.iter()
- .map(|e| OpensslError::from_error_code(e.error_code()))
- .collect())
- .into()
- }
- }
- }
-
- /// Read bytes from the SSL stream into `buf`.
- ///
- /// Given the SSL state machine, this method may return either `WantWrite`
- /// or `WantRead` to indicate that your event loop should respectively wait
- /// for write or read readiness on the underlying stream. Upon readiness,
- /// repeat your `read()` call with the same arguments each time until you
- /// receive an `Ok(count)`.
- ///
- /// An `SslError` return value, is terminal; do not re-attempt your read.
- ///
- /// As expected of a nonblocking API, this method will never block your
- /// thread on I/O.
- ///
- /// On a return value of `Ok(count)`, count is the number of decrypted
- /// plaintext bytes copied into the `buf` slice.
- pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, NonblockingSslError> {
- match self.0.ssl_read(buf) {
- Ok(n) => Ok(n),
- Err(Error::ZeroReturn) => Ok(0),
- Err(e) => Err(self.convert_err(e)),
- }
- }
-
- /// Write bytes from `buf` to the SSL stream.
- ///
- /// Given the SSL state machine, this method may return either `WantWrite`
- /// or `WantRead` to indicate that your event loop should respectively wait
- /// for write or read readiness on the underlying stream. Upon readiness,
- /// repeat your `write()` call with the same arguments each time until you
- /// receive an `Ok(count)`.
- ///
- /// An `SslError` return value, is terminal; do not re-attempt your write.
- ///
- /// As expected of a nonblocking API, this method will never block your
- /// thread on I/O.
- ///
- /// Given a return value of `Ok(count)`, count is the number of plaintext bytes
- /// from the `buf` slice that were encrypted and written onto the stream.
- pub fn write(&mut self, buf: &[u8]) -> Result<usize, NonblockingSslError> {
- self.0.ssl_write(buf).map_err(|e| self.convert_err(e))
- }
-}
diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs
index 5339f27e..b774b383 100644
--- a/openssl/src/ssl/tests/mod.rs
+++ b/openssl/src/ssl/tests/mod.rs
@@ -17,9 +17,9 @@ use crypto::hash::Type::SHA256;
use ssl;
use ssl::SSL_VERIFY_PEER;
use ssl::SslMethod::Sslv23;
-use ssl::SslMethod;
-use ssl::error::NonblockingSslError;
-use ssl::{SslContext, SslStream, VerifyCallback, NonblockingSslStream};
+use ssl::{SslMethod, HandshakeError};
+use ssl::error::Error;
+use ssl::{SslContext, SslStream};
use x509::X509StoreContext;
use x509::X509FileType;
use x509::X509;
@@ -133,6 +133,7 @@ impl Drop for Server {
}
#[cfg(feature = "dtlsv1")]
+#[derive(Debug)]
struct UdpConnected(UdpSocket);
#[cfg(feature = "dtlsv1")]
@@ -194,9 +195,9 @@ macro_rules! run_test(
use std::net::TcpStream;
use ssl;
use ssl::SslMethod;
- use ssl::{SslContext, Ssl, SslStream, VerifyCallback};
+ use ssl::{SslContext, Ssl, SslStream};
use ssl::SSL_VERIFY_PEER;
- use crypto::hash::Type::SHA1;
+ use crypto::hash::Type::{SHA1, SHA256};
use x509::X509StoreContext;
use serialize::hex::FromHex;
use super::Server;
@@ -222,19 +223,19 @@ run_test!(new_ctx, |method, _| {
});
run_test!(new_sslstream, |method, stream| {
- SslStream::connect_generic(&SslContext::new(method).unwrap(), stream).unwrap();
+ SslStream::connect(&SslContext::new(method).unwrap(), stream).unwrap();
});
run_test!(get_ssl_method, |method, _| {
let ssl = Ssl::new(&SslContext::new(method).unwrap()).unwrap();
- assert_eq!(ssl.get_ssl_method(), Some(method));
+ assert_eq!(ssl.ssl_method(), Some(method));
});
run_test!(verify_untrusted, |method, stream| {
let mut ctx = SslContext::new(method).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, None);
+ ctx.set_verify(SSL_VERIFY_PEER);
- match SslStream::connect_generic(&ctx, stream) {
+ match SslStream::connect(&ctx, stream) {
Ok(_) => panic!("expected failure"),
Err(err) => println!("error {:?}", err),
}
@@ -242,127 +243,95 @@ run_test!(verify_untrusted, |method, stream| {
run_test!(verify_trusted, |method, stream| {
let mut ctx = SslContext::new(method).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, None);
+ ctx.set_verify(SSL_VERIFY_PEER);
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
- match SslStream::connect_generic(&ctx, stream) {
+ match SslStream::connect(&ctx, stream) {
Ok(_) => (),
Err(err) => panic!("Expected success, got {:?}", err),
}
});
run_test!(verify_untrusted_callback_override_ok, |method, stream| {
- fn callback(_preverify_ok: bool, _x509_ctx: &X509StoreContext) -> bool {
- true
- }
-
let mut ctx = SslContext::new(method).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback));
+ ctx.set_verify_callback(SSL_VERIFY_PEER, |_, _| true);
- match SslStream::connect_generic(&ctx, stream) {
+ match SslStream::connect(&ctx, stream) {
Ok(_) => (),
Err(err) => panic!("Expected success, got {:?}", err),
}
});
run_test!(verify_untrusted_callback_override_bad, |method, stream| {
- fn callback(_preverify_ok: bool, _x509_ctx: &X509StoreContext) -> bool {
- false
- }
-
let mut ctx = SslContext::new(method).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback));
+ ctx.set_verify_callback(SSL_VERIFY_PEER, |_, _| false);
- assert!(SslStream::connect_generic(&ctx, stream).is_err());
+ assert!(SslStream::connect(&ctx, stream).is_err());
});
run_test!(verify_trusted_callback_override_ok, |method, stream| {
- fn callback(_preverify_ok: bool, _x509_ctx: &X509StoreContext) -> bool {
- true
- }
-
let mut ctx = SslContext::new(method).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback));
+ ctx.set_verify_callback(SSL_VERIFY_PEER, |_, _| true);
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
- match SslStream::connect_generic(&ctx, stream) {
+ match SslStream::connect(&ctx, stream) {
Ok(_) => (),
Err(err) => panic!("Expected success, got {:?}", err),
}
});
run_test!(verify_trusted_callback_override_bad, |method, stream| {
- fn callback(_preverify_ok: bool, _x509_ctx: &X509StoreContext) -> bool {
- false
- }
-
let mut ctx = SslContext::new(method).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback));
+ ctx.set_verify_callback(SSL_VERIFY_PEER, |_, _| false);
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
- assert!(SslStream::connect_generic(&ctx, stream).is_err());
+ assert!(SslStream::connect(&ctx, stream).is_err());
});
run_test!(verify_callback_load_certs, |method, stream| {
- fn callback(_preverify_ok: bool, x509_ctx: &X509StoreContext) -> bool {
+ let mut ctx = SslContext::new(method).unwrap();
+ ctx.set_verify_callback(SSL_VERIFY_PEER, |_, x509_ctx| {
assert!(x509_ctx.get_current_cert().is_some());
true
- }
-
- let mut ctx = SslContext::new(method).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback));
+ });
- assert!(SslStream::connect_generic(&ctx, stream).is_ok());
+ assert!(SslStream::connect(&ctx, stream).is_ok());
});
run_test!(verify_trusted_get_error_ok, |method, stream| {
- fn callback(_preverify_ok: bool, x509_ctx: &X509StoreContext) -> bool {
+ let mut ctx = SslContext::new(method).unwrap();
+ ctx.set_verify_callback(SSL_VERIFY_PEER, |_, x509_ctx| {
assert!(x509_ctx.get_error().is_none());
true
- }
-
- let mut ctx = SslContext::new(method).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback));
+ });
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
- assert!(SslStream::connect_generic(&ctx, stream).is_ok());
+ assert!(SslStream::connect(&ctx, stream).is_ok());
});
run_test!(verify_trusted_get_error_err, |method, stream| {
- fn callback(_preverify_ok: bool, x509_ctx: &X509StoreContext) -> bool {
+ let mut ctx = SslContext::new(method).unwrap();
+ ctx.set_verify_callback(SSL_VERIFY_PEER, |_, x509_ctx| {
assert!(x509_ctx.get_error().is_some());
false
- }
-
- let mut ctx = SslContext::new(method).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback));
+ });
- assert!(SslStream::connect_generic(&ctx, stream).is_err());
+ assert!(SslStream::connect(&ctx, stream).is_err());
});
run_test!(verify_callback_data, |method, stream| {
- fn callback(_preverify_ok: bool, x509_ctx: &X509StoreContext, node_id: &Vec<u8>) -> bool {
- let cert = x509_ctx.get_current_cert();
- match cert {
- None => false,
- Some(cert) => {
- let fingerprint = cert.fingerprint(SHA1).unwrap();
- &fingerprint == node_id
- }
- }
- }
let mut ctx = SslContext::new(method).unwrap();
// Node id was generated as SHA256 hash of certificate "test/cert.pem"
@@ -371,10 +340,19 @@ run_test!(verify_callback_data, |method, stream| {
// Please update if "test/cert.pem" will ever change
let node_hash_str = "E19427DAC79FBE758394945276A6E4F15F0BEBE6";
let node_id = node_hash_str.from_hex().unwrap();
- ctx.set_verify_with_data(SSL_VERIFY_PEER, callback, node_id);
+ ctx.set_verify_callback(SSL_VERIFY_PEER, move |_preverify_ok, x509_ctx| {
+ let cert = x509_ctx.get_current_cert();
+ match cert {
+ None => false,
+ Some(cert) => {
+ let fingerprint = cert.fingerprint(SHA1).unwrap();
+ fingerprint == node_id
+ }
+ }
+ });
ctx.set_verify_depth(1);
- match SslStream::connect_generic(&ctx, stream) {
+ match SslStream::connect(&ctx, stream) {
Ok(_) => (),
Err(err) => panic!("Expected success, got {:?}", err),
}
@@ -402,7 +380,7 @@ run_test!(ssl_verify_callback, |method, stream| {
}
});
- match SslStream::connect_generic(ssl, stream) {
+ match SslStream::connect(ssl, stream) {
Ok(_) => (),
Err(err) => panic!("Expected success, got {:?}", err),
}
@@ -419,14 +397,14 @@ fn test_write_hits_stream() {
let guard = thread::spawn(move || {
let ctx = SslContext::new(Sslv23).unwrap();
let stream = TcpStream::connect(addr).unwrap();
- let mut stream = SslStream::connect_generic(&ctx, stream).unwrap();
+ let mut stream = SslStream::connect(&ctx, stream).unwrap();
stream.write_all(b"hello").unwrap();
stream
});
let mut ctx = SslContext::new(Sslv23).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, None);
+ ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM).unwrap();
ctx.set_private_key_file(&Path::new("test/key.pem"), X509FileType::PEM).unwrap();
let stream = listener.accept().unwrap().0;
@@ -440,17 +418,10 @@ fn test_write_hits_stream() {
#[test]
fn test_set_certificate_and_private_key() {
- let key_path = Path::new("test/key.pem");
- let cert_path = Path::new("test/cert.pem");
- let mut key_file = File::open(&key_path)
- .ok()
- .expect("Failed to open `test/key.pem`");
- let mut cert_file = File::open(&cert_path)
- .ok()
- .expect("Failed to open `test/cert.pem`");
-
- let key = PKey::private_key_from_pem(&mut key_file).unwrap();
- let cert = X509::from_pem(&mut cert_file).unwrap();
+ let key = include_bytes!("../../../test/key.pem");
+ let key = PKey::private_key_from_pem(key).unwrap();
+ let cert = include_bytes!("../../../test/cert.pem");
+ let cert = X509::from_pem(cert).unwrap();
let mut ctx = SslContext::new(Sslv23).unwrap();
ctx.set_private_key(&key).unwrap();
@@ -460,8 +431,8 @@ fn test_set_certificate_and_private_key() {
}
run_test!(get_ctx_options, |method, _| {
- let mut ctx = SslContext::new(method).unwrap();
- ctx.get_options();
+ let ctx = SslContext::new(method).unwrap();
+ ctx.options();
});
run_test!(set_ctx_options, |method, _| {
@@ -480,7 +451,7 @@ run_test!(clear_ctx_options, |method, _| {
#[test]
fn test_write() {
let (_s, stream) = Server::new();
- let mut stream = SslStream::connect_generic(&SslContext::new(Sslv23).unwrap(), stream).unwrap();
+ let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), stream).unwrap();
stream.write_all("hello".as_bytes()).unwrap();
stream.flush().unwrap();
stream.write_all(" there".as_bytes()).unwrap();
@@ -498,7 +469,7 @@ fn test_write_direct() {
}
run_test!(get_peer_certificate, |method, stream| {
- let stream = SslStream::connect_generic(&SslContext::new(method).unwrap(), stream).unwrap();
+ let stream = SslStream::connect(&SslContext::new(method).unwrap(), stream).unwrap();
let cert = stream.ssl().peer_certificate().unwrap();
let fingerprint = cert.fingerprint(SHA1).unwrap();
let node_hash_str = "E19427DAC79FBE758394945276A6E4F15F0BEBE6";
@@ -511,7 +482,7 @@ run_test!(get_peer_certificate, |method, stream| {
fn test_write_dtlsv1() {
let (_s, stream) = Server::new_dtlsv1(iter::repeat("y\n"));
- let mut stream = SslStream::connect_generic(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap();
+ let mut stream = SslStream::connect(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap();
stream.write_all(b"hello").unwrap();
stream.flush().unwrap();
stream.write_all(b" there").unwrap();
@@ -521,7 +492,7 @@ fn test_write_dtlsv1() {
#[test]
fn test_read() {
let (_s, tcp) = Server::new();
- let mut stream = SslStream::connect_generic(&SslContext::new(Sslv23).unwrap(), tcp).unwrap();
+ let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap();
stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap();
stream.flush().unwrap();
io::copy(&mut stream, &mut io::sink()).ok().expect("read error");
@@ -539,7 +510,7 @@ fn test_read_direct() {
#[test]
fn test_pending() {
let (_s, tcp) = Server::new();
- let mut stream = SslStream::connect_generic(&SslContext::new(Sslv23).unwrap(), tcp).unwrap();
+ let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap();
stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap();
stream.flush().unwrap();
@@ -562,7 +533,7 @@ fn test_pending() {
#[test]
fn test_state() {
let (_s, tcp) = Server::new();
- let stream = SslStream::connect_generic(&SslContext::new(Sslv23).unwrap(), tcp).unwrap();
+ let stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap();
assert_eq!(stream.ssl().state_string(), "SSLOK ");
assert_eq!(stream.ssl().state_string_long(),
"SSL negotiation finished successfully");
@@ -575,7 +546,7 @@ fn test_state() {
fn test_connect_with_unilateral_alpn() {
let (_s, stream) = Server::new();
let mut ctx = SslContext::new(Sslv23).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, None);
+ ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {}
@@ -597,13 +568,13 @@ fn test_connect_with_unilateral_alpn() {
fn test_connect_with_unilateral_npn() {
let (_s, stream) = Server::new();
let mut ctx = SslContext::new(Sslv23).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, None);
+ ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_npn_protocols(&[b"http/1.1", b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
- let stream = match SslStream::connect_generic(&ctx, stream) {
+ let stream = match SslStream::connect(&ctx, stream) {
Ok(stream) => stream,
Err(err) => panic!("Expected success, got {:?}", err),
};
@@ -619,7 +590,7 @@ fn test_connect_with_unilateral_npn() {
fn test_connect_with_alpn_successful_multiple_matching() {
let (_s, stream) = Server::new_alpn();
let mut ctx = SslContext::new(Sslv23).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, None);
+ ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"spdy/3.1", b"http/1.1"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {}
@@ -641,13 +612,13 @@ fn test_connect_with_alpn_successful_multiple_matching() {
fn test_connect_with_npn_successful_multiple_matching() {
let (_s, stream) = Server::new_alpn();
let mut ctx = SslContext::new(Sslv23).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, None);
+ ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_npn_protocols(&[b"spdy/3.1", b"http/1.1"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
- let stream = match SslStream::connect_generic(&ctx, stream) {
+ let stream = match SslStream::connect(&ctx, stream) {
Ok(stream) => stream,
Err(err) => panic!("Expected success, got {:?}", err),
};
@@ -664,7 +635,7 @@ fn test_connect_with_npn_successful_multiple_matching() {
fn test_connect_with_alpn_successful_single_match() {
let (_s, stream) = Server::new_alpn();
let mut ctx = SslContext::new(Sslv23).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, None);
+ ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {}
@@ -688,13 +659,13 @@ fn test_connect_with_alpn_successful_single_match() {
fn test_connect_with_npn_successful_single_match() {
let (_s, stream) = Server::new_alpn();
let mut ctx = SslContext::new(Sslv23).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, None);
+ ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_npn_protocols(&[b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
- let stream = match SslStream::connect_generic(&ctx, stream) {
+ let stream = match SslStream::connect(&ctx, stream) {
Ok(stream) => stream,
Err(err) => panic!("Expected success, got {:?}", err),
};
@@ -713,7 +684,7 @@ fn test_npn_server_advertise_multiple() {
// We create a different context instance for the server...
let listener_ctx = {
let mut ctx = SslContext::new(Sslv23).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, None);
+ ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_npn_protocols(&[b"http/1.1", b"spdy/3.1"]);
assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM)
.is_ok());
@@ -728,7 +699,7 @@ fn test_npn_server_advertise_multiple() {
});
let mut ctx = SslContext::new(Sslv23).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, None);
+ ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_npn_protocols(&[b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {}
@@ -736,7 +707,7 @@ fn test_npn_server_advertise_multiple() {
}
// Now connect to the socket and make sure the protocol negotiation works...
let stream = TcpStream::connect(localhost).unwrap();
- let stream = match SslStream::connect_generic(&ctx, stream) {
+ let stream = match SslStream::connect(&ctx, stream) {
Ok(stream) => stream,
Err(err) => panic!("Expected success, got {:?}", err),
};
@@ -754,7 +725,7 @@ fn test_alpn_server_advertise_multiple() {
// We create a different context instance for the server...
let listener_ctx = {
let mut ctx = SslContext::new(Sslv23).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, None);
+ ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]);
assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM)
.is_ok());
@@ -769,7 +740,7 @@ fn test_alpn_server_advertise_multiple() {
});
let mut ctx = SslContext::new(Sslv23).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, None);
+ ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"spdy/3.1"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {}
@@ -795,7 +766,7 @@ fn test_alpn_server_select_none() {
// We create a different context instance for the server...
let listener_ctx = {
let mut ctx = SslContext::new(Sslv23).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, None);
+ ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]);
assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM)
.is_ok());
@@ -810,7 +781,7 @@ fn test_alpn_server_select_none() {
});
let mut ctx = SslContext::new(Sslv23).unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, None);
+ ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"http/2"]);
match ctx.set_CA_file(&Path::new("test/cert.pem")) {
Ok(_) => {}
@@ -838,7 +809,7 @@ mod dtlsv1 {
use crypto::hash::Type::SHA256;
use ssl::SslMethod;
use ssl::SslMethod::Dtlsv1;
- use ssl::{SslContext, SslStream, VerifyCallback};
+ use ssl::{SslContext, SslStream};
use ssl::SSL_VERIFY_PEER;
use x509::X509StoreContext;
@@ -855,7 +826,7 @@ mod dtlsv1 {
fn test_read_dtlsv1() {
let (_s, stream) = Server::new_dtlsv1(Some("hello"));
- let mut stream = SslStream::connect_generic(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap();
+ let mut stream = SslStream::connect(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap();
let mut buf = [0u8; 100];
assert!(stream.read(&mut buf).is_ok());
}
@@ -864,15 +835,15 @@ fn test_read_dtlsv1() {
#[cfg(feature = "sslv2")]
fn test_sslv2_connect_failure() {
let (_s, tcp) = Server::new_tcp(&["-no_ssl2", "-www"]);
- SslStream::connect_generic(&SslContext::new(Sslv2).unwrap(), tcp)
+ SslStream::connect(&SslContext::new(Sslv2).unwrap(), tcp)
.err()
.unwrap();
}
-fn wait_io(stream: &NonblockingSslStream<TcpStream>, read: bool, timeout_ms: u32) -> bool {
+fn wait_io(stream: &TcpStream, read: bool, timeout_ms: u32) -> bool {
unsafe {
let mut set: select::fd_set = mem::zeroed();
- select::fd_set(&mut set, stream.get_ref());
+ select::fd_set(&mut set, stream);
let write = if read {
0 as *mut _
@@ -884,7 +855,19 @@ fn wait_io(stream: &NonblockingSslStream<TcpStream>, read: bool, timeout_ms: u32
} else {
&mut set as *mut _
};
- select::select(stream.get_ref(), read, write, 0 as *mut _, timeout_ms).unwrap()
+ select::select(stream, read, write, 0 as *mut _, timeout_ms).unwrap()
+ }
+}
+
+fn handshake(res: Result<SslStream<TcpStream>, HandshakeError<TcpStream>>)
+ -> SslStream<TcpStream> {
+ match res {
+ Ok(s) => s,
+ Err(HandshakeError::Interrupted(s)) => {
+ wait_io(s.get_ref(), true, 1_000);
+ handshake(s.handshake())
+ }
+ Err(err) => panic!("error on handshake {:?}", err),
}
}
@@ -893,7 +876,7 @@ fn test_write_nonblocking() {
let (_s, stream) = Server::new();
stream.set_nonblocking(true).unwrap();
let cx = SslContext::new(Sslv23).unwrap();
- let mut stream = NonblockingSslStream::connect(&cx, stream).unwrap();
+ let mut stream = handshake(SslStream::connect(&cx, stream));
let mut iterations = 0;
loop {
@@ -903,16 +886,16 @@ fn test_write_nonblocking() {
// openssl.
panic!("Too many read/write round trips in handshake!!");
}
- let result = stream.write(b"hello");
+ let result = stream.ssl_write(b"hello");
match result {
Ok(_) => {
break;
}
- Err(NonblockingSslError::WantRead) => {
- assert!(wait_io(&stream, true, 1000));
+ Err(Error::WantRead(_)) => {
+ assert!(wait_io(stream.get_ref(), true, 1000));
}
- Err(NonblockingSslError::WantWrite) => {
- assert!(wait_io(&stream, false, 1000));
+ Err(Error::WantWrite(_)) => {
+ assert!(wait_io(stream.get_ref(), false, 1000));
}
Err(other) => {
panic!("Unexpected SSL Error: {:?}", other);
@@ -930,7 +913,7 @@ fn test_read_nonblocking() {
let (_s, stream) = Server::new();
stream.set_nonblocking(true).unwrap();
let cx = SslContext::new(Sslv23).unwrap();
- let mut stream = NonblockingSslStream::connect(&cx, stream).unwrap();
+ let mut stream = handshake(SslStream::connect(&cx, stream));
let mut iterations = 0;
loop {
@@ -940,17 +923,17 @@ fn test_read_nonblocking() {
// openssl.
panic!("Too many read/write round trips in handshake!!");
}
- let result = stream.write(b"GET /\r\n\r\n");
+ let result = stream.ssl_write(b"GET /\r\n\r\n");
match result {
Ok(n) => {
assert_eq!(n, 9);
break;
}
- Err(NonblockingSslError::WantRead) => {
- assert!(wait_io(&stream, true, 1000));
+ Err(Error::WantRead(..)) => {
+ assert!(wait_io(stream.get_ref(), true, 1000));
}
- Err(NonblockingSslError::WantWrite) => {
- assert!(wait_io(&stream, false, 1000));
+ Err(Error::WantWrite(..)) => {
+ assert!(wait_io(stream.get_ref(), false, 1000));
}
Err(other) => {
panic!("Unexpected SSL Error: {:?}", other);
@@ -958,7 +941,7 @@ fn test_read_nonblocking() {
}
}
let mut input_buffer = [0u8; 1500];
- let result = stream.read(&mut input_buffer);
+ let result = stream.ssl_read(&mut input_buffer);
let bytes_read = match result {
Ok(n) => {
// This branch is unlikely, but on an overloaded VM with
@@ -966,8 +949,8 @@ fn test_read_nonblocking() {
// be in the receive buffer before we issue the read() syscall...
n
}
- Err(NonblockingSslError::WantRead) => {
- assert!(wait_io(&stream, true, 3000));
+ Err(Error::WantRead(..)) => {
+ assert!(wait_io(stream.get_ref(), true, 3000));
// Second read should return application data.
stream.read(&mut input_buffer).unwrap()
}
@@ -980,14 +963,6 @@ fn test_read_nonblocking() {
}
#[test]
-fn broken_try_clone_doesnt_crash() {
- let context = SslContext::new(SslMethod::Sslv23).unwrap();
- let inner = TcpStream::connect("example.com:443").unwrap();
- let stream1 = SslStream::connect(&context, inner).unwrap();
- let _stream2 = stream1.try_clone().unwrap();
-}
-
-#[test]
#[should_panic(expected = "blammo")]
#[cfg(feature = "nightly")]
fn write_panic() {
@@ -1093,7 +1068,7 @@ fn refcount_ssl_context() {
fn default_verify_paths() {
let mut ctx = SslContext::new(SslMethod::Sslv23).unwrap();
ctx.set_default_verify_paths().unwrap();
- ctx.set_verify(SSL_VERIFY_PEER, None);
+ ctx.set_verify(SSL_VERIFY_PEER);
let s = TcpStream::connect("google.com:443").unwrap();
let mut socket = SslStream::connect(&ctx, s).unwrap();
diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs
index c9d1772d..64a61df0 100644
--- a/openssl/src/x509/mod.rs
+++ b/openssl/src/x509/mod.rs
@@ -1,6 +1,4 @@
use libc::{c_char, c_int, c_long, c_ulong, c_uint, c_void};
-use std::io;
-use std::io::prelude::*;
use std::cmp::Ordering;
use std::ffi::CString;
use std::iter::repeat;
@@ -14,15 +12,15 @@ use std::collections::HashMap;
use std::marker::PhantomData;
use asn1::Asn1Time;
-use bio::MemBio;
+use bio::{MemBio, MemBioSlice};
use crypto::hash;
use crypto::hash::Type as HashType;
use crypto::pkey::{PKey, Parts};
use crypto::rand::rand_bytes;
use ffi;
use ffi_extras;
-use ssl::error::{SslError, StreamError};
use nid::Nid;
+use error::ErrorStack;
pub mod extension;
@@ -116,13 +114,6 @@ impl X509StoreContext {
/// # Example
///
/// ```
-/// # #[allow(unstable)]
-/// # fn main() {
-/// use std::fs;
-/// use std::fs::File;
-/// use std::io::prelude::*;
-/// use std::path::Path;
-///
/// use openssl::crypto::hash::Type;
/// use openssl::x509::X509Generator;
/// use openssl::x509::extension::{Extension, KeyUsageOption};
@@ -135,17 +126,8 @@ impl X509StoreContext {
/// .add_extension(Extension::KeyUsage(vec![KeyUsageOption::DigitalSignature]));
///
/// let (cert, pkey) = gen.generate().unwrap();
-///
-/// let cert_path = "doc_cert.pem";
-/// let mut file = File::create(cert_path).unwrap();
-/// assert!(cert.write_pem(&mut file).is_ok());
-/// # let _ = fs::remove_file(cert_path);
-///
-/// let pkey_path = "doc_key.pem";
-/// let mut file = File::create(pkey_path).unwrap();
-/// assert!(pkey.write_pem(&mut file).is_ok());
-/// # let _ = fs::remove_file(pkey_path);
-/// # }
+/// let cert_pem = cert.write_pem().unwrap();
+/// let pkey_pem = pkey.write_pem().unwrap();
/// ```
pub struct X509Generator {
bits: u32,
@@ -256,7 +238,7 @@ impl X509Generator {
fn add_extension_internal(x509: *mut ffi::X509,
exttype: &extension::ExtensionType,
value: &str)
- -> Result<(), SslError> {
+ -> Result<(), ErrorStack> {
unsafe {
let mut ctx: ffi::X509V3_CTX = mem::zeroed();
ffi::X509V3_set_ctx(&mut ctx, x509, x509, ptr::null_mut(), ptr::null_mut(), 0);
@@ -288,7 +270,7 @@ impl X509Generator {
fn add_name_internal(name: *mut ffi::X509_NAME,
key: &str,
value: &str)
- -> Result<(), SslError> {
+ -> Result<(), ErrorStack> {
let value_len = value.len() as c_int;
lift_ssl!(unsafe {
let key = CString::new(key.as_bytes()).unwrap();
@@ -319,7 +301,7 @@ impl X509Generator {
}
/// Generates a private key and a self-signed certificate and returns them
- pub fn generate<'a>(&self) -> Result<(X509<'a>, PKey), SslError> {
+ pub fn generate<'a>(&self) -> Result<(X509<'a>, PKey), ErrorStack> {
ffi::init();
let mut p_key = PKey::new();
@@ -331,7 +313,7 @@ impl X509Generator {
/// Sets the certificate public-key, then self-sign and return it
/// Note: That the bit-length of the private key is used (set_bitlength is ignored)
- pub fn sign<'a>(&self, p_key: &PKey) -> Result<X509<'a>, SslError> {
+ pub fn sign<'a>(&self, p_key: &PKey) -> Result<X509<'a>, ErrorStack> {
ffi::init();
unsafe {
@@ -391,7 +373,7 @@ impl X509Generator {
}
/// Obtain a certificate signing request (CSR)
- pub fn request(&self, p_key: &PKey) -> Result<X509Req, SslError> {
+ pub fn request(&self, p_key: &PKey) -> Result<X509Req, ErrorStack> {
let cert = match self.sign(p_key) {
Ok(c) => c,
Err(x) => return Err(x),
@@ -444,12 +426,8 @@ impl<'ctx> X509<'ctx> {
}
/// Reads certificate from PEM, takes ownership of handle
- pub fn from_pem<R>(reader: &mut R) -> Result<X509<'ctx>, SslError>
- where R: Read
- {
- let mut mem_bio = try!(MemBio::new());
- try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
-
+ pub fn from_pem(buf: &[u8]) -> Result<X509<'ctx>, ErrorStack> {
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let handle = try_ssl_null!(ffi::PEM_read_bio_X509(mem_bio.get_handle(),
ptr::null_mut(),
@@ -523,25 +501,21 @@ impl<'ctx> X509<'ctx> {
}
/// Writes certificate as PEM
- pub fn write_pem<W>(&self, writer: &mut W) -> Result<(), SslError>
- where W: Write
- {
- let mut mem_bio = try!(MemBio::new());
+ pub fn write_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
unsafe {
try_ssl!(ffi::PEM_write_bio_X509(mem_bio.get_handle(), self.handle));
}
- io::copy(&mut mem_bio, writer).map_err(StreamError).map(|_| ())
+ Ok(mem_bio.get_buf().to_owned())
}
/// Returns a DER serialized form of the certificate
- pub fn save_der(&self) -> Result<Vec<u8>, SslError> {
- let mut mem_bio = try!(MemBio::new());
+ pub fn save_der(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
unsafe {
ffi::i2d_X509_bio(mem_bio.get_handle(), self.handle);
}
- let mut v = Vec::new();
- try!(io::copy(&mut mem_bio, &mut v).map_err(StreamError));
- Ok(v)
+ Ok(mem_bio.get_buf().to_owned())
}
}
@@ -627,12 +601,8 @@ impl X509Req {
}
/// Reads CSR from PEM
- pub fn from_pem<R>(reader: &mut R) -> Result<X509Req, SslError>
- where R: Read
- {
- let mut mem_bio = try!(MemBio::new());
- try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
-
+ pub fn from_pem(buf: &[u8]) -> Result<X509Req, ErrorStack> {
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let handle = try_ssl_null!(ffi::PEM_read_bio_X509_REQ(mem_bio.get_handle(),
ptr::null_mut(),
@@ -643,25 +613,21 @@ impl X509Req {
}
/// Writes CSR as PEM
- pub fn write_pem<W>(&self, writer: &mut W) -> Result<(), SslError>
- where W: Write
- {
- let mut mem_bio = try!(MemBio::new());
- unsafe {
- try_ssl!(ffi::PEM_write_bio_X509_REQ(mem_bio.get_handle(), self.handle));
+ pub fn write_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
+ if unsafe { ffi::PEM_write_bio_X509_REQ(mem_bio.get_handle(), self.handle) } != 1 {
+ return Err(ErrorStack::get());
}
- io::copy(&mut mem_bio, writer).map_err(StreamError).map(|_| ())
+ Ok(mem_bio.get_buf().to_owned())
}
/// Returns a DER serialized form of the CSR
- pub fn save_der(&self) -> Result<Vec<u8>, SslError> {
- let mut mem_bio = try!(MemBio::new());
+ pub fn save_der(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
unsafe {
ffi::i2d_X509_REQ_bio(mem_bio.get_handle(), self.handle);
}
- let mut v = Vec::new();
- try!(io::copy(&mut mem_bio, &mut v).map_err(StreamError));
- Ok(v)
+ Ok(mem_bio.get_buf().to_owned())
}
}
diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs
index 5d9b30ab..167ca8cf 100644
--- a/openssl/src/x509/tests.rs
+++ b/openssl/src/x509/tests.rs
@@ -1,7 +1,4 @@
use serialize::hex::FromHex;
-use std::io;
-use std::path::Path;
-use std::fs::File;
use crypto::hash::Type::SHA1;
use crypto::pkey::PKey;
@@ -30,8 +27,8 @@ fn get_generator() -> X509Generator {
#[test]
fn test_cert_gen() {
let (cert, pkey) = get_generator().generate().unwrap();
- cert.write_pem(&mut io::sink()).unwrap();
- pkey.write_pem(&mut io::sink()).unwrap();
+ cert.write_pem().unwrap();
+ pkey.write_pem().unwrap();
// FIXME: check data in result to be correct, needs implementation
// of X509 getters
@@ -70,7 +67,7 @@ fn test_req_gen() {
pkey.gen(512);
let req = get_generator().request(&pkey).unwrap();
- req.write_pem(&mut io::sink()).unwrap();
+ req.write_pem().unwrap();
// FIXME: check data in result to be correct, needs implementation
// of X509_REQ getters
@@ -78,12 +75,8 @@ fn test_req_gen() {
#[test]
fn test_cert_loading() {
- let cert_path = Path::new("test/cert.pem");
- let mut file = File::open(&cert_path)
- .ok()
- .expect("Failed to open `test/cert.pem`");
-
- let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM");
+ let cert = include_bytes!("../../test/cert.pem");
+ let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
let fingerprint = cert.fingerprint(SHA1).unwrap();
let hash_str = "E19427DAC79FBE758394945276A6E4F15F0BEBE6";
@@ -94,12 +87,8 @@ fn test_cert_loading() {
#[test]
fn test_save_der() {
- let cert_path = Path::new("test/cert.pem");
- let mut file = File::open(&cert_path)
- .ok()
- .expect("Failed to open `test/cert.pem`");
-
- let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM");
+ let cert = include_bytes!("../../test/cert.pem");
+ let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
let der = cert.save_der().unwrap();
assert!(!der.is_empty());
@@ -107,12 +96,8 @@ fn test_save_der() {
#[test]
fn test_subject_read_cn() {
- let cert_path = Path::new("test/cert.pem");
- let mut file = File::open(&cert_path)
- .ok()
- .expect("Failed to open `test/cert.pem`");
-
- let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM");
+ let cert = include_bytes!("../../test/cert.pem");
+ let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
let subject = cert.subject_name();
let cn = match subject.text_by_nid(Nid::CN) {
Some(x) => x,
@@ -124,12 +109,8 @@ fn test_subject_read_cn() {
#[test]
fn test_nid_values() {
- let cert_path = Path::new("test/nid_test_cert.pem");
- let mut file = File::open(&cert_path)
- .ok()
- .expect("Failed to open `test/nid_test_cert.pem`");
-
- let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM");
+ let cert = include_bytes!("../../test/nid_test_cert.pem");
+ let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
let subject = cert.subject_name();
let cn = match subject.text_by_nid(Nid::CN) {
@@ -153,12 +134,8 @@ fn test_nid_values() {
#[test]
fn test_nid_uid_value() {
- let cert_path = Path::new("test/nid_uid_test_cert.pem");
- let mut file = File::open(&cert_path)
- .ok()
- .expect("Failed to open `test/nid_uid_test_cert.pem`");
-
- let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM");
+ let cert = include_bytes!("../../test/nid_uid_test_cert.pem");
+ let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
let subject = cert.subject_name();
let cn = match subject.text_by_nid(Nid::UserId) {
@@ -170,8 +147,8 @@ fn test_nid_uid_value() {
#[test]
fn test_subject_alt_name() {
- let mut file = File::open("test/alt_name_cert.pem").unwrap();
- let cert = X509::from_pem(&mut file).unwrap();
+ let cert = include_bytes!("../../test/alt_name_cert.pem");
+ let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
let subject_alt_names = cert.subject_alt_names().unwrap();
assert_eq!(3, subject_alt_names.len());
@@ -184,8 +161,8 @@ fn test_subject_alt_name() {
#[test]
fn test_subject_alt_name_iter() {
- let mut file = File::open("test/alt_name_cert.pem").unwrap();
- let cert = X509::from_pem(&mut file).unwrap();
+ let cert = include_bytes!("../../test/alt_name_cert.pem");
+ let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
let subject_alt_names = cert.subject_alt_names().unwrap();
let mut subject_alt_names_iter = subject_alt_names.iter();