aboutsummaryrefslogtreecommitdiff
path: root/openssl/src
diff options
context:
space:
mode:
authorSteven Fackler <[email protected]>2016-11-05 20:06:50 -0700
committerSteven Fackler <[email protected]>2016-11-05 20:06:50 -0700
commita0b56c437803a08413755928040a0970a93a7b83 (patch)
tree0f21848301b62d6078eafaee10e513df4163087b /openssl/src
parentMerge branch 'release-v0.8.3' into release (diff)
parentRelease v0.9.0 (diff)
downloadrust-openssl-0.9.0.tar.xz
rust-openssl-0.9.0.zip
Merge branch 'release-v0.9.0' into releasev0.9.0
Diffstat (limited to 'openssl/src')
-rw-r--r--openssl/src/asn1.rs73
-rw-r--r--openssl/src/asn1/mod.rs72
-rw-r--r--openssl/src/bio.rs19
-rw-r--r--openssl/src/bn.rs843
-rw-r--r--openssl/src/bn/mod.rs1023
-rw-r--r--openssl/src/c_helpers.c67
-rw-r--r--openssl/src/c_helpers.rs15
-rw-r--r--openssl/src/crypto.rs59
-rw-r--r--openssl/src/crypto/dsa.rs338
-rw-r--r--openssl/src/crypto/hmac.rs511
-rw-r--r--openssl/src/crypto/mod.rs28
-rw-r--r--openssl/src/crypto/pkcs5.rs245
-rw-r--r--openssl/src/crypto/pkey.rs166
-rw-r--r--openssl/src/crypto/rsa.rs337
-rw-r--r--openssl/src/dh.rs145
-rw-r--r--openssl/src/dh/mod.rs124
-rw-r--r--openssl/src/dsa.rs223
-rw-r--r--openssl/src/ec_key.rs24
-rw-r--r--openssl/src/error.rs95
-rw-r--r--openssl/src/hash.rs (renamed from openssl/src/crypto/hash.rs)177
-rw-r--r--openssl/src/lib.rs90
-rw-r--r--openssl/src/macros.rs59
-rw-r--r--openssl/src/memcmp.rs (renamed from openssl/src/crypto/memcmp.rs)2
-rw-r--r--openssl/src/nid.rs1144
-rw-r--r--openssl/src/pkcs12.rs (renamed from openssl/src/crypto/pkcs12.rs)46
-rw-r--r--openssl/src/pkcs5.rs203
-rw-r--r--openssl/src/pkey.rs178
-rw-r--r--openssl/src/rand.rs (renamed from openssl/src/crypto/rand.rs)5
-rw-r--r--openssl/src/rsa.rs457
-rw-r--r--openssl/src/sign.rs397
-rw-r--r--openssl/src/ssl/bio.rs169
-rw-r--r--openssl/src/ssl/connector.rs452
-rw-r--r--openssl/src/ssl/error.rs55
-rw-r--r--openssl/src/ssl/mod.rs1159
-rw-r--r--openssl/src/ssl/tests/mod.rs690
-rw-r--r--openssl/src/stack.rs331
-rw-r--r--openssl/src/symm.rs (renamed from openssl/src/crypto/symm.rs)290
-rw-r--r--openssl/src/types.rs40
-rw-r--r--openssl/src/util.rs (renamed from openssl/src/crypto/util.rs)41
-rw-r--r--openssl/src/verify.rs39
-rw-r--r--openssl/src/version.rs26
-rw-r--r--openssl/src/x509/extension.rs14
-rw-r--r--openssl/src/x509/mod.rs697
-rw-r--r--openssl/src/x509/tests.rs83
-rw-r--r--openssl/src/x509/verify.rs5
45 files changed, 6413 insertions, 4843 deletions
diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs
new file mode 100644
index 00000000..c0a23591
--- /dev/null
+++ b/openssl/src/asn1.rs
@@ -0,0 +1,73 @@
+use ffi;
+use libc::c_long;
+use std::fmt;
+use std::ptr;
+use std::slice;
+use std::str;
+
+use {cvt, cvt_p};
+use bio::MemBio;
+use crypto::CryptoString;
+use error::ErrorStack;
+use types::{OpenSslType, OpenSslTypeRef};
+
+type_!(Asn1Time, Asn1TimeRef, ffi::ASN1_TIME, ffi::ASN1_TIME_free);
+
+impl fmt::Display for Asn1TimeRef {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ unsafe {
+ let mem_bio = try!(MemBio::new());
+ try!(cvt(ffi::ASN1_TIME_print(mem_bio.as_ptr(), self.as_ptr())));
+ write!(f, "{}", str::from_utf8_unchecked(mem_bio.get_buf()))
+ }
+ }
+}
+
+impl Asn1Time {
+ fn from_period(period: c_long) -> Result<Asn1Time, ErrorStack> {
+ ffi::init();
+
+ unsafe {
+ let handle = try!(cvt_p(ffi::X509_gmtime_adj(ptr::null_mut(), period)));
+ Ok(Asn1Time::from_ptr(handle))
+ }
+ }
+
+ /// Creates a new time on specified interval in days from now
+ pub fn days_from_now(days: u32) -> Result<Asn1Time, ErrorStack> {
+ Asn1Time::from_period(days as c_long * 60 * 60 * 24)
+ }
+}
+
+type_!(Asn1String, Asn1StringRef, ffi::ASN1_STRING, ffi::ASN1_STRING_free);
+
+impl Asn1StringRef {
+ pub fn as_utf8(&self) -> Result<CryptoString, ErrorStack> {
+ unsafe {
+ let mut ptr = ptr::null_mut();
+ let len = ffi::ASN1_STRING_to_UTF8(&mut ptr, self.as_ptr());
+ if len < 0 {
+ return Err(ErrorStack::get());
+ }
+
+ Ok(CryptoString::from_raw_parts(ptr, len as usize))
+ }
+ }
+
+ pub fn as_slice(&self) -> &[u8] {
+ unsafe { slice::from_raw_parts(ASN1_STRING_data(self.as_ptr()), self.len()) }
+ }
+
+ pub fn len(&self) -> usize {
+ unsafe { ffi::ASN1_STRING_length(self.as_ptr()) as usize }
+ }
+}
+
+#[cfg(any(ossl101, ossl102))]
+use ffi::ASN1_STRING_data;
+
+#[cfg(ossl110)]
+#[allow(bad_style)]
+unsafe fn ASN1_STRING_data(s: *mut ffi::ASN1_STRING) -> *mut ::libc::c_uchar {
+ ffi::ASN1_STRING_get0_data(s) as *mut _
+}
diff --git a/openssl/src/asn1/mod.rs b/openssl/src/asn1/mod.rs
deleted file mode 100644
index 1eab9f04..00000000
--- a/openssl/src/asn1/mod.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-use libc::c_long;
-use std::{ptr, fmt};
-use std::marker::PhantomData;
-use std::ops::Deref;
-
-use bio::MemBio;
-use ffi;
-use error::ErrorStack;
-
-/// Corresponds to the ASN.1 structure Time defined in RFC5280
-pub struct Asn1Time(Asn1TimeRef<'static>);
-
-impl Asn1Time {
- /// Wraps existing ASN1_TIME and takes ownership
- pub unsafe fn from_ptr(handle: *mut ffi::ASN1_TIME) -> Asn1Time {
- Asn1Time(Asn1TimeRef::from_ptr(handle))
- }
-
- fn from_period(period: c_long) -> Result<Asn1Time, ErrorStack> {
- ffi::init();
-
- unsafe {
- let handle = try_ssl_null!(ffi::X509_gmtime_adj(ptr::null_mut(), period));
- Ok(Asn1Time::from_ptr(handle))
- }
- }
-
- /// Creates a new time on specified interval in days from now
- pub fn days_from_now(days: u32) -> Result<Asn1Time, ErrorStack> {
- Asn1Time::from_period(days as c_long * 60 * 60 * 24)
- }
-}
-
-impl Deref for Asn1Time {
- type Target = Asn1TimeRef<'static>;
-
- fn deref(&self) -> &Asn1TimeRef<'static> {
- &self.0
- }
-}
-
-/// A borrowed Asn1Time
-pub struct Asn1TimeRef<'a>(*mut ffi::ASN1_TIME, PhantomData<&'a ()>);
-
-impl<'a> Asn1TimeRef<'a> {
- /// Creates a new `Asn1TimeRef` wrapping the provided handle.
- pub unsafe fn from_ptr(handle: *mut ffi::ASN1_TIME) -> Asn1TimeRef<'a> {
- Asn1TimeRef(handle, PhantomData)
- }
-
- /// Returns the raw handle
- pub fn as_ptr(&self) -> *mut ffi::ASN1_TIME {
- self.0
- }
-}
-
-impl<'a> fmt::Display for Asn1TimeRef<'a> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let mem_bio = try!(MemBio::new());
- let as_str = unsafe {
- try_ssl!(ffi::ASN1_TIME_print(mem_bio.as_ptr(), self.0));
- String::from_utf8_unchecked(mem_bio.get_buf().to_owned())
- };
- write!(f, "{}", as_str)
- }
-}
-
-impl Drop for Asn1Time {
- fn drop(&mut self) {
- unsafe { ffi::ASN1_TIME_free(self.as_ptr()) };
- }
-}
diff --git a/openssl/src/bio.rs b/openssl/src/bio.rs
index 0d82a6c3..5fc4f31f 100644
--- a/openssl/src/bio.rs
+++ b/openssl/src/bio.rs
@@ -4,6 +4,7 @@ use std::slice;
use libc::c_int;
use ffi;
+use cvt_p;
use error::ErrorStack;
pub struct MemBioSlice<'a>(*mut ffi::BIO, PhantomData<&'a [u8]>);
@@ -21,9 +22,8 @@ impl<'a> MemBioSlice<'a> {
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))
- };
+ let bio =
+ unsafe { try!(cvt_p(BIO_new_mem_buf(buf.as_ptr() as *const _, buf.len() as c_int))) };
Ok(MemBioSlice(bio, PhantomData))
}
@@ -47,9 +47,7 @@ impl MemBio {
pub fn new() -> Result<MemBio, ErrorStack> {
ffi::init();
- let bio = unsafe {
- try_ssl_null!(ffi::BIO_new(ffi::BIO_s_mem()))
- };
+ let bio = unsafe { try!(cvt_p(ffi::BIO_new(ffi::BIO_s_mem()))) };
Ok(MemBio(bio))
}
@@ -65,3 +63,12 @@ impl MemBio {
}
}
}
+
+#[cfg(not(ossl101))]
+use ffi::BIO_new_mem_buf;
+
+#[cfg(ossl101)]
+#[allow(bad_style)]
+unsafe fn BIO_new_mem_buf(buf: *const ::libc::c_void, len: ::libc::c_int) -> *mut ffi::BIO {
+ ffi::BIO_new_mem_buf(buf as *mut _, len)
+}
diff --git a/openssl/src/bn.rs b/openssl/src/bn.rs
new file mode 100644
index 00000000..d52be884
--- /dev/null
+++ b/openssl/src/bn.rs
@@ -0,0 +1,843 @@
+use ffi;
+use libc::c_int;
+use std::cmp::Ordering;
+use std::ffi::CString;
+use std::{fmt, ptr};
+use std::ops::{Add, Div, Mul, Neg, Rem, Shl, Shr, Sub, Deref};
+
+use {cvt, cvt_p, cvt_n};
+use crypto::CryptoString;
+use error::ErrorStack;
+use types::{OpenSslType, OpenSslTypeRef};
+
+/// Options for the most significant bits of a randomly generated `BigNum`.
+pub struct MsbOption(c_int);
+
+/// The most significant bit of the number may be 0.
+pub const MSB_MAYBE_ZERO: MsbOption = MsbOption(-1);
+
+/// The most significant bit of the number must be 1.
+pub const MSB_ONE: MsbOption = MsbOption(0);
+
+/// The most significant two bits of the number must be 1.
+///
+/// The number of bits in the product of two such numbers will always be exactly twice the number
+/// of bits in the original numbers.
+pub const TWO_MSB_ONE: MsbOption = MsbOption(1);
+
+type_!(BigNumContext, BigNumContextRef, ffi::BN_CTX, ffi::BN_CTX_free);
+
+impl BigNumContext {
+ /// Returns a new `BigNumContext`.
+ pub fn new() -> Result<BigNumContext, ErrorStack> {
+ unsafe { cvt_p(ffi::BN_CTX_new()).map(BigNumContext) }
+ }
+}
+
+impl BigNumRef {
+ /// Erases the memory used by this `BigNum`, resetting its value to 0.
+ ///
+ /// This can be used to destroy sensitive data such as keys when they are no longer needed.
+ pub fn clear(&mut self) {
+ unsafe { ffi::BN_clear(self.as_ptr()) }
+ }
+
+ /// Adds a `u32` to `self`.
+ pub fn add_word(&mut self, w: u32) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_add_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) }
+ }
+
+ /// Subtracts a `u32` from `self`.
+ pub fn sub_word(&mut self, w: u32) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_sub_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) }
+ }
+
+ /// Multiplies a `u32` by `self`.
+ pub fn mul_word(&mut self, w: u32) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_mul_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) }
+ }
+
+ /// Divides `self` by a `u32`, returning the remainder.
+ pub fn div_word(&mut self, w: u32) -> Result<u64, ErrorStack> {
+ unsafe {
+ let r = ffi::BN_div_word(self.as_ptr(), w.into());
+ if r == ffi::BN_ULONG::max_value() {
+ Err(ErrorStack::get())
+ } else {
+ Ok(r.into())
+ }
+ }
+ }
+
+ /// Returns the result of `self` modulo `w`.
+ pub fn mod_word(&self, w: u32) -> Result<u64, ErrorStack> {
+ unsafe {
+ let r = ffi::BN_mod_word(self.as_ptr(), w.into());
+ if r == ffi::BN_ULONG::max_value() {
+ Err(ErrorStack::get())
+ } else {
+ Ok(r.into())
+ }
+ }
+ }
+
+ /// Places a cryptographically-secure pseudo-random number nonnegative
+ /// number less than `self` in `rnd`.
+ pub fn rand_range(&self, rnd: &mut BigNumRef) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_rand_range(self.as_ptr(), rnd.as_ptr())).map(|_| ()) }
+ }
+
+ /// The cryptographically weak counterpart to `rand_in_range`.
+ pub fn pseudo_rand_range(&self, rnd: &mut BigNumRef) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_pseudo_rand_range(self.as_ptr(), rnd.as_ptr())).map(|_| ()) }
+ }
+
+ /// 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<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_set_bit(self.as_ptr(), n.into())).map(|_| ()) }
+ }
+
+ /// 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<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_clear_bit(self.as_ptr(), n.into())).map(|_| ()) }
+ }
+
+ /// Returns `true` if the `n`th bit of `self` is set to 1, `false` otherwise.
+ pub fn is_bit_set(&self, n: i32) -> bool {
+ unsafe { ffi::BN_is_bit_set(self.as_ptr(), n.into()) == 1 }
+ }
+
+ /// Truncates `self` to the lowest `n` bits.
+ ///
+ /// An error occurs if `self` is already shorter than `n` bits.
+ pub fn mask_bits(&mut self, n: i32) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_mask_bits(self.as_ptr(), n.into())).map(|_| ()) }
+ }
+
+ /// Places `a << 1` in `self`.
+ pub fn lshift1(&mut self, a: &BigNumRef) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_lshift1(self.as_ptr(), a.as_ptr())).map(|_| ()) }
+ }
+
+ /// Places `a >> 1` in `self`.
+ pub fn rshift1(&mut self, a: &BigNumRef) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_rshift1(self.as_ptr(), a.as_ptr())).map(|_| ()) }
+ }
+
+ /// Places `a + b` in `self`.
+ pub fn checked_add(&mut self, a: &BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_add(self.as_ptr(), a.as_ptr(), b.as_ptr())).map(|_| ()) }
+ }
+
+ /// Places `a - b` in `self`.
+ pub fn checked_sub(&mut self, a: &BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_sub(self.as_ptr(), a.as_ptr(), b.as_ptr())).map(|_| ()) }
+ }
+
+ /// Places `a << n` in `self`.
+ pub fn lshift(&mut self, a: &BigNumRef, n: i32) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_lshift(self.as_ptr(), a.as_ptr(), n.into())).map(|_| ()) }
+ }
+
+ /// Places `a >> n` in `self`.
+ pub fn rshift(&mut self, a: &BigNumRef, n: i32) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_rshift(self.as_ptr(), a.as_ptr(), n.into())).map(|_| ()) }
+ }
+
+ pub fn to_owned(&self) -> Result<BigNum, ErrorStack> {
+ unsafe { cvt_p(ffi::BN_dup(self.as_ptr())).map(|b| BigNum::from_ptr(b)) }
+ }
+
+ /// Sets the sign of `self`.
+ pub fn set_negative(&mut self, negative: bool) {
+ unsafe { ffi::BN_set_negative(self.as_ptr(), negative as c_int) }
+ }
+
+ /// Compare the absolute values of `self` and `oth`.
+ ///
+ /// ```
+ /// # use openssl::bn::BigNum;
+ /// # use std::cmp::Ordering;
+ /// let s = -BigNum::from_u32(8).unwrap();
+ /// let o = BigNum::from_u32(8).unwrap();
+ ///
+ /// assert_eq!(s.ucmp(&o), Ordering::Equal);
+ /// ```
+ pub fn ucmp(&self, oth: &BigNumRef) -> Ordering {
+ unsafe { ffi::BN_ucmp(self.as_ptr(), oth.as_ptr()).cmp(&0) }
+ }
+
+ pub fn is_negative(&self) -> bool {
+ self._is_negative()
+ }
+
+ #[cfg(ossl10x)]
+ fn _is_negative(&self) -> bool {
+ unsafe { (*self.as_ptr()).neg == 1 }
+ }
+
+ #[cfg(ossl110)]
+ fn _is_negative(&self) -> bool {
+ unsafe { ffi::BN_is_negative(self.as_ptr()) == 1 }
+ }
+
+ /// Returns the number of significant bits in `self`.
+ pub fn num_bits(&self) -> i32 {
+ unsafe { ffi::BN_num_bits(self.as_ptr()) as i32 }
+ }
+
+ /// Returns the size of `self` in bytes.
+ pub fn num_bytes(&self) -> i32 {
+ (self.num_bits() + 7) / 8
+ }
+
+ /// Generates a cryptographically strong pseudo-random `BigNum`, placing it in `self`.
+ ///
+ /// # Parameters
+ ///
+ /// * `bits`: Length of the number in bits.
+ /// * `msb`: The desired properties of the number.
+ /// * `odd`: If `true`, the generated number will be odd.
+ pub fn rand(&mut self, bits: i32, msb: MsbOption, odd: bool) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_rand(self.as_ptr(), bits.into(), msb.0, odd as c_int)).map(|_| ()) }
+ }
+
+ /// The cryptographically weak counterpart to `rand`.
+ pub fn pseudo_rand(&mut self, bits: i32, msb: MsbOption, odd: bool) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::BN_pseudo_rand(self.as_ptr(), bits.into(), msb.0, odd as c_int)).map(|_| ())
+ }
+ }
+
+ /// Generates a prime number, placing it in `self`.
+ ///
+ /// # Parameters
+ ///
+ /// * `bits`: The length of the prime in bits (lower bound).
+ /// * `safe`: If true, returns a "safe" prime `p` so that `(p-1)/2` is also prime.
+ /// * `add`/`rem`: If `add` is set to `Some(add)`, `p % add == rem` will hold, where `p` is the
+ /// generated prime and `rem` is `1` if not specified (`None`).
+ pub fn generate_prime(&mut self,
+ bits: i32,
+ safe: bool,
+ add: Option<&BigNumRef>,
+ rem: Option<&BigNumRef>)
+ -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::BN_generate_prime_ex(self.as_ptr(),
+ bits as c_int,
+ safe as c_int,
+ add.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut()),
+ rem.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut()),
+ ptr::null_mut()))
+ .map(|_| ())
+ }
+ }
+
+ /// Places the result of `a * b` in `self`.
+ pub fn checked_mul(&mut self,
+ a: &BigNumRef,
+ b: &BigNumRef,
+ ctx: &mut BigNumContextRef)
+ -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_mul(self.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())).map(|_| ()) }
+ }
+
+ /// Places the result of `a / b` in `self`.
+ pub fn checked_div(&mut self,
+ a: &BigNumRef,
+ b: &BigNumRef,
+ ctx: &mut BigNumContextRef)
+ -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::BN_div(self.as_ptr(),
+ ptr::null_mut(),
+ a.as_ptr(),
+ b.as_ptr(),
+ ctx.as_ptr()))
+ .map(|_| ())
+ }
+ }
+
+ /// Places the result of `a % b` in `self`.
+ pub fn checked_rem(&mut self,
+ a: &BigNumRef,
+ b: &BigNumRef,
+ ctx: &mut BigNumContextRef)
+ -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::BN_div(ptr::null_mut(),
+ self.as_ptr(),
+ a.as_ptr(),
+ b.as_ptr(),
+ ctx.as_ptr()))
+ .map(|_| ())
+ }
+ }
+
+ /// Places the result of `a / b` in `self` and `a % b` in `rem`.
+ pub fn div_rem(&mut self,
+ rem: &mut BigNumRef,
+ a: &BigNumRef,
+ b: &BigNumRef,
+ ctx: &mut BigNumContextRef)
+ -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::BN_div(self.as_ptr(),
+ rem.as_ptr(),
+ a.as_ptr(),
+ b.as_ptr(),
+ ctx.as_ptr()))
+ .map(|_| ())
+ }
+ }
+
+ /// Places the result of `a²` in `self`.
+ pub fn sqr(&mut self, a: &BigNumRef, ctx: &mut BigNumContextRef) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_sqr(self.as_ptr(), a.as_ptr(), ctx.as_ptr())).map(|_| ()) }
+ }
+
+ /// Places the result of `a mod m` in `self`.
+ pub fn nnmod(&mut self,
+ a: &BigNumRef,
+ m: &BigNumRef,
+ ctx: &mut BigNumContextRef)
+ -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::BN_nnmod(self.as_ptr(), a.as_ptr(), m.as_ptr(), ctx.as_ptr())).map(|_| ())
+ }
+ }
+
+ /// Places the result of `(a + b) mod m` in `self`.
+ pub fn mod_add(&mut self,
+ a: &BigNumRef,
+ b: &BigNumRef,
+ m: &BigNumRef,
+ ctx: &mut BigNumContextRef)
+ -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::BN_mod_add(self.as_ptr(), a.as_ptr(), b.as_ptr(), m.as_ptr(), ctx.as_ptr()))
+ .map(|_| ())
+ }
+ }
+
+ /// Places the result of `(a - b) mod m` in `self`.
+ pub fn mod_sub(&mut self,
+ a: &BigNumRef,
+ b: &BigNumRef,
+ m: &BigNumRef,
+ ctx: &mut BigNumContextRef)
+ -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::BN_mod_sub(self.as_ptr(), a.as_ptr(), b.as_ptr(), m.as_ptr(), ctx.as_ptr()))
+ .map(|_| ())
+ }
+ }
+
+ /// Places the result of `(a * b) mod m` in `self`.
+ pub fn mod_mul(&mut self,
+ a: &BigNumRef,
+ b: &BigNumRef,
+ m: &BigNumRef,
+ ctx: &mut BigNumContextRef)
+ -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::BN_mod_mul(self.as_ptr(), a.as_ptr(), b.as_ptr(), m.as_ptr(), ctx.as_ptr()))
+ .map(|_| ())
+ }
+ }
+
+ /// Places the result of `a² mod m` in `self`.
+ pub fn mod_sqr(&mut self,
+ a: &BigNumRef,
+ m: &BigNumRef,
+ ctx: &mut BigNumContextRef)
+ -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::BN_mod_sqr(self.as_ptr(), a.as_ptr(), m.as_ptr(), ctx.as_ptr())).map(|_| ())
+ }
+ }
+
+ /// Places the result of `a^p` in `self`.
+ pub fn exp(&mut self,
+ a: &BigNumRef,
+ p: &BigNumRef,
+ ctx: &mut BigNumContextRef)
+ -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_exp(self.as_ptr(), a.as_ptr(), p.as_ptr(), ctx.as_ptr())).map(|_| ()) }
+ }
+
+ /// Places the result of `a^p mod m` in `self`.
+ pub fn mod_exp(&mut self,
+ a: &BigNumRef,
+ p: &BigNumRef,
+ m: &BigNumRef,
+ ctx: &mut BigNumContextRef)
+ -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::BN_mod_exp(self.as_ptr(), a.as_ptr(), p.as_ptr(), m.as_ptr(), ctx.as_ptr()))
+ .map(|_| ())
+ }
+ }
+
+ /// Places the inverse of `a` modulo `n` in `self`.
+ pub fn mod_inverse(&mut self,
+ a: &BigNumRef,
+ n: &BigNumRef,
+ ctx: &mut BigNumContextRef)
+ -> Result<(), ErrorStack> {
+ unsafe {
+ cvt_p(ffi::BN_mod_inverse(self.as_ptr(), a.as_ptr(), n.as_ptr(), ctx.as_ptr()))
+ .map(|_| ())
+ }
+ }
+
+ /// Places the greatest common denominator of `a` and `b` in `self`.
+ pub fn gcd(&mut self,
+ a: &BigNumRef,
+ b: &BigNumRef,
+ ctx: &mut BigNumContextRef)
+ -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::BN_gcd(self.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())).map(|_| ()) }
+ }
+
+ /// Checks whether `self` is prime.
+ ///
+ /// Performs a Miller-Rabin probabilistic primality test with `checks` iterations.
+ ///
+ /// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`.
+ pub fn is_prime(&self, checks: i32, ctx: &mut BigNumContextRef) -> Result<bool, ErrorStack> {
+ unsafe {
+ cvt_n(ffi::BN_is_prime_ex(self.as_ptr(), checks.into(), ctx.as_ptr(), ptr::null_mut()))
+ .map(|r| r != 0)
+ }
+ }
+
+ /// Checks whether `self` is prime with optional trial division.
+ ///
+ /// If `do_trial_division` is `true`, first performs trial division by a number of small primes.
+ /// Then, like `is_prime`, performs a Miller-Rabin probabilistic primality test with `checks`
+ /// iterations.
+ ///
+ /// # Return Value
+ ///
+ /// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`.
+ pub fn is_prime_fasttest(&self,
+ checks: i32,
+ ctx: &mut BigNumContextRef,
+ do_trial_division: bool)
+ -> Result<bool, ErrorStack> {
+ unsafe {
+ cvt_n(ffi::BN_is_prime_fasttest_ex(self.as_ptr(),
+ checks.into(),
+ ctx.as_ptr(),
+ do_trial_division as c_int,
+ ptr::null_mut()))
+ .map(|r| r != 0)
+ }
+ }
+
+ /// Returns a big-endian byte vector representation of the absolute value of `self`.
+ ///
+ /// `self` can be recreated by using `new_from_slice`.
+ ///
+ /// ```
+ /// # use openssl::bn::BigNum;
+ /// let s = -BigNum::from_u32(4543).unwrap();
+ /// let r = BigNum::from_u32(4543).unwrap();
+ ///
+ /// let s_vec = s.to_vec();
+ /// assert_eq!(BigNum::from_slice(&s_vec).unwrap(), r);
+ /// ```
+ pub fn to_vec(&self) -> Vec<u8> {
+ let size = self.num_bytes() as usize;
+ let mut v = Vec::with_capacity(size);
+ unsafe {
+ ffi::BN_bn2bin(self.as_ptr(), v.as_mut_ptr());
+ v.set_len(size);
+ }
+ v
+ }
+
+ /// Returns a decimal string representation of `self`.
+ ///
+ /// ```
+ /// # use openssl::bn::BigNum;
+ /// let s = -BigNum::from_u32(12345).unwrap();
+ ///
+ /// assert_eq!(&*s.to_dec_str().unwrap(), "-12345");
+ /// ```
+ pub fn to_dec_str(&self) -> Result<CryptoString, ErrorStack> {
+ unsafe {
+ let buf = try!(cvt_p(ffi::BN_bn2dec(self.as_ptr())));
+ Ok(CryptoString::from_null_terminated(buf))
+ }
+ }
+
+ /// Returns a hexadecimal string representation of `self`.
+ ///
+ /// ```
+ /// # use openssl::bn::BigNum;
+ /// let s = -BigNum::from_u32(0x99ff).unwrap();
+ ///
+ /// assert_eq!(&*s.to_hex_str().unwrap(), "-99FF");
+ /// ```
+ pub fn to_hex_str(&self) -> Result<CryptoString, ErrorStack> {
+ unsafe {
+ let buf = try!(cvt_p(ffi::BN_bn2hex(self.as_ptr())));
+ Ok(CryptoString::from_null_terminated(buf))
+ }
+ }
+}
+
+type_!(BigNum, BigNumRef, ffi::BIGNUM, ffi::BN_free);
+
+impl BigNum {
+ /// Creates a new `BigNum` with the value 0.
+ pub fn new() -> Result<BigNum, ErrorStack> {
+ unsafe {
+ ffi::init();
+ let v = try!(cvt_p(ffi::BN_new()));
+ Ok(BigNum::from_ptr(v))
+ }
+ }
+
+ /// Creates a new `BigNum` with the given value.
+ pub fn from_u32(n: u32) -> Result<BigNum, ErrorStack> {
+ BigNum::new().and_then(|v| unsafe {
+ cvt(ffi::BN_set_word(v.as_ptr(), n as ffi::BN_ULONG)).map(|_| v)
+ })
+ }
+
+ /// Creates a `BigNum` from a decimal string.
+ pub fn from_dec_str(s: &str) -> Result<BigNum, ErrorStack> {
+ unsafe {
+ let c_str = CString::new(s.as_bytes()).unwrap();
+ let mut bn = ptr::null_mut();
+ try!(cvt(ffi::BN_dec2bn(&mut bn, c_str.as_ptr() as *const _)));
+ Ok(BigNum::from_ptr(bn))
+ }
+ }
+
+ /// Creates a `BigNum` from a hexadecimal string.
+ pub fn from_hex_str(s: &str) -> Result<BigNum, ErrorStack> {
+ unsafe {
+ let c_str = CString::new(s.as_bytes()).unwrap();
+ let mut bn = ptr::null_mut();
+ try!(cvt(ffi::BN_hex2bn(&mut bn, c_str.as_ptr() as *const _)));
+ Ok(BigNum::from_ptr(bn))
+ }
+ }
+
+ /// Creates a new `BigNum` from an unsigned, big-endian encoded number of arbitrary length.
+ ///
+ /// ```
+ /// # use openssl::bn::BigNum;
+ /// let bignum = BigNum::from_slice(&[0x12, 0x00, 0x34]).unwrap();
+ ///
+ /// assert_eq!(bignum, BigNum::from_u32(0x120034).unwrap());
+ /// ```
+ pub fn from_slice(n: &[u8]) -> Result<BigNum, ErrorStack> {
+ unsafe {
+ assert!(n.len() <= c_int::max_value() as usize);
+ cvt_p(ffi::BN_bin2bn(n.as_ptr(), n.len() as c_int, ptr::null_mut()))
+ .map(|p| BigNum::from_ptr(p))
+ }
+ }
+}
+
+impl AsRef<BigNumRef> for BigNum {
+ fn as_ref(&self) -> &BigNumRef {
+ self.deref()
+ }
+}
+
+impl fmt::Debug for BigNumRef {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self.to_dec_str() {
+ Ok(s) => f.write_str(&s),
+ Err(e) => Err(e.into()),
+ }
+ }
+}
+
+impl fmt::Debug for BigNum {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self.to_dec_str() {
+ Ok(s) => f.write_str(&s),
+ Err(e) => Err(e.into()),
+ }
+ }
+}
+
+impl fmt::Display for BigNumRef {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self.to_dec_str() {
+ Ok(s) => f.write_str(&s),
+ Err(e) => Err(e.into()),
+ }
+ }
+}
+
+impl fmt::Display for BigNum {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self.to_dec_str() {
+ Ok(s) => f.write_str(&s),
+ Err(e) => Err(e.into()),
+ }
+ }
+}
+
+impl PartialEq<BigNumRef> for BigNumRef {
+ fn eq(&self, oth: &BigNumRef) -> bool {
+ self.cmp(oth) == Ordering::Equal
+ }
+}
+
+impl PartialEq<BigNum> for BigNumRef {
+ fn eq(&self, oth: &BigNum) -> bool {
+ self.eq(oth.deref())
+ }
+}
+
+impl Eq for BigNumRef {}
+
+impl PartialEq for BigNum {
+ fn eq(&self, oth: &BigNum) -> bool {
+ self.deref().eq(oth)
+ }
+}
+
+impl PartialEq<BigNumRef> for BigNum {
+ fn eq(&self, oth: &BigNumRef) -> bool {
+ self.deref().eq(oth)
+ }
+}
+
+impl Eq for BigNum {}
+
+impl PartialOrd<BigNumRef> for BigNumRef {
+ fn partial_cmp(&self, oth: &BigNumRef) -> Option<Ordering> {
+ Some(self.cmp(oth))
+ }
+}
+
+impl PartialOrd<BigNum> for BigNumRef {
+ fn partial_cmp(&self, oth: &BigNum) -> Option<Ordering> {
+ Some(self.cmp(oth.deref()))
+ }
+}
+
+impl Ord for BigNumRef {
+ fn cmp(&self, oth: &BigNumRef) -> Ordering {
+ unsafe { ffi::BN_cmp(self.as_ptr(), oth.as_ptr()).cmp(&0) }
+ }
+}
+
+impl PartialOrd for BigNum {
+ fn partial_cmp(&self, oth: &BigNum) -> Option<Ordering> {
+ self.deref().partial_cmp(oth.deref())
+ }
+}
+
+impl PartialOrd<BigNumRef> for BigNum {
+ fn partial_cmp(&self, oth: &BigNumRef) -> Option<Ordering> {
+ self.deref().partial_cmp(oth)
+ }
+}
+
+impl Ord for BigNum {
+ fn cmp(&self, oth: &BigNum) -> Ordering {
+ self.deref().cmp(oth.deref())
+ }
+}
+
+macro_rules! delegate {
+ ($t:ident, $m:ident) => {
+ impl<'a, 'b> $t<&'b BigNum> for &'a BigNumRef {
+ type Output = BigNum;
+
+ fn $m(self, oth: &BigNum) -> BigNum {
+ $t::$m(self, oth.deref())
+ }
+ }
+
+ impl<'a, 'b> $t<&'b BigNumRef> for &'a BigNum {
+ type Output = BigNum;
+
+ fn $m(self, oth: &BigNumRef) -> BigNum {
+ $t::$m(self.deref(), oth)
+ }
+ }
+
+ impl<'a, 'b> $t<&'b BigNum> for &'a BigNum {
+ type Output = BigNum;
+
+ fn $m(self, oth: &BigNum) -> BigNum {
+ $t::$m(self.deref(), oth.deref())
+ }
+ }
+ }
+}
+
+impl<'a, 'b> Add<&'b BigNumRef> for &'a BigNumRef {
+ type Output = BigNum;
+
+ fn add(self, oth: &BigNumRef) -> BigNum {
+ let mut r = BigNum::new().unwrap();
+ r.checked_add(self, oth).unwrap();
+ r
+ }
+}
+
+delegate!(Add, add);
+
+impl<'a, 'b> Sub<&'b BigNumRef> for &'a BigNumRef {
+ type Output = BigNum;
+
+ fn sub(self, oth: &BigNumRef) -> BigNum {
+ let mut r = BigNum::new().unwrap();
+ r.checked_sub(self, oth).unwrap();
+ r
+ }
+}
+
+delegate!(Sub, sub);
+
+impl<'a, 'b> Mul<&'b BigNumRef> for &'a BigNumRef {
+ type Output = BigNum;
+
+ fn mul(self, oth: &BigNumRef) -> BigNum {
+ let mut ctx = BigNumContext::new().unwrap();
+ let mut r = BigNum::new().unwrap();
+ r.checked_mul(self, oth, &mut ctx).unwrap();
+ r
+ }
+}
+
+delegate!(Mul, mul);
+
+impl<'a, 'b> Div<&'b BigNumRef> for &'a BigNumRef {
+ type Output = BigNum;
+
+ fn div(self, oth: &'b BigNumRef) -> BigNum {
+ let mut ctx = BigNumContext::new().unwrap();
+ let mut r = BigNum::new().unwrap();
+ r.checked_div(self, oth, &mut ctx).unwrap();
+ r
+ }
+}
+
+delegate!(Div, div);
+
+impl<'a, 'b> Rem<&'b BigNumRef> for &'a BigNumRef {
+ type Output = BigNum;
+
+ fn rem(self, oth: &'b BigNumRef) -> BigNum {
+ let mut ctx = BigNumContext::new().unwrap();
+ let mut r = BigNum::new().unwrap();
+ r.checked_rem(self, oth, &mut ctx).unwrap();
+ r
+ }
+}
+
+delegate!(Rem, rem);
+
+impl<'a> Shl<i32> for &'a BigNumRef {
+ type Output = BigNum;
+
+ fn shl(self, n: i32) -> BigNum {
+ let mut r = BigNum::new().unwrap();
+ r.lshift(self, n).unwrap();
+ r
+ }
+}
+
+impl<'a> Shl<i32> for &'a BigNum {
+ type Output = BigNum;
+
+ fn shl(self, n: i32) -> BigNum {
+ self.deref().shl(n)
+ }
+}
+
+impl<'a> Shr<i32> for &'a BigNumRef {
+ type Output = BigNum;
+
+ fn shr(self, n: i32) -> BigNum {
+ let mut r = BigNum::new().unwrap();
+ r.rshift(self, n).unwrap();
+ r
+ }
+}
+
+impl<'a> Shr<i32> for &'a BigNum {
+ type Output = BigNum;
+
+ fn shr(self, n: i32) -> BigNum {
+ self.deref().shl(n)
+ }
+}
+
+impl<'a> Neg for &'a BigNumRef {
+ type Output = BigNum;
+
+ fn neg(self) -> BigNum {
+ self.to_owned().unwrap().neg()
+ }
+}
+
+impl<'a> Neg for &'a BigNum {
+ type Output = BigNum;
+
+ fn neg(self) -> BigNum {
+ self.deref().neg()
+ }
+}
+
+impl Neg for BigNum {
+ type Output = BigNum;
+
+ fn neg(mut self) -> BigNum {
+ let negative = self.is_negative();
+ self.set_negative(!negative);
+ self
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use bn::{BigNumContext, BigNum};
+
+ #[test]
+ fn test_to_from_slice() {
+ let v0 = BigNum::from_u32(10203004).unwrap();
+ let vec = v0.to_vec();
+ let v1 = BigNum::from_slice(&vec).unwrap();
+
+ assert!(v0 == v1);
+ }
+
+ #[test]
+ fn test_negation() {
+ let a = BigNum::from_u32(909829283).unwrap();
+
+ assert!(!a.is_negative());
+ assert!((-a).is_negative());
+ }
+
+ #[test]
+ fn test_prime_numbers() {
+ let a = BigNum::from_u32(19029017).unwrap();
+ let mut p = BigNum::new().unwrap();
+ p.generate_prime(128, true, None, Some(&a)).unwrap();
+
+ let mut ctx = BigNumContext::new().unwrap();
+ assert!(p.is_prime(100, &mut ctx).unwrap());
+ assert!(p.is_prime_fasttest(100, &mut ctx, true).unwrap());
+ }
+}
diff --git a/openssl/src/bn/mod.rs b/openssl/src/bn/mod.rs
deleted file mode 100644
index de9d0d2a..00000000
--- a/openssl/src/bn/mod.rs
+++ /dev/null
@@ -1,1023 +0,0 @@
-use libc::{c_int, c_ulong, c_void};
-use std::ffi::{CStr, CString};
-use std::cmp::Ordering;
-use std::{fmt, ptr};
-use std::marker::PhantomData;
-use std::ops::{Add, Div, Mul, Neg, Rem, Shl, Shr, Sub, Deref, DerefMut};
-
-use ffi;
-use error::ErrorStack;
-
-/// Specifies the desired properties of a randomly generated `BigNum`.
-#[derive(Copy, Clone)]
-#[repr(C)]
-pub enum RNGProperty {
- /// The most significant bit of the number is allowed to be 0.
- MsbMaybeZero = -1,
- /// The MSB should be set to 1.
- MsbOne = 0,
- /// The two most significant bits of the number will be set to 1, so that the product of two
- /// such random numbers will always have `2 * bits` length.
- TwoMsbOne = 1,
-}
-
-macro_rules! with_ctx(
- ($name:ident, $action:block) => ({
- let $name = ffi::BN_CTX_new();
- if ($name).is_null() {
- Err(ErrorStack::get())
- } else {
- let r = $action;
- ffi::BN_CTX_free($name);
- r
- }
- });
-);
-
-macro_rules! with_bn(
- ($name:ident, $action:block) => ({
- let tmp = BigNum::new();
- match tmp {
- Ok($name) => {
- if $action {
- Ok($name)
- } else {
- Err(ErrorStack::get())
- }
- },
- Err(err) => Err(err),
- }
- });
-);
-
-macro_rules! with_bn_in_ctx(
- ($name:ident, $ctx_name:ident, $action:block) => ({
- let tmp = BigNum::new();
- match tmp {
- Ok($name) => {
- let $ctx_name = ffi::BN_CTX_new();
- if ($ctx_name).is_null() {
- Err(ErrorStack::get())
- } else {
- let r =
- if $action {
- Ok($name)
- } else {
- Err(ErrorStack::get())
- };
- ffi::BN_CTX_free($ctx_name);
- r
- }
- },
- Err(err) => Err(err),
- }
- });
-);
-
-/// A borrowed, signed, arbitrary-precision integer.
-#[derive(Copy, Clone)]
-pub struct BigNumRef<'a>(*mut ffi::BIGNUM, PhantomData<&'a ()>);
-
-
-impl<'a> BigNumRef<'a> {
- pub unsafe fn from_ptr(handle: *mut ffi::BIGNUM) -> BigNumRef<'a> {
- BigNumRef(handle, PhantomData)
- }
-
- /// Returns the square of `self`.
- ///
- /// ```
- /// # use openssl::bn::BigNum;
- /// let ref n = BigNum::new_from(10).unwrap();
- /// let squared = BigNum::new_from(100).unwrap();
- ///
- /// assert_eq!(n.checked_sqr().unwrap(), squared);
- /// assert_eq!(n * n, squared);
- /// ```
- pub fn checked_sqr(&self) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_sqr(r.as_ptr(), self.as_ptr(), ctx) == 1
- })
- }
- }
-
- /// Returns the unsigned remainder of the division `self / n`.
- pub fn checked_nnmod(&self, n: &BigNumRef) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_nnmod(r.as_ptr(), self.as_ptr(), n.as_ptr(), ctx) == 1
- })
- }
- }
-
- /// Equivalent to `(self + a) mod n`.
- ///
- /// ```
- /// # use openssl::bn::BigNum;
- /// let ref s = BigNum::new_from(10).unwrap();
- /// let ref a = BigNum::new_from(20).unwrap();
- /// let ref n = BigNum::new_from(29).unwrap();
- /// let result = BigNum::new_from(1).unwrap();
- ///
- /// assert_eq!(s.checked_mod_add(a, n).unwrap(), result);
- /// ```
- pub fn checked_mod_add(&self, a: &BigNumRef, n: &BigNumRef) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_mod_add(r.as_ptr(), self.as_ptr(), a.as_ptr(), n.as_ptr(), ctx) == 1
- })
- }
- }
-
- /// Equivalent to `(self - a) mod n`.
- pub fn checked_mod_sub(&self, a: &BigNumRef, n: &BigNumRef) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_mod_sub(r.as_ptr(), self.as_ptr(), a.as_ptr(), n.as_ptr(), ctx) == 1
- })
- }
- }
-
- /// Equivalent to `(self * a) mod n`.
- pub fn checked_mod_mul(&self, a: &BigNumRef, n: &BigNumRef) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_mod_mul(r.as_ptr(), self.as_ptr(), a.as_ptr(), n.as_ptr(), ctx) == 1
- })
- }
- }
-
- /// Equivalent to `self² mod n`.
- pub fn checked_mod_sqr(&self, n: &BigNumRef) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_mod_sqr(r.as_ptr(), self.as_ptr(), n.as_ptr(), ctx) == 1
- })
- }
- }
-
- /// Raises `self` to the `p`th power.
- pub fn checked_exp(&self, p: &BigNumRef) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_exp(r.as_ptr(), self.as_ptr(), p.as_ptr(), ctx) == 1
- })
- }
- }
-
- /// Equivalent to `self.checked_exp(p) mod n`.
- pub fn checked_mod_exp(&self, p: &BigNumRef, n: &BigNumRef) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_mod_exp(r.as_ptr(), self.as_ptr(), p.as_ptr(), n.as_ptr(), ctx) == 1
- })
- }
- }
-
- /// Calculates the modular multiplicative inverse of `self` modulo `n`, that is, an integer `r`
- /// such that `(self * r) % n == 1`.
- pub fn checked_mod_inv(&self, n: &BigNumRef) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- !ffi::BN_mod_inverse(r.as_ptr(), self.as_ptr(), n.as_ptr(), ctx).is_null()
- })
- }
- }
-
- /// Add an `unsigned long` to `self`. This is more efficient than adding a `BigNum`.
- pub fn add_word(&mut self, w: c_ulong) -> Result<(), ErrorStack> {
- unsafe {
- if ffi::BN_add_word(self.as_ptr(), w) == 1 {
- Ok(())
- } else {
- Err(ErrorStack::get())
- }
- }
- }
-
- pub fn sub_word(&mut self, w: c_ulong) -> Result<(), ErrorStack> {
- unsafe {
- if ffi::BN_sub_word(self.as_ptr(), w) == 1 {
- Ok(())
- } else {
- Err(ErrorStack::get())
- }
- }
- }
-
- pub fn mul_word(&mut self, w: c_ulong) -> Result<(), ErrorStack> {
- unsafe {
- if ffi::BN_mul_word(self.as_ptr(), w) == 1 {
- Ok(())
- } else {
- Err(ErrorStack::get())
- }
- }
- }
-
- pub fn div_word(&mut self, w: c_ulong) -> Result<c_ulong, ErrorStack> {
- unsafe {
- let result = ffi::BN_div_word(self.as_ptr(), w);
- if result != !0 as c_ulong {
- Ok(result)
- } else {
- Err(ErrorStack::get())
- }
- }
- }
-
- pub fn mod_word(&self, w: c_ulong) -> Result<c_ulong, ErrorStack> {
- unsafe {
- let result = ffi::BN_mod_word(self.as_ptr(), w);
- if result != !0 as c_ulong {
- Ok(result)
- } else {
- Err(ErrorStack::get())
- }
- }
- }
-
- /// Computes the greatest common denominator of `self` and `a`.
- pub fn checked_gcd(&self, a: &BigNumRef) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_gcd(r.as_ptr(), self.as_ptr(), a.as_ptr(), ctx) == 1
- })
- }
- }
-
- /// Checks whether `self` is prime.
- ///
- /// Performs a Miller-Rabin probabilistic primality test with `checks` iterations.
- ///
- /// # 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, ErrorStack> {
- unsafe {
- with_ctx!(ctx, {
- Ok(ffi::BN_is_prime_ex(self.as_ptr(), checks as c_int, ctx, ptr::null()) == 1)
- })
- }
- }
-
- /// Checks whether `self` is prime with optional trial division.
- ///
- /// If `do_trial_division` is `true`, first performs trial division by a number of small primes.
- /// Then, like `is_prime`, performs a Miller-Rabin probabilistic primality test with `checks`
- /// iterations.
- ///
- /// # 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, ErrorStack> {
- unsafe {
- with_ctx!(ctx, {
- Ok(ffi::BN_is_prime_fasttest_ex(self.as_ptr(),
- checks as c_int,
- ctx,
- do_trial_division as c_int,
- ptr::null()) == 1)
- })
- }
- }
-
- /// Generates a cryptographically strong pseudo-random `BigNum` `r` in the range
- /// `0 <= r < self`.
- pub fn checked_rand_in_range(&self) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_rand_range(r.as_ptr(), self.as_ptr()) == 1
- })
- }
- }
-
- /// The cryptographically weak counterpart to `checked_rand_in_range`.
- pub fn checked_pseudo_rand_in_range(&self) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_pseudo_rand_range(r.as_ptr(), self.as_ptr()) == 1
- })
- }
- }
-
- /// 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<(), ErrorStack> {
- unsafe {
- if ffi::BN_set_bit(self.as_ptr(), n as c_int) == 1 {
- Ok(())
- } else {
- Err(ErrorStack::get())
- }
- }
- }
-
- /// 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<(), ErrorStack> {
- unsafe {
- if ffi::BN_clear_bit(self.as_ptr(), n as c_int) == 1 {
- Ok(())
- } else {
- Err(ErrorStack::get())
- }
- }
- }
-
- /// Returns `true` if the `n`th bit of `self` is set to 1, `false` otherwise.
- pub fn is_bit_set(&self, n: i32) -> bool {
- unsafe { ffi::BN_is_bit_set(self.as_ptr(), n as c_int) == 1 }
- }
-
- /// Truncates `self` to the lowest `n` bits.
- ///
- /// An error occurs if `self` is already shorter than `n` bits.
- pub fn mask_bits(&mut self, n: i32) -> Result<(), ErrorStack> {
- unsafe {
- if ffi::BN_mask_bits(self.as_ptr(), n as c_int) == 1 {
- Ok(())
- } else {
- Err(ErrorStack::get())
- }
- }
- }
-
- /// Returns `self`, shifted left by 1 bit. `self` may be negative.
- ///
- /// ```
- /// # use openssl::bn::BigNum;
- /// let ref s = BigNum::new_from(0b0100).unwrap();
- /// let result = BigNum::new_from(0b1000).unwrap();
- ///
- /// assert_eq!(s.checked_shl1().unwrap(), result);
- /// ```
- ///
- /// ```
- /// # use openssl::bn::BigNum;
- /// let ref s = -BigNum::new_from(8).unwrap();
- /// let result = -BigNum::new_from(16).unwrap();
- ///
- /// // (-8) << 1 == -16
- /// assert_eq!(s.checked_shl1().unwrap(), result);
- /// ```
- pub fn checked_shl1(&self) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn!(r, {
- ffi::BN_lshift1(r.as_ptr(), self.as_ptr()) == 1
- })
- }
- }
-
- /// Returns `self`, shifted right by 1 bit. `self` may be negative.
- pub fn checked_shr1(&self) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn!(r, {
- ffi::BN_rshift1(r.as_ptr(), self.as_ptr()) == 1
- })
- }
- }
-
- pub fn checked_add(&self, a: &BigNumRef) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn!(r, {
- ffi::BN_add(r.as_ptr(), self.as_ptr(), a.as_ptr()) == 1
- })
- }
- }
-
- pub fn checked_sub(&self, a: &BigNumRef) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn!(r, {
- ffi::BN_sub(r.as_ptr(), self.as_ptr(), a.as_ptr()) == 1
- })
- }
- }
-
- pub fn checked_mul(&self, a: &BigNumRef) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_mul(r.as_ptr(), self.as_ptr(), a.as_ptr(), ctx) == 1
- })
- }
- }
-
- pub fn checked_div(&self, a: &BigNumRef) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_div(r.as_ptr(), ptr::null_mut(), self.as_ptr(), a.as_ptr(), ctx) == 1
- })
- }
- }
-
- pub fn checked_mod(&self, a: &BigNumRef) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_div(ptr::null_mut(), r.as_ptr(), self.as_ptr(), a.as_ptr(), ctx) == 1
- })
- }
- }
-
- pub fn checked_shl(&self, a: &i32) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn!(r, {
- ffi::BN_lshift(r.as_ptr(), self.as_ptr(), *a as c_int) == 1
- })
- }
- }
-
- pub fn checked_shr(&self, a: &i32) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn!(r, {
- ffi::BN_rshift(r.as_ptr(), self.as_ptr(), *a as c_int) == 1
- })
- }
- }
-
- pub fn to_owned(&self) -> Result<BigNum, ErrorStack> {
- unsafe {
- let r = try_ssl_null!(ffi::BN_dup(self.as_ptr()));
- Ok(BigNum::from_ptr(r))
- }
- }
-
- /// Inverts the sign of `self`.
- ///
- /// ```
- /// # use openssl::bn::BigNum;
- /// let mut s = BigNum::new_from(8).unwrap();
- ///
- /// s.negate();
- /// assert_eq!(s, -BigNum::new_from(8).unwrap());
- /// s.negate();
- /// assert_eq!(s, BigNum::new_from(8).unwrap());
- /// ```
- pub fn negate(&mut self) {
- unsafe { ffi::BN_set_negative(self.as_ptr(), !self.is_negative() as c_int) }
- }
-
- /// Compare the absolute values of `self` and `oth`.
- ///
- /// ```
- /// # use openssl::bn::BigNum;
- /// # use std::cmp::Ordering;
- /// let s = -BigNum::new_from(8).unwrap();
- /// let o = BigNum::new_from(8).unwrap();
- ///
- /// assert_eq!(s.abs_cmp(&o), Ordering::Equal);
- /// ```
- pub fn abs_cmp(&self, oth: &BigNumRef) -> Ordering {
- unsafe {
- let res = ffi::BN_ucmp(self.as_ptr(), oth.as_ptr()) as i32;
- if res < 0 {
- Ordering::Less
- } else if res > 0 {
- Ordering::Greater
- } else {
- Ordering::Equal
- }
- }
- }
-
- pub fn is_negative(&self) -> bool {
- unsafe { (*self.as_ptr()).neg == 1 }
- }
-
- /// Returns the number of significant bits in `self`.
- pub fn num_bits(&self) -> i32 {
- unsafe { ffi::BN_num_bits(self.as_ptr()) as i32 }
- }
-
- /// Returns the size of `self` in bytes.
- pub fn num_bytes(&self) -> i32 {
- (self.num_bits() + 7) / 8
- }
-
- pub fn as_ptr(&self) -> *mut ffi::BIGNUM {
- self.0
- }
-
- /// Returns a big-endian byte vector representation of the absolute value of `self`.
- ///
- /// `self` can be recreated by using `new_from_slice`.
- ///
- /// ```
- /// # use openssl::bn::BigNum;
- /// let s = -BigNum::new_from(4543).unwrap();
- /// let r = BigNum::new_from(4543).unwrap();
- ///
- /// let s_vec = s.to_vec();
- /// assert_eq!(BigNum::new_from_slice(&s_vec).unwrap(), r);
- /// ```
- pub fn to_vec(&self) -> Vec<u8> {
- let size = self.num_bytes() as usize;
- let mut v = Vec::with_capacity(size);
- unsafe {
- ffi::BN_bn2bin(self.as_ptr(), v.as_mut_ptr());
- v.set_len(size);
- }
- v
- }
-
- /// Returns a decimal string representation of `self`.
- ///
- /// ```
- /// # use openssl::bn::BigNum;
- /// let s = -BigNum::new_from(12345).unwrap();
- ///
- /// assert_eq!(s.to_dec_str(), "-12345");
- /// ```
- pub fn to_dec_str(&self) -> String {
- unsafe {
- let buf = ffi::BN_bn2dec(self.as_ptr());
- assert!(!buf.is_null());
- let str = String::from_utf8(CStr::from_ptr(buf as *const _).to_bytes().to_vec())
- .unwrap();
- ffi::CRYPTO_free(buf as *mut c_void);
- str
- }
- }
-
- /// Returns a hexadecimal string representation of `self`.
- ///
- /// ```
- /// # use openssl::bn::BigNum;
- /// let s = -BigNum::new_from(0x99ff).unwrap();
- ///
- /// assert_eq!(s.to_hex_str(), "-99FF");
- /// ```
- pub fn to_hex_str(&self) -> String {
- unsafe {
- let buf = ffi::BN_bn2hex(self.as_ptr());
- assert!(!buf.is_null());
- let str = String::from_utf8(CStr::from_ptr(buf as *const _).to_bytes().to_vec())
- .unwrap();
- ffi::CRYPTO_free(buf as *mut c_void);
- str
- }
- }
-}
-
-/// An owned, signed, arbitrary-precision integer.
-///
-/// `BigNum` provides wrappers around OpenSSL's checked arithmetic functions.
-/// Additionally, it implements the standard operators (`std::ops`), which
-/// perform unchecked arithmetic, unwrapping the returned `Result` of the
-/// checked operations.
-pub struct BigNum(BigNumRef<'static>);
-
-impl BigNum {
- /// Creates a new `BigNum` with the value 0.
- pub fn new() -> Result<BigNum, ErrorStack> {
- unsafe {
- ffi::init();
- let v = try_ssl_null!(ffi::BN_new());
- Ok(BigNum::from_ptr(v))
- }
- }
-
- /// Creates a new `BigNum` with the given value.
- pub fn new_from(n: c_ulong) -> Result<BigNum, ErrorStack> {
- BigNum::new().and_then(|v| unsafe {
- try_ssl!(ffi::BN_set_word(v.as_ptr(), n));
- Ok(v)
- })
- }
-
- /// Creates a `BigNum` from a decimal string.
- pub fn from_dec_str(s: &str) -> Result<BigNum, ErrorStack> {
- BigNum::new().and_then(|v| unsafe {
- let c_str = CString::new(s.as_bytes()).unwrap();
- try_ssl!(ffi::BN_dec2bn(&(v.0).0, c_str.as_ptr() as *const _));
- Ok(v)
- })
- }
-
- /// Creates a `BigNum` from a hexadecimal string.
- pub fn from_hex_str(s: &str) -> Result<BigNum, ErrorStack> {
- BigNum::new().and_then(|v| unsafe {
- let c_str = CString::new(s.as_bytes()).unwrap();
- try_ssl!(ffi::BN_hex2bn(&(v.0).0, c_str.as_ptr() as *const _));
- Ok(v)
- })
- }
-
- pub unsafe fn from_ptr(handle: *mut ffi::BIGNUM) -> BigNum {
- BigNum(BigNumRef::from_ptr(handle))
- }
-
- /// Creates a new `BigNum` from an unsigned, big-endian encoded number of arbitrary length.
- ///
- /// ```
- /// # use openssl::bn::BigNum;
- /// let bignum = BigNum::new_from_slice(&[0x12, 0x00, 0x34]).unwrap();
- ///
- /// assert_eq!(bignum, BigNum::new_from(0x120034).unwrap());
- /// ```
- pub fn new_from_slice(n: &[u8]) -> Result<BigNum, ErrorStack> {
- BigNum::new().and_then(|v| unsafe {
- try_ssl_null!(ffi::BN_bin2bn(n.as_ptr(), n.len() as c_int, v.as_ptr()));
- Ok(v)
- })
- }
- /// Generates a prime number.
- ///
- /// # Parameters
- ///
- /// * `bits`: The length of the prime in bits (lower bound).
- /// * `safe`: If true, returns a "safe" prime `p` so that `(p-1)/2` is also prime.
- /// * `add`/`rem`: If `add` is set to `Some(add)`, `p % add == rem` will hold, where `p` is the
- /// generated prime and `rem` is `1` if not specified (`None`).
- pub fn checked_generate_prime(bits: i32,
- safe: bool,
- add: Option<&BigNum>,
- rem: Option<&BigNum>)
- -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- let add_arg = add.map(|a| a.as_ptr()).unwrap_or(ptr::null_mut());
- let rem_arg = rem.map(|r| r.as_ptr()).unwrap_or(ptr::null_mut());
-
- ffi::BN_generate_prime_ex(r.as_ptr(),
- bits as c_int,
- safe as c_int,
- add_arg,
- rem_arg,
- ptr::null()) == 1
- })
- }
- }
-
- /// Generates a cryptographically strong pseudo-random `BigNum`.
- ///
- /// # Parameters
- ///
- /// * `bits`: Length of the number in bits.
- /// * `prop`: The desired properties of the number.
- /// * `odd`: If `true`, the generated number will be odd.
- pub fn checked_new_random(bits: i32, prop: RNGProperty, odd: bool) -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_rand(r.as_ptr(), bits as c_int, prop as c_int, odd as c_int) == 1
- })
- }
- }
-
- /// The cryptographically weak counterpart to `checked_new_random`.
- pub fn checked_new_pseudo_random(bits: i32,
- prop: RNGProperty,
- odd: bool)
- -> Result<BigNum, ErrorStack> {
- unsafe {
- with_bn_in_ctx!(r, ctx, {
- ffi::BN_pseudo_rand(r.as_ptr(), bits as c_int, prop as c_int, odd as c_int) == 1
- })
- }
- }
-}
-
-impl Drop for BigNum {
- fn drop(&mut self) {
- unsafe { ffi::BN_clear_free(self.as_ptr()); }
- }
-}
-
-impl Deref for BigNum {
- type Target = BigNumRef<'static>;
-
- fn deref(&self) -> &BigNumRef<'static> {
- &self.0
- }
-}
-
-impl DerefMut for BigNum {
- fn deref_mut(&mut self) -> &mut BigNumRef<'static> {
- &mut self.0
- }
-}
-
-impl AsRef<BigNumRef<'static>> for BigNum {
- fn as_ref(&self) -> &BigNumRef<'static> {
- self.deref()
- }
-}
-
-impl<'a> fmt::Debug for BigNumRef<'a> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", self.to_dec_str())
- }
-}
-
-impl fmt::Debug for BigNum {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", self.to_dec_str())
- }
-}
-
-impl<'a> fmt::Display for BigNumRef<'a> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", self.to_dec_str())
- }
-}
-
-impl fmt::Display for BigNum {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", self.to_dec_str())
- }
-}
-
-impl<'a, 'b> PartialEq<BigNumRef<'b>> for BigNumRef<'a> {
- fn eq(&self, oth: &BigNumRef) -> bool {
- unsafe { ffi::BN_cmp(self.as_ptr(), oth.as_ptr()) == 0 }
- }
-}
-
-impl<'a> PartialEq<BigNum> for BigNumRef<'a> {
- fn eq(&self, oth: &BigNum) -> bool {
- self.eq(oth.deref())
- }
-}
-
-impl<'a> Eq for BigNumRef<'a> {}
-
-impl PartialEq for BigNum {
- fn eq(&self, oth: &BigNum) -> bool {
- self.deref().eq(oth)
- }
-}
-
-impl<'a> PartialEq<BigNumRef<'a>> for BigNum {
- fn eq(&self, oth: &BigNumRef) -> bool {
- self.deref().eq(oth)
- }
-}
-
-impl Eq for BigNum {}
-
-impl<'a, 'b> PartialOrd<BigNumRef<'b>> for BigNumRef<'a> {
- fn partial_cmp(&self, oth: &BigNumRef) -> Option<Ordering> {
- Some(self.cmp(oth))
- }
-}
-
-impl<'a> PartialOrd<BigNum> for BigNumRef<'a> {
- fn partial_cmp(&self, oth: &BigNum) -> Option<Ordering> {
- Some(self.cmp(oth.deref()))
- }
-}
-
-impl<'a> Ord for BigNumRef<'a> {
- fn cmp(&self, oth: &BigNumRef) -> Ordering {
- unsafe { ffi::BN_cmp(self.as_ptr(), oth.as_ptr()).cmp(&0) }
- }
-}
-
-impl PartialOrd for BigNum {
- fn partial_cmp(&self, oth: &BigNum) -> Option<Ordering> {
- self.deref().partial_cmp(oth.deref())
- }
-}
-
-impl<'a> PartialOrd<BigNumRef<'a>> for BigNum {
- fn partial_cmp(&self, oth: &BigNumRef) -> Option<Ordering> {
- self.deref().partial_cmp(oth)
- }
-}
-
-impl Ord for BigNum {
- fn cmp(&self, oth: &BigNum) -> Ordering {
- self.deref().cmp(oth.deref())
- }
-}
-
-impl<'a, 'b> Add<&'b BigNumRef<'b>> for &'a BigNumRef<'a> {
- type Output = BigNum;
-
- fn add(self, oth: &BigNumRef) -> BigNum {
- self.checked_add(oth).unwrap()
- }
-}
-
-impl<'a, 'b> Sub<&'b BigNumRef<'b>> for &'a BigNumRef<'a> {
- type Output = BigNum;
-
- fn sub(self, oth: &BigNumRef) -> BigNum {
- self.checked_sub(oth).unwrap()
- }
-}
-
-impl<'a, 'b> Sub<&'b BigNum> for &'a BigNumRef<'a> {
- type Output = BigNum;
-
- fn sub(self, oth: &BigNum) -> BigNum {
- self.checked_sub(oth).unwrap()
- }
-}
-
-impl<'a, 'b> Sub<&'b BigNum> for &'a BigNum {
- type Output = BigNum;
-
- fn sub(self, oth: &BigNum) -> BigNum {
- self.checked_sub(oth).unwrap()
- }
-}
-
-impl<'a, 'b> Sub<&'b BigNumRef<'b>> for &'a BigNum {
- type Output = BigNum;
-
- fn sub(self, oth: &BigNumRef) -> BigNum {
- self.checked_sub(oth).unwrap()
- }
-}
-
-impl<'a, 'b> Mul<&'b BigNumRef<'b>> for &'a BigNumRef<'a> {
- type Output = BigNum;
-
- fn mul(self, oth: &BigNumRef) -> BigNum {
- self.checked_mul(oth).unwrap()
- }
-}
-
-impl<'a, 'b> Mul<&'b BigNum> for &'a BigNumRef<'a> {
- type Output = BigNum;
-
- fn mul(self, oth: &BigNum) -> BigNum {
- self.checked_mul(oth).unwrap()
- }
-}
-
-impl<'a, 'b> Mul<&'b BigNum> for &'a BigNum {
- type Output = BigNum;
-
- fn mul(self, oth: &BigNum) -> BigNum {
- self.checked_mul(oth).unwrap()
- }
-}
-
-impl<'a, 'b> Mul<&'b BigNumRef<'b>> for &'a BigNum {
- type Output = BigNum;
-
- fn mul(self, oth: &BigNumRef) -> BigNum {
- self.checked_mul(oth).unwrap()
- }
-}
-
-impl<'a, 'b> Div<&'b BigNumRef<'b>> for &'a BigNumRef<'a> {
- type Output = BigNum;
-
- fn div(self, oth: &'b BigNumRef<'b>) -> BigNum {
- self.checked_div(oth).unwrap()
- }
-}
-
-impl<'a, 'b> Div<&'b BigNum> for &'a BigNumRef<'a> {
- type Output = BigNum;
-
- fn div(self, oth: &'b BigNum) -> BigNum {
- self.checked_div(oth).unwrap()
- }
-}
-
-impl<'a, 'b> Div<&'b BigNum> for &'a BigNum {
- type Output = BigNum;
-
- fn div(self, oth: &'b BigNum) -> BigNum {
- self.checked_div(oth).unwrap()
- }
-}
-
-impl<'a, 'b> Div<&'b BigNumRef<'b>> for &'a BigNum {
- type Output = BigNum;
-
- fn div(self, oth: &'b BigNumRef<'b>) -> BigNum {
- self.checked_div(oth).unwrap()
- }
-}
-
-impl<'a, 'b> Rem<&'b BigNumRef<'b>> for &'a BigNumRef<'a> {
- type Output = BigNum;
-
- fn rem(self, oth: &'b BigNumRef<'b>) -> BigNum {
- self.checked_mod(oth).unwrap()
- }
-}
-
-impl<'a, 'b> Rem<&'b BigNum> for &'a BigNumRef<'a> {
- type Output = BigNum;
-
- fn rem(self, oth: &'b BigNum) -> BigNum {
- self.checked_mod(oth).unwrap()
- }
-}
-
-impl<'a, 'b> Rem<&'b BigNumRef<'b>> for &'a BigNum {
- type Output = BigNum;
-
- fn rem(self, oth: &'b BigNumRef<'b>) -> BigNum {
- self.checked_mod(oth).unwrap()
- }
-}
-
-impl<'a, 'b> Rem<&'b BigNum> for &'a BigNum {
- type Output = BigNum;
-
- fn rem(self, oth: &'b BigNum) -> BigNum {
- self.checked_mod(oth).unwrap()
- }
-}
-
-impl<'a> Shl<i32> for &'a BigNumRef<'a> {
- type Output = BigNum;
-
- fn shl(self, n: i32) -> BigNum {
- self.checked_shl(&n).unwrap()
- }
-}
-
-impl<'a> Shl<i32> for &'a BigNum {
- type Output = BigNum;
-
- fn shl(self, n: i32) -> BigNum {
- self.checked_shl(&n).unwrap()
- }
-}
-
-impl<'a> Shr<i32> for &'a BigNumRef<'a> {
- type Output = BigNum;
-
- fn shr(self, n: i32) -> BigNum {
- self.checked_shr(&n).unwrap()
- }
-}
-
-impl<'a> Shr<i32> for &'a BigNum {
- type Output = BigNum;
-
- fn shr(self, n: i32) -> BigNum {
- self.checked_shr(&n).unwrap()
- }
-}
-
-impl<'a> Neg for &'a BigNumRef<'a> {
- type Output = BigNum;
-
- fn neg(self) -> BigNum {
- let mut n = self.to_owned().unwrap();
- n.negate();
- n
- }
-}
-
-impl<'a> Neg for &'a BigNum {
- type Output = BigNum;
-
- fn neg(self) -> BigNum {
- let mut n = self.deref().to_owned().unwrap();
- n.negate();
- n
- }
-}
-
-impl Neg for BigNum {
- type Output = BigNum;
-
- fn neg(mut self) -> BigNum {
- self.negate();
- self
- }
-}
-
-#[cfg(test)]
-mod tests {
- use bn::BigNum;
-
- #[test]
- fn test_to_from_slice() {
- let v0 = BigNum::new_from(10203004).unwrap();
- let vec = v0.to_vec();
- let v1 = BigNum::new_from_slice(&vec).unwrap();
-
- assert!(v0 == v1);
- }
-
- #[test]
- fn test_negation() {
- let a = BigNum::new_from(909829283).unwrap();
-
- assert!(!a.is_negative());
- assert!((-a).is_negative());
- }
-
-
- #[test]
- fn test_prime_numbers() {
- let a = BigNum::new_from(19029017).unwrap();
- let p = BigNum::checked_generate_prime(128, true, None, Some(&a)).unwrap();
-
- assert!(p.is_prime(100).unwrap());
- assert!(p.is_prime_fast(100, true).unwrap());
- }
-}
diff --git a/openssl/src/c_helpers.c b/openssl/src/c_helpers.c
deleted file mode 100644
index 6e6a5021..00000000
--- a/openssl/src/c_helpers.c
+++ /dev/null
@@ -1,67 +0,0 @@
-#include <openssl/hmac.h>
-#include <openssl/ssl.h>
-#include <openssl/dh.h>
-#include <openssl/bn.h>
-
-void rust_0_8_SSL_CTX_clone(SSL_CTX *ctx) {
- CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
-}
-
-void rust_0_8_X509_clone(X509 *x509) {
- CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509);
-}
-
-STACK_OF(X509_EXTENSION) *rust_0_8_X509_get_extensions(X509 *x) {
- return x->cert_info ? x->cert_info->extensions : NULL;
-}
-
-ASN1_TIME* rust_0_8_X509_get_notAfter(X509 *x) {
- return X509_get_notAfter(x);
-}
-
-ASN1_TIME* rust_0_8_X509_get_notBefore(X509 *x) {
- return X509_get_notBefore(x);
-}
-
-DH *rust_0_8_DH_new_from_params(BIGNUM *p, BIGNUM *g, BIGNUM *q) {
- DH *dh;
-
- if ((dh = DH_new()) == NULL) {
- return NULL;
- }
- dh->p = p;
- dh->g = g;
- dh->q = q;
- return dh;
-}
-
-#if OPENSSL_VERSION_NUMBER < 0x10000000L
-int rust_0_8_HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md, ENGINE *impl) {
- HMAC_Init_ex(ctx, key, key_len, md, impl);
- return 1;
-}
-
-int rust_0_8_HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, int len) {
- HMAC_Update(ctx, data, len);
- return 1;
-}
-
-int rust_0_8_HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len) {
- HMAC_Final(ctx, md, len);
- return 1;
-}
-
-#else
-
-int rust_0_8_HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md, ENGINE *impl) {
- return HMAC_Init_ex(ctx, key, key_len, md, impl);
-}
-
-int rust_0_8_HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, int len) {
- return HMAC_Update(ctx, data, len);
-}
-
-int rust_0_8_HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len) {
- return HMAC_Final(ctx, md, len);
-}
-#endif
diff --git a/openssl/src/c_helpers.rs b/openssl/src/c_helpers.rs
deleted file mode 100644
index d16c3125..00000000
--- a/openssl/src/c_helpers.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use ffi;
-use libc::{c_int, c_void, c_uint, c_uchar};
-
-#[allow(dead_code)]
-extern "C" {
- pub fn rust_0_8_SSL_CTX_clone(cxt: *mut ffi::SSL_CTX);
- pub fn rust_0_8_X509_clone(x509: *mut ffi::X509);
- pub fn rust_0_8_X509_get_extensions(x: *mut ffi::X509) -> *mut ffi::stack_st_X509_EXTENSION;
- pub fn rust_0_8_X509_get_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME;
- pub fn rust_0_8_X509_get_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME;
- pub fn rust_0_8_HMAC_Init_ex(ctx: *mut ffi::HMAC_CTX, key: *const c_void, keylen: c_int, md: *const ffi::EVP_MD, impl_: *mut ffi::ENGINE) -> c_int;
- pub fn rust_0_8_HMAC_Final(ctx: *mut ffi::HMAC_CTX, output: *mut c_uchar, len: *mut c_uint) -> c_int;
- pub fn rust_0_8_HMAC_Update(ctx: *mut ffi::HMAC_CTX, input: *const c_uchar, len: c_uint) -> c_int;
- pub fn rust_0_8_DH_new_from_params(p: *mut ffi::BIGNUM, g: *mut ffi::BIGNUM, q: *mut ffi::BIGNUM) -> *mut ffi::DH;
-}
diff --git a/openssl/src/crypto.rs b/openssl/src/crypto.rs
new file mode 100644
index 00000000..ce83cbae
--- /dev/null
+++ b/openssl/src/crypto.rs
@@ -0,0 +1,59 @@
+use libc::{c_char, c_int, c_void};
+use std::fmt;
+use std::ffi::CStr;
+use std::slice;
+use std::ops::Deref;
+use std::str;
+
+pub struct CryptoString(&'static str);
+
+impl Drop for CryptoString {
+ fn drop(&mut self) {
+ unsafe {
+ CRYPTO_free(self.0.as_ptr() as *mut c_void,
+ concat!(file!(), "\0").as_ptr() as *const c_char,
+ line!() as c_int);
+ }
+ }
+}
+
+impl Deref for CryptoString {
+ type Target = str;
+
+ fn deref(&self) -> &str {
+ self.0
+ }
+}
+
+impl CryptoString {
+ pub unsafe fn from_raw_parts(buf: *mut u8, len: usize) -> CryptoString {
+ let slice = slice::from_raw_parts(buf, len);
+ CryptoString(str::from_utf8_unchecked(slice))
+ }
+
+ pub unsafe fn from_null_terminated(buf: *mut c_char) -> CryptoString {
+ let slice = CStr::from_ptr(buf).to_bytes();
+ CryptoString(str::from_utf8_unchecked(slice))
+ }
+}
+
+impl fmt::Display for CryptoString {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self.0, f)
+ }
+}
+
+impl fmt::Debug for CryptoString {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(self.0, f)
+ }
+}
+
+#[cfg(not(ossl110))]
+#[allow(non_snake_case)]
+unsafe fn CRYPTO_free(buf: *mut c_void, _: *const c_char, _: c_int) {
+ ::ffi::CRYPTO_free(buf);
+}
+
+#[cfg(ossl110)]
+use ffi::CRYPTO_free;
diff --git a/openssl/src/crypto/dsa.rs b/openssl/src/crypto/dsa.rs
deleted file mode 100644
index 97ba7a97..00000000
--- a/openssl/src/crypto/dsa.rs
+++ /dev/null
@@ -1,338 +0,0 @@
-use ffi;
-use std::fmt;
-use error::ErrorStack;
-use std::ptr;
-use libc::{c_uint, c_int, c_char, c_void};
-
-use bn::BigNumRef;
-use bio::{MemBio, MemBioSlice};
-use crypto::hash;
-use HashTypeInternals;
-use crypto::util::{CallbackState, invoke_passwd_cb};
-
-
-/// Builder for upfront DSA parameter generateration
-pub struct DSAParams(*mut ffi::DSA);
-
-impl DSAParams {
- pub fn with_size(size: u32) -> Result<DSAParams, ErrorStack> {
- unsafe {
- // Wrap it so that if we panic we'll call the dtor
- let dsa = DSAParams(try_ssl_null!(ffi::DSA_new()));
- try_ssl!(ffi::DSA_generate_parameters_ex(dsa.0, size as c_int, ptr::null(), 0,
- ptr::null_mut(), ptr::null_mut(), ptr::null()));
- Ok(dsa)
- }
- }
-
- /// Generate a key pair from the initialized parameters
- pub fn generate(self) -> Result<DSA, ErrorStack> {
- unsafe {
- try_ssl!(ffi::DSA_generate_key(self.0));
- let dsa = DSA(self.0);
- ::std::mem::forget(self);
- Ok(dsa)
- }
- }
-}
-
-impl Drop for DSAParams {
- fn drop(&mut self) {
- unsafe {
- ffi::DSA_free(self.0);
- }
- }
-}
-
-pub struct DSA(*mut ffi::DSA);
-
-impl Drop for DSA {
- fn drop(&mut self) {
- unsafe {
- ffi::DSA_free(self.0);
- }
- }
-}
-
-impl DSA {
- pub unsafe fn from_ptr(dsa: *mut ffi::DSA) -> DSA {
- DSA(dsa)
- }
-
- /// Generate a DSA key pair
- /// For more complicated key generation scenarios see the `DSAParams` type
- pub fn generate(size: u32) -> Result<DSA, ErrorStack> {
- let params = try!(DSAParams::with_size(size));
- params.generate()
- }
-
- /// Reads a DSA private key from PEM formatted data.
- pub fn private_key_from_pem(buf: &[u8]) -> Result<DSA, ErrorStack> {
- ffi::init();
- let mem_bio = try!(MemBioSlice::new(buf));
-
- unsafe {
- let dsa = try_ssl_null!(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(),
- ptr::null_mut(),
- None,
- ptr::null_mut()));
- let dsa = DSA(dsa);
- assert!(dsa.has_private_key());
- Ok(dsa)
- }
- }
-
- /// Read a private key from PEM supplying a password callback to be invoked if the private key
- /// is encrypted.
- ///
- /// The callback will be passed the password buffer and should return the number of characters
- /// placed into the buffer.
- pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<DSA, ErrorStack>
- where F: FnOnce(&mut [c_char]) -> usize
- {
- ffi::init();
- let mut cb = CallbackState::new(pass_cb);
- let mem_bio = try!(MemBioSlice::new(buf));
-
- unsafe {
- let cb_ptr = &mut cb as *mut _ as *mut c_void;
- let dsa = try_ssl_null!(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(),
- ptr::null_mut(),
- Some(invoke_passwd_cb::<F>),
- cb_ptr));
- let dsa = DSA(dsa);
- assert!(dsa.has_private_key());
- Ok(dsa)
- }
- }
-
- /// Writes an DSA private key as unencrypted PEM formatted data
- pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack>
- {
- assert!(self.has_private_key());
- let mem_bio = try!(MemBio::new());
-
- unsafe {
- try_ssl!(ffi::PEM_write_bio_DSAPrivateKey(mem_bio.as_ptr(), self.0,
- ptr::null(), ptr::null_mut(), 0,
- None, ptr::null_mut()))
- };
-
- Ok(mem_bio.get_buf().to_owned())
- }
-
- /// Reads an DSA public key from PEM formatted data.
- pub fn public_key_from_pem(buf: &[u8]) -> Result<DSA, ErrorStack>
- {
- ffi::init();
-
- let mem_bio = try!(MemBioSlice::new(buf));
- unsafe {
- let dsa = try_ssl_null!(ffi::PEM_read_bio_DSA_PUBKEY(mem_bio.as_ptr(),
- ptr::null_mut(),
- None,
- ptr::null_mut()));
- Ok(DSA(dsa))
- }
- }
-
- /// Writes an DSA public key as PEM formatted data
- pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
- let mem_bio = try!(MemBio::new());
- unsafe { try_ssl!(ffi::PEM_write_bio_DSA_PUBKEY(mem_bio.as_ptr(), self.0)) };
- Ok(mem_bio.get_buf().to_owned())
- }
-
- pub fn size(&self) -> Option<u32> {
- if self.q().is_some() {
- unsafe { Some(ffi::DSA_size(self.0) as u32) }
- } else {
- None
- }
- }
-
- pub fn sign(&self, hash: hash::Type, message: &[u8]) -> Result<Vec<u8>, ErrorStack> {
- let k_len = self.size().expect("DSA missing a q") as c_uint;
- let mut sig = vec![0; k_len as usize];
- let mut sig_len = k_len;
- assert!(self.has_private_key());
-
- unsafe {
- try_ssl!(ffi::DSA_sign(hash.as_nid() as c_int,
- message.as_ptr(),
- message.len() as c_int,
- sig.as_mut_ptr(),
- &mut sig_len,
- self.0));
- sig.set_len(sig_len as usize);
- sig.shrink_to_fit();
- Ok(sig)
- }
- }
-
- pub fn verify(&self, hash: hash::Type, message: &[u8], sig: &[u8]) -> Result<bool, ErrorStack> {
- unsafe {
- let result = ffi::DSA_verify(hash.as_nid() as c_int,
- message.as_ptr(),
- message.len() as c_int,
- sig.as_ptr(),
- sig.len() as c_int,
- self.0);
-
- try_ssl_if!(result == -1);
- Ok(result == 1)
- }
- }
-
- pub fn as_ptr(&self) -> *mut ffi::DSA {
- self.0
- }
-
- pub fn p<'a>(&'a self) -> Option<BigNumRef<'a>> {
- unsafe {
- let p = (*self.0).p;
- if p.is_null() {
- None
- } else {
- Some(BigNumRef::from_ptr((*self.0).p))
- }
- }
- }
-
- pub fn q<'a>(&'a self) -> Option<BigNumRef<'a>> {
- unsafe {
- let q = (*self.0).q;
- if q.is_null() {
- None
- } else {
- Some(BigNumRef::from_ptr((*self.0).q))
- }
- }
- }
-
- pub fn g<'a>(&'a self) -> Option<BigNumRef<'a>> {
- unsafe {
- let g = (*self.0).g;
- if g.is_null() {
- None
- } else {
- Some(BigNumRef::from_ptr((*self.0).g))
- }
- }
- }
-
- pub fn has_public_key(&self) -> bool {
- unsafe { !(*self.0).pub_key.is_null() }
- }
-
- pub fn has_private_key(&self) -> bool {
- unsafe { !(*self.0).priv_key.is_null() }
- }
-}
-
-impl fmt::Debug for DSA {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "DSA")
- }
-}
-
-#[cfg(test)]
-mod test {
- use std::io::Write;
- use libc::c_char;
-
- use super::*;
- use crypto::hash::*;
-
- #[test]
- pub fn test_generate() {
- let key = DSA::generate(1024).unwrap();
-
- key.public_key_to_pem().unwrap();
- key.private_key_to_pem().unwrap();
-
- let input: Vec<u8> = (0..25).cycle().take(1024).collect();
-
- let digest = {
- let mut sha = Hasher::new(Type::SHA1).unwrap();
- sha.write_all(&input).unwrap();
- sha.finish().unwrap()
- };
-
- let sig = key.sign(Type::SHA1, &digest).unwrap();
- let verified = key.verify(Type::SHA1, &digest, &sig).unwrap();
- assert!(verified);
- }
-
- #[test]
- pub fn test_sign_verify() {
- let input: Vec<u8> = (0..25).cycle().take(1024).collect();
-
- let private_key = {
- let key = include_bytes!("../../test/dsa.pem");
- DSA::private_key_from_pem(key).unwrap()
- };
-
- let public_key = {
- let key = include_bytes!("../../test/dsa.pem.pub");
- DSA::public_key_from_pem(key).unwrap()
- };
-
- let digest = {
- let mut sha = Hasher::new(Type::SHA1).unwrap();
- sha.write_all(&input).unwrap();
- sha.finish().unwrap()
- };
-
- let sig = private_key.sign(Type::SHA1, &digest).unwrap();
- let verified = public_key.verify(Type::SHA1, &digest, &sig).unwrap();
- assert!(verified);
- }
-
- #[test]
- pub fn test_sign_verify_fail() {
- let input: Vec<u8> = (0..25).cycle().take(128).collect();
- let private_key = {
- let key = include_bytes!("../../test/dsa.pem");
- DSA::private_key_from_pem(key).unwrap()
- };
-
- let public_key = {
- let key = include_bytes!("../../test/dsa.pem.pub");
- DSA::public_key_from_pem(key).unwrap()
- };
-
- let digest = {
- let mut sha = Hasher::new(Type::SHA1).unwrap();
- sha.write_all(&input).unwrap();
- sha.finish().unwrap()
- };
-
- let mut sig = private_key.sign(Type::SHA1, &digest).unwrap();
- // tamper with the sig this should cause a failure
- let len = sig.len();
- sig[len / 2] = 0;
- sig[len - 1] = 0;
- if let Ok(true) = public_key.verify(Type::SHA1, &digest, &sig) {
- panic!("Tampered with signatures should not verify!");
- }
- }
-
- #[test]
- pub fn test_password() {
- let mut password_queried = false;
- let key = include_bytes!("../../test/dsa-encrypted.pem");
- DSA::private_key_from_pem_cb(key, |password| {
- password_queried = true;
- password[0] = b'm' as c_char;
- password[1] = b'y' as c_char;
- password[2] = b'p' as c_char;
- password[3] = b'a' as c_char;
- password[4] = b's' as c_char;
- password[5] = b's' as c_char;
- 6
- }).unwrap();
-
- assert!(password_queried);
- }
-}
diff --git a/openssl/src/crypto/hmac.rs b/openssl/src/crypto/hmac.rs
deleted file mode 100644
index 1847d6b1..00000000
--- a/openssl/src/crypto/hmac.rs
+++ /dev/null
@@ -1,511 +0,0 @@
-// Copyright 2013 Jack Lloyd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-use libc::{c_int, c_uint};
-use std::io;
-use std::io::prelude::*;
-use std::cmp;
-use ffi;
-
-use HashTypeInternals;
-use crypto::hash::Type;
-use error::ErrorStack;
-use c_helpers;
-
-#[derive(PartialEq, Copy, Clone)]
-enum State {
- Reset,
- Updated,
- Finalized,
-}
-
-use self::State::*;
-
-/// Provides HMAC computation.
-///
-/// Requires the `hmac` feature.
-///
-/// # Examples
-///
-/// Calculate a HMAC in one go.
-///
-/// ```
-/// use openssl::crypto::hash::Type;
-/// use openssl::crypto::hmac::hmac;
-/// let key = b"Jefe";
-/// let data = b"what do ya want for nothing?";
-/// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38";
-/// let res = hmac(Type::MD5, key, data).unwrap();
-/// assert_eq!(res, spec);
-/// ```
-///
-/// Use the `Write` trait to supply the input in chunks.
-///
-/// ```
-/// use openssl::crypto::hash::Type;
-/// use openssl::crypto::hmac::HMAC;
-/// let key = b"Jefe";
-/// let data: &[&[u8]] = &[b"what do ya ", b"want for nothing?"];
-/// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38";
-/// let mut h = HMAC::new(Type::MD5, &*key).unwrap();
-/// h.update(data[0]).unwrap();
-/// h.update(data[1]).unwrap();
-/// let res = h.finish().unwrap();
-/// assert_eq!(res, spec);
-/// ```
-pub struct HMAC {
- ctx: ffi::HMAC_CTX,
- state: State,
-}
-
-impl HMAC {
- /// Creates a new `HMAC` with the specified hash type using the `key`.
- pub fn new(ty: Type, key: &[u8]) -> Result<HMAC, ErrorStack> {
- ffi::init();
-
- let ctx = unsafe {
- let mut ctx = ::std::mem::uninitialized();
- ffi::HMAC_CTX_init(&mut ctx);
- ctx
- };
- let md = ty.evp_md();
-
- let mut h = HMAC {
- ctx: ctx,
- state: Finalized,
- };
- try!(h.init_once(md, key));
- Ok(h)
- }
-
- fn init_once(&mut self, md: *const ffi::EVP_MD, key: &[u8]) -> Result<(), ErrorStack> {
- unsafe {
- try_ssl!(c_helpers::rust_0_8_HMAC_Init_ex(&mut self.ctx,
- key.as_ptr() as *const _,
- key.len() as c_int,
- md,
- 0 as *mut _));
- }
- self.state = Reset;
- Ok(())
- }
-
- fn init(&mut self) -> Result<(), ErrorStack> {
- match self.state {
- Reset => return Ok(()),
- Updated => {
- try!(self.finish());
- }
- Finalized => (),
- }
- // If the key and/or md is not supplied it's reused from the last time
- // avoiding redundant initializations
- unsafe {
- try_ssl!(c_helpers::rust_0_8_HMAC_Init_ex(&mut self.ctx,
- 0 as *const _,
- 0,
- 0 as *const _,
- 0 as *mut _));
- }
- self.state = Reset;
- Ok(())
- }
-
- pub fn update(&mut self, mut data: &[u8]) -> Result<(), ErrorStack> {
- if self.state == Finalized {
- try!(self.init());
- }
- while !data.is_empty() {
- let len = cmp::min(data.len(), c_uint::max_value() as usize);
- unsafe {
- try_ssl!(c_helpers::rust_0_8_HMAC_Update(&mut self.ctx, data.as_ptr(), len as c_uint));
- }
- data = &data[len..];
- }
- self.state = Updated;
- Ok(())
- }
-
- /// Returns the hash of the data written since creation or
- /// the last `finish` and resets the hasher.
- pub fn finish(&mut self) -> Result<Vec<u8>, ErrorStack> {
- if self.state == Finalized {
- try!(self.init());
- }
- unsafe {
- let mut len = ffi::EVP_MAX_MD_SIZE;
- let mut res = vec![0; len as usize];
- try_ssl!(c_helpers::rust_0_8_HMAC_Final(&mut self.ctx, res.as_mut_ptr(), &mut len));
- res.truncate(len as usize);
- self.state = Finalized;
- Ok(res)
- }
- }
-}
-
-impl Write for HMAC {
- #[inline]
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- try!(self.update(buf));
- Ok(buf.len())
- }
-
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
-}
-
-#[cfg(feature = "hmac_clone")]
-impl Clone for HMAC {
- /// Requires the `hmac_clone` feature.
- fn clone(&self) -> HMAC {
- let mut ctx: ffi::HMAC_CTX;
- unsafe {
- ctx = ::std::mem::uninitialized();
- let r = ffi::HMAC_CTX_copy(&mut ctx, &self.ctx);
- assert_eq!(r, 1);
- }
- HMAC {
- ctx: ctx,
- state: self.state,
- }
- }
-}
-
-impl Drop for HMAC {
- fn drop(&mut self) {
- unsafe {
- if self.state != Finalized {
- drop(self.finish());
- }
- ffi::HMAC_CTX_cleanup(&mut self.ctx);
- }
- }
-}
-
-/// Computes the HMAC of the `data` with the hash `t` and `key`.
-pub fn hmac(t: Type, key: &[u8], data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
- let mut h = try!(HMAC::new(t, key));
- try!(h.update(data));
- h.finish()
-}
-
-#[cfg(test)]
-mod tests {
- use std::iter::repeat;
- use serialize::hex::FromHex;
- use crypto::hash::Type;
- use crypto::hash::Type::*;
- use super::{hmac, HMAC};
- use std::io::prelude::*;
-
- fn test_hmac(ty: Type, tests: &[(Vec<u8>, Vec<u8>, Vec<u8>)]) {
- for &(ref key, ref data, ref res) in tests.iter() {
- assert_eq!(hmac(ty, &**key, &**data).unwrap(), *res);
- }
- }
-
- fn test_hmac_recycle(h: &mut HMAC, test: &(Vec<u8>, Vec<u8>, Vec<u8>)) {
- let &(_, ref data, ref res) = test;
- h.write_all(&**data).unwrap();
- assert_eq!(h.finish().unwrap(), *res);
- }
-
- #[test]
- fn test_hmac_md5() {
- // test vectors from RFC 2202
- let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 7] =
- [(repeat(0x0b_u8).take(16).collect(),
- b"Hi There".to_vec(),
- "9294727a3638bb1c13f48ef8158bfc9d".from_hex().unwrap()),
- (b"Jefe".to_vec(),
- b"what do ya want for nothing?".to_vec(),
- "750c783e6ab0b503eaa86e310a5db738".from_hex().unwrap()),
- (repeat(0xaa_u8).take(16).collect(),
- repeat(0xdd_u8).take(50).collect(),
- "56be34521d144c88dbb8c733f0e8b3f6".from_hex().unwrap()),
- ("0102030405060708090a0b0c0d0e0f10111213141516171819".from_hex().unwrap(),
- repeat(0xcd_u8).take(50).collect(),
- "697eaf0aca3a3aea3a75164746ffaa79".from_hex().unwrap()),
- (repeat(0x0c_u8).take(16).collect(),
- b"Test With Truncation".to_vec(),
- "56461ef2342edc00f9bab995690efd4c".from_hex().unwrap()),
- (repeat(0xaa_u8).take(80).collect(),
- b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
- "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap()),
- (repeat(0xaa_u8).take(80).collect(),
- b"Test Using Larger Than Block-Size Key \
- and Larger Than One Block-Size Data"
- .to_vec(),
- "6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())];
-
- test_hmac(MD5, &tests);
- }
-
- #[test]
- fn test_hmac_md5_recycle() {
- let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 2] =
- [(repeat(0xaa_u8).take(80).collect(),
- b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
- "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap()),
- (repeat(0xaa_u8).take(80).collect(),
- b"Test Using Larger Than Block-Size Key \
- and Larger Than One Block-Size Data"
- .to_vec(),
- "6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())];
-
- let mut h = HMAC::new(MD5, &*tests[0].0).unwrap();
- for i in 0..100usize {
- let test = &tests[i % 2];
- test_hmac_recycle(&mut h, test);
- }
- }
-
- #[test]
- fn test_finish_twice() {
- let test: (Vec<u8>, Vec<u8>, Vec<u8>) =
- (repeat(0xaa_u8).take(80).collect(),
- b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
- "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap());
-
- let mut h = HMAC::new(Type::MD5, &*test.0).unwrap();
- h.write_all(&*test.1).unwrap();
- h.finish().unwrap();
- let res = h.finish().unwrap();
- let null = hmac(Type::MD5, &*test.0, &[]).unwrap();
- assert_eq!(res, null);
- }
-
- #[test]
- #[cfg(feature = "hmac_clone")]
- fn test_clone() {
- let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 2] =
- [(repeat(0xaa_u8).take(80).collect(),
- b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
- "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap()),
- (repeat(0xaa_u8).take(80).collect(),
- b"Test Using Larger Than Block-Size Key \
- and Larger Than One Block-Size Data"
- .to_vec(),
- "6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())];
- let p = tests[0].0.len() / 2;
- let h0 = HMAC::new(Type::MD5, &*tests[0].0).unwrap();
-
- println!("Clone a new hmac");
- let mut h1 = h0.clone();
- h1.write_all(&tests[0].1[..p]).unwrap();
- {
- println!("Clone an updated hmac");
- let mut h2 = h1.clone();
- h2.write_all(&tests[0].1[p..]).unwrap();
- let res = h2.finish().unwrap();
- assert_eq!(res, tests[0].2);
- }
- h1.write_all(&tests[0].1[p..]).unwrap();
- let res = h1.finish().unwrap();
- assert_eq!(res, tests[0].2);
-
- println!("Clone a finished hmac");
- let mut h3 = h1.clone();
- h3.write_all(&*tests[1].1).unwrap();
- let res = h3.finish().unwrap();
- assert_eq!(res, tests[1].2);
- }
-
- #[test]
- fn test_hmac_sha1() {
- // test vectors from RFC 2202
- let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 7] =
- [(repeat(0x0b_u8).take(20).collect(),
- b"Hi There".to_vec(),
- "b617318655057264e28bc0b6fb378c8ef146be00".from_hex().unwrap()),
- (b"Jefe".to_vec(),
- b"what do ya want for nothing?".to_vec(),
- "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79".from_hex().unwrap()),
- (repeat(0xaa_u8).take(20).collect(),
- repeat(0xdd_u8).take(50).collect(),
- "125d7342b9ac11cd91a39af48aa17b4f63f175d3".from_hex().unwrap()),
- ("0102030405060708090a0b0c0d0e0f10111213141516171819".from_hex().unwrap(),
- repeat(0xcd_u8).take(50).collect(),
- "4c9007f4026250c6bc8414f9bf50c86c2d7235da".from_hex().unwrap()),
- (repeat(0x0c_u8).take(20).collect(),
- b"Test With Truncation".to_vec(),
- "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04".from_hex().unwrap()),
- (repeat(0xaa_u8).take(80).collect(),
- b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
- "aa4ae5e15272d00e95705637ce8a3b55ed402112".from_hex().unwrap()),
- (repeat(0xaa_u8).take(80).collect(),
- b"Test Using Larger Than Block-Size Key \
- and Larger Than One Block-Size Data"
- .to_vec(),
- "e8e99d0f45237d786d6bbaa7965c7808bbff1a91".from_hex().unwrap())];
-
- test_hmac(SHA1, &tests);
- }
-
- #[test]
- fn test_hmac_sha1_recycle() {
- let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 2] =
- [(repeat(0xaa_u8).take(80).collect(),
- b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
- "aa4ae5e15272d00e95705637ce8a3b55ed402112".from_hex().unwrap()),
- (repeat(0xaa_u8).take(80).collect(),
- b"Test Using Larger Than Block-Size Key \
- and Larger Than One Block-Size Data"
- .to_vec(),
- "e8e99d0f45237d786d6bbaa7965c7808bbff1a91".from_hex().unwrap())];
-
- let mut h = HMAC::new(SHA1, &*tests[0].0).unwrap();
- for i in 0..100usize {
- let test = &tests[i % 2];
- test_hmac_recycle(&mut h, test);
- }
- }
-
-
-
- fn test_sha2(ty: Type, results: &[Vec<u8>]) {
- // test vectors from RFC 4231
- let tests: [(Vec<u8>, Vec<u8>); 6] =
- [(repeat(0xb_u8).take(20).collect(), b"Hi There".to_vec()),
- (b"Jefe".to_vec(), b"what do ya want for nothing?".to_vec()),
- (repeat(0xaa_u8).take(20).collect(), repeat(0xdd_u8).take(50).collect()),
- ("0102030405060708090a0b0c0d0e0f10111213141516171819".from_hex().unwrap(),
- repeat(0xcd_u8).take(50).collect()),
- (repeat(0xaa_u8).take(131).collect(),
- b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec()),
- (repeat(0xaa_u8).take(131).collect(),
- b"This is a test using a larger than block-size key and a \
- larger than block-size data. The key needs to be hashed \
- before being used by the HMAC algorithm."
- .to_vec())];
-
- for (&(ref key, ref data), res) in tests.iter().zip(results.iter()) {
- assert_eq!(hmac(ty, &**key, &**data).unwrap(), *res);
- }
-
- // recycle test
- let mut h = HMAC::new(ty, &*tests[5].0).unwrap();
- for i in 0..100usize {
- let test = &tests[4 + i % 2];
- let tup = (test.0.clone(), test.1.clone(), results[4 + i % 2].clone());
- test_hmac_recycle(&mut h, &tup);
- }
- }
-
- #[test]
- fn test_hmac_sha224() {
- let results = ["896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22"
- .from_hex()
- .unwrap(),
- "a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44"
- .from_hex()
- .unwrap(),
- "7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea"
- .from_hex()
- .unwrap(),
- "6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a"
- .from_hex()
- .unwrap(),
- "95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e"
- .from_hex()
- .unwrap(),
- "3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1"
- .from_hex()
- .unwrap()];
- test_sha2(SHA224, &results);
- }
-
- #[test]
- fn test_hmac_sha256() {
- let results = ["b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"
- .from_hex()
- .unwrap(),
- "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"
- .from_hex()
- .unwrap(),
- "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe"
- .from_hex()
- .unwrap(),
- "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b"
- .from_hex()
- .unwrap(),
- "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54"
- .from_hex()
- .unwrap(),
- "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2"
- .from_hex()
- .unwrap()];
- test_sha2(SHA256, &results);
- }
-
- #[test]
- fn test_hmac_sha384() {
- let results = ["afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea90\
- 76ede7f4af152e8b2fa9cb6"
- .from_hex()
- .unwrap(),
- "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5\
- e69e2c78b3239ecfab21649"
- .from_hex()
- .unwrap(),
- "88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc\
- 13814b94e3ab6e101a34f27"
- .from_hex()
- .unwrap(),
- "3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e6801dd23c\
- 4a7d679ccf8a386c674cffb"
- .from_hex()
- .unwrap(),
- "4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c60c2ef6ab4\
- 030fe8296248df163f44952"
- .from_hex()
- .unwrap(),
- "6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5a678cc31e\
- 799176d3860e6110c46523e"
- .from_hex()
- .unwrap()];
- test_sha2(SHA384, &results);
- }
-
- #[test]
- fn test_hmac_sha512() {
- let results = ["87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d\
- 6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854"
- .from_hex()
- .unwrap(),
- "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c\
- 05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737"
- .from_hex()
- .unwrap(),
- "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e84827\
- 9a722c806b485a47e67c807b946a337bee8942674278859e13292fb"
- .from_hex()
- .unwrap(),
- "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11\
- aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd"
- .from_hex()
- .unwrap(),
- "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e\
- 05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598"
- .from_hex()
- .unwrap(),
- "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3\
- c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58"
- .from_hex()
- .unwrap()];
- test_sha2(SHA512, &results);
- }
-}
diff --git a/openssl/src/crypto/mod.rs b/openssl/src/crypto/mod.rs
deleted file mode 100644
index b8b109a2..00000000
--- a/openssl/src/crypto/mod.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2011 Google Inc.
-// 2013 Jack Lloyd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-pub mod hash;
-#[cfg(feature = "hmac")]
-pub mod hmac;
-pub mod pkcs5;
-pub mod pkcs12;
-pub mod pkey;
-pub mod rand;
-pub mod symm;
-pub mod memcmp;
-pub mod rsa;
-pub mod dsa;
-mod util;
diff --git a/openssl/src/crypto/pkcs5.rs b/openssl/src/crypto/pkcs5.rs
deleted file mode 100644
index ef84fbe1..00000000
--- a/openssl/src/crypto/pkcs5.rs
+++ /dev/null
@@ -1,245 +0,0 @@
-use libc::c_int;
-use std::ptr;
-use ffi;
-
-use HashTypeInternals;
-use crypto::hash;
-use crypto::symm;
-use error::ErrorStack;
-
-#[derive(Clone, Eq, PartialEq, Hash, Debug)]
-pub struct KeyIvPair {
- pub key: Vec<u8>,
- pub iv: Vec<u8>,
-}
-
-/// Derives a key and an IV from various parameters.
-///
-/// If specified `salt` must be 8 bytes in length.
-///
-/// If the total key and IV length is less than 16 bytes and MD5 is used then
-/// the algorithm is compatible with the key derivation algorithm from PKCS#5
-/// v1.5 or PBKDF1 from PKCS#5 v2.0.
-///
-/// New applications should not use this and instead use `pbkdf2_hmac_sha1` or
-/// another more modern key derivation algorithm.
-pub fn evp_bytes_to_key_pbkdf1_compatible(typ: symm::Type,
- message_digest_type: hash::Type,
- data: &[u8],
- salt: Option<&[u8]>,
- count: u32)
- -> Result<KeyIvPair, ErrorStack> {
- unsafe {
- let salt_ptr = match salt {
- Some(salt) => {
- assert_eq!(salt.len(), ffi::PKCS5_SALT_LEN as usize);
- salt.as_ptr()
- }
- None => ptr::null(),
- };
-
- ffi::init();
-
- let typ = typ.as_ptr();
- let message_digest_type = message_digest_type.evp_md();
-
- let len = ffi::EVP_BytesToKey(typ,
- message_digest_type,
- salt_ptr,
- data.as_ptr(),
- data.len() as c_int,
- count as c_int,
- ptr::null_mut(),
- ptr::null_mut());
- if len == 0 {
- return Err(ErrorStack::get());
- }
-
- let mut key = vec![0; len as usize];
- let mut iv = vec![0; len as usize];
-
- try_ssl!(ffi::EVP_BytesToKey(typ,
- message_digest_type,
- salt_ptr,
- data.as_ptr(),
- data.len() as c_int,
- count as c_int,
- key.as_mut_ptr(),
- iv.as_mut_ptr()));
-
- Ok(KeyIvPair { key: key, iv: iv })
- }
-}
-
-/// Derives a key from a password and salt using the PBKDF2-HMAC-SHA1 algorithm.
-pub fn pbkdf2_hmac_sha1(pass: &[u8],
- salt: &[u8],
- iter: usize,
- keylen: usize)
- -> Result<Vec<u8>, ErrorStack> {
- unsafe {
- let mut out = vec![0; keylen];
-
- ffi::init();
-
- try_ssl!(ffi::PKCS5_PBKDF2_HMAC_SHA1(pass.as_ptr(),
- pass.len() as c_int,
- salt.as_ptr(),
- salt.len() as c_int,
- iter as c_int,
- keylen as c_int,
- out.as_mut_ptr()));
- Ok(out)
- }
-}
-
-/// Derives a key from a password and salt using the PBKDF2-HMAC algorithm with a digest function.
-#[cfg(feature = "pkcs5_pbkdf2_hmac")]
-pub fn pbkdf2_hmac(pass: &[u8],
- salt: &[u8],
- iter: usize,
- hash: hash::Type,
- keylen: usize)
- -> Result<Vec<u8>, ErrorStack> {
- unsafe {
- let mut out = vec![0; keylen];
- ffi::init();
- try_ssl!(ffi::PKCS5_PBKDF2_HMAC(pass.as_ptr(),
- pass.len() as c_int,
- salt.as_ptr(),
- salt.len() as c_int,
- iter as c_int,
- hash.evp_md(),
- keylen as c_int,
- out.as_mut_ptr()));
- Ok(out)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crypto::hash;
- use crypto::symm;
-
- // Test vectors from
- // http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06
- #[test]
- fn test_pbkdf2_hmac_sha1() {
- assert_eq!(super::pbkdf2_hmac_sha1(b"password", b"salt", 1, 20).unwrap(),
- vec![0x0c_u8, 0x60_u8, 0xc8_u8, 0x0f_u8, 0x96_u8, 0x1f_u8, 0x0e_u8, 0x71_u8,
- 0xf3_u8, 0xa9_u8, 0xb5_u8, 0x24_u8, 0xaf_u8, 0x60_u8, 0x12_u8, 0x06_u8,
- 0x2f_u8, 0xe0_u8, 0x37_u8, 0xa6_u8]);
-
- assert_eq!(super::pbkdf2_hmac_sha1(b"password", b"salt", 2, 20).unwrap(),
- vec![0xea_u8, 0x6c_u8, 0x01_u8, 0x4d_u8, 0xc7_u8, 0x2d_u8, 0x6f_u8, 0x8c_u8,
- 0xcd_u8, 0x1e_u8, 0xd9_u8, 0x2a_u8, 0xce_u8, 0x1d_u8, 0x41_u8, 0xf0_u8,
- 0xd8_u8, 0xde_u8, 0x89_u8, 0x57_u8]);
-
- assert_eq!(super::pbkdf2_hmac_sha1(b"password", b"salt", 4096, 20).unwrap(),
- vec![0x4b_u8, 0x00_u8, 0x79_u8, 0x01_u8, 0xb7_u8, 0x65_u8, 0x48_u8, 0x9a_u8,
- 0xbe_u8, 0xad_u8, 0x49_u8, 0xd9_u8, 0x26_u8, 0xf7_u8, 0x21_u8, 0xd0_u8,
- 0x65_u8, 0xa4_u8, 0x29_u8, 0xc1_u8]);
-
- assert_eq!(super::pbkdf2_hmac_sha1(b"password", b"salt", 16777216, 20).unwrap(),
- vec![0xee_u8, 0xfe_u8, 0x3d_u8, 0x61_u8, 0xcd_u8, 0x4d_u8, 0xa4_u8, 0xe4_u8,
- 0xe9_u8, 0x94_u8, 0x5b_u8, 0x3d_u8, 0x6b_u8, 0xa2_u8, 0x15_u8, 0x8c_u8,
- 0x26_u8, 0x34_u8, 0xe9_u8, 0x84_u8]);
-
- assert_eq!(super::pbkdf2_hmac_sha1(b"passwordPASSWORDpassword",
- b"saltSALTsaltSALTsaltSALTsaltSALTsalt",
- 4096,
- 25).unwrap(),
- vec![0x3d_u8, 0x2e_u8, 0xec_u8, 0x4f_u8, 0xe4_u8, 0x1c_u8, 0x84_u8, 0x9b_u8,
- 0x80_u8, 0xc8_u8, 0xd8_u8, 0x36_u8, 0x62_u8, 0xc0_u8, 0xe4_u8, 0x4a_u8,
- 0x8b_u8, 0x29_u8, 0x1a_u8, 0x96_u8, 0x4c_u8, 0xf2_u8, 0xf0_u8, 0x70_u8,
- 0x38_u8]);
-
- assert_eq!(super::pbkdf2_hmac_sha1(b"pass\x00word", b"sa\x00lt", 4096, 16).unwrap(),
- vec![0x56_u8, 0xfa_u8, 0x6a_u8, 0xa7_u8, 0x55_u8, 0x48_u8, 0x09_u8, 0x9d_u8,
- 0xcc_u8, 0x37_u8, 0xd7_u8, 0xf0_u8, 0x34_u8, 0x25_u8, 0xe0_u8, 0xc3_u8]);
- }
-
- // Test vectors from
- // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c
- #[test]
- #[cfg(feature = "pkcs5_pbkdf2_hmac")]
- fn test_pbkdf2_hmac_sha256() {
- assert_eq!(super::pbkdf2_hmac(b"passwd", b"salt", 1, hash::Type::SHA256, 16).unwrap(),
- vec![0x55_u8, 0xac_u8, 0x04_u8, 0x6e_u8, 0x56_u8, 0xe3_u8, 0x08_u8, 0x9f_u8,
- 0xec_u8, 0x16_u8, 0x91_u8, 0xc2_u8, 0x25_u8, 0x44_u8, 0xb6_u8, 0x05_u8]);
-
- assert_eq!(super::pbkdf2_hmac(b"Password", b"NaCl", 80000, hash::Type::SHA256, 16).unwrap(),
- vec![0x4d_u8, 0xdc_u8, 0xd8_u8, 0xf6_u8, 0x0b_u8, 0x98_u8, 0xbe_u8, 0x21_u8,
- 0x83_u8, 0x0c_u8, 0xee_u8, 0x5e_u8, 0xf2_u8, 0x27_u8, 0x01_u8, 0xf9_u8]);
- }
-
- // Test vectors from
- // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c
- #[test]
- #[cfg(feature = "pkcs5_pbkdf2_hmac")]
- fn test_pbkdf2_hmac_sha512() {
- assert_eq!(super::pbkdf2_hmac(b"password", b"NaCL", 1, hash::Type::SHA512, 64).unwrap(),
- vec![0x73_u8, 0xde_u8, 0xcf_u8, 0xa5_u8, 0x8a_u8, 0xa2_u8, 0xe8_u8, 0x4f_u8,
- 0x94_u8, 0x77_u8, 0x1a_u8, 0x75_u8, 0x73_u8, 0x6b_u8, 0xb8_u8, 0x8b_u8,
- 0xd3_u8, 0xc7_u8, 0xb3_u8, 0x82_u8, 0x70_u8, 0xcf_u8, 0xb5_u8, 0x0c_u8,
- 0xb3_u8, 0x90_u8, 0xed_u8, 0x78_u8, 0xb3_u8, 0x05_u8, 0x65_u8, 0x6a_u8,
- 0xf8_u8, 0x14_u8, 0x8e_u8, 0x52_u8, 0x45_u8, 0x2b_u8, 0x22_u8, 0x16_u8,
- 0xb2_u8, 0xb8_u8, 0x09_u8, 0x8b_u8, 0x76_u8, 0x1f_u8, 0xc6_u8, 0x33_u8,
- 0x60_u8, 0x60_u8, 0xa0_u8, 0x9f_u8, 0x76_u8, 0x41_u8, 0x5e_u8, 0x9f_u8,
- 0x71_u8, 0xea_u8, 0x47_u8, 0xf9_u8, 0xe9_u8, 0x06_u8, 0x43_u8, 0x06_u8]);
-
- assert_eq!(super::pbkdf2_hmac(b"pass\0word", b"sa\0lt", 1, hash::Type::SHA512, 64).unwrap(),
- vec![0x71_u8, 0xa0_u8, 0xec_u8, 0x84_u8, 0x2a_u8, 0xbd_u8, 0x5c_u8, 0x67_u8,
- 0x8b_u8, 0xcf_u8, 0xd1_u8, 0x45_u8, 0xf0_u8, 0x9d_u8, 0x83_u8, 0x52_u8,
- 0x2f_u8, 0x93_u8, 0x36_u8, 0x15_u8, 0x60_u8, 0x56_u8, 0x3c_u8, 0x4d_u8,
- 0x0d_u8, 0x63_u8, 0xb8_u8, 0x83_u8, 0x29_u8, 0x87_u8, 0x10_u8, 0x90_u8,
- 0xe7_u8, 0x66_u8, 0x04_u8, 0xa4_u8, 0x9a_u8, 0xf0_u8, 0x8f_u8, 0xe7_u8,
- 0xc9_u8, 0xf5_u8, 0x71_u8, 0x56_u8, 0xc8_u8, 0x79_u8, 0x09_u8, 0x96_u8,
- 0xb2_u8, 0x0f_u8, 0x06_u8, 0xbc_u8, 0x53_u8, 0x5e_u8, 0x5a_u8, 0xb5_u8,
- 0x44_u8, 0x0d_u8, 0xf7_u8, 0xe8_u8, 0x78_u8, 0x29_u8, 0x6f_u8, 0xa7_u8]);
-
- assert_eq!(super::pbkdf2_hmac(b"passwordPASSWORDpassword",
- b"salt\0\0\0",
- 50,
- hash::Type::SHA512,
- 64).unwrap(),
- vec![0x01_u8, 0x68_u8, 0x71_u8, 0xa4_u8, 0xc4_u8, 0xb7_u8, 0x5f_u8, 0x96_u8,
- 0x85_u8, 0x7f_u8, 0xd2_u8, 0xb9_u8, 0xf8_u8, 0xca_u8, 0x28_u8, 0x02_u8,
- 0x3b_u8, 0x30_u8, 0xee_u8, 0x2a_u8, 0x39_u8, 0xf5_u8, 0xad_u8, 0xca_u8,
- 0xc8_u8, 0xc9_u8, 0x37_u8, 0x5f_u8, 0x9b_u8, 0xda_u8, 0x1c_u8, 0xcd_u8,
- 0x1b_u8, 0x6f_u8, 0x0b_u8, 0x2f_u8, 0xc3_u8, 0xad_u8, 0xda_u8, 0x50_u8,
- 0x54_u8, 0x12_u8, 0xe7_u8, 0x9d_u8, 0x89_u8, 0x00_u8, 0x56_u8, 0xc6_u8,
- 0x2e_u8, 0x52_u8, 0x4c_u8, 0x7d_u8, 0x51_u8, 0x15_u8, 0x4b_u8, 0x1a_u8,
- 0x85_u8, 0x34_u8, 0x57_u8, 0x5b_u8, 0xd0_u8, 0x2d_u8, 0xee_u8, 0x39_u8]);
- }
- #[test]
- fn test_evp_bytes_to_key_pbkdf1_compatible() {
- let salt = [16_u8, 34_u8, 19_u8, 23_u8, 141_u8, 4_u8, 207_u8, 221_u8];
-
- let data = [143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8, 241_u8, 242_u8, 31_u8,
- 154_u8, 56_u8, 198_u8, 145_u8, 192_u8, 64_u8, 2_u8, 245_u8, 167_u8, 220_u8,
- 55_u8, 119_u8, 233_u8, 136_u8, 139_u8, 27_u8, 71_u8, 242_u8, 119_u8, 175_u8,
- 65_u8, 207_u8];
-
-
-
- let expected_key = vec![249_u8, 115_u8, 114_u8, 97_u8, 32_u8, 213_u8, 165_u8, 146_u8,
- 58_u8, 87_u8, 234_u8, 3_u8, 43_u8, 250_u8, 97_u8, 114_u8, 26_u8,
- 98_u8, 245_u8, 246_u8, 238_u8, 177_u8, 229_u8, 161_u8, 183_u8,
- 224_u8, 174_u8, 3_u8, 6_u8, 244_u8, 236_u8, 255_u8];
- let expected_iv = vec![4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8,
- 69_u8, 98_u8, 107_u8, 208_u8, 14_u8, 236_u8, 60_u8, 0_u8, 0_u8,
- 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8,
- 0_u8, 0_u8, 0_u8];
-
- assert_eq!(super::evp_bytes_to_key_pbkdf1_compatible(symm::Type::AES_256_CBC,
- hash::Type::SHA1,
- &data,
- Some(&salt),
- 1).unwrap(),
- super::KeyIvPair {
- key: expected_key,
- iv: expected_iv,
- });
- }
-}
diff --git a/openssl/src/crypto/pkey.rs b/openssl/src/crypto/pkey.rs
deleted file mode 100644
index a2a6f9c1..00000000
--- a/openssl/src/crypto/pkey.rs
+++ /dev/null
@@ -1,166 +0,0 @@
-use libc::{c_void, c_char};
-use std::ptr;
-use std::mem;
-use ffi;
-
-use bio::{MemBio, MemBioSlice};
-use crypto::rsa::RSA;
-use error::ErrorStack;
-use crypto::util::{CallbackState, invoke_passwd_cb};
-
-pub struct PKey(*mut ffi::EVP_PKEY);
-
-unsafe impl Send for PKey {}
-unsafe impl Sync for PKey {}
-
-/// Represents a public key, optionally with a private key attached.
-impl PKey {
- /// Create a new `PKey` containing an RSA key.
- pub fn from_rsa(rsa: RSA) -> Result<PKey, ErrorStack> {
- unsafe {
- let evp = try_ssl_null!(ffi::EVP_PKEY_new());
- let pkey = PKey(evp);
- try_ssl!(ffi::EVP_PKEY_assign(pkey.0, ffi::EVP_PKEY_RSA, rsa.as_ptr() as *mut _));
- mem::forget(rsa);
- Ok(pkey)
- }
- }
-
- pub unsafe fn from_ptr(handle: *mut ffi::EVP_PKEY) -> PKey {
- PKey(handle)
- }
-
- /// Reads private key from PEM, takes ownership of handle
- pub fn private_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
- ffi::init();
- let mem_bio = try!(MemBioSlice::new(buf));
- unsafe {
- let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(),
- ptr::null_mut(),
- None,
- ptr::null_mut()));
- Ok(PKey::from_ptr(evp))
- }
- }
-
- /// Read a private key from PEM, supplying a password callback to be invoked if the private key
- /// is encrypted.
- ///
- /// The callback will be passed the password buffer and should return the number of characters
- /// placed into the buffer.
- pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<PKey, ErrorStack>
- where F: FnOnce(&mut [c_char]) -> usize
- {
- ffi::init();
- let mut cb = CallbackState::new(pass_cb);
- let mem_bio = try!(MemBioSlice::new(buf));
- unsafe {
- let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(),
- ptr::null_mut(),
- Some(invoke_passwd_cb::<F>),
- &mut cb as *mut _ as *mut c_void));
- Ok(PKey::from_ptr(evp))
- }
- }
-
- /// Reads public key from PEM, takes ownership of handle
- pub fn public_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
- ffi::init();
- let mem_bio = try!(MemBioSlice::new(buf));
- unsafe {
- let evp = try_ssl_null!(ffi::PEM_read_bio_PUBKEY(mem_bio.as_ptr(),
- ptr::null_mut(),
- None,
- ptr::null_mut()));
- Ok(PKey::from_ptr(evp))
- }
- }
-
- /// assign RSA key to this pkey
- pub fn set_rsa(&mut self, rsa: &RSA) -> Result<(), ErrorStack> {
- unsafe {
- // this needs to be a reference as the set1_RSA ups the reference count
- let rsa_ptr = rsa.as_ptr();
- try_ssl!(ffi::EVP_PKEY_set1_RSA(self.0, rsa_ptr));
- Ok(())
- }
- }
-
- /// Get a reference to the interal RSA key for direct access to the key components
- pub fn get_rsa(&self) -> Result<RSA, ErrorStack> {
- unsafe {
- let rsa = try_ssl_null!(ffi::EVP_PKEY_get1_RSA(self.0));
- // this is safe as the ffi increments a reference counter to the internal key
- Ok(RSA::from_ptr(rsa))
- }
- }
-
- /// Stores private key as a PEM
- // FIXME: also add password and encryption
- pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
- let mem_bio = try!(MemBio::new());
- unsafe {
- try_ssl!(ffi::PEM_write_bio_PrivateKey(mem_bio.as_ptr(),
- self.0,
- ptr::null(),
- ptr::null_mut(),
- -1,
- None,
- ptr::null_mut()));
-
- }
- Ok(mem_bio.get_buf().to_owned())
- }
-
- /// Stores public key as a PEM
- pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
- let mem_bio = try!(MemBio::new());
- unsafe { try_ssl!(ffi::PEM_write_bio_PUBKEY(mem_bio.as_ptr(), self.0)) }
- Ok(mem_bio.get_buf().to_owned())
- }
-
- pub fn as_ptr(&self) -> *mut ffi::EVP_PKEY {
- return self.0;
- }
-
- pub fn public_eq(&self, other: &PKey) -> bool {
- unsafe { ffi::EVP_PKEY_cmp(self.0, other.0) == 1 }
- }
-}
-
-impl Drop for PKey {
- fn drop(&mut self) {
- unsafe {
- ffi::EVP_PKEY_free(self.0);
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- #[test]
- fn test_private_key_from_pem() {
- let key = include_bytes!("../../test/key.pem");
- super::PKey::private_key_from_pem(key).unwrap();
- }
-
- #[test]
- fn test_public_key_from_pem() {
- let key = include_bytes!("../../test/key.pem.pub");
- super::PKey::public_key_from_pem(key).unwrap();
- }
-
- #[test]
- fn test_pem() {
- let key = include_bytes!("../../test/key.pem");
- let key = super::PKey::private_key_from_pem(key).unwrap();
-
- let priv_key = key.private_key_to_pem().unwrap();
- let pub_key = key.public_key_to_pem().unwrap();
-
- // As a super-simple verification, just check that the buffers contain
- // the `PRIVATE KEY` or `PUBLIC KEY` strings.
- assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY"));
- assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY"));
- }
-}
diff --git a/openssl/src/crypto/rsa.rs b/openssl/src/crypto/rsa.rs
deleted file mode 100644
index feb66a6f..00000000
--- a/openssl/src/crypto/rsa.rs
+++ /dev/null
@@ -1,337 +0,0 @@
-use ffi;
-use std::fmt;
-use std::ptr;
-use std::mem;
-use libc::{c_int, c_void, c_char, c_ulong};
-
-use bn::{BigNum, BigNumRef};
-use bio::{MemBio, MemBioSlice};
-use error::ErrorStack;
-use HashTypeInternals;
-use crypto::hash;
-use crypto::util::{CallbackState, invoke_passwd_cb};
-
-pub struct RSA(*mut ffi::RSA);
-
-impl Drop for RSA {
- fn drop(&mut self) {
- unsafe {
- ffi::RSA_free(self.0);
- }
- }
-}
-
-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, ErrorStack> {
- unsafe {
- let rsa = try_ssl_null!(ffi::RSA_new());
- (*rsa).n = n.as_ptr();
- (*rsa).e = e.as_ptr();
- mem::forget(n);
- mem::forget(e);
- Ok(RSA(rsa))
- }
- }
-
- pub fn from_private_components(n: BigNum,
- e: BigNum,
- d: BigNum,
- p: BigNum,
- q: BigNum,
- dp: BigNum,
- dq: BigNum,
- qi: BigNum)
- -> Result<RSA, ErrorStack> {
- unsafe {
- let rsa = try_ssl_null!(ffi::RSA_new());
- (*rsa).n = n.as_ptr();
- (*rsa).e = e.as_ptr();
- (*rsa).d = d.as_ptr();
- (*rsa).p = p.as_ptr();
- (*rsa).q = q.as_ptr();
- (*rsa).dmp1 = dp.as_ptr();
- (*rsa).dmq1 = dq.as_ptr();
- (*rsa).iqmp = qi.as_ptr();
- mem::forget(n);
- mem::forget(e);
- mem::forget(d);
- mem::forget(p);
- mem::forget(q);
- mem::forget(dp);
- mem::forget(dq);
- mem::forget(qi);
- Ok(RSA(rsa))
- }
- }
-
- pub unsafe fn from_ptr(rsa: *mut ffi::RSA) -> RSA {
- RSA(rsa)
- }
-
- /// Generates a public/private key pair with the specified size.
- ///
- /// The public exponent will be 65537.
- pub fn generate(bits: u32) -> Result<RSA, ErrorStack> {
- unsafe {
- let rsa = try_ssl_null!(ffi::RSA_new());
- let rsa = RSA(rsa);
- let e = try!(BigNum::new_from(ffi::RSA_F4 as c_ulong));
-
- try_ssl!(ffi::RSA_generate_key_ex(rsa.0, bits as c_int, e.as_ptr(), ptr::null_mut()));
-
- Ok(rsa)
- }
- }
-
- /// Reads an RSA private key from PEM formatted data.
- pub fn private_key_from_pem(buf: &[u8]) -> Result<RSA, ErrorStack> {
- let mem_bio = try!(MemBioSlice::new(buf));
- unsafe {
- let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(),
- ptr::null_mut(),
- None,
- ptr::null_mut()));
- Ok(RSA(rsa))
- }
- }
-
- /// Reads an RSA private key from PEM formatted data and supplies a password callback.
- pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<RSA, ErrorStack>
- where F: FnOnce(&mut [c_char]) -> usize
- {
- let mut cb = CallbackState::new(pass_cb);
- let mem_bio = try!(MemBioSlice::new(buf));
-
- unsafe {
- let cb_ptr = &mut cb as *mut _ as *mut c_void;
- let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(),
- ptr::null_mut(),
- Some(invoke_passwd_cb::<F>),
- cb_ptr));
-
- Ok(RSA(rsa))
- }
- }
-
- /// Reads an RSA public key from PEM formatted data.
- 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.as_ptr(),
- ptr::null_mut(),
- None,
- ptr::null_mut()));
- Ok(RSA(rsa))
- }
- }
-
- /// Writes an RSA private key as unencrypted PEM formatted data
- pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
- let mem_bio = try!(MemBio::new());
-
- unsafe {
- try_ssl!(ffi::PEM_write_bio_RSAPrivateKey(mem_bio.as_ptr(),
- self.0,
- ptr::null(),
- ptr::null_mut(),
- 0,
- None,
- ptr::null_mut()));
- }
- Ok(mem_bio.get_buf().to_owned())
- }
-
- /// Writes an RSA public key as PEM formatted data
- pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
- let mem_bio = try!(MemBio::new());
-
- unsafe {
- try_ssl!(ffi::PEM_write_bio_RSA_PUBKEY(mem_bio.as_ptr(), self.0))
- };
-
- Ok(mem_bio.get_buf().to_owned())
- }
-
- pub fn size(&self) -> Option<u32> {
- if self.n().is_some() {
- unsafe { Some(ffi::RSA_size(self.0) as u32) }
- } else {
- None
- }
- }
-
- pub fn sign(&self, hash: hash::Type, message: &[u8]) -> Result<Vec<u8>, ErrorStack> {
- let k_len = self.size().expect("RSA missing an n");
- let mut sig = vec![0; k_len as usize];
- let mut sig_len = k_len;
-
- unsafe {
- try_ssl!(ffi::RSA_sign(hash.as_nid() as c_int,
- message.as_ptr(),
- message.len() as u32,
- sig.as_mut_ptr(),
- &mut sig_len,
- self.0));
- assert!(sig_len == k_len);
- Ok(sig)
- }
- }
-
- pub fn verify(&self, hash: hash::Type, message: &[u8], sig: &[u8]) -> Result<(), ErrorStack> {
- unsafe {
- try_ssl!(ffi::RSA_verify(hash.as_nid() as c_int,
- message.as_ptr(),
- message.len() as u32,
- sig.as_ptr(),
- sig.len() as u32,
- self.0));
- }
- Ok(())
- }
-
- pub fn as_ptr(&self) -> *mut ffi::RSA {
- self.0
- }
-
- pub fn n<'a>(&'a self) -> Option<BigNumRef<'a>> {
- unsafe {
- let n = (*self.0).n;
- if n.is_null() {
- None
- } else {
- Some(BigNumRef::from_ptr(n))
- }
- }
- }
-
- pub fn d<'a>(&self) -> Option<BigNumRef<'a>> {
- unsafe {
- let d = (*self.0).d;
- if d.is_null() {
- None
- } else {
- Some(BigNumRef::from_ptr(d))
- }
- }
- }
-
- pub fn e<'a>(&'a self) -> Option<BigNumRef<'a>> {
- unsafe {
- let e = (*self.0).e;
- if e.is_null() {
- None
- } else {
- Some(BigNumRef::from_ptr(e))
- }
- }
- }
-
- pub fn p<'a>(&'a self) -> Option<BigNumRef<'a>> {
- unsafe {
- let p = (*self.0).p;
- if p.is_null() {
- None
- } else {
- Some(BigNumRef::from_ptr(p))
- }
- }
- }
-
- pub fn q<'a>(&'a self) -> Option<BigNumRef<'a>> {
- unsafe {
- let q = (*self.0).q;
- if q.is_null() {
- None
- } else {
- Some(BigNumRef::from_ptr(q))
- }
- }
- }
-}
-
-impl fmt::Debug for RSA {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "RSA")
- }
-}
-
-#[cfg(test)]
-mod test {
- use std::io::Write;
- use libc::c_char;
-
- use super::*;
- use crypto::hash::*;
-
- fn signing_input_rs256() -> Vec<u8> {
- vec![101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 83, 85, 122, 73, 49, 78, 105, 74, 57,
- 46, 101, 121, 74, 112, 99, 51, 77, 105, 79, 105, 74, 113, 98, 50, 85, 105, 76, 65, 48,
- 75, 73, 67, 74, 108, 101, 72, 65, 105, 79, 106, 69, 122, 77, 68, 65, 52, 77, 84, 107,
- 122, 79, 68, 65, 115, 68, 81, 111, 103, 73, 109, 104, 48, 100, 72, 65, 54, 76, 121,
- 57, 108, 101, 71, 70, 116, 99, 71, 120, 108, 76, 109, 78, 118, 98, 83, 57, 112, 99,
- 49, 57, 121, 98, 50, 57, 48, 73, 106, 112, 48, 99, 110, 86, 108, 102, 81]
- }
-
- fn signature_rs256() -> Vec<u8> {
- vec![112, 46, 33, 137, 67, 232, 143, 209, 30, 181, 216, 45, 191, 120, 69, 243, 65, 6, 174,
- 27, 129, 255, 247, 115, 17, 22, 173, 209, 113, 125, 131, 101, 109, 66, 10, 253, 60,
- 150, 238, 221, 115, 162, 102, 62, 81, 102, 104, 123, 0, 11, 135, 34, 110, 1, 135, 237,
- 16, 115, 249, 69, 229, 130, 173, 252, 239, 22, 216, 90, 121, 142, 232, 198, 109, 219,
- 61, 184, 151, 91, 23, 208, 148, 2, 190, 237, 213, 217, 217, 112, 7, 16, 141, 178, 129,
- 96, 213, 248, 4, 12, 167, 68, 87, 98, 184, 31, 190, 127, 249, 217, 46, 10, 231, 111,
- 36, 242, 91, 51, 187, 230, 244, 74, 230, 30, 177, 4, 10, 203, 32, 4, 77, 62, 249, 18,
- 142, 212, 1, 48, 121, 91, 212, 189, 59, 65, 238, 202, 208, 102, 171, 101, 25, 129,
- 253, 228, 141, 247, 127, 55, 45, 195, 139, 159, 175, 221, 59, 239, 177, 139, 93, 163,
- 204, 60, 46, 176, 47, 158, 58, 65, 214, 18, 202, 173, 21, 145, 18, 115, 160, 95, 35,
- 185, 232, 56, 250, 175, 132, 157, 105, 132, 41, 239, 90, 30, 136, 121, 130, 54, 195,
- 212, 14, 96, 69, 34, 165, 68, 200, 242, 122, 122, 45, 184, 6, 99, 209, 108, 247, 202,
- 234, 86, 222, 64, 92, 178, 33, 90, 69, 178, 194, 85, 102, 181, 90, 193, 167, 72, 160,
- 112, 223, 200, 163, 42, 70, 149, 67, 208, 25, 238, 251, 71]
- }
-
- #[test]
- pub fn test_sign() {
- let key = include_bytes!("../../test/rsa.pem");
- let private_key = RSA::private_key_from_pem(key).unwrap();
-
- let mut sha = Hasher::new(Type::SHA256).unwrap();
- sha.write_all(&signing_input_rs256()).unwrap();
- let digest = sha.finish().unwrap();
-
- let result = private_key.sign(Type::SHA256, &digest).unwrap();
-
- assert_eq!(result, signature_rs256());
- }
-
- #[test]
- pub fn test_verify() {
- 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).unwrap();
- sha.write_all(&signing_input_rs256()).unwrap();
- let digest = sha.finish().unwrap();
-
- assert!(public_key.verify(Type::SHA256, &digest, &signature_rs256()).is_ok());
- }
-
- #[test]
- pub fn test_password() {
- let mut password_queried = false;
- let key = include_bytes!("../../test/rsa-encrypted.pem");
- RSA::private_key_from_pem_cb(key, |password| {
- password_queried = true;
- password[0] = b'm' as c_char;
- password[1] = b'y' as c_char;
- password[2] = b'p' as c_char;
- password[3] = b'a' as c_char;
- password[4] = b's' as c_char;
- password[5] = b's' as c_char;
- 6
- }).unwrap();
-
- assert!(password_queried);
- }
-}
diff --git a/openssl/src/dh.rs b/openssl/src/dh.rs
new file mode 100644
index 00000000..5a07e50f
--- /dev/null
+++ b/openssl/src/dh.rs
@@ -0,0 +1,145 @@
+use ffi;
+use error::ErrorStack;
+use bio::MemBioSlice;
+use std::ptr;
+use std::mem;
+
+use {cvt, cvt_p};
+use bio::MemBio;
+use bn::BigNum;
+use types::OpenSslTypeRef;
+
+type_!(Dh, DhRef, ffi::DH, ffi::DH_free);
+
+impl DhRef {
+ /// Encodes the parameters to PEM.
+ pub fn to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
+
+ unsafe {
+ try!(cvt(ffi::PEM_write_bio_DHparams(mem_bio.as_ptr(), self.as_ptr())));
+ }
+
+ Ok(mem_bio.get_buf().to_owned())
+ }
+}
+
+impl Dh {
+ pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result<Dh, ErrorStack> {
+ unsafe {
+ let dh = Dh(try!(cvt_p(ffi::DH_new())));
+ try!(cvt(compat::DH_set0_pqg(dh.0, p.as_ptr(), q.as_ptr(), g.as_ptr())));
+ mem::forget((p, g, q));
+ Ok(dh)
+ }
+ }
+
+ pub fn from_pem(buf: &[u8]) -> Result<Dh, ErrorStack> {
+ let mem_bio = try!(MemBioSlice::new(buf));
+ unsafe {
+ cvt_p(ffi::PEM_read_bio_DHparams(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ None,
+ ptr::null_mut()))
+ .map(Dh)
+ }
+ }
+
+ /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
+ #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
+ pub fn get_1024_160() -> Result<Dh, ErrorStack> {
+ unsafe { cvt_p(ffi::DH_get_1024_160()).map(Dh) }
+ }
+
+ /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
+ #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
+ pub fn get_2048_224() -> Result<Dh, ErrorStack> {
+ unsafe { cvt_p(ffi::DH_get_2048_224()).map(Dh) }
+ }
+
+ /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
+ #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
+ pub fn get_2048_256() -> Result<Dh, ErrorStack> {
+ unsafe { cvt_p(ffi::DH_get_2048_256()).map(Dh) }
+ }
+}
+
+#[cfg(ossl110)]
+mod compat {
+ pub use ffi::DH_set0_pqg;
+}
+
+#[cfg(ossl10x)]
+#[allow(bad_style)]
+mod compat {
+ use ffi;
+ use libc::c_int;
+
+ pub unsafe fn DH_set0_pqg(dh: *mut ffi::DH,
+ p: *mut ffi::BIGNUM,
+ q: *mut ffi::BIGNUM,
+ g: *mut ffi::BIGNUM)
+ -> c_int {
+ (*dh).p = p;
+ (*dh).q = q;
+ (*dh).g = g;
+ 1
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use dh::Dh;
+ use bn::BigNum;
+ use ssl::{SslMethod, SslContext};
+
+ #[test]
+ #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
+ fn test_dh_rfc5114() {
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ let dh1 = Dh::get_1024_160().unwrap();
+ ctx.set_tmp_dh(&dh1).unwrap();
+ let dh2 = Dh::get_2048_224().unwrap();
+ ctx.set_tmp_dh(&dh2).unwrap();
+ let dh3 = Dh::get_2048_256().unwrap();
+ ctx.set_tmp_dh(&dh3).unwrap();
+ }
+
+ #[test]
+ fn test_dh() {
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ let p = BigNum::from_hex_str("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435\
+ E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF429\
+ 6D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C02\
+ 2E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF1230\
+ 7F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9\
+ A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251C\
+ CACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE\
+ 621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D227\
+ 6E11715F693877FAD7EF09CADB094AE91E1A1597")
+ .unwrap();
+ let g = BigNum::from_hex_str("3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0\
+ BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773\
+ BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2D\
+ DF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428E\
+ BC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BF\
+ FE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7\
+ D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92\
+ B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148\
+ D47954515E2327CFEF98C582664B4C0F6CC41659")
+ .unwrap();
+ let q = BigNum::from_hex_str("8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F\
+ 5FBD3")
+ .unwrap();
+ let dh = Dh::from_params(p, g, q).unwrap();
+ ctx.set_tmp_dh(&dh).unwrap();
+ }
+
+ #[test]
+ fn test_dh_from_pem() {
+ let mut ctx = SslContext::builder(SslMethod::tls()).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/dh/mod.rs b/openssl/src/dh/mod.rs
deleted file mode 100644
index e0cf885a..00000000
--- a/openssl/src/dh/mod.rs
+++ /dev/null
@@ -1,124 +0,0 @@
-use ffi;
-use error::ErrorStack;
-use bio::MemBioSlice;
-use std::ptr;
-
-#[cfg(feature = "dh_from_params")]
-use bn::BigNum;
-#[cfg(feature = "dh_from_params")]
-use std::mem;
-
-pub struct DH(*mut ffi::DH);
-
-impl DH {
- /// Requires the `dh_from_params` feature.
- #[cfg(feature = "dh_from_params")]
- pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result<DH, ErrorStack> {
- let dh = unsafe {
- try_ssl_null!(::c_helpers::rust_0_8_DH_new_from_params(p.as_ptr(), g.as_ptr(), q.as_ptr()))
- };
- mem::forget(p);
- mem::forget(g);
- mem::forget(q);
- Ok(DH(dh))
- }
-
- pub fn from_pem(buf: &[u8]) -> Result<DH, ErrorStack> {
- let mem_bio = try!(MemBioSlice::new(buf));
- let dh = unsafe {
- ffi::PEM_read_bio_DHparams(mem_bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut())
- };
- try_ssl_null!(dh);
- Ok(DH(dh))
- }
-
- #[cfg(feature = "rfc5114")]
- pub fn get_1024_160() -> Result<DH, 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, 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, ErrorStack> {
- let dh = try_ssl_null!(unsafe { ffi::DH_get_2048_256() });
- Ok(DH(dh))
- }
-
- pub unsafe fn as_ptr(&self) -> *mut ffi::DH {
- let DH(n) = *self;
- n
- }
-}
-
-impl Drop for DH {
- fn drop(&mut self) {
- unsafe {
- ffi::DH_free(self.as_ptr())
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::DH;
- use bn::BigNum;
- use ssl::SslContext;
- use ssl::SslMethod::Sslv23;
-
- #[test]
- #[cfg(feature = "rfc5114")]
- fn test_dh_rfc5114() {
- 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();
- ctx.set_tmp_dh(&dh2).unwrap();
- let dh3 = DH::get_2048_256().unwrap();
- ctx.set_tmp_dh(&dh3).unwrap();
- }
-
- #[test]
- #[cfg(feature = "dh_from_params")]
- fn test_dh() {
- let mut ctx = SslContext::new(Sslv23).unwrap();
- let p = BigNum::from_hex_str("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435\
- E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF429\
- 6D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C02\
- 2E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF1230\
- 7F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9\
- A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251C\
- CACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE\
- 621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D227\
- 6E11715F693877FAD7EF09CADB094AE91E1A1597")
- .unwrap();
- let g = BigNum::from_hex_str("3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0\
- BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773\
- BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2D\
- DF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428E\
- BC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BF\
- FE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7\
- D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92\
- B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148\
- D47954515E2327CFEF98C582664B4C0F6CC41659")
- .unwrap();
- let q = BigNum::from_hex_str("8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F\
- 5FBD3")
- .unwrap();
- let dh = DH::from_params(p, g, q).unwrap();
- ctx.set_tmp_dh(&dh).unwrap();
- }
-
- #[test]
- fn test_dh_from_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/dsa.rs b/openssl/src/dsa.rs
new file mode 100644
index 00000000..9dd5669c
--- /dev/null
+++ b/openssl/src/dsa.rs
@@ -0,0 +1,223 @@
+use error::ErrorStack;
+use ffi;
+use libc::{c_int, c_char, c_void};
+use std::fmt;
+use std::ptr;
+
+use bio::{MemBio, MemBioSlice};
+use bn::BigNumRef;
+use {cvt, cvt_p};
+use types::OpenSslTypeRef;
+use util::{CallbackState, invoke_passwd_cb};
+
+type_!(Dsa, DsaRef, ffi::DSA, ffi::DSA_free);
+
+impl DsaRef {
+ /// Writes an DSA private key as unencrypted PEM formatted data
+ pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ assert!(self.has_private_key());
+ let mem_bio = try!(MemBio::new());
+
+ unsafe {
+ try!(cvt(ffi::PEM_write_bio_DSAPrivateKey(mem_bio.as_ptr(), self.as_ptr(),
+ ptr::null(), ptr::null_mut(), 0,
+ None, ptr::null_mut())))
+ };
+
+ Ok(mem_bio.get_buf().to_owned())
+ }
+
+ /// Writes an DSA public key as PEM formatted data
+ pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
+ unsafe {
+ try!(cvt(ffi::PEM_write_bio_DSA_PUBKEY(mem_bio.as_ptr(), self.as_ptr())));
+ }
+ Ok(mem_bio.get_buf().to_owned())
+ }
+
+ pub fn size(&self) -> Option<u32> {
+ if self.q().is_some() {
+ unsafe { Some(ffi::DSA_size(self.as_ptr()) as u32) }
+ } else {
+ None
+ }
+ }
+
+ pub fn p(&self) -> Option<&BigNumRef> {
+ unsafe {
+ let p = compat::pqg(self.as_ptr())[0];
+ if p.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr(p as *mut _))
+ }
+ }
+ }
+
+ pub fn q(&self) -> Option<&BigNumRef> {
+ unsafe {
+ let q = compat::pqg(self.as_ptr())[1];
+ if q.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr(q as *mut _))
+ }
+ }
+ }
+
+ pub fn g(&self) -> Option<&BigNumRef> {
+ unsafe {
+ let g = compat::pqg(self.as_ptr())[2];
+ if g.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr(g as *mut _))
+ }
+ }
+ }
+
+ pub fn has_public_key(&self) -> bool {
+ unsafe { !compat::keys(self.as_ptr())[0].is_null() }
+ }
+
+ pub fn has_private_key(&self) -> bool {
+ unsafe { !compat::keys(self.as_ptr())[1].is_null() }
+ }
+}
+
+impl Dsa {
+ /// Generate a DSA key pair.
+ pub fn generate(bits: u32) -> Result<Dsa, ErrorStack> {
+ unsafe {
+ let dsa = Dsa(try!(cvt_p(ffi::DSA_new())));
+ try!(cvt(ffi::DSA_generate_parameters_ex(dsa.0,
+ bits as c_int,
+ ptr::null(),
+ 0,
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ptr::null_mut())));
+ try!(cvt(ffi::DSA_generate_key(dsa.0)));
+ Ok(dsa)
+ }
+ }
+
+ /// Reads a DSA private key from PEM formatted data.
+ pub fn private_key_from_pem(buf: &[u8]) -> Result<Dsa, ErrorStack> {
+ ffi::init();
+ let mem_bio = try!(MemBioSlice::new(buf));
+
+ unsafe {
+ let dsa = try!(cvt_p(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ None,
+ ptr::null_mut())));
+ Ok(Dsa(dsa))
+ }
+ }
+
+ /// Read a private key from PEM supplying a password callback to be invoked if the private key
+ /// is encrypted.
+ ///
+ /// The callback will be passed the password buffer and should return the number of characters
+ /// placed into the buffer.
+ pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<Dsa, ErrorStack>
+ where F: FnOnce(&mut [c_char]) -> usize
+ {
+ ffi::init();
+ let mut cb = CallbackState::new(pass_cb);
+ let mem_bio = try!(MemBioSlice::new(buf));
+
+ unsafe {
+ let cb_ptr = &mut cb as *mut _ as *mut c_void;
+ let dsa = try!(cvt_p(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ Some(invoke_passwd_cb::<F>),
+ cb_ptr)));
+ Ok(Dsa(dsa))
+ }
+ }
+
+ /// Reads an DSA public key from PEM formatted data.
+ pub fn public_key_from_pem(buf: &[u8]) -> Result<Dsa, ErrorStack> {
+ ffi::init();
+
+ let mem_bio = try!(MemBioSlice::new(buf));
+ unsafe {
+ let dsa = try!(cvt_p(ffi::PEM_read_bio_DSA_PUBKEY(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ None,
+ ptr::null_mut())));
+ Ok(Dsa(dsa))
+ }
+ }
+}
+
+impl fmt::Debug for Dsa {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "DSA")
+ }
+}
+
+#[cfg(ossl110)]
+mod compat {
+ use std::ptr;
+ use ffi::{self, BIGNUM, DSA};
+
+ pub unsafe fn pqg(d: *const DSA) -> [*const BIGNUM; 3] {
+ let (mut p, mut q, mut g) = (ptr::null(), ptr::null(), ptr::null());
+ ffi::DSA_get0_pqg(d, &mut p, &mut q, &mut g);
+ [p, q, g]
+ }
+
+ pub unsafe fn keys(d: *const DSA) -> [*const BIGNUM; 2] {
+ let (mut pub_key, mut priv_key) = (ptr::null(), ptr::null());
+ ffi::DSA_get0_key(d, &mut pub_key, &mut priv_key);
+ [pub_key, priv_key]
+ }
+}
+
+#[cfg(ossl10x)]
+mod compat {
+ use ffi::{BIGNUM, DSA};
+
+ pub unsafe fn pqg(d: *const DSA) -> [*const BIGNUM; 3] {
+ [(*d).p, (*d).q, (*d).g]
+ }
+
+ pub unsafe fn keys(d: *const DSA) -> [*const BIGNUM; 2] {
+ [(*d).pub_key, (*d).priv_key]
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use libc::c_char;
+
+ use super::*;
+
+ #[test]
+ pub fn test_generate() {
+ Dsa::generate(1024).unwrap();
+ }
+
+ #[test]
+ pub fn test_password() {
+ let mut password_queried = false;
+ let key = include_bytes!("../test/dsa-encrypted.pem");
+ Dsa::private_key_from_pem_cb(key, |password| {
+ password_queried = true;
+ password[0] = b'm' as c_char;
+ password[1] = b'y' as c_char;
+ password[2] = b'p' as c_char;
+ password[3] = b'a' as c_char;
+ password[4] = b's' as c_char;
+ password[5] = b's' as c_char;
+ 6
+ })
+ .unwrap();
+
+ assert!(password_queried);
+ }
+}
diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs
new file mode 100644
index 00000000..41501c14
--- /dev/null
+++ b/openssl/src/ec_key.rs
@@ -0,0 +1,24 @@
+use ffi;
+
+use cvt_p;
+use error::ErrorStack;
+use nid::Nid;
+
+type_!(EcKey, EcKeyRef, ffi::EC_KEY, ffi::EC_KEY_free);
+
+impl EcKey {
+ pub fn new_by_curve_name(nid: Nid) -> Result<EcKey, ErrorStack> {
+ unsafe { cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(EcKey) }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use nid;
+ use super::*;
+
+ #[test]
+ fn new_by_curve_name() {
+ EcKey::new_by_curve_name(nid::X9_62_PRIME256V1).unwrap();
+ }
+}
diff --git a/openssl/src/error.rs b/openssl/src/error.rs
index d76e7cbd..4dd219af 100644
--- a/openssl/src/error.rs
+++ b/openssl/src/error.rs
@@ -71,44 +71,84 @@ impl Error {
match unsafe { ffi::ERR_get_error() } {
0 => None,
- err => Some((Error(err))),
+ err => Some(Error(err)),
}
}
/// Returns the raw OpenSSL error code for this error.
- pub fn error_code(&self) -> c_ulong {
+ pub fn 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 library reporting the error, if available.
+ pub fn library(&self) -> Option<&'static str> {
+ unsafe {
+ let cstr = ffi::ERR_lib_error_string(self.0);
+ if cstr.is_null() {
+ return None;
+ }
+ let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
+ Some(str::from_utf8(bytes).unwrap())
+ }
}
/// Returns the name of the function reporting the error.
- pub fn function(&self) -> &'static str {
- get_func(self.0)
+ pub fn function(&self) -> Option<&'static str> {
+ unsafe {
+ let cstr = ffi::ERR_func_error_string(self.0);
+ if cstr.is_null() {
+ return None;
+ }
+ let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
+ Some(str::from_utf8(bytes).unwrap())
+ }
}
/// Returns the reason for the error.
- pub fn reason(&self) -> &'static str {
- get_reason(self.0)
+ pub fn reason(&self) -> Option<&'static str> {
+ unsafe {
+ let cstr = ffi::ERR_reason_error_string(self.0);
+ if cstr.is_null() {
+ return None;
+ }
+ let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
+ Some(str::from_utf8(bytes).unwrap())
+ }
}
}
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()
+ let mut builder = fmt.debug_struct("Error");
+ builder.field("code", &self.code());
+ if let Some(library) = self.library() {
+ builder.field("library", &library);
+ }
+ if let Some(function) = self.function() {
+ builder.field("function", &function);
+ }
+ if let Some(reason) = self.reason() {
+ builder.field("reason", &reason);
+ }
+ builder.finish()
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- fmt.write_str(&self.reason())
+ try!(write!(fmt, "error:{:08X}", self.0));
+ match self.library() {
+ Some(l) => try!(write!(fmt, ":{}", l)),
+ None => try!(write!(fmt, ":lib({})", ffi::ERR_GET_LIB(self.0))),
+ }
+ match self.function() {
+ Some(f) => try!(write!(fmt, ":{}", f)),
+ None => try!(write!(fmt, ":func({})", ffi::ERR_GET_FUNC(self.0))),
+ }
+ match self.reason() {
+ Some(r) => write!(fmt, ":{}", r),
+ None => write!(fmt, ":reason({})", ffi::ERR_GET_FUNC(self.0)),
+ }
}
}
@@ -117,28 +157,3 @@ impl error::Error for Error {
"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/crypto/hash.rs b/openssl/src/hash.rs
index 207a55f5..6a13371d 100644
--- a/openssl/src/crypto/hash.rs
+++ b/openssl/src/hash.rs
@@ -1,51 +1,49 @@
-use libc::c_uint;
use std::io::prelude::*;
use std::io;
-use std::ptr;
-use std::cmp;
use ffi;
-use HashTypeInternals;
+#[cfg(ossl110)]
+use ffi::{EVP_MD_CTX_new, EVP_MD_CTX_free};
+#[cfg(any(ossl101, ossl102))]
+use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free};
+
+use {cvt, cvt_p};
use error::ErrorStack;
-use nid::Nid;
-/// Message digest (hash) type.
#[derive(Copy, Clone)]
-pub enum Type {
- MD5,
- SHA1,
- SHA224,
- SHA256,
- SHA384,
- SHA512,
- RIPEMD160,
-}
+pub struct MessageDigest(*const ffi::EVP_MD);
-impl HashTypeInternals for Type {
- fn as_nid(&self) -> Nid {
- match *self {
- Type::MD5 => Nid::MD5,
- Type::SHA1 => Nid::SHA1,
- Type::SHA224 => Nid::SHA224,
- Type::SHA256 => Nid::SHA256,
- Type::SHA384 => Nid::SHA384,
- Type::SHA512 => Nid::SHA512,
- Type::RIPEMD160 => Nid::RIPEMD160,
- }
+impl MessageDigest {
+ pub fn md5() -> MessageDigest {
+ unsafe { MessageDigest(ffi::EVP_md5()) }
}
- fn evp_md(&self) -> *const ffi::EVP_MD {
- unsafe {
- match *self {
- Type::MD5 => ffi::EVP_md5(),
- Type::SHA1 => ffi::EVP_sha1(),
- Type::SHA224 => ffi::EVP_sha224(),
- Type::SHA256 => ffi::EVP_sha256(),
- Type::SHA384 => ffi::EVP_sha384(),
- Type::SHA512 => ffi::EVP_sha512(),
- Type::RIPEMD160 => ffi::EVP_ripemd160(),
- }
- }
+ pub fn sha1() -> MessageDigest {
+ unsafe { MessageDigest(ffi::EVP_sha1()) }
+ }
+
+ pub fn sha224() -> MessageDigest {
+ unsafe { MessageDigest(ffi::EVP_sha224()) }
+ }
+
+ pub fn sha256() -> MessageDigest {
+ unsafe { MessageDigest(ffi::EVP_sha256()) }
+ }
+
+ pub fn sha384() -> MessageDigest {
+ unsafe { MessageDigest(ffi::EVP_sha384()) }
+ }
+
+ pub fn sha512() -> MessageDigest {
+ unsafe { MessageDigest(ffi::EVP_sha512()) }
+ }
+
+ pub fn ripemd160() -> MessageDigest {
+ unsafe { MessageDigest(ffi::EVP_ripemd160()) }
+ }
+
+ pub fn as_ptr(&self) -> *const ffi::EVP_MD {
+ self.0
}
}
@@ -65,20 +63,22 @@ use self::State::*;
/// Calculate a hash in one go.
///
/// ```
-/// use openssl::crypto::hash::{hash, Type};
+/// use openssl::hash::{hash, MessageDigest};
+///
/// let data = b"\x42\xF4\x97\xE0";
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
-/// let res = hash(Type::MD5, data).unwrap();
+/// let res = hash(MessageDigest::md5(), data).unwrap();
/// assert_eq!(res, spec);
/// ```
///
/// Use the `Write` trait to supply the input in chunks.
///
/// ```
-/// use openssl::crypto::hash::{Hasher, Type};
+/// use openssl::hash::{Hasher, MessageDigest};
+///
/// let data = [b"\x42\xF4", b"\x97\xE0"];
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
-/// let mut h = Hasher::new(Type::MD5).unwrap();
+/// let mut h = Hasher::new(MessageDigest::md5()).unwrap();
/// h.update(data[0]).unwrap();
/// h.update(data[1]).unwrap();
/// let res = h.finish().unwrap();
@@ -89,25 +89,24 @@ use self::State::*;
///
/// Don't actually use MD5 and SHA-1 hashes, they're not secure anymore.
///
-/// Don't ever hash passwords, use `crypto::pkcs5` or bcrypt/scrypt instead.
+/// Don't ever hash passwords, use the functions in the `pkcs5` module or bcrypt/scrypt instead.
pub struct Hasher {
ctx: *mut ffi::EVP_MD_CTX,
md: *const ffi::EVP_MD,
- type_: Type,
+ type_: MessageDigest,
state: State,
}
impl Hasher {
/// Creates a new `Hasher` with the specified hash type.
- pub fn new(ty: Type) -> Result<Hasher, ErrorStack> {
+ pub fn new(ty: MessageDigest) -> Result<Hasher, ErrorStack> {
ffi::init();
- let ctx = unsafe { try_ssl_null!(ffi::EVP_MD_CTX_create()) };
- let md = ty.evp_md();
+ let ctx = unsafe { try!(cvt_p(EVP_MD_CTX_new())) };
let mut h = Hasher {
ctx: ctx,
- md: md,
+ md: ty.as_ptr(),
type_: ty,
state: Finalized,
};
@@ -123,22 +122,20 @@ impl Hasher {
}
Finalized => (),
}
- unsafe { try_ssl!(ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *const _)); }
+ unsafe {
+ try!(cvt(ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *mut _)));
+ }
self.state = Reset;
Ok(())
}
/// Feeds data into the hasher.
- pub fn update(&mut self, mut data: &[u8]) -> Result<(), ErrorStack> {
+ pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
if self.state == Finalized {
try!(self.init());
}
- while !data.is_empty() {
- let len = cmp::min(data.len(), c_uint::max_value() as usize);
- unsafe {
- try_ssl!(ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), len as c_uint));
- }
- data = &data[len..];
+ unsafe {
+ try!(cvt(ffi::EVP_DigestUpdate(self.ctx, data.as_ptr() as *mut _, data.len())));
}
self.state = Updated;
Ok(())
@@ -153,7 +150,7 @@ impl Hasher {
unsafe {
let mut len = ffi::EVP_MAX_MD_SIZE;
let mut res = vec![0; len as usize];
- try_ssl!(ffi::EVP_DigestFinal_ex(self.ctx, res.as_mut_ptr(), &mut len));
+ try!(cvt(ffi::EVP_DigestFinal_ex(self.ctx, res.as_mut_ptr(), &mut len)));
res.truncate(len as usize);
self.state = Finalized;
Ok(res)
@@ -176,7 +173,7 @@ impl Write for Hasher {
impl Clone for Hasher {
fn clone(&self) -> Hasher {
let ctx = unsafe {
- let ctx = ffi::EVP_MD_CTX_create();
+ let ctx = EVP_MD_CTX_new();
assert!(!ctx.is_null());
let r = ffi::EVP_MD_CTX_copy_ex(ctx, self.ctx);
assert_eq!(r, 1);
@@ -197,13 +194,13 @@ impl Drop for Hasher {
if self.state != Finalized {
drop(self.finish());
}
- ffi::EVP_MD_CTX_destroy(self.ctx);
+ EVP_MD_CTX_free(self.ctx);
}
}
}
/// Computes the hash of the `data` with the hash `t`.
-pub fn hash(t: Type, data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
+pub fn hash(t: MessageDigest, data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
let mut h = try!(Hasher::new(t));
try!(h.update(data));
h.finish()
@@ -212,10 +209,10 @@ pub fn hash(t: Type, data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
#[cfg(test)]
mod tests {
use serialize::hex::{FromHex, ToHex};
- use super::{hash, Hasher, Type};
+ use super::{hash, Hasher, MessageDigest};
use std::io::prelude::*;
- fn hash_test(hashtype: Type, hashtest: &(&str, &str)) {
+ fn hash_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
let res = hash(hashtype, &*hashtest.0.from_hex().unwrap()).unwrap();
assert_eq!(res.to_hex(), hashtest.1);
}
@@ -228,43 +225,31 @@ mod tests {
// Test vectors from http://www.nsrl.nist.gov/testdata/
#[allow(non_upper_case_globals)]
- const md5_tests: [(&'static str, &'static str); 13] = [("",
- "d41d8cd98f00b204e9800998ecf8427e"),
- ("7F",
- "83acb6e67e50e31db6ed341dd2de1595"),
- ("EC9C",
- "0b07f0d4ca797d8ac58874f887cb0b68"),
- ("FEE57A",
- "e0d583171eb06d56198fc0ef22173907"),
- ("42F497E0",
- "7c430f178aefdf1487fee7144e9641e2"),
- ("C53B777F1C",
- "75ef141d64cb37ec423da2d9d440c925"),
- ("89D5B576327B",
- "ebbaf15eb0ed784c6faa9dc32831bf33"),
- ("5D4CCE781EB190",
- "ce175c4b08172019f05e6b5279889f2c"),
- ("81901FE94932D7B9",
- "cd4d2f62b8cdb3a0cf968a735a239281"),
- ("C9FFDEE7788EFB4EC9",
- "e0841a231ab698db30c6c0f3f246c014"),
- ("66AC4B7EBA95E53DC10B",
- "a3b3cea71910d9af56742aa0bb2fe329"),
- ("A510CD18F7A56852EB0319",
- "577e216843dd11573574d3fb209b97d8"),
- ("AAED18DBE8938C19ED734A8D",
- "6f80fb775f27e0a4ce5c2f42fc72c5f1")];
+ const md5_tests: [(&'static str, &'static str); 13] =
+ [("", "d41d8cd98f00b204e9800998ecf8427e"),
+ ("7F", "83acb6e67e50e31db6ed341dd2de1595"),
+ ("EC9C", "0b07f0d4ca797d8ac58874f887cb0b68"),
+ ("FEE57A", "e0d583171eb06d56198fc0ef22173907"),
+ ("42F497E0", "7c430f178aefdf1487fee7144e9641e2"),
+ ("C53B777F1C", "75ef141d64cb37ec423da2d9d440c925"),
+ ("89D5B576327B", "ebbaf15eb0ed784c6faa9dc32831bf33"),
+ ("5D4CCE781EB190", "ce175c4b08172019f05e6b5279889f2c"),
+ ("81901FE94932D7B9", "cd4d2f62b8cdb3a0cf968a735a239281"),
+ ("C9FFDEE7788EFB4EC9", "e0841a231ab698db30c6c0f3f246c014"),
+ ("66AC4B7EBA95E53DC10B", "a3b3cea71910d9af56742aa0bb2fe329"),
+ ("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"),
+ ("AAED18DBE8938C19ED734A8D", "6f80fb775f27e0a4ce5c2f42fc72c5f1")];
#[test]
fn test_md5() {
for test in md5_tests.iter() {
- hash_test(Type::MD5, test);
+ hash_test(MessageDigest::md5(), test);
}
}
#[test]
fn test_md5_recycle() {
- let mut h = Hasher::new(Type::MD5).unwrap();
+ let mut h = Hasher::new(MessageDigest::md5()).unwrap();
for test in md5_tests.iter() {
hash_recycle_test(&mut h, test);
}
@@ -272,11 +257,11 @@ mod tests {
#[test]
fn test_finish_twice() {
- let mut h = Hasher::new(Type::MD5).unwrap();
+ let mut h = Hasher::new(MessageDigest::md5()).unwrap();
h.write_all(&*md5_tests[6].0.from_hex().unwrap()).unwrap();
h.finish().unwrap();
let res = h.finish().unwrap();
- let null = hash(Type::MD5, &[]).unwrap();
+ let null = hash(MessageDigest::md5(), &[]).unwrap();
assert_eq!(res, null);
}
@@ -286,7 +271,7 @@ mod tests {
let inp = md5_tests[i].0.from_hex().unwrap();
assert!(inp.len() > 2);
let p = inp.len() / 2;
- let h0 = Hasher::new(Type::MD5).unwrap();
+ let h0 = Hasher::new(MessageDigest::md5()).unwrap();
println!("Clone a new hasher");
let mut h1 = h0.clone();
@@ -314,7 +299,7 @@ mod tests {
let tests = [("616263", "a9993e364706816aba3e25717850c26c9cd0d89d")];
for test in tests.iter() {
- hash_test(Type::SHA1, test);
+ hash_test(MessageDigest::sha1(), test);
}
}
@@ -324,7 +309,7 @@ mod tests {
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")];
for test in tests.iter() {
- hash_test(Type::SHA256, test);
+ hash_test(MessageDigest::sha256(), test);
}
}
@@ -333,7 +318,7 @@ mod tests {
let tests = [("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")];
for test in tests.iter() {
- hash_test(Type::RIPEMD160, test);
+ hash_test(MessageDigest::ripemd160(), test);
}
}
}
diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs
index 879681f4..a9d937ba 100644
--- a/openssl/src/lib.rs
+++ b/openssl/src/lib.rs
@@ -1,4 +1,4 @@
-#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.8.3")]
+#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.9.0")]
#[macro_use]
extern crate bitflags;
@@ -11,29 +11,99 @@ extern crate openssl_sys as ffi;
extern crate rustc_serialize as serialize;
#[cfg(test)]
-extern crate net2;
+extern crate tempdir;
#[doc(inline)]
pub use ffi::init;
-use nid::Nid;
+use libc::c_int;
-mod macros;
+use error::ErrorStack;
+
+macro_rules! type_ {
+ ($n:ident, $r:ident, $c:path, $d:path) => {
+ pub struct $n(*mut $c);
+
+ impl ::types::OpenSslType for $n {
+ type CType = $c;
+ type Ref = $r;
+
+ unsafe fn from_ptr(ptr: *mut $c) -> $n {
+ $n(ptr)
+ }
+ }
+
+ impl Drop for $n {
+ fn drop(&mut self) {
+ unsafe { $d(self.0) }
+ }
+ }
+
+ impl ::std::ops::Deref for $n {
+ type Target = $r;
+
+ fn deref(&self) -> &$r {
+ unsafe { ::types::OpenSslTypeRef::from_ptr(self.0) }
+ }
+ }
+
+ impl ::std::ops::DerefMut for $n {
+ fn deref_mut(&mut self) -> &mut $r {
+ unsafe { ::types::OpenSslTypeRef::from_ptr_mut(self.0) }
+ }
+ }
+
+ pub struct $r(::util::Opaque);
+
+ impl ::types::OpenSslTypeRef for $r {
+ type CType = $c;
+ }
+ }
+}
-pub mod asn1;
mod bio;
+mod util;
+pub mod asn1;
pub mod bn;
-#[cfg(feature = "c_helpers")]
-mod c_helpers;
pub mod crypto;
pub mod dh;
+pub mod dsa;
+pub mod ec_key;
pub mod error;
+pub mod hash;
+pub mod memcmp;
pub mod nid;
+pub mod pkcs12;
+pub mod pkcs5;
+pub mod pkey;
+pub mod rand;
+pub mod types;
+pub mod rsa;
+pub mod sign;
pub mod ssl;
+pub mod symm;
pub mod version;
pub mod x509;
+pub mod stack;
+#[cfg(any(ossl102, ossl110))]
+mod verify;
+
+fn cvt_p<T>(r: *mut T) -> Result<*mut T, ErrorStack> {
+ if r.is_null() {
+ Err(ErrorStack::get())
+ } else {
+ Ok(r)
+ }
+}
+
+fn cvt(r: c_int) -> Result<c_int, ErrorStack> {
+ if r <= 0 {
+ Err(ErrorStack::get())
+ } else {
+ Ok(r)
+ }
+}
-trait HashTypeInternals {
- fn as_nid(&self) -> Nid;
- fn evp_md(&self) -> *const ffi::EVP_MD;
+fn cvt_n(r: c_int) -> Result<c_int, ErrorStack> {
+ if r < 0 { Err(ErrorStack::get()) } else { Ok(r) }
}
diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs
deleted file mode 100644
index 35221f1c..00000000
--- a/openssl/src/macros.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-#![macro_use]
-
-macro_rules! try_ssl_stream {
- ($e:expr) => (
- match $e {
- Ok(ok) => ok,
- Err(err) => return Err(StreamError(err))
- }
- )
-}
-
-/// Shortcut return with SSL error if something went wrong
-macro_rules! try_ssl_if {
- ($e:expr) => (
- if $e {
- return Err(::error::ErrorStack::get().into())
- }
- )
-}
-
-/// Shortcut return with SSL error if last error result is 0
-/// (default)
-macro_rules! try_ssl{
- ($e:expr) => (try_ssl_if!($e == 0))
-}
-
-/// Shortcut return with SSL if got a null result
-macro_rules! try_ssl_null{
- ($e:expr) => ({
- let t = $e;
- try_ssl_if!(t == ptr::null_mut());
- t
- })
-}
-
-
-/// Lifts current SSL error code into Result<(), Error>
-/// if expression is true
-/// Lifting is actually a shortcut of the following form:
-///
-/// ```ignore
-/// let _ = try!(something)
-/// Ok(())
-/// ```
-macro_rules! lift_ssl_if{
- ($e:expr) => ( {
- if $e {
- Err(::error::ErrorStack::get().into())
- } else {
- Ok(())
- }
- })
-}
-
-/// Lifts current SSL error code into Result<(), Error>
-/// if SSL returned 0 (default error indication)
-macro_rules! lift_ssl {
- ($e:expr) => (lift_ssl_if!($e == 0))
-}
diff --git a/openssl/src/crypto/memcmp.rs b/openssl/src/memcmp.rs
index cf08bdb5..0a7124bd 100644
--- a/openssl/src/crypto/memcmp.rs
+++ b/openssl/src/memcmp.rs
@@ -6,7 +6,7 @@ use ffi;
/// This operation takes an amount of time dependent on the length of the two
/// arrays given, but is independent of the contents of a and b.
///
-/// # Failure
+/// # Panics
///
/// This function will panic the current task if `a` and `b` do not have the same
/// length.
diff --git a/openssl/src/nid.rs b/openssl/src/nid.rs
index 874d4a6f..afbd60a5 100644
--- a/openssl/src/nid.rs
+++ b/openssl/src/nid.rs
@@ -1,196 +1,954 @@
-#[allow(non_camel_case_types)]
-#[derive(Copy, Clone, Hash, PartialEq, Eq)]
-#[repr(usize)]
-pub enum Nid {
- Undefined, // 0
- Rsadsi,
- Pkcs,
- MD2,
- MD4,
- MD5,
- RC4,
- RsaEncryption,
- RSA_MD2,
- RSA_MD5,
- PBE_MD2_DES, // 10
- X500,
- x509,
- CN,
- C,
- L,
- ST,
- O,
- OU,
- RSA,
- Pkcs7, // 20
- Pkcs7_data,
- Pkcs7_signedData,
- Pkcs7_envelopedData,
- Pkcs7_signedAndEnvelopedData,
- Pkcs7_digestData,
- Pkcs7_encryptedData,
- Pkcs3,
- DhKeyAgreement,
- DES_ECB,
- DES_CFB, // 30
- DES_CBC,
- DES_EDE,
- DES_EDE3,
- IDEA_CBC,
- IDEA_CFB,
- IDEA_ECB,
- RC2_CBC,
- RC2_ECB,
- RC2_CFB,
- RC2_OFB, // 40
- SHA,
- RSA_SHA,
- DES_EDE_CBC,
- DES_EDE3_CBC,
- DES_OFB,
- IDEA_OFB,
- Pkcs9,
- Email,
- UnstructuredName,
- ContentType, // 50
- MessageDigest,
- SigningTime,
- CounterSignature,
- ChallengePassword,
- UnstructuredAddress,
- ExtendedCertificateAttributes,
- Netscape,
- NetscapeCertExtention,
- NetscapeDatatype,
- DES_EDE_CFB64, // 60
- DES_EDE3_CFB64,
- DES_EDE_OFB64,
- DES_EDE3_OFB64,
- SHA1,
- RSA_SHA1,
- DSA_SHA,
- DSA_OLD,
- PBE_SHA1_RC2_64,
- PBKDF2,
- DSA_SHA1_OLD, // 70
- NetscapeCertType,
- NetscapeBaseUrl,
- NetscapeRevocationUrl,
- NetscapeCARevocationUrl,
- NetscapeRenewalUrl,
- NetscapeCAPolicyUrl,
- NetscapeSSLServerName,
- NetscapeComment,
- NetscapeCertSequence,
- DESX_CBC, // 80
- ID_CE,
- SubjectKeyIdentifier,
- KeyUsage,
- PrivateKeyUsagePeriod,
- SubjectAltName,
- IssuerAltName,
- BasicConstraints,
- CrlNumber,
- CertificatePolicies,
- AuthorityKeyIdentifier, // 90
- BF_CBC,
- BF_ECB,
- BF_CFB,
- BF_OFB,
- MDC2,
- RSA_MDC2,
- RC4_40,
- RC2_40_CBC,
- G,
- S, // 100
- I,
- /// uniqueIdentifier
- UID,
- CrlDistributionPoints,
- RSA_NP_MD5,
- SN,
- T,
- D,
- CAST5_CBC,
- CAST5_ECB,
- CAST5_CFB, // 110
- CAST5_OFB,
- PbeWithMD5AndCast5CBC,
- DSA_SHA1,
- MD5_SHA1,
- RSA_SHA1_2,
- DSA,
- RIPEMD160,
- // 118 missing
- RSA_RIPEMD160 = 119,
- RC5_CBC, // 120
- RC5_ECB,
- RC5_CFB,
- RC5_OFB,
- RLE,
- ZLIB,
- ExtendedKeyUsage,
- PKIX,
- ID_KP,
- ServerAuth,
- ClientAuth, // 130
- CodeSigning,
- EmailProtection,
- TimeStamping,
- MsCodeInd,
- MsCodeCom,
- MsCtlSigh,
- MsSGC,
- MsEFS,
- NsSGC,
- DeltaCRL, // 140
- CRLReason,
- InvalidityDate,
- SXNetID,
- PBE_SHA1_RC4_128,
- PBE_SHA1_RC4_40,
- PBE_SHA1_3DES,
- PBE_SHA1_2DES,
- PBE_SHA1_RC2_128,
- PBE_SHA1_RC2_40,
- KeyBag, // 150
- Pkcs8ShroudedKeyBag,
- CertBag,
- CrlBag,
- SecretBag,
- SafeContentsBag,
- FriendlyName,
- LocalKeyID,
- X509Certificate,
- SdsiCertificate,
- X509Crl, // 160
- PBES2,
- PBMAC1,
- HmacWithSha1,
- ID_QT_CPS,
- ID_QT_UNOTICE,
- RC2_64_CBC,
- SMIMECaps,
- PBE_MD2_RC2_64,
- PBE_MD5_RC2_64,
- PBE_SHA1_DES,
- MicrosoftExtensionRequest,
- ExtensionRequest,
- Name,
- DnQualifier,
- IdPe,
- IdAd,
- AuthorityInfoAccess,
- OCSP,
- CaIssuers,
- OCSPSigning, // 180
+use ffi;
+use libc::c_int;
- // 181 and up are from openssl's obj_mac.h
- /// Shown as UID in cert subject
- UserId = 458,
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct Nid(c_int);
- SHA256 = 672,
- SHA384,
- SHA512,
- SHA224,
+#[allow(non_snake_case)]
+impl Nid {
+ pub fn from_raw(raw: c_int) -> Nid {
+ Nid(raw)
+ }
+
+ pub fn as_raw(&self) -> c_int {
+ self.0
+ }
}
+
+pub const UNDEF: Nid = Nid(ffi::NID_undef);
+pub const ITU_T: Nid = Nid(ffi::NID_itu_t);
+pub const CCITT: Nid = Nid(ffi::NID_ccitt);
+pub const ISO: Nid = Nid(ffi::NID_iso);
+pub const JOINT_ISO_ITU_T: Nid = Nid(ffi::NID_joint_iso_itu_t);
+pub const JOINT_ISO_CCITT: Nid = Nid(ffi::NID_joint_iso_ccitt);
+pub const MEMBER_BODY: Nid = Nid(ffi::NID_member_body);
+pub const IDENTIFIED_ORGANIZATION: Nid = Nid(ffi::NID_identified_organization);
+pub const HMAC_MD5: Nid = Nid(ffi::NID_hmac_md5);
+pub const HMAC_SHA1: Nid = Nid(ffi::NID_hmac_sha1);
+pub const CERTICOM_ARC: Nid = Nid(ffi::NID_certicom_arc);
+pub const INTERNATIONAL_ORGANIZATIONS: Nid = Nid(ffi::NID_international_organizations);
+pub const WAP: Nid = Nid(ffi::NID_wap);
+pub const WAP_WSG: Nid = Nid(ffi::NID_wap_wsg);
+pub const SELECTED_ATTRIBUTE_TYPES: Nid = Nid(ffi::NID_selected_attribute_types);
+pub const CLEARANCE: Nid = Nid(ffi::NID_clearance);
+pub const ISO_US: Nid = Nid(ffi::NID_ISO_US);
+pub const X9_57: Nid = Nid(ffi::NID_X9_57);
+pub const X9CM: Nid = Nid(ffi::NID_X9cm);
+pub const DSA: Nid = Nid(ffi::NID_dsa);
+pub const DSAWITHSHA1: Nid = Nid(ffi::NID_dsaWithSHA1);
+pub const ANSI_X9_62: Nid = Nid(ffi::NID_ansi_X9_62);
+pub const X9_62_PRIME_FIELD: Nid = Nid(ffi::NID_X9_62_prime_field);
+pub const X9_62_CHARACTERISTIC_TWO_FIELD: Nid = Nid(ffi::NID_X9_62_characteristic_two_field);
+pub const X9_62_ID_CHARACTERISTIC_TWO_BASIS: Nid = Nid(ffi::NID_X9_62_id_characteristic_two_basis);
+pub const X9_62_ONBASIS: Nid = Nid(ffi::NID_X9_62_onBasis);
+pub const X9_62_TPBASIS: Nid = Nid(ffi::NID_X9_62_tpBasis);
+pub const X9_62_PPBASIS: Nid = Nid(ffi::NID_X9_62_ppBasis);
+pub const X9_62_ID_ECPUBLICKEY: Nid = Nid(ffi::NID_X9_62_id_ecPublicKey);
+pub const X9_62_C2PNB163V1: Nid = Nid(ffi::NID_X9_62_c2pnb163v1);
+pub const X9_62_C2PNB163V2: Nid = Nid(ffi::NID_X9_62_c2pnb163v2);
+pub const X9_62_C2PNB163V3: Nid = Nid(ffi::NID_X9_62_c2pnb163v3);
+pub const X9_62_C2PNB176V1: Nid = Nid(ffi::NID_X9_62_c2pnb176v1);
+pub const X9_62_C2TNB191V1: Nid = Nid(ffi::NID_X9_62_c2tnb191v1);
+pub const X9_62_C2TNB191V2: Nid = Nid(ffi::NID_X9_62_c2tnb191v2);
+pub const X9_62_C2TNB191V3: Nid = Nid(ffi::NID_X9_62_c2tnb191v3);
+pub const X9_62_C2ONB191V4: Nid = Nid(ffi::NID_X9_62_c2onb191v4);
+pub const X9_62_C2ONB191V5: Nid = Nid(ffi::NID_X9_62_c2onb191v5);
+pub const X9_62_C2PNB208W1: Nid = Nid(ffi::NID_X9_62_c2pnb208w1);
+pub const X9_62_C2TNB239V1: Nid = Nid(ffi::NID_X9_62_c2tnb239v1);
+pub const X9_62_C2TNB239V2: Nid = Nid(ffi::NID_X9_62_c2tnb239v2);
+pub const X9_62_C2TNB239V3: Nid = Nid(ffi::NID_X9_62_c2tnb239v3);
+pub const X9_62_C2ONB239V4: Nid = Nid(ffi::NID_X9_62_c2onb239v4);
+pub const X9_62_C2ONB239V5: Nid = Nid(ffi::NID_X9_62_c2onb239v5);
+pub const X9_62_C2PNB272W1: Nid = Nid(ffi::NID_X9_62_c2pnb272w1);
+pub const X9_62_C2PNB304W1: Nid = Nid(ffi::NID_X9_62_c2pnb304w1);
+pub const X9_62_C2TNB359V1: Nid = Nid(ffi::NID_X9_62_c2tnb359v1);
+pub const X9_62_C2PNB368W1: Nid = Nid(ffi::NID_X9_62_c2pnb368w1);
+pub const X9_62_C2TNB431R1: Nid = Nid(ffi::NID_X9_62_c2tnb431r1);
+pub const X9_62_PRIME192V1: Nid = Nid(ffi::NID_X9_62_prime192v1);
+pub const X9_62_PRIME192V2: Nid = Nid(ffi::NID_X9_62_prime192v2);
+pub const X9_62_PRIME192V3: Nid = Nid(ffi::NID_X9_62_prime192v3);
+pub const X9_62_PRIME239V1: Nid = Nid(ffi::NID_X9_62_prime239v1);
+pub const X9_62_PRIME239V2: Nid = Nid(ffi::NID_X9_62_prime239v2);
+pub const X9_62_PRIME239V3: Nid = Nid(ffi::NID_X9_62_prime239v3);
+pub const X9_62_PRIME256V1: Nid = Nid(ffi::NID_X9_62_prime256v1);
+pub const ECDSA_WITH_SHA1: Nid = Nid(ffi::NID_ecdsa_with_SHA1);
+pub const ECDSA_WITH_RECOMMENDED: Nid = Nid(ffi::NID_ecdsa_with_Recommended);
+pub const ECDSA_WITH_SPECIFIED: Nid = Nid(ffi::NID_ecdsa_with_Specified);
+pub const ECDSA_WITH_SHA224: Nid = Nid(ffi::NID_ecdsa_with_SHA224);
+pub const ECDSA_WITH_SHA256: Nid = Nid(ffi::NID_ecdsa_with_SHA256);
+pub const ECDSA_WITH_SHA384: Nid = Nid(ffi::NID_ecdsa_with_SHA384);
+pub const ECDSA_WITH_SHA512: Nid = Nid(ffi::NID_ecdsa_with_SHA512);
+pub const SECP112R1: Nid = Nid(ffi::NID_secp112r1);
+pub const SECP112R2: Nid = Nid(ffi::NID_secp112r2);
+pub const SECP128R1: Nid = Nid(ffi::NID_secp128r1);
+pub const SECP128R2: Nid = Nid(ffi::NID_secp128r2);
+pub const SECP160K1: Nid = Nid(ffi::NID_secp160k1);
+pub const SECP160R1: Nid = Nid(ffi::NID_secp160r1);
+pub const SECP160R2: Nid = Nid(ffi::NID_secp160r2);
+pub const SECP192K1: Nid = Nid(ffi::NID_secp192k1);
+pub const SECP224K1: Nid = Nid(ffi::NID_secp224k1);
+pub const SECP224R1: Nid = Nid(ffi::NID_secp224r1);
+pub const SECP256K1: Nid = Nid(ffi::NID_secp256k1);
+pub const SECP384R1: Nid = Nid(ffi::NID_secp384r1);
+pub const SECP521R1: Nid = Nid(ffi::NID_secp521r1);
+pub const SECT113R1: Nid = Nid(ffi::NID_sect113r1);
+pub const SECT113R2: Nid = Nid(ffi::NID_sect113r2);
+pub const SECT131R1: Nid = Nid(ffi::NID_sect131r1);
+pub const SECT131R2: Nid = Nid(ffi::NID_sect131r2);
+pub const SECT163K1: Nid = Nid(ffi::NID_sect163k1);
+pub const SECT163R1: Nid = Nid(ffi::NID_sect163r1);
+pub const SECT163R2: Nid = Nid(ffi::NID_sect163r2);
+pub const SECT193R1: Nid = Nid(ffi::NID_sect193r1);
+pub const SECT193R2: Nid = Nid(ffi::NID_sect193r2);
+pub const SECT233K1: Nid = Nid(ffi::NID_sect233k1);
+pub const SECT233R1: Nid = Nid(ffi::NID_sect233r1);
+pub const SECT239K1: Nid = Nid(ffi::NID_sect239k1);
+pub const SECT283K1: Nid = Nid(ffi::NID_sect283k1);
+pub const SECT283R1: Nid = Nid(ffi::NID_sect283r1);
+pub const SECT409K1: Nid = Nid(ffi::NID_sect409k1);
+pub const SECT409R1: Nid = Nid(ffi::NID_sect409r1);
+pub const SECT571K1: Nid = Nid(ffi::NID_sect571k1);
+pub const SECT571R1: Nid = Nid(ffi::NID_sect571r1);
+pub const WAP_WSG_IDM_ECID_WTLS1: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls1);
+pub const WAP_WSG_IDM_ECID_WTLS3: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls3);
+pub const WAP_WSG_IDM_ECID_WTLS4: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls4);
+pub const WAP_WSG_IDM_ECID_WTLS5: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls5);
+pub const WAP_WSG_IDM_ECID_WTLS6: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls6);
+pub const WAP_WSG_IDM_ECID_WTLS7: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls7);
+pub const WAP_WSG_IDM_ECID_WTLS8: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls8);
+pub const WAP_WSG_IDM_ECID_WTLS9: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls9);
+pub const WAP_WSG_IDM_ECID_WTLS10: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls10);
+pub const WAP_WSG_IDM_ECID_WTLS11: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls11);
+pub const WAP_WSG_IDM_ECID_WTLS12: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls12);
+pub const CAST5_CBC: Nid = Nid(ffi::NID_cast5_cbc);
+pub const CAST5_ECB: Nid = Nid(ffi::NID_cast5_ecb);
+pub const CAST5_CFB64: Nid = Nid(ffi::NID_cast5_cfb64);
+pub const CAST5_OFB64: Nid = Nid(ffi::NID_cast5_ofb64);
+pub const PBEWITHMD5ANDCAST5_CBC: Nid = Nid(ffi::NID_pbeWithMD5AndCast5_CBC);
+pub const ID_PASSWORDBASEDMAC: Nid = Nid(ffi::NID_id_PasswordBasedMAC);
+pub const ID_DHBASEDMAC: Nid = Nid(ffi::NID_id_DHBasedMac);
+pub const RSADSI: Nid = Nid(ffi::NID_rsadsi);
+pub const PKCS: Nid = Nid(ffi::NID_pkcs);
+pub const PKCS1: Nid = Nid(ffi::NID_pkcs1);
+pub const RSAENCRYPTION: Nid = Nid(ffi::NID_rsaEncryption);
+pub const MD2WITHRSAENCRYPTION: Nid = Nid(ffi::NID_md2WithRSAEncryption);
+pub const MD4WITHRSAENCRYPTION: Nid = Nid(ffi::NID_md4WithRSAEncryption);
+pub const MD5WITHRSAENCRYPTION: Nid = Nid(ffi::NID_md5WithRSAEncryption);
+pub const SHA1WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha1WithRSAEncryption);
+pub const RSAESOAEP: Nid = Nid(ffi::NID_rsaesOaep);
+pub const MGF1: Nid = Nid(ffi::NID_mgf1);
+pub const RSASSAPSS: Nid = Nid(ffi::NID_rsassaPss);
+pub const SHA256WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha256WithRSAEncryption);
+pub const SHA384WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha384WithRSAEncryption);
+pub const SHA512WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha512WithRSAEncryption);
+pub const SHA224WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha224WithRSAEncryption);
+pub const PKCS3: Nid = Nid(ffi::NID_pkcs3);
+pub const DHKEYAGREEMENT: Nid = Nid(ffi::NID_dhKeyAgreement);
+pub const PKCS5: Nid = Nid(ffi::NID_pkcs5);
+pub const PBEWITHMD2ANDDES_CBC: Nid = Nid(ffi::NID_pbeWithMD2AndDES_CBC);
+pub const PBEWITHMD5ANDDES_CBC: Nid = Nid(ffi::NID_pbeWithMD5AndDES_CBC);
+pub const PBEWITHMD2ANDRC2_CBC: Nid = Nid(ffi::NID_pbeWithMD2AndRC2_CBC);
+pub const PBEWITHMD5ANDRC2_CBC: Nid = Nid(ffi::NID_pbeWithMD5AndRC2_CBC);
+pub const PBEWITHSHA1ANDDES_CBC: Nid = Nid(ffi::NID_pbeWithSHA1AndDES_CBC);
+pub const PBEWITHSHA1ANDRC2_CBC: Nid = Nid(ffi::NID_pbeWithSHA1AndRC2_CBC);
+pub const ID_PBKDF2: Nid = Nid(ffi::NID_id_pbkdf2);
+pub const PBES2: Nid = Nid(ffi::NID_pbes2);
+pub const PBMAC1: Nid = Nid(ffi::NID_pbmac1);
+pub const PKCS7: Nid = Nid(ffi::NID_pkcs7);
+pub const PKCS7_DATA: Nid = Nid(ffi::NID_pkcs7_data);
+pub const PKCS7_SIGNED: Nid = Nid(ffi::NID_pkcs7_signed);
+pub const PKCS7_ENVELOPED: Nid = Nid(ffi::NID_pkcs7_enveloped);
+pub const PKCS7_SIGNEDANDENVELOPED: Nid = Nid(ffi::NID_pkcs7_signedAndEnveloped);
+pub const PKCS7_DIGEST: Nid = Nid(ffi::NID_pkcs7_digest);
+pub const PKCS7_ENCRYPTED: Nid = Nid(ffi::NID_pkcs7_encrypted);
+pub const PKCS9: Nid = Nid(ffi::NID_pkcs9);
+pub const PKCS9_EMAILADDRESS: Nid = Nid(ffi::NID_pkcs9_emailAddress);
+pub const PKCS9_UNSTRUCTUREDNAME: Nid = Nid(ffi::NID_pkcs9_unstructuredName);
+pub const PKCS9_CONTENTTYPE: Nid = Nid(ffi::NID_pkcs9_contentType);
+pub const PKCS9_MESSAGEDIGEST: Nid = Nid(ffi::NID_pkcs9_messageDigest);
+pub const PKCS9_SIGNINGTIME: Nid = Nid(ffi::NID_pkcs9_signingTime);
+pub const PKCS9_COUNTERSIGNATURE: Nid = Nid(ffi::NID_pkcs9_countersignature);
+pub const PKCS9_CHALLENGEPASSWORD: Nid = Nid(ffi::NID_pkcs9_challengePassword);
+pub const PKCS9_UNSTRUCTUREDADDRESS: Nid = Nid(ffi::NID_pkcs9_unstructuredAddress);
+pub const PKCS9_EXTCERTATTRIBUTES: Nid = Nid(ffi::NID_pkcs9_extCertAttributes);
+pub const EXT_REQ: Nid = Nid(ffi::NID_ext_req);
+pub const SMIMECAPABILITIES: Nid = Nid(ffi::NID_SMIMECapabilities);
+pub const SMIME: Nid = Nid(ffi::NID_SMIME);
+pub const ID_SMIME_MOD: Nid = Nid(ffi::NID_id_smime_mod);
+pub const ID_SMIME_CT: Nid = Nid(ffi::NID_id_smime_ct);
+pub const ID_SMIME_AA: Nid = Nid(ffi::NID_id_smime_aa);
+pub const ID_SMIME_ALG: Nid = Nid(ffi::NID_id_smime_alg);
+pub const ID_SMIME_CD: Nid = Nid(ffi::NID_id_smime_cd);
+pub const ID_SMIME_SPQ: Nid = Nid(ffi::NID_id_smime_spq);
+pub const ID_SMIME_CTI: Nid = Nid(ffi::NID_id_smime_cti);
+pub const ID_SMIME_MOD_CMS: Nid = Nid(ffi::NID_id_smime_mod_cms);
+pub const ID_SMIME_MOD_ESS: Nid = Nid(ffi::NID_id_smime_mod_ess);
+pub const ID_SMIME_MOD_OID: Nid = Nid(ffi::NID_id_smime_mod_oid);
+pub const ID_SMIME_MOD_MSG_V3: Nid = Nid(ffi::NID_id_smime_mod_msg_v3);
+pub const ID_SMIME_MOD_ETS_ESIGNATURE_88: Nid = Nid(ffi::NID_id_smime_mod_ets_eSignature_88);
+pub const ID_SMIME_MOD_ETS_ESIGNATURE_97: Nid = Nid(ffi::NID_id_smime_mod_ets_eSignature_97);
+pub const ID_SMIME_MOD_ETS_ESIGPOLICY_88: Nid = Nid(ffi::NID_id_smime_mod_ets_eSigPolicy_88);
+pub const ID_SMIME_MOD_ETS_ESIGPOLICY_97: Nid = Nid(ffi::NID_id_smime_mod_ets_eSigPolicy_97);
+pub const ID_SMIME_CT_RECEIPT: Nid = Nid(ffi::NID_id_smime_ct_receipt);
+pub const ID_SMIME_CT_AUTHDATA: Nid = Nid(ffi::NID_id_smime_ct_authData);
+pub const ID_SMIME_CT_PUBLISHCERT: Nid = Nid(ffi::NID_id_smime_ct_publishCert);
+pub const ID_SMIME_CT_TSTINFO: Nid = Nid(ffi::NID_id_smime_ct_TSTInfo);
+pub const ID_SMIME_CT_TDTINFO: Nid = Nid(ffi::NID_id_smime_ct_TDTInfo);
+pub const ID_SMIME_CT_CONTENTINFO: Nid = Nid(ffi::NID_id_smime_ct_contentInfo);
+pub const ID_SMIME_CT_DVCSREQUESTDATA: Nid = Nid(ffi::NID_id_smime_ct_DVCSRequestData);
+pub const ID_SMIME_CT_DVCSRESPONSEDATA: Nid = Nid(ffi::NID_id_smime_ct_DVCSResponseData);
+pub const ID_SMIME_CT_COMPRESSEDDATA: Nid = Nid(ffi::NID_id_smime_ct_compressedData);
+pub const ID_CT_ASCIITEXTWITHCRLF: Nid = Nid(ffi::NID_id_ct_asciiTextWithCRLF);
+pub const ID_SMIME_AA_RECEIPTREQUEST: Nid = Nid(ffi::NID_id_smime_aa_receiptRequest);
+pub const ID_SMIME_AA_SECURITYLABEL: Nid = Nid(ffi::NID_id_smime_aa_securityLabel);
+pub const ID_SMIME_AA_MLEXPANDHISTORY: Nid = Nid(ffi::NID_id_smime_aa_mlExpandHistory);
+pub const ID_SMIME_AA_CONTENTHINT: Nid = Nid(ffi::NID_id_smime_aa_contentHint);
+pub const ID_SMIME_AA_MSGSIGDIGEST: Nid = Nid(ffi::NID_id_smime_aa_msgSigDigest);
+pub const ID_SMIME_AA_ENCAPCONTENTTYPE: Nid = Nid(ffi::NID_id_smime_aa_encapContentType);
+pub const ID_SMIME_AA_CONTENTIDENTIFIER: Nid = Nid(ffi::NID_id_smime_aa_contentIdentifier);
+pub const ID_SMIME_AA_MACVALUE: Nid = Nid(ffi::NID_id_smime_aa_macValue);
+pub const ID_SMIME_AA_EQUIVALENTLABELS: Nid = Nid(ffi::NID_id_smime_aa_equivalentLabels);
+pub const ID_SMIME_AA_CONTENTREFERENCE: Nid = Nid(ffi::NID_id_smime_aa_contentReference);
+pub const ID_SMIME_AA_ENCRYPKEYPREF: Nid = Nid(ffi::NID_id_smime_aa_encrypKeyPref);
+pub const ID_SMIME_AA_SIGNINGCERTIFICATE: Nid = Nid(ffi::NID_id_smime_aa_signingCertificate);
+pub const ID_SMIME_AA_SMIMEENCRYPTCERTS: Nid = Nid(ffi::NID_id_smime_aa_smimeEncryptCerts);
+pub const ID_SMIME_AA_TIMESTAMPTOKEN: Nid = Nid(ffi::NID_id_smime_aa_timeStampToken);
+pub const ID_SMIME_AA_ETS_SIGPOLICYID: Nid = Nid(ffi::NID_id_smime_aa_ets_sigPolicyId);
+pub const ID_SMIME_AA_ETS_COMMITMENTTYPE: Nid = Nid(ffi::NID_id_smime_aa_ets_commitmentType);
+pub const ID_SMIME_AA_ETS_SIGNERLOCATION: Nid = Nid(ffi::NID_id_smime_aa_ets_signerLocation);
+pub const ID_SMIME_AA_ETS_SIGNERATTR: Nid = Nid(ffi::NID_id_smime_aa_ets_signerAttr);
+pub const ID_SMIME_AA_ETS_OTHERSIGCERT: Nid = Nid(ffi::NID_id_smime_aa_ets_otherSigCert);
+pub const ID_SMIME_AA_ETS_CONTENTTIMESTAMP: Nid = Nid(ffi::NID_id_smime_aa_ets_contentTimestamp);
+pub const ID_SMIME_AA_ETS_CERTIFICATEREFS: Nid = Nid(ffi::NID_id_smime_aa_ets_CertificateRefs);
+pub const ID_SMIME_AA_ETS_REVOCATIONREFS: Nid = Nid(ffi::NID_id_smime_aa_ets_RevocationRefs);
+pub const ID_SMIME_AA_ETS_CERTVALUES: Nid = Nid(ffi::NID_id_smime_aa_ets_certValues);
+pub const ID_SMIME_AA_ETS_REVOCATIONVALUES: Nid = Nid(ffi::NID_id_smime_aa_ets_revocationValues);
+pub const ID_SMIME_AA_ETS_ESCTIMESTAMP: Nid = Nid(ffi::NID_id_smime_aa_ets_escTimeStamp);
+pub const ID_SMIME_AA_ETS_CERTCRLTIMESTAMP: Nid = Nid(ffi::NID_id_smime_aa_ets_certCRLTimestamp);
+pub const ID_SMIME_AA_ETS_ARCHIVETIMESTAMP: Nid = Nid(ffi::NID_id_smime_aa_ets_archiveTimeStamp);
+pub const ID_SMIME_AA_SIGNATURETYPE: Nid = Nid(ffi::NID_id_smime_aa_signatureType);
+pub const ID_SMIME_AA_DVCS_DVC: Nid = Nid(ffi::NID_id_smime_aa_dvcs_dvc);
+pub const ID_SMIME_ALG_ESDHWITH3DES: Nid = Nid(ffi::NID_id_smime_alg_ESDHwith3DES);
+pub const ID_SMIME_ALG_ESDHWITHRC2: Nid = Nid(ffi::NID_id_smime_alg_ESDHwithRC2);
+pub const ID_SMIME_ALG_3DESWRAP: Nid = Nid(ffi::NID_id_smime_alg_3DESwrap);
+pub const ID_SMIME_ALG_RC2WRAP: Nid = Nid(ffi::NID_id_smime_alg_RC2wrap);
+pub const ID_SMIME_ALG_ESDH: Nid = Nid(ffi::NID_id_smime_alg_ESDH);
+pub const ID_SMIME_ALG_CMS3DESWRAP: Nid = Nid(ffi::NID_id_smime_alg_CMS3DESwrap);
+pub const ID_SMIME_ALG_CMSRC2WRAP: Nid = Nid(ffi::NID_id_smime_alg_CMSRC2wrap);
+pub const ID_ALG_PWRI_KEK: Nid = Nid(ffi::NID_id_alg_PWRI_KEK);
+pub const ID_SMIME_CD_LDAP: Nid = Nid(ffi::NID_id_smime_cd_ldap);
+pub const ID_SMIME_SPQ_ETS_SQT_URI: Nid = Nid(ffi::NID_id_smime_spq_ets_sqt_uri);
+pub const ID_SMIME_SPQ_ETS_SQT_UNOTICE: Nid = Nid(ffi::NID_id_smime_spq_ets_sqt_unotice);
+pub const ID_SMIME_CTI_ETS_PROOFOFORIGIN: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfOrigin);
+pub const ID_SMIME_CTI_ETS_PROOFOFRECEIPT: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfReceipt);
+pub const ID_SMIME_CTI_ETS_PROOFOFDELIVERY: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfDelivery);
+pub const ID_SMIME_CTI_ETS_PROOFOFSENDER: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfSender);
+pub const ID_SMIME_CTI_ETS_PROOFOFAPPROVAL: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfApproval);
+pub const ID_SMIME_CTI_ETS_PROOFOFCREATION: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfCreation);
+pub const FRIENDLYNAME: Nid = Nid(ffi::NID_friendlyName);
+pub const LOCALKEYID: Nid = Nid(ffi::NID_localKeyID);
+pub const MS_CSP_NAME: Nid = Nid(ffi::NID_ms_csp_name);
+pub const LOCALKEYSET: Nid = Nid(ffi::NID_LocalKeySet);
+pub const X509CERTIFICATE: Nid = Nid(ffi::NID_x509Certificate);
+pub const SDSICERTIFICATE: Nid = Nid(ffi::NID_sdsiCertificate);
+pub const X509CRL: Nid = Nid(ffi::NID_x509Crl);
+pub const PBE_WITHSHA1AND128BITRC4: Nid = Nid(ffi::NID_pbe_WithSHA1And128BitRC4);
+pub const PBE_WITHSHA1AND40BITRC4: Nid = Nid(ffi::NID_pbe_WithSHA1And40BitRC4);
+pub const PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC: Nid =
+ Nid(ffi::NID_pbe_WithSHA1And3_Key_TripleDES_CBC);
+pub const PBE_WITHSHA1AND2_KEY_TRIPLEDES_CBC: Nid =
+ Nid(ffi::NID_pbe_WithSHA1And2_Key_TripleDES_CBC);
+pub const PBE_WITHSHA1AND128BITRC2_CBC: Nid = Nid(ffi::NID_pbe_WithSHA1And128BitRC2_CBC);
+pub const PBE_WITHSHA1AND40BITRC2_CBC: Nid = Nid(ffi::NID_pbe_WithSHA1And40BitRC2_CBC);
+pub const KEYBAG: Nid = Nid(ffi::NID_keyBag);
+pub const PKCS8SHROUDEDKEYBAG: Nid = Nid(ffi::NID_pkcs8ShroudedKeyBag);
+pub const CERTBAG: Nid = Nid(ffi::NID_certBag);
+pub const CRLBAG: Nid = Nid(ffi::NID_crlBag);
+pub const SECRETBAG: Nid = Nid(ffi::NID_secretBag);
+pub const SAFECONTENTSBAG: Nid = Nid(ffi::NID_safeContentsBag);
+pub const MD2: Nid = Nid(ffi::NID_md2);
+pub const MD4: Nid = Nid(ffi::NID_md4);
+pub const MD5: Nid = Nid(ffi::NID_md5);
+pub const MD5_SHA1: Nid = Nid(ffi::NID_md5_sha1);
+pub const HMACWITHMD5: Nid = Nid(ffi::NID_hmacWithMD5);
+pub const HMACWITHSHA1: Nid = Nid(ffi::NID_hmacWithSHA1);
+pub const HMACWITHSHA224: Nid = Nid(ffi::NID_hmacWithSHA224);
+pub const HMACWITHSHA256: Nid = Nid(ffi::NID_hmacWithSHA256);
+pub const HMACWITHSHA384: Nid = Nid(ffi::NID_hmacWithSHA384);
+pub const HMACWITHSHA512: Nid = Nid(ffi::NID_hmacWithSHA512);
+pub const RC2_CBC: Nid = Nid(ffi::NID_rc2_cbc);
+pub const RC2_ECB: Nid = Nid(ffi::NID_rc2_ecb);
+pub const RC2_CFB64: Nid = Nid(ffi::NID_rc2_cfb64);
+pub const RC2_OFB64: Nid = Nid(ffi::NID_rc2_ofb64);
+pub const RC2_40_CBC: Nid = Nid(ffi::NID_rc2_40_cbc);
+pub const RC2_64_CBC: Nid = Nid(ffi::NID_rc2_64_cbc);
+pub const RC4: Nid = Nid(ffi::NID_rc4);
+pub const RC4_40: Nid = Nid(ffi::NID_rc4_40);
+pub const DES_EDE3_CBC: Nid = Nid(ffi::NID_des_ede3_cbc);
+pub const RC5_CBC: Nid = Nid(ffi::NID_rc5_cbc);
+pub const RC5_ECB: Nid = Nid(ffi::NID_rc5_ecb);
+pub const RC5_CFB64: Nid = Nid(ffi::NID_rc5_cfb64);
+pub const RC5_OFB64: Nid = Nid(ffi::NID_rc5_ofb64);
+pub const MS_EXT_REQ: Nid = Nid(ffi::NID_ms_ext_req);
+pub const MS_CODE_IND: Nid = Nid(ffi::NID_ms_code_ind);
+pub const MS_CODE_COM: Nid = Nid(ffi::NID_ms_code_com);
+pub const MS_CTL_SIGN: Nid = Nid(ffi::NID_ms_ctl_sign);
+pub const MS_SGC: Nid = Nid(ffi::NID_ms_sgc);
+pub const MS_EFS: Nid = Nid(ffi::NID_ms_efs);
+pub const MS_SMARTCARD_LOGIN: Nid = Nid(ffi::NID_ms_smartcard_login);
+pub const MS_UPN: Nid = Nid(ffi::NID_ms_upn);
+pub const IDEA_CBC: Nid = Nid(ffi::NID_idea_cbc);
+pub const IDEA_ECB: Nid = Nid(ffi::NID_idea_ecb);
+pub const IDEA_CFB64: Nid = Nid(ffi::NID_idea_cfb64);
+pub const IDEA_OFB64: Nid = Nid(ffi::NID_idea_ofb64);
+pub const BF_CBC: Nid = Nid(ffi::NID_bf_cbc);
+pub const BF_ECB: Nid = Nid(ffi::NID_bf_ecb);
+pub const BF_CFB64: Nid = Nid(ffi::NID_bf_cfb64);
+pub const BF_OFB64: Nid = Nid(ffi::NID_bf_ofb64);
+pub const ID_PKIX: Nid = Nid(ffi::NID_id_pkix);
+pub const ID_PKIX_MOD: Nid = Nid(ffi::NID_id_pkix_mod);
+pub const ID_PE: Nid = Nid(ffi::NID_id_pe);
+pub const ID_QT: Nid = Nid(ffi::NID_id_qt);
+pub const ID_KP: Nid = Nid(ffi::NID_id_kp);
+pub const ID_IT: Nid = Nid(ffi::NID_id_it);
+pub const ID_PKIP: Nid = Nid(ffi::NID_id_pkip);
+pub const ID_ALG: Nid = Nid(ffi::NID_id_alg);
+pub const ID_CMC: Nid = Nid(ffi::NID_id_cmc);
+pub const ID_ON: Nid = Nid(ffi::NID_id_on);
+pub const ID_PDA: Nid = Nid(ffi::NID_id_pda);
+pub const ID_ACA: Nid = Nid(ffi::NID_id_aca);
+pub const ID_QCS: Nid = Nid(ffi::NID_id_qcs);
+pub const ID_CCT: Nid = Nid(ffi::NID_id_cct);
+pub const ID_PPL: Nid = Nid(ffi::NID_id_ppl);
+pub const ID_AD: Nid = Nid(ffi::NID_id_ad);
+pub const ID_PKIX1_EXPLICIT_88: Nid = Nid(ffi::NID_id_pkix1_explicit_88);
+pub const ID_PKIX1_IMPLICIT_88: Nid = Nid(ffi::NID_id_pkix1_implicit_88);
+pub const ID_PKIX1_EXPLICIT_93: Nid = Nid(ffi::NID_id_pkix1_explicit_93);
+pub const ID_PKIX1_IMPLICIT_93: Nid = Nid(ffi::NID_id_pkix1_implicit_93);
+pub const ID_MOD_CRMF: Nid = Nid(ffi::NID_id_mod_crmf);
+pub const ID_MOD_CMC: Nid = Nid(ffi::NID_id_mod_cmc);
+pub const ID_MOD_KEA_PROFILE_88: Nid = Nid(ffi::NID_id_mod_kea_profile_88);
+pub const ID_MOD_KEA_PROFILE_93: Nid = Nid(ffi::NID_id_mod_kea_profile_93);
+pub const ID_MOD_CMP: Nid = Nid(ffi::NID_id_mod_cmp);
+pub const ID_MOD_QUALIFIED_CERT_88: Nid = Nid(ffi::NID_id_mod_qualified_cert_88);
+pub const ID_MOD_QUALIFIED_CERT_93: Nid = Nid(ffi::NID_id_mod_qualified_cert_93);
+pub const ID_MOD_ATTRIBUTE_CERT: Nid = Nid(ffi::NID_id_mod_attribute_cert);
+pub const ID_MOD_TIMESTAMP_PROTOCOL: Nid = Nid(ffi::NID_id_mod_timestamp_protocol);
+pub const ID_MOD_OCSP: Nid = Nid(ffi::NID_id_mod_ocsp);
+pub const ID_MOD_DVCS: Nid = Nid(ffi::NID_id_mod_dvcs);
+pub const ID_MOD_CMP2000: Nid = Nid(ffi::NID_id_mod_cmp2000);
+pub const INFO_ACCESS: Nid = Nid(ffi::NID_info_access);
+pub const BIOMETRICINFO: Nid = Nid(ffi::NID_biometricInfo);
+pub const QCSTATEMENTS: Nid = Nid(ffi::NID_qcStatements);
+pub const AC_AUDITENTITY: Nid = Nid(ffi::NID_ac_auditEntity);
+pub const AC_TARGETING: Nid = Nid(ffi::NID_ac_targeting);
+pub const AACONTROLS: Nid = Nid(ffi::NID_aaControls);
+pub const SBGP_IPADDRBLOCK: Nid = Nid(ffi::NID_sbgp_ipAddrBlock);
+pub const SBGP_AUTONOMOUSSYSNUM: Nid = Nid(ffi::NID_sbgp_autonomousSysNum);
+pub const SBGP_ROUTERIDENTIFIER: Nid = Nid(ffi::NID_sbgp_routerIdentifier);
+pub const AC_PROXYING: Nid = Nid(ffi::NID_ac_proxying);
+pub const SINFO_ACCESS: Nid = Nid(ffi::NID_sinfo_access);
+pub const PROXYCERTINFO: Nid = Nid(ffi::NID_proxyCertInfo);
+pub const ID_QT_CPS: Nid = Nid(ffi::NID_id_qt_cps);
+pub const ID_QT_UNOTICE: Nid = Nid(ffi::NID_id_qt_unotice);
+pub const TEXTNOTICE: Nid = Nid(ffi::NID_textNotice);
+pub const SERVER_AUTH: Nid = Nid(ffi::NID_server_auth);
+pub const CLIENT_AUTH: Nid = Nid(ffi::NID_client_auth);
+pub const CODE_SIGN: Nid = Nid(ffi::NID_code_sign);
+pub const EMAIL_PROTECT: Nid = Nid(ffi::NID_email_protect);
+pub const IPSECENDSYSTEM: Nid = Nid(ffi::NID_ipsecEndSystem);
+pub const IPSECTUNNEL: Nid = Nid(ffi::NID_ipsecTunnel);
+pub const IPSECUSER: Nid = Nid(ffi::NID_ipsecUser);
+pub const TIME_STAMP: Nid = Nid(ffi::NID_time_stamp);
+pub const OCSP_SIGN: Nid = Nid(ffi::NID_OCSP_sign);
+pub const DVCS: Nid = Nid(ffi::NID_dvcs);
+pub const ID_IT_CAPROTENCCERT: Nid = Nid(ffi::NID_id_it_caProtEncCert);
+pub const ID_IT_SIGNKEYPAIRTYPES: Nid = Nid(ffi::NID_id_it_signKeyPairTypes);
+pub const ID_IT_ENCKEYPAIRTYPES: Nid = Nid(ffi::NID_id_it_encKeyPairTypes);
+pub const ID_IT_PREFERREDSYMMALG: Nid = Nid(ffi::NID_id_it_preferredSymmAlg);
+pub const ID_IT_CAKEYUPDATEINFO: Nid = Nid(ffi::NID_id_it_caKeyUpdateInfo);
+pub const ID_IT_CURRENTCRL: Nid = Nid(ffi::NID_id_it_currentCRL);
+pub const ID_IT_UNSUPPORTEDOIDS: Nid = Nid(ffi::NID_id_it_unsupportedOIDs);
+pub const ID_IT_SUBSCRIPTIONREQUEST: Nid = Nid(ffi::NID_id_it_subscriptionRequest);
+pub const ID_IT_SUBSCRIPTIONRESPONSE: Nid = Nid(ffi::NID_id_it_subscriptionResponse);
+pub const ID_IT_KEYPAIRPARAMREQ: Nid = Nid(ffi::NID_id_it_keyPairParamReq);
+pub const ID_IT_KEYPAIRPARAMREP: Nid = Nid(ffi::NID_id_it_keyPairParamRep);
+pub const ID_IT_REVPASSPHRASE: Nid = Nid(ffi::NID_id_it_revPassphrase);
+pub const ID_IT_IMPLICITCONFIRM: Nid = Nid(ffi::NID_id_it_implicitConfirm);
+pub const ID_IT_CONFIRMWAITTIME: Nid = Nid(ffi::NID_id_it_confirmWaitTime);
+pub const ID_IT_ORIGPKIMESSAGE: Nid = Nid(ffi::NID_id_it_origPKIMessage);
+pub const ID_IT_SUPPLANGTAGS: Nid = Nid(ffi::NID_id_it_suppLangTags);
+pub const ID_REGCTRL: Nid = Nid(ffi::NID_id_regCtrl);
+pub const ID_REGINFO: Nid = Nid(ffi::NID_id_regInfo);
+pub const ID_REGCTRL_REGTOKEN: Nid = Nid(ffi::NID_id_regCtrl_regToken);
+pub const ID_REGCTRL_AUTHENTICATOR: Nid = Nid(ffi::NID_id_regCtrl_authenticator);
+pub const ID_REGCTRL_PKIPUBLICATIONINFO: Nid = Nid(ffi::NID_id_regCtrl_pkiPublicationInfo);
+pub const ID_REGCTRL_PKIARCHIVEOPTIONS: Nid = Nid(ffi::NID_id_regCtrl_pkiArchiveOptions);
+pub const ID_REGCTRL_OLDCERTID: Nid = Nid(ffi::NID_id_regCtrl_oldCertID);
+pub const ID_REGCTRL_PROTOCOLENCRKEY: Nid = Nid(ffi::NID_id_regCtrl_protocolEncrKey);
+pub const ID_REGINFO_UTF8PAIRS: Nid = Nid(ffi::NID_id_regInfo_utf8Pairs);
+pub const ID_REGINFO_CERTREQ: Nid = Nid(ffi::NID_id_regInfo_certReq);
+pub const ID_ALG_DES40: Nid = Nid(ffi::NID_id_alg_des40);
+pub const ID_ALG_NOSIGNATURE: Nid = Nid(ffi::NID_id_alg_noSignature);
+pub const ID_ALG_DH_SIG_HMAC_SHA1: Nid = Nid(ffi::NID_id_alg_dh_sig_hmac_sha1);
+pub const ID_ALG_DH_POP: Nid = Nid(ffi::NID_id_alg_dh_pop);
+pub const ID_CMC_STATUSINFO: Nid = Nid(ffi::NID_id_cmc_statusInfo);
+pub const ID_CMC_IDENTIFICATION: Nid = Nid(ffi::NID_id_cmc_identification);
+pub const ID_CMC_IDENTITYPROOF: Nid = Nid(ffi::NID_id_cmc_identityProof);
+pub const ID_CMC_DATARETURN: Nid = Nid(ffi::NID_id_cmc_dataReturn);
+pub const ID_CMC_TRANSACTIONID: Nid = Nid(ffi::NID_id_cmc_transactionId);
+pub const ID_CMC_SENDERNONCE: Nid = Nid(ffi::NID_id_cmc_senderNonce);
+pub const ID_CMC_RECIPIENTNONCE: Nid = Nid(ffi::NID_id_cmc_recipientNonce);
+pub const ID_CMC_ADDEXTENSIONS: Nid = Nid(ffi::NID_id_cmc_addExtensions);
+pub const ID_CMC_ENCRYPTEDPOP: Nid = Nid(ffi::NID_id_cmc_encryptedPOP);
+pub const ID_CMC_DECRYPTEDPOP: Nid = Nid(ffi::NID_id_cmc_decryptedPOP);
+pub const ID_CMC_LRAPOPWITNESS: Nid = Nid(ffi::NID_id_cmc_lraPOPWitness);
+pub const ID_CMC_GETCERT: Nid = Nid(ffi::NID_id_cmc_getCert);
+pub const ID_CMC_GETCRL: Nid = Nid(ffi::NID_id_cmc_getCRL);
+pub const ID_CMC_REVOKEREQUEST: Nid = Nid(ffi::NID_id_cmc_revokeRequest);
+pub const ID_CMC_REGINFO: Nid = Nid(ffi::NID_id_cmc_regInfo);
+pub const ID_CMC_RESPONSEINFO: Nid = Nid(ffi::NID_id_cmc_responseInfo);
+pub const ID_CMC_QUERYPENDING: Nid = Nid(ffi::NID_id_cmc_queryPending);
+pub const ID_CMC_POPLINKRANDOM: Nid = Nid(ffi::NID_id_cmc_popLinkRandom);
+pub const ID_CMC_POPLINKWITNESS: Nid = Nid(ffi::NID_id_cmc_popLinkWitness);
+pub const ID_CMC_CONFIRMCERTACCEPTANCE: Nid = Nid(ffi::NID_id_cmc_confirmCertAcceptance);
+pub const ID_ON_PERSONALDATA: Nid = Nid(ffi::NID_id_on_personalData);
+pub const ID_ON_PERMANENTIDENTIFIER: Nid = Nid(ffi::NID_id_on_permanentIdentifier);
+pub const ID_PDA_DATEOFBIRTH: Nid = Nid(ffi::NID_id_pda_dateOfBirth);
+pub const ID_PDA_PLACEOFBIRTH: Nid = Nid(ffi::NID_id_pda_placeOfBirth);
+pub const ID_PDA_GENDER: Nid = Nid(ffi::NID_id_pda_gender);
+pub const ID_PDA_COUNTRYOFCITIZENSHIP: Nid = Nid(ffi::NID_id_pda_countryOfCitizenship);
+pub const ID_PDA_COUNTRYOFRESIDENCE: Nid = Nid(ffi::NID_id_pda_countryOfResidence);
+pub const ID_ACA_AUTHENTICATIONINFO: Nid = Nid(ffi::NID_id_aca_authenticationInfo);
+pub const ID_ACA_ACCESSIDENTITY: Nid = Nid(ffi::NID_id_aca_accessIdentity);
+pub const ID_ACA_CHARGINGIDENTITY: Nid = Nid(ffi::NID_id_aca_chargingIdentity);
+pub const ID_ACA_GROUP: Nid = Nid(ffi::NID_id_aca_group);
+pub const ID_ACA_ROLE: Nid = Nid(ffi::NID_id_aca_role);
+pub const ID_ACA_ENCATTRS: Nid = Nid(ffi::NID_id_aca_encAttrs);
+pub const ID_QCS_PKIXQCSYNTAX_V1: Nid = Nid(ffi::NID_id_qcs_pkixQCSyntax_v1);
+pub const ID_CCT_CRS: Nid = Nid(ffi::NID_id_cct_crs);
+pub const ID_CCT_PKIDATA: Nid = Nid(ffi::NID_id_cct_PKIData);
+pub const ID_CCT_PKIRESPONSE: Nid = Nid(ffi::NID_id_cct_PKIResponse);
+pub const ID_PPL_ANYLANGUAGE: Nid = Nid(ffi::NID_id_ppl_anyLanguage);
+pub const ID_PPL_INHERITALL: Nid = Nid(ffi::NID_id_ppl_inheritAll);
+pub const INDEPENDENT: Nid = Nid(ffi::NID_Independent);
+pub const AD_OCSP: Nid = Nid(ffi::NID_ad_OCSP);
+pub const AD_CA_ISSUERS: Nid = Nid(ffi::NID_ad_ca_issuers);
+pub const AD_TIMESTAMPING: Nid = Nid(ffi::NID_ad_timeStamping);
+pub const AD_DVCS: Nid = Nid(ffi::NID_ad_dvcs);
+pub const CAREPOSITORY: Nid = Nid(ffi::NID_caRepository);
+pub const ID_PKIX_OCSP_BASIC: Nid = Nid(ffi::NID_id_pkix_OCSP_basic);
+pub const ID_PKIX_OCSP_NONCE: Nid = Nid(ffi::NID_id_pkix_OCSP_Nonce);
+pub const ID_PKIX_OCSP_CRLID: Nid = Nid(ffi::NID_id_pkix_OCSP_CrlID);
+pub const ID_PKIX_OCSP_ACCEPTABLERESPONSES: Nid = Nid(ffi::NID_id_pkix_OCSP_acceptableResponses);
+pub const ID_PKIX_OCSP_NOCHECK: Nid = Nid(ffi::NID_id_pkix_OCSP_noCheck);
+pub const ID_PKIX_OCSP_ARCHIVECUTOFF: Nid = Nid(ffi::NID_id_pkix_OCSP_archiveCutoff);
+pub const ID_PKIX_OCSP_SERVICELOCATOR: Nid = Nid(ffi::NID_id_pkix_OCSP_serviceLocator);
+pub const ID_PKIX_OCSP_EXTENDEDSTATUS: Nid = Nid(ffi::NID_id_pkix_OCSP_extendedStatus);
+pub const ID_PKIX_OCSP_VALID: Nid = Nid(ffi::NID_id_pkix_OCSP_valid);
+pub const ID_PKIX_OCSP_PATH: Nid = Nid(ffi::NID_id_pkix_OCSP_path);
+pub const ID_PKIX_OCSP_TRUSTROOT: Nid = Nid(ffi::NID_id_pkix_OCSP_trustRoot);
+pub const ALGORITHM: Nid = Nid(ffi::NID_algorithm);
+pub const MD5WITHRSA: Nid = Nid(ffi::NID_md5WithRSA);
+pub const DES_ECB: Nid = Nid(ffi::NID_des_ecb);
+pub const DES_CBC: Nid = Nid(ffi::NID_des_cbc);
+pub const DES_OFB64: Nid = Nid(ffi::NID_des_ofb64);
+pub const DES_CFB64: Nid = Nid(ffi::NID_des_cfb64);
+pub const RSASIGNATURE: Nid = Nid(ffi::NID_rsaSignature);
+pub const DSA_2: Nid = Nid(ffi::NID_dsa_2);
+pub const DSAWITHSHA: Nid = Nid(ffi::NID_dsaWithSHA);
+pub const SHAWITHRSAENCRYPTION: Nid = Nid(ffi::NID_shaWithRSAEncryption);
+pub const DES_EDE_ECB: Nid = Nid(ffi::NID_des_ede_ecb);
+pub const DES_EDE3_ECB: Nid = Nid(ffi::NID_des_ede3_ecb);
+pub const DES_EDE_CBC: Nid = Nid(ffi::NID_des_ede_cbc);
+pub const DES_EDE_CFB64: Nid = Nid(ffi::NID_des_ede_cfb64);
+pub const DES_EDE3_CFB64: Nid = Nid(ffi::NID_des_ede3_cfb64);
+pub const DES_EDE_OFB64: Nid = Nid(ffi::NID_des_ede_ofb64);
+pub const DES_EDE3_OFB64: Nid = Nid(ffi::NID_des_ede3_ofb64);
+pub const DESX_CBC: Nid = Nid(ffi::NID_desx_cbc);
+pub const SHA: Nid = Nid(ffi::NID_sha);
+pub const SHA1: Nid = Nid(ffi::NID_sha1);
+pub const DSAWITHSHA1_2: Nid = Nid(ffi::NID_dsaWithSHA1_2);
+pub const SHA1WITHRSA: Nid = Nid(ffi::NID_sha1WithRSA);
+pub const RIPEMD160: Nid = Nid(ffi::NID_ripemd160);
+pub const RIPEMD160WITHRSA: Nid = Nid(ffi::NID_ripemd160WithRSA);
+pub const SXNET: Nid = Nid(ffi::NID_sxnet);
+pub const X500: Nid = Nid(ffi::NID_X500);
+pub const X509: Nid = Nid(ffi::NID_X509);
+pub const COMMONNAME: Nid = Nid(ffi::NID_commonName);
+pub const SURNAME: Nid = Nid(ffi::NID_surname);
+pub const SERIALNUMBER: Nid = Nid(ffi::NID_serialNumber);
+pub const COUNTRYNAME: Nid = Nid(ffi::NID_countryName);
+pub const LOCALITYNAME: Nid = Nid(ffi::NID_localityName);
+pub const STATEORPROVINCENAME: Nid = Nid(ffi::NID_stateOrProvinceName);
+pub const STREETADDRESS: Nid = Nid(ffi::NID_streetAddress);
+pub const ORGANIZATIONNAME: Nid = Nid(ffi::NID_organizationName);
+pub const ORGANIZATIONALUNITNAME: Nid = Nid(ffi::NID_organizationalUnitName);
+pub const TITLE: Nid = Nid(ffi::NID_title);
+pub const DESCRIPTION: Nid = Nid(ffi::NID_description);
+pub const SEARCHGUIDE: Nid = Nid(ffi::NID_searchGuide);
+pub const BUSINESSCATEGORY: Nid = Nid(ffi::NID_businessCategory);
+pub const POSTALADDRESS: Nid = Nid(ffi::NID_postalAddress);
+pub const POSTALCODE: Nid = Nid(ffi::NID_postalCode);
+pub const POSTOFFICEBOX: Nid = Nid(ffi::NID_postOfficeBox);
+pub const PHYSICALDELIVERYOFFICENAME: Nid = Nid(ffi::NID_physicalDeliveryOfficeName);
+pub const TELEPHONENUMBER: Nid = Nid(ffi::NID_telephoneNumber);
+pub const TELEXNUMBER: Nid = Nid(ffi::NID_telexNumber);
+pub const TELETEXTERMINALIDENTIFIER: Nid = Nid(ffi::NID_teletexTerminalIdentifier);
+pub const FACSIMILETELEPHONENUMBER: Nid = Nid(ffi::NID_facsimileTelephoneNumber);
+pub const X121ADDRESS: Nid = Nid(ffi::NID_x121Address);
+pub const INTERNATIONALISDNNUMBER: Nid = Nid(ffi::NID_internationaliSDNNumber);
+pub const REGISTEREDADDRESS: Nid = Nid(ffi::NID_registeredAddress);
+pub const DESTINATIONINDICATOR: Nid = Nid(ffi::NID_destinationIndicator);
+pub const PREFERREDDELIVERYMETHOD: Nid = Nid(ffi::NID_preferredDeliveryMethod);
+pub const PRESENTATIONADDRESS: Nid = Nid(ffi::NID_presentationAddress);
+pub const SUPPORTEDAPPLICATIONCONTEXT: Nid = Nid(ffi::NID_supportedApplicationContext);
+pub const MEMBER: Nid = Nid(ffi::NID_member);
+pub const OWNER: Nid = Nid(ffi::NID_owner);
+pub const ROLEOCCUPANT: Nid = Nid(ffi::NID_roleOccupant);
+pub const SEEALSO: Nid = Nid(ffi::NID_seeAlso);
+pub const USERPASSWORD: Nid = Nid(ffi::NID_userPassword);
+pub const USERCERTIFICATE: Nid = Nid(ffi::NID_userCertificate);
+pub const CACERTIFICATE: Nid = Nid(ffi::NID_cACertificate);
+pub const AUTHORITYREVOCATIONLIST: Nid = Nid(ffi::NID_authorityRevocationList);
+pub const CERTIFICATEREVOCATIONLIST: Nid = Nid(ffi::NID_certificateRevocationList);
+pub const CROSSCERTIFICATEPAIR: Nid = Nid(ffi::NID_crossCertificatePair);
+pub const NAME: Nid = Nid(ffi::NID_name);
+pub const GIVENNAME: Nid = Nid(ffi::NID_givenName);
+pub const INITIALS: Nid = Nid(ffi::NID_initials);
+pub const GENERATIONQUALIFIER: Nid = Nid(ffi::NID_generationQualifier);
+pub const X500UNIQUEIDENTIFIER: Nid = Nid(ffi::NID_x500UniqueIdentifier);
+pub const DNQUALIFIER: Nid = Nid(ffi::NID_dnQualifier);
+pub const ENHANCEDSEARCHGUIDE: Nid = Nid(ffi::NID_enhancedSearchGuide);
+pub const PROTOCOLINFORMATION: Nid = Nid(ffi::NID_protocolInformation);
+pub const DISTINGUISHEDNAME: Nid = Nid(ffi::NID_distinguishedName);
+pub const UNIQUEMEMBER: Nid = Nid(ffi::NID_uniqueMember);
+pub const HOUSEIDENTIFIER: Nid = Nid(ffi::NID_houseIdentifier);
+pub const SUPPORTEDALGORITHMS: Nid = Nid(ffi::NID_supportedAlgorithms);
+pub const DELTAREVOCATIONLIST: Nid = Nid(ffi::NID_deltaRevocationList);
+pub const DMDNAME: Nid = Nid(ffi::NID_dmdName);
+pub const PSEUDONYM: Nid = Nid(ffi::NID_pseudonym);
+pub const ROLE: Nid = Nid(ffi::NID_role);
+pub const X500ALGORITHMS: Nid = Nid(ffi::NID_X500algorithms);
+pub const RSA: Nid = Nid(ffi::NID_rsa);
+pub const MDC2WITHRSA: Nid = Nid(ffi::NID_mdc2WithRSA);
+pub const MDC2: Nid = Nid(ffi::NID_mdc2);
+pub const ID_CE: Nid = Nid(ffi::NID_id_ce);
+pub const SUBJECT_DIRECTORY_ATTRIBUTES: Nid = Nid(ffi::NID_subject_directory_attributes);
+pub const SUBJECT_KEY_IDENTIFIER: Nid = Nid(ffi::NID_subject_key_identifier);
+pub const KEY_USAGE: Nid = Nid(ffi::NID_key_usage);
+pub const PRIVATE_KEY_USAGE_PERIOD: Nid = Nid(ffi::NID_private_key_usage_period);
+pub const SUBJECT_ALT_NAME: Nid = Nid(ffi::NID_subject_alt_name);
+pub const ISSUER_ALT_NAME: Nid = Nid(ffi::NID_issuer_alt_name);
+pub const BASIC_CONSTRAINTS: Nid = Nid(ffi::NID_basic_constraints);
+pub const CRL_NUMBER: Nid = Nid(ffi::NID_crl_number);
+pub const CRL_REASON: Nid = Nid(ffi::NID_crl_reason);
+pub const INVALIDITY_DATE: Nid = Nid(ffi::NID_invalidity_date);
+pub const DELTA_CRL: Nid = Nid(ffi::NID_delta_crl);
+pub const ISSUING_DISTRIBUTION_POINT: Nid = Nid(ffi::NID_issuing_distribution_point);
+pub const CERTIFICATE_ISSUER: Nid = Nid(ffi::NID_certificate_issuer);
+pub const NAME_CONSTRAINTS: Nid = Nid(ffi::NID_name_constraints);
+pub const CRL_DISTRIBUTION_POINTS: Nid = Nid(ffi::NID_crl_distribution_points);
+pub const CERTIFICATE_POLICIES: Nid = Nid(ffi::NID_certificate_policies);
+pub const ANY_POLICY: Nid = Nid(ffi::NID_any_policy);
+pub const POLICY_MAPPINGS: Nid = Nid(ffi::NID_policy_mappings);
+pub const AUTHORITY_KEY_IDENTIFIER: Nid = Nid(ffi::NID_authority_key_identifier);
+pub const POLICY_CONSTRAINTS: Nid = Nid(ffi::NID_policy_constraints);
+pub const EXT_KEY_USAGE: Nid = Nid(ffi::NID_ext_key_usage);
+pub const FRESHEST_CRL: Nid = Nid(ffi::NID_freshest_crl);
+pub const INHIBIT_ANY_POLICY: Nid = Nid(ffi::NID_inhibit_any_policy);
+pub const TARGET_INFORMATION: Nid = Nid(ffi::NID_target_information);
+pub const NO_REV_AVAIL: Nid = Nid(ffi::NID_no_rev_avail);
+pub const ANYEXTENDEDKEYUSAGE: Nid = Nid(ffi::NID_anyExtendedKeyUsage);
+pub const NETSCAPE: Nid = Nid(ffi::NID_netscape);
+pub const NETSCAPE_CERT_EXTENSION: Nid = Nid(ffi::NID_netscape_cert_extension);
+pub const NETSCAPE_DATA_TYPE: Nid = Nid(ffi::NID_netscape_data_type);
+pub const NETSCAPE_CERT_TYPE: Nid = Nid(ffi::NID_netscape_cert_type);
+pub const NETSCAPE_BASE_URL: Nid = Nid(ffi::NID_netscape_base_url);
+pub const NETSCAPE_REVOCATION_URL: Nid = Nid(ffi::NID_netscape_revocation_url);
+pub const NETSCAPE_CA_REVOCATION_URL: Nid = Nid(ffi::NID_netscape_ca_revocation_url);
+pub const NETSCAPE_RENEWAL_URL: Nid = Nid(ffi::NID_netscape_renewal_url);
+pub const NETSCAPE_CA_POLICY_URL: Nid = Nid(ffi::NID_netscape_ca_policy_url);
+pub const NETSCAPE_SSL_SERVER_NAME: Nid = Nid(ffi::NID_netscape_ssl_server_name);
+pub const NETSCAPE_COMMENT: Nid = Nid(ffi::NID_netscape_comment);
+pub const NETSCAPE_CERT_SEQUENCE: Nid = Nid(ffi::NID_netscape_cert_sequence);
+pub const NS_SGC: Nid = Nid(ffi::NID_ns_sgc);
+pub const ORG: Nid = Nid(ffi::NID_org);
+pub const DOD: Nid = Nid(ffi::NID_dod);
+pub const IANA: Nid = Nid(ffi::NID_iana);
+pub const DIRECTORY: Nid = Nid(ffi::NID_Directory);
+pub const MANAGEMENT: Nid = Nid(ffi::NID_Management);
+pub const EXPERIMENTAL: Nid = Nid(ffi::NID_Experimental);
+pub const PRIVATE: Nid = Nid(ffi::NID_Private);
+pub const SECURITY: Nid = Nid(ffi::NID_Security);
+pub const SNMPV2: Nid = Nid(ffi::NID_SNMPv2);
+pub const MAIL: Nid = Nid(ffi::NID_Mail);
+pub const ENTERPRISES: Nid = Nid(ffi::NID_Enterprises);
+pub const DCOBJECT: Nid = Nid(ffi::NID_dcObject);
+pub const MIME_MHS: Nid = Nid(ffi::NID_mime_mhs);
+pub const MIME_MHS_HEADINGS: Nid = Nid(ffi::NID_mime_mhs_headings);
+pub const MIME_MHS_BODIES: Nid = Nid(ffi::NID_mime_mhs_bodies);
+pub const ID_HEX_PARTIAL_MESSAGE: Nid = Nid(ffi::NID_id_hex_partial_message);
+pub const ID_HEX_MULTIPART_MESSAGE: Nid = Nid(ffi::NID_id_hex_multipart_message);
+pub const ZLIB_COMPRESSION: Nid = Nid(ffi::NID_zlib_compression);
+pub const AES_128_ECB: Nid = Nid(ffi::NID_aes_128_ecb);
+pub const AES_128_CBC: Nid = Nid(ffi::NID_aes_128_cbc);
+pub const AES_128_OFB128: Nid = Nid(ffi::NID_aes_128_ofb128);
+pub const AES_128_CFB128: Nid = Nid(ffi::NID_aes_128_cfb128);
+pub const ID_AES128_WRAP: Nid = Nid(ffi::NID_id_aes128_wrap);
+pub const AES_128_GCM: Nid = Nid(ffi::NID_aes_128_gcm);
+pub const AES_128_CCM: Nid = Nid(ffi::NID_aes_128_ccm);
+pub const ID_AES128_WRAP_PAD: Nid = Nid(ffi::NID_id_aes128_wrap_pad);
+pub const AES_192_ECB: Nid = Nid(ffi::NID_aes_192_ecb);
+pub const AES_192_CBC: Nid = Nid(ffi::NID_aes_192_cbc);
+pub const AES_192_OFB128: Nid = Nid(ffi::NID_aes_192_ofb128);
+pub const AES_192_CFB128: Nid = Nid(ffi::NID_aes_192_cfb128);
+pub const ID_AES192_WRAP: Nid = Nid(ffi::NID_id_aes192_wrap);
+pub const AES_192_GCM: Nid = Nid(ffi::NID_aes_192_gcm);
+pub const AES_192_CCM: Nid = Nid(ffi::NID_aes_192_ccm);
+pub const ID_AES192_WRAP_PAD: Nid = Nid(ffi::NID_id_aes192_wrap_pad);
+pub const AES_256_ECB: Nid = Nid(ffi::NID_aes_256_ecb);
+pub const AES_256_CBC: Nid = Nid(ffi::NID_aes_256_cbc);
+pub const AES_256_OFB128: Nid = Nid(ffi::NID_aes_256_ofb128);
+pub const AES_256_CFB128: Nid = Nid(ffi::NID_aes_256_cfb128);
+pub const ID_AES256_WRAP: Nid = Nid(ffi::NID_id_aes256_wrap);
+pub const AES_256_GCM: Nid = Nid(ffi::NID_aes_256_gcm);
+pub const AES_256_CCM: Nid = Nid(ffi::NID_aes_256_ccm);
+pub const ID_AES256_WRAP_PAD: Nid = Nid(ffi::NID_id_aes256_wrap_pad);
+pub const AES_128_CFB1: Nid = Nid(ffi::NID_aes_128_cfb1);
+pub const AES_192_CFB1: Nid = Nid(ffi::NID_aes_192_cfb1);
+pub const AES_256_CFB1: Nid = Nid(ffi::NID_aes_256_cfb1);
+pub const AES_128_CFB8: Nid = Nid(ffi::NID_aes_128_cfb8);
+pub const AES_192_CFB8: Nid = Nid(ffi::NID_aes_192_cfb8);
+pub const AES_256_CFB8: Nid = Nid(ffi::NID_aes_256_cfb8);
+pub const AES_128_CTR: Nid = Nid(ffi::NID_aes_128_ctr);
+pub const AES_192_CTR: Nid = Nid(ffi::NID_aes_192_ctr);
+pub const AES_256_CTR: Nid = Nid(ffi::NID_aes_256_ctr);
+pub const AES_128_XTS: Nid = Nid(ffi::NID_aes_128_xts);
+pub const AES_256_XTS: Nid = Nid(ffi::NID_aes_256_xts);
+pub const DES_CFB1: Nid = Nid(ffi::NID_des_cfb1);
+pub const DES_CFB8: Nid = Nid(ffi::NID_des_cfb8);
+pub const DES_EDE3_CFB1: Nid = Nid(ffi::NID_des_ede3_cfb1);
+pub const DES_EDE3_CFB8: Nid = Nid(ffi::NID_des_ede3_cfb8);
+pub const SHA256: Nid = Nid(ffi::NID_sha256);
+pub const SHA384: Nid = Nid(ffi::NID_sha384);
+pub const SHA512: Nid = Nid(ffi::NID_sha512);
+pub const SHA224: Nid = Nid(ffi::NID_sha224);
+pub const DSA_WITH_SHA224: Nid = Nid(ffi::NID_dsa_with_SHA224);
+pub const DSA_WITH_SHA256: Nid = Nid(ffi::NID_dsa_with_SHA256);
+pub const HOLD_INSTRUCTION_CODE: Nid = Nid(ffi::NID_hold_instruction_code);
+pub const HOLD_INSTRUCTION_NONE: Nid = Nid(ffi::NID_hold_instruction_none);
+pub const HOLD_INSTRUCTION_CALL_ISSUER: Nid = Nid(ffi::NID_hold_instruction_call_issuer);
+pub const HOLD_INSTRUCTION_REJECT: Nid = Nid(ffi::NID_hold_instruction_reject);
+pub const DATA: Nid = Nid(ffi::NID_data);
+pub const PSS: Nid = Nid(ffi::NID_pss);
+pub const UCL: Nid = Nid(ffi::NID_ucl);
+pub const PILOT: Nid = Nid(ffi::NID_pilot);
+pub const PILOTATTRIBUTETYPE: Nid = Nid(ffi::NID_pilotAttributeType);
+pub const PILOTATTRIBUTESYNTAX: Nid = Nid(ffi::NID_pilotAttributeSyntax);
+pub const PILOTOBJECTCLASS: Nid = Nid(ffi::NID_pilotObjectClass);
+pub const PILOTGROUPS: Nid = Nid(ffi::NID_pilotGroups);
+pub const IA5STRINGSYNTAX: Nid = Nid(ffi::NID_iA5StringSyntax);
+pub const CASEIGNOREIA5STRINGSYNTAX: Nid = Nid(ffi::NID_caseIgnoreIA5StringSyntax);
+pub const PILOTOBJECT: Nid = Nid(ffi::NID_pilotObject);
+pub const PILOTPERSON: Nid = Nid(ffi::NID_pilotPerson);
+pub const ACCOUNT: Nid = Nid(ffi::NID_account);
+pub const DOCUMENT: Nid = Nid(ffi::NID_document);
+pub const ROOM: Nid = Nid(ffi::NID_room);
+pub const DOCUMENTSERIES: Nid = Nid(ffi::NID_documentSeries);
+pub const DOMAIN: Nid = Nid(ffi::NID_Domain);
+pub const RFC822LOCALPART: Nid = Nid(ffi::NID_rFC822localPart);
+pub const DNSDOMAIN: Nid = Nid(ffi::NID_dNSDomain);
+pub const DOMAINRELATEDOBJECT: Nid = Nid(ffi::NID_domainRelatedObject);
+pub const FRIENDLYCOUNTRY: Nid = Nid(ffi::NID_friendlyCountry);
+pub const SIMPLESECURITYOBJECT: Nid = Nid(ffi::NID_simpleSecurityObject);
+pub const PILOTORGANIZATION: Nid = Nid(ffi::NID_pilotOrganization);
+pub const PILOTDSA: Nid = Nid(ffi::NID_pilotDSA);
+pub const QUALITYLABELLEDDATA: Nid = Nid(ffi::NID_qualityLabelledData);
+pub const USERID: Nid = Nid(ffi::NID_userId);
+pub const TEXTENCODEDORADDRESS: Nid = Nid(ffi::NID_textEncodedORAddress);
+pub const RFC822MAILBOX: Nid = Nid(ffi::NID_rfc822Mailbox);
+pub const INFO: Nid = Nid(ffi::NID_info);
+pub const FAVOURITEDRINK: Nid = Nid(ffi::NID_favouriteDrink);
+pub const ROOMNUMBER: Nid = Nid(ffi::NID_roomNumber);
+pub const PHOTO: Nid = Nid(ffi::NID_photo);
+pub const USERCLASS: Nid = Nid(ffi::NID_userClass);
+pub const HOST: Nid = Nid(ffi::NID_host);
+pub const MANAGER: Nid = Nid(ffi::NID_manager);
+pub const DOCUMENTIDENTIFIER: Nid = Nid(ffi::NID_documentIdentifier);
+pub const DOCUMENTTITLE: Nid = Nid(ffi::NID_documentTitle);
+pub const DOCUMENTVERSION: Nid = Nid(ffi::NID_documentVersion);
+pub const DOCUMENTAUTHOR: Nid = Nid(ffi::NID_documentAuthor);
+pub const DOCUMENTLOCATION: Nid = Nid(ffi::NID_documentLocation);
+pub const HOMETELEPHONENUMBER: Nid = Nid(ffi::NID_homeTelephoneNumber);
+pub const SECRETARY: Nid = Nid(ffi::NID_secretary);
+pub const OTHERMAILBOX: Nid = Nid(ffi::NID_otherMailbox);
+pub const LASTMODIFIEDTIME: Nid = Nid(ffi::NID_lastModifiedTime);
+pub const LASTMODIFIEDBY: Nid = Nid(ffi::NID_lastModifiedBy);
+pub const DOMAINCOMPONENT: Nid = Nid(ffi::NID_domainComponent);
+pub const ARECORD: Nid = Nid(ffi::NID_aRecord);
+pub const PILOTATTRIBUTETYPE27: Nid = Nid(ffi::NID_pilotAttributeType27);
+pub const MXRECORD: Nid = Nid(ffi::NID_mXRecord);
+pub const NSRECORD: Nid = Nid(ffi::NID_nSRecord);
+pub const SOARECORD: Nid = Nid(ffi::NID_sOARecord);
+pub const CNAMERECORD: Nid = Nid(ffi::NID_cNAMERecord);
+pub const ASSOCIATEDDOMAIN: Nid = Nid(ffi::NID_associatedDomain);
+pub const ASSOCIATEDNAME: Nid = Nid(ffi::NID_associatedName);
+pub const HOMEPOSTALADDRESS: Nid = Nid(ffi::NID_homePostalAddress);
+pub const PERSONALTITLE: Nid = Nid(ffi::NID_personalTitle);
+pub const MOBILETELEPHONENUMBER: Nid = Nid(ffi::NID_mobileTelephoneNumber);
+pub const PAGERTELEPHONENUMBER: Nid = Nid(ffi::NID_pagerTelephoneNumber);
+pub const FRIENDLYCOUNTRYNAME: Nid = Nid(ffi::NID_friendlyCountryName);
+pub const ORGANIZATIONALSTATUS: Nid = Nid(ffi::NID_organizationalStatus);
+pub const JANETMAILBOX: Nid = Nid(ffi::NID_janetMailbox);
+pub const MAILPREFERENCEOPTION: Nid = Nid(ffi::NID_mailPreferenceOption);
+pub const BUILDINGNAME: Nid = Nid(ffi::NID_buildingName);
+pub const DSAQUALITY: Nid = Nid(ffi::NID_dSAQuality);
+pub const SINGLELEVELQUALITY: Nid = Nid(ffi::NID_singleLevelQuality);
+pub const SUBTREEMINIMUMQUALITY: Nid = Nid(ffi::NID_subtreeMinimumQuality);
+pub const SUBTREEMAXIMUMQUALITY: Nid = Nid(ffi::NID_subtreeMaximumQuality);
+pub const PERSONALSIGNATURE: Nid = Nid(ffi::NID_personalSignature);
+pub const DITREDIRECT: Nid = Nid(ffi::NID_dITRedirect);
+pub const AUDIO: Nid = Nid(ffi::NID_audio);
+pub const DOCUMENTPUBLISHER: Nid = Nid(ffi::NID_documentPublisher);
+pub const ID_SET: Nid = Nid(ffi::NID_id_set);
+pub const SET_CTYPE: Nid = Nid(ffi::NID_set_ctype);
+pub const SET_MSGEXT: Nid = Nid(ffi::NID_set_msgExt);
+pub const SET_ATTR: Nid = Nid(ffi::NID_set_attr);
+pub const SET_POLICY: Nid = Nid(ffi::NID_set_policy);
+pub const SET_CERTEXT: Nid = Nid(ffi::NID_set_certExt);
+pub const SET_BRAND: Nid = Nid(ffi::NID_set_brand);
+pub const SETCT_PANDATA: Nid = Nid(ffi::NID_setct_PANData);
+pub const SETCT_PANTOKEN: Nid = Nid(ffi::NID_setct_PANToken);
+pub const SETCT_PANONLY: Nid = Nid(ffi::NID_setct_PANOnly);
+pub const SETCT_OIDATA: Nid = Nid(ffi::NID_setct_OIData);
+pub const SETCT_PI: Nid = Nid(ffi::NID_setct_PI);
+pub const SETCT_PIDATA: Nid = Nid(ffi::NID_setct_PIData);
+pub const SETCT_PIDATAUNSIGNED: Nid = Nid(ffi::NID_setct_PIDataUnsigned);
+pub const SETCT_HODINPUT: Nid = Nid(ffi::NID_setct_HODInput);
+pub const SETCT_AUTHRESBAGGAGE: Nid = Nid(ffi::NID_setct_AuthResBaggage);
+pub const SETCT_AUTHREVREQBAGGAGE: Nid = Nid(ffi::NID_setct_AuthRevReqBaggage);
+pub const SETCT_AUTHREVRESBAGGAGE: Nid = Nid(ffi::NID_setct_AuthRevResBaggage);
+pub const SETCT_CAPTOKENSEQ: Nid = Nid(ffi::NID_setct_CapTokenSeq);
+pub const SETCT_PINITRESDATA: Nid = Nid(ffi::NID_setct_PInitResData);
+pub const SETCT_PI_TBS: Nid = Nid(ffi::NID_setct_PI_TBS);
+pub const SETCT_PRESDATA: Nid = Nid(ffi::NID_setct_PResData);
+pub const SETCT_AUTHREQTBS: Nid = Nid(ffi::NID_setct_AuthReqTBS);
+pub const SETCT_AUTHRESTBS: Nid = Nid(ffi::NID_setct_AuthResTBS);
+pub const SETCT_AUTHRESTBSX: Nid = Nid(ffi::NID_setct_AuthResTBSX);
+pub const SETCT_AUTHTOKENTBS: Nid = Nid(ffi::NID_setct_AuthTokenTBS);
+pub const SETCT_CAPTOKENDATA: Nid = Nid(ffi::NID_setct_CapTokenData);
+pub const SETCT_CAPTOKENTBS: Nid = Nid(ffi::NID_setct_CapTokenTBS);
+pub const SETCT_ACQCARDCODEMSG: Nid = Nid(ffi::NID_setct_AcqCardCodeMsg);
+pub const SETCT_AUTHREVREQTBS: Nid = Nid(ffi::NID_setct_AuthRevReqTBS);
+pub const SETCT_AUTHREVRESDATA: Nid = Nid(ffi::NID_setct_AuthRevResData);
+pub const SETCT_AUTHREVRESTBS: Nid = Nid(ffi::NID_setct_AuthRevResTBS);
+pub const SETCT_CAPREQTBS: Nid = Nid(ffi::NID_setct_CapReqTBS);
+pub const SETCT_CAPREQTBSX: Nid = Nid(ffi::NID_setct_CapReqTBSX);
+pub const SETCT_CAPRESDATA: Nid = Nid(ffi::NID_setct_CapResData);
+pub const SETCT_CAPREVREQTBS: Nid = Nid(ffi::NID_setct_CapRevReqTBS);
+pub const SETCT_CAPREVREQTBSX: Nid = Nid(ffi::NID_setct_CapRevReqTBSX);
+pub const SETCT_CAPREVRESDATA: Nid = Nid(ffi::NID_setct_CapRevResData);
+pub const SETCT_CREDREQTBS: Nid = Nid(ffi::NID_setct_CredReqTBS);
+pub const SETCT_CREDREQTBSX: Nid = Nid(ffi::NID_setct_CredReqTBSX);
+pub const SETCT_CREDRESDATA: Nid = Nid(ffi::NID_setct_CredResData);
+pub const SETCT_CREDREVREQTBS: Nid = Nid(ffi::NID_setct_CredRevReqTBS);
+pub const SETCT_CREDREVREQTBSX: Nid = Nid(ffi::NID_setct_CredRevReqTBSX);
+pub const SETCT_CREDREVRESDATA: Nid = Nid(ffi::NID_setct_CredRevResData);
+pub const SETCT_PCERTREQDATA: Nid = Nid(ffi::NID_setct_PCertReqData);
+pub const SETCT_PCERTRESTBS: Nid = Nid(ffi::NID_setct_PCertResTBS);
+pub const SETCT_BATCHADMINREQDATA: Nid = Nid(ffi::NID_setct_BatchAdminReqData);
+pub const SETCT_BATCHADMINRESDATA: Nid = Nid(ffi::NID_setct_BatchAdminResData);
+pub const SETCT_CARDCINITRESTBS: Nid = Nid(ffi::NID_setct_CardCInitResTBS);
+pub const SETCT_MEAQCINITRESTBS: Nid = Nid(ffi::NID_setct_MeAqCInitResTBS);
+pub const SETCT_REGFORMRESTBS: Nid = Nid(ffi::NID_setct_RegFormResTBS);
+pub const SETCT_CERTREQDATA: Nid = Nid(ffi::NID_setct_CertReqData);
+pub const SETCT_CERTREQTBS: Nid = Nid(ffi::NID_setct_CertReqTBS);
+pub const SETCT_CERTRESDATA: Nid = Nid(ffi::NID_setct_CertResData);
+pub const SETCT_CERTINQREQTBS: Nid = Nid(ffi::NID_setct_CertInqReqTBS);
+pub const SETCT_ERRORTBS: Nid = Nid(ffi::NID_setct_ErrorTBS);
+pub const SETCT_PIDUALSIGNEDTBE: Nid = Nid(ffi::NID_setct_PIDualSignedTBE);
+pub const SETCT_PIUNSIGNEDTBE: Nid = Nid(ffi::NID_setct_PIUnsignedTBE);
+pub const SETCT_AUTHREQTBE: Nid = Nid(ffi::NID_setct_AuthReqTBE);
+pub const SETCT_AUTHRESTBE: Nid = Nid(ffi::NID_setct_AuthResTBE);
+pub const SETCT_AUTHRESTBEX: Nid = Nid(ffi::NID_setct_AuthResTBEX);
+pub const SETCT_AUTHTOKENTBE: Nid = Nid(ffi::NID_setct_AuthTokenTBE);
+pub const SETCT_CAPTOKENTBE: Nid = Nid(ffi::NID_setct_CapTokenTBE);
+pub const SETCT_CAPTOKENTBEX: Nid = Nid(ffi::NID_setct_CapTokenTBEX);
+pub const SETCT_ACQCARDCODEMSGTBE: Nid = Nid(ffi::NID_setct_AcqCardCodeMsgTBE);
+pub const SETCT_AUTHREVREQTBE: Nid = Nid(ffi::NID_setct_AuthRevReqTBE);
+pub const SETCT_AUTHREVRESTBE: Nid = Nid(ffi::NID_setct_AuthRevResTBE);
+pub const SETCT_AUTHREVRESTBEB: Nid = Nid(ffi::NID_setct_AuthRevResTBEB);
+pub const SETCT_CAPREQTBE: Nid = Nid(ffi::NID_setct_CapReqTBE);
+pub const SETCT_CAPREQTBEX: Nid = Nid(ffi::NID_setct_CapReqTBEX);
+pub const SETCT_CAPRESTBE: Nid = Nid(ffi::NID_setct_CapResTBE);
+pub const SETCT_CAPREVREQTBE: Nid = Nid(ffi::NID_setct_CapRevReqTBE);
+pub const SETCT_CAPREVREQTBEX: Nid = Nid(ffi::NID_setct_CapRevReqTBEX);
+pub const SETCT_CAPREVRESTBE: Nid = Nid(ffi::NID_setct_CapRevResTBE);
+pub const SETCT_CREDREQTBE: Nid = Nid(ffi::NID_setct_CredReqTBE);
+pub const SETCT_CREDREQTBEX: Nid = Nid(ffi::NID_setct_CredReqTBEX);
+pub const SETCT_CREDRESTBE: Nid = Nid(ffi::NID_setct_CredResTBE);
+pub const SETCT_CREDREVREQTBE: Nid = Nid(ffi::NID_setct_CredRevReqTBE);
+pub const SETCT_CREDREVREQTBEX: Nid = Nid(ffi::NID_setct_CredRevReqTBEX);
+pub const SETCT_CREDREVRESTBE: Nid = Nid(ffi::NID_setct_CredRevResTBE);
+pub const SETCT_BATCHADMINREQTBE: Nid = Nid(ffi::NID_setct_BatchAdminReqTBE);
+pub const SETCT_BATCHADMINRESTBE: Nid = Nid(ffi::NID_setct_BatchAdminResTBE);
+pub const SETCT_REGFORMREQTBE: Nid = Nid(ffi::NID_setct_RegFormReqTBE);
+pub const SETCT_CERTREQTBE: Nid = Nid(ffi::NID_setct_CertReqTBE);
+pub const SETCT_CERTREQTBEX: Nid = Nid(ffi::NID_setct_CertReqTBEX);
+pub const SETCT_CERTRESTBE: Nid = Nid(ffi::NID_setct_CertResTBE);
+pub const SETCT_CRLNOTIFICATIONTBS: Nid = Nid(ffi::NID_setct_CRLNotificationTBS);
+pub const SETCT_CRLNOTIFICATIONRESTBS: Nid = Nid(ffi::NID_setct_CRLNotificationResTBS);
+pub const SETCT_BCIDISTRIBUTIONTBS: Nid = Nid(ffi::NID_setct_BCIDistributionTBS);
+pub const SETEXT_GENCRYPT: Nid = Nid(ffi::NID_setext_genCrypt);
+pub const SETEXT_MIAUTH: Nid = Nid(ffi::NID_setext_miAuth);
+pub const SETEXT_PINSECURE: Nid = Nid(ffi::NID_setext_pinSecure);
+pub const SETEXT_PINANY: Nid = Nid(ffi::NID_setext_pinAny);
+pub const SETEXT_TRACK2: Nid = Nid(ffi::NID_setext_track2);
+pub const SETEXT_CV: Nid = Nid(ffi::NID_setext_cv);
+pub const SET_POLICY_ROOT: Nid = Nid(ffi::NID_set_policy_root);
+pub const SETCEXT_HASHEDROOT: Nid = Nid(ffi::NID_setCext_hashedRoot);
+pub const SETCEXT_CERTTYPE: Nid = Nid(ffi::NID_setCext_certType);
+pub const SETCEXT_MERCHDATA: Nid = Nid(ffi::NID_setCext_merchData);
+pub const SETCEXT_CCERTREQUIRED: Nid = Nid(ffi::NID_setCext_cCertRequired);
+pub const SETCEXT_TUNNELING: Nid = Nid(ffi::NID_setCext_tunneling);
+pub const SETCEXT_SETEXT: Nid = Nid(ffi::NID_setCext_setExt);
+pub const SETCEXT_SETQUALF: Nid = Nid(ffi::NID_setCext_setQualf);
+pub const SETCEXT_PGWYCAPABILITIES: Nid = Nid(ffi::NID_setCext_PGWYcapabilities);
+pub const SETCEXT_TOKENIDENTIFIER: Nid = Nid(ffi::NID_setCext_TokenIdentifier);
+pub const SETCEXT_TRACK2DATA: Nid = Nid(ffi::NID_setCext_Track2Data);
+pub const SETCEXT_TOKENTYPE: Nid = Nid(ffi::NID_setCext_TokenType);
+pub const SETCEXT_ISSUERCAPABILITIES: Nid = Nid(ffi::NID_setCext_IssuerCapabilities);
+pub const SETATTR_CERT: Nid = Nid(ffi::NID_setAttr_Cert);
+pub const SETATTR_PGWYCAP: Nid = Nid(ffi::NID_setAttr_PGWYcap);
+pub const SETATTR_TOKENTYPE: Nid = Nid(ffi::NID_setAttr_TokenType);
+pub const SETATTR_ISSCAP: Nid = Nid(ffi::NID_setAttr_IssCap);
+pub const SET_ROOTKEYTHUMB: Nid = Nid(ffi::NID_set_rootKeyThumb);
+pub const SET_ADDPOLICY: Nid = Nid(ffi::NID_set_addPolicy);
+pub const SETATTR_TOKEN_EMV: Nid = Nid(ffi::NID_setAttr_Token_EMV);
+pub const SETATTR_TOKEN_B0PRIME: Nid = Nid(ffi::NID_setAttr_Token_B0Prime);
+pub const SETATTR_ISSCAP_CVM: Nid = Nid(ffi::NID_setAttr_IssCap_CVM);
+pub const SETATTR_ISSCAP_T2: Nid = Nid(ffi::NID_setAttr_IssCap_T2);
+pub const SETATTR_ISSCAP_SIG: Nid = Nid(ffi::NID_setAttr_IssCap_Sig);
+pub const SETATTR_GENCRYPTGRM: Nid = Nid(ffi::NID_setAttr_GenCryptgrm);
+pub const SETATTR_T2ENC: Nid = Nid(ffi::NID_setAttr_T2Enc);
+pub const SETATTR_T2CLEARTXT: Nid = Nid(ffi::NID_setAttr_T2cleartxt);
+pub const SETATTR_TOKICCSIG: Nid = Nid(ffi::NID_setAttr_TokICCsig);
+pub const SETATTR_SECDEVSIG: Nid = Nid(ffi::NID_setAttr_SecDevSig);
+pub const SET_BRAND_IATA_ATA: Nid = Nid(ffi::NID_set_brand_IATA_ATA);
+pub const SET_BRAND_DINERS: Nid = Nid(ffi::NID_set_brand_Diners);
+pub const SET_BRAND_AMERICANEXPRESS: Nid = Nid(ffi::NID_set_brand_AmericanExpress);
+pub const SET_BRAND_JCB: Nid = Nid(ffi::NID_set_brand_JCB);
+pub const SET_BRAND_VISA: Nid = Nid(ffi::NID_set_brand_Visa);
+pub const SET_BRAND_MASTERCARD: Nid = Nid(ffi::NID_set_brand_MasterCard);
+pub const SET_BRAND_NOVUS: Nid = Nid(ffi::NID_set_brand_Novus);
+pub const DES_CDMF: Nid = Nid(ffi::NID_des_cdmf);
+pub const RSAOAEPENCRYPTIONSET: Nid = Nid(ffi::NID_rsaOAEPEncryptionSET);
+pub const IPSEC3: Nid = Nid(ffi::NID_ipsec3);
+pub const IPSEC4: Nid = Nid(ffi::NID_ipsec4);
+pub const WHIRLPOOL: Nid = Nid(ffi::NID_whirlpool);
+pub const CRYPTOPRO: Nid = Nid(ffi::NID_cryptopro);
+pub const CRYPTOCOM: Nid = Nid(ffi::NID_cryptocom);
+pub const ID_GOSTR3411_94_WITH_GOSTR3410_2001: Nid =
+ Nid(ffi::NID_id_GostR3411_94_with_GostR3410_2001);
+pub const ID_GOSTR3411_94_WITH_GOSTR3410_94: Nid = Nid(ffi::NID_id_GostR3411_94_with_GostR3410_94);
+pub const ID_GOSTR3411_94: Nid = Nid(ffi::NID_id_GostR3411_94);
+pub const ID_HMACGOSTR3411_94: Nid = Nid(ffi::NID_id_HMACGostR3411_94);
+pub const ID_GOSTR3410_2001: Nid = Nid(ffi::NID_id_GostR3410_2001);
+pub const ID_GOSTR3410_94: Nid = Nid(ffi::NID_id_GostR3410_94);
+pub const ID_GOST28147_89: Nid = Nid(ffi::NID_id_Gost28147_89);
+pub const GOST89_CNT: Nid = Nid(ffi::NID_gost89_cnt);
+pub const ID_GOST28147_89_MAC: Nid = Nid(ffi::NID_id_Gost28147_89_MAC);
+pub const ID_GOSTR3411_94_PRF: Nid = Nid(ffi::NID_id_GostR3411_94_prf);
+pub const ID_GOSTR3410_2001DH: Nid = Nid(ffi::NID_id_GostR3410_2001DH);
+pub const ID_GOSTR3410_94DH: Nid = Nid(ffi::NID_id_GostR3410_94DH);
+pub const ID_GOST28147_89_CRYPTOPRO_KEYMESHING: Nid =
+ Nid(ffi::NID_id_Gost28147_89_CryptoPro_KeyMeshing);
+pub const ID_GOST28147_89_NONE_KEYMESHING: Nid = Nid(ffi::NID_id_Gost28147_89_None_KeyMeshing);
+pub const ID_GOSTR3411_94_TESTPARAMSET: Nid = Nid(ffi::NID_id_GostR3411_94_TestParamSet);
+pub const ID_GOSTR3411_94_CRYPTOPROPARAMSET: Nid = Nid(ffi::NID_id_GostR3411_94_CryptoProParamSet);
+pub const ID_GOST28147_89_TESTPARAMSET: Nid = Nid(ffi::NID_id_Gost28147_89_TestParamSet);
+pub const ID_GOST28147_89_CRYPTOPRO_A_PARAMSET: Nid =
+ Nid(ffi::NID_id_Gost28147_89_CryptoPro_A_ParamSet);
+pub const ID_GOST28147_89_CRYPTOPRO_B_PARAMSET: Nid =
+ Nid(ffi::NID_id_Gost28147_89_CryptoPro_B_ParamSet);
+pub const ID_GOST28147_89_CRYPTOPRO_C_PARAMSET: Nid =
+ Nid(ffi::NID_id_Gost28147_89_CryptoPro_C_ParamSet);
+pub const ID_GOST28147_89_CRYPTOPRO_D_PARAMSET: Nid =
+ Nid(ffi::NID_id_Gost28147_89_CryptoPro_D_ParamSet);
+pub const ID_GOST28147_89_CRYPTOPRO_OSCAR_1_1_PARAMSET: Nid =
+ Nid(ffi::NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet);
+pub const ID_GOST28147_89_CRYPTOPRO_OSCAR_1_0_PARAMSET: Nid =
+ Nid(ffi::NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet);
+pub const ID_GOST28147_89_CRYPTOPRO_RIC_1_PARAMSET: Nid =
+ Nid(ffi::NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet);
+pub const ID_GOSTR3410_94_TESTPARAMSET: Nid = Nid(ffi::NID_id_GostR3410_94_TestParamSet);
+pub const ID_GOSTR3410_94_CRYPTOPRO_A_PARAMSET: Nid =
+ Nid(ffi::NID_id_GostR3410_94_CryptoPro_A_ParamSet);
+pub const ID_GOSTR3410_94_CRYPTOPRO_B_PARAMSET: Nid =
+ Nid(ffi::NID_id_GostR3410_94_CryptoPro_B_ParamSet);
+pub const ID_GOSTR3410_94_CRYPTOPRO_C_PARAMSET: Nid =
+ Nid(ffi::NID_id_GostR3410_94_CryptoPro_C_ParamSet);
+pub const ID_GOSTR3410_94_CRYPTOPRO_D_PARAMSET: Nid =
+ Nid(ffi::NID_id_GostR3410_94_CryptoPro_D_ParamSet);
+pub const ID_GOSTR3410_94_CRYPTOPRO_XCHA_PARAMSET: Nid =
+ Nid(ffi::NID_id_GostR3410_94_CryptoPro_XchA_ParamSet);
+pub const ID_GOSTR3410_94_CRYPTOPRO_XCHB_PARAMSET: Nid =
+ Nid(ffi::NID_id_GostR3410_94_CryptoPro_XchB_ParamSet);
+pub const ID_GOSTR3410_94_CRYPTOPRO_XCHC_PARAMSET: Nid =
+ Nid(ffi::NID_id_GostR3410_94_CryptoPro_XchC_ParamSet);
+pub const ID_GOSTR3410_2001_TESTPARAMSET: Nid = Nid(ffi::NID_id_GostR3410_2001_TestParamSet);
+pub const ID_GOSTR3410_2001_CRYPTOPRO_A_PARAMSET: Nid =
+ Nid(ffi::NID_id_GostR3410_2001_CryptoPro_A_ParamSet);
+pub const ID_GOSTR3410_2001_CRYPTOPRO_B_PARAMSET: Nid =
+ Nid(ffi::NID_id_GostR3410_2001_CryptoPro_B_ParamSet);
+pub const ID_GOSTR3410_2001_CRYPTOPRO_C_PARAMSET: Nid =
+ Nid(ffi::NID_id_GostR3410_2001_CryptoPro_C_ParamSet);
+pub const ID_GOSTR3410_2001_CRYPTOPRO_XCHA_PARAMSET: Nid =
+ Nid(ffi::NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet);
+pub const ID_GOSTR3410_2001_CRYPTOPRO_XCHB_PARAMSET: Nid =
+ Nid(ffi::NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet);
+pub const ID_GOSTR3410_94_A: Nid = Nid(ffi::NID_id_GostR3410_94_a);
+pub const ID_GOSTR3410_94_ABIS: Nid = Nid(ffi::NID_id_GostR3410_94_aBis);
+pub const ID_GOSTR3410_94_B: Nid = Nid(ffi::NID_id_GostR3410_94_b);
+pub const ID_GOSTR3410_94_BBIS: Nid = Nid(ffi::NID_id_GostR3410_94_bBis);
+pub const ID_GOST28147_89_CC: Nid = Nid(ffi::NID_id_Gost28147_89_cc);
+pub const ID_GOSTR3410_94_CC: Nid = Nid(ffi::NID_id_GostR3410_94_cc);
+pub const ID_GOSTR3410_2001_CC: Nid = Nid(ffi::NID_id_GostR3410_2001_cc);
+pub const ID_GOSTR3411_94_WITH_GOSTR3410_94_CC: Nid =
+ Nid(ffi::NID_id_GostR3411_94_with_GostR3410_94_cc);
+pub const ID_GOSTR3411_94_WITH_GOSTR3410_2001_CC: Nid =
+ Nid(ffi::NID_id_GostR3411_94_with_GostR3410_2001_cc);
+pub const ID_GOSTR3410_2001_PARAMSET_CC: Nid = Nid(ffi::NID_id_GostR3410_2001_ParamSet_cc);
+pub const CAMELLIA_128_CBC: Nid = Nid(ffi::NID_camellia_128_cbc);
+pub const CAMELLIA_192_CBC: Nid = Nid(ffi::NID_camellia_192_cbc);
+pub const CAMELLIA_256_CBC: Nid = Nid(ffi::NID_camellia_256_cbc);
+pub const ID_CAMELLIA128_WRAP: Nid = Nid(ffi::NID_id_camellia128_wrap);
+pub const ID_CAMELLIA192_WRAP: Nid = Nid(ffi::NID_id_camellia192_wrap);
+pub const ID_CAMELLIA256_WRAP: Nid = Nid(ffi::NID_id_camellia256_wrap);
+pub const CAMELLIA_128_ECB: Nid = Nid(ffi::NID_camellia_128_ecb);
+pub const CAMELLIA_128_OFB128: Nid = Nid(ffi::NID_camellia_128_ofb128);
+pub const CAMELLIA_128_CFB128: Nid = Nid(ffi::NID_camellia_128_cfb128);
+pub const CAMELLIA_192_ECB: Nid = Nid(ffi::NID_camellia_192_ecb);
+pub const CAMELLIA_192_OFB128: Nid = Nid(ffi::NID_camellia_192_ofb128);
+pub const CAMELLIA_192_CFB128: Nid = Nid(ffi::NID_camellia_192_cfb128);
+pub const CAMELLIA_256_ECB: Nid = Nid(ffi::NID_camellia_256_ecb);
+pub const CAMELLIA_256_OFB128: Nid = Nid(ffi::NID_camellia_256_ofb128);
+pub const CAMELLIA_256_CFB128: Nid = Nid(ffi::NID_camellia_256_cfb128);
+pub const CAMELLIA_128_CFB1: Nid = Nid(ffi::NID_camellia_128_cfb1);
+pub const CAMELLIA_192_CFB1: Nid = Nid(ffi::NID_camellia_192_cfb1);
+pub const CAMELLIA_256_CFB1: Nid = Nid(ffi::NID_camellia_256_cfb1);
+pub const CAMELLIA_128_CFB8: Nid = Nid(ffi::NID_camellia_128_cfb8);
+pub const CAMELLIA_192_CFB8: Nid = Nid(ffi::NID_camellia_192_cfb8);
+pub const CAMELLIA_256_CFB8: Nid = Nid(ffi::NID_camellia_256_cfb8);
+pub const KISA: Nid = Nid(ffi::NID_kisa);
+pub const SEED_ECB: Nid = Nid(ffi::NID_seed_ecb);
+pub const SEED_CBC: Nid = Nid(ffi::NID_seed_cbc);
+pub const SEED_CFB128: Nid = Nid(ffi::NID_seed_cfb128);
+pub const SEED_OFB128: Nid = Nid(ffi::NID_seed_ofb128);
+pub const HMAC: Nid = Nid(ffi::NID_hmac);
+pub const CMAC: Nid = Nid(ffi::NID_cmac);
+pub const RC4_HMAC_MD5: Nid = Nid(ffi::NID_rc4_hmac_md5);
+pub const AES_128_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_128_cbc_hmac_sha1);
+pub const AES_192_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_192_cbc_hmac_sha1);
+pub const AES_256_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_256_cbc_hmac_sha1);
diff --git a/openssl/src/crypto/pkcs12.rs b/openssl/src/pkcs12.rs
index 89bcbd5c..1ef0bf3f 100644
--- a/openssl/src/crypto/pkcs12.rs
+++ b/openssl/src/pkcs12.rs
@@ -6,18 +6,14 @@ use std::cmp;
use std::ptr;
use std::ffi::CString;
-use crypto::pkey::PKey;
+use {cvt, cvt_p};
+use pkey::PKey;
use error::ErrorStack;
use x509::X509;
+use types::{OpenSslType, OpenSslTypeRef};
+use stack::Stack;
-/// A PKCS #12 archive.
-pub struct Pkcs12(*mut ffi::PKCS12);
-
-impl Drop for Pkcs12 {
- fn drop(&mut self) {
- unsafe { ffi::PKCS12_free(self.0); }
- }
-}
+type_!(Pkcs12, Pkcs12Ref, ffi::PKCS12, ffi::PKCS12_free);
impl Pkcs12 {
/// Deserializes a `Pkcs12` structure from DER-encoded data.
@@ -26,11 +22,13 @@ impl Pkcs12 {
ffi::init();
let mut ptr = der.as_ptr() as *const c_uchar;
let length = cmp::min(der.len(), c_long::max_value() as usize) as c_long;
- let p12 = try_ssl_null!(ffi::d2i_PKCS12(ptr::null_mut(), &mut ptr, length));
+ let p12 = try!(cvt_p(ffi::d2i_PKCS12(ptr::null_mut(), &mut ptr, length)));
Ok(Pkcs12(p12))
}
}
+}
+impl Pkcs12Ref {
/// Extracts the contents of the `Pkcs12`.
pub fn parse(&self, pass: &str) -> Result<ParsedPkcs12, ErrorStack> {
unsafe {
@@ -40,23 +38,20 @@ impl Pkcs12 {
let mut cert = ptr::null_mut();
let mut chain = ptr::null_mut();
- try_ssl!(ffi::PKCS12_parse(self.0, pass.as_ptr(), &mut pkey, &mut cert, &mut chain));
+ try!(cvt(ffi::PKCS12_parse(self.as_ptr(),
+ pass.as_ptr(),
+ &mut pkey,
+ &mut cert,
+ &mut chain)));
let pkey = PKey::from_ptr(pkey);
let cert = X509::from_ptr(cert);
-
- let mut chain_out = vec![];
- for i in 0..(*chain).stack.num {
- let x509 = *(*chain).stack.data.offset(i as isize) as *mut _;
- chain_out.push(X509::from_ptr(x509));
- }
- ffi::sk_free(&mut (*chain).stack);
+ let chain = Stack::from_ptr(chain);
Ok(ParsedPkcs12 {
pkey: pkey,
cert: cert,
- chain: chain_out,
- _p: (),
+ chain: chain,
})
}
}
@@ -65,28 +60,27 @@ impl Pkcs12 {
pub struct ParsedPkcs12 {
pub pkey: PKey,
pub cert: X509,
- pub chain: Vec<X509>,
- _p: (),
+ pub chain: Stack<X509>,
}
#[cfg(test)]
mod test {
- use crypto::hash::Type::SHA1;
+ use hash::MessageDigest;
use serialize::hex::ToHex;
use super::*;
#[test]
fn parse() {
- let der = include_bytes!("../../test/identity.p12");
+ let der = include_bytes!("../test/identity.p12");
let pkcs12 = Pkcs12::from_der(der).unwrap();
let parsed = pkcs12.parse("mypass").unwrap();
- assert_eq!(parsed.cert.fingerprint(SHA1).unwrap().to_hex(),
+ assert_eq!(parsed.cert.fingerprint(MessageDigest::sha1()).unwrap().to_hex(),
"59172d9313e84459bcff27f967e79e6e9217e584");
assert_eq!(parsed.chain.len(), 1);
- assert_eq!(parsed.chain[0].fingerprint(SHA1).unwrap().to_hex(),
+ assert_eq!(parsed.chain[0].fingerprint(MessageDigest::sha1()).unwrap().to_hex(),
"c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875");
}
}
diff --git a/openssl/src/pkcs5.rs b/openssl/src/pkcs5.rs
new file mode 100644
index 00000000..8d6dcce8
--- /dev/null
+++ b/openssl/src/pkcs5.rs
@@ -0,0 +1,203 @@
+use libc::c_int;
+use std::ptr;
+use ffi;
+
+use cvt;
+use hash::MessageDigest;
+use symm::Cipher;
+use error::ErrorStack;
+
+#[derive(Clone, Eq, PartialEq, Hash, Debug)]
+pub struct KeyIvPair {
+ pub key: Vec<u8>,
+ pub iv: Option<Vec<u8>>,
+}
+
+/// Derives a key and an IV from various parameters.
+///
+/// If specified, `salt` must be 8 bytes in length.
+///
+/// If the total key and IV length is less than 16 bytes and MD5 is used then
+/// the algorithm is compatible with the key derivation algorithm from PKCS#5
+/// v1.5 or PBKDF1 from PKCS#5 v2.0.
+///
+/// New applications should not use this and instead use
+/// `pkcs5_pbkdf2_hmac_sha1` or another more modern key derivation algorithm.
+pub fn bytes_to_key(cipher: Cipher,
+ digest: MessageDigest,
+ data: &[u8],
+ salt: Option<&[u8]>,
+ count: i32)
+ -> Result<KeyIvPair, ErrorStack> {
+ unsafe {
+ assert!(data.len() <= c_int::max_value() as usize);
+ let salt_ptr = match salt {
+ Some(salt) => {
+ assert_eq!(salt.len(), ffi::PKCS5_SALT_LEN as usize);
+ salt.as_ptr()
+ }
+ None => ptr::null(),
+ };
+
+ ffi::init();
+
+ let mut iv = cipher.iv_len().map(|l| vec![0; l]);
+
+ let cipher = cipher.as_ptr();
+ let digest = digest.as_ptr();
+
+ let len = try!(cvt(ffi::EVP_BytesToKey(cipher,
+ digest,
+ salt_ptr,
+ ptr::null(),
+ data.len() as c_int,
+ count.into(),
+ ptr::null_mut(),
+ ptr::null_mut())));
+
+ let mut key = vec![0; len as usize];
+ let iv_ptr = iv.as_mut().map(|v| v.as_mut_ptr()).unwrap_or(ptr::null_mut());
+
+ try!(cvt(ffi::EVP_BytesToKey(cipher,
+ digest,
+ salt_ptr,
+ data.as_ptr(),
+ data.len() as c_int,
+ count as c_int,
+ key.as_mut_ptr(),
+ iv_ptr)));
+
+ Ok(KeyIvPair { key: key, iv: iv })
+ }
+}
+
+/// Derives a key from a password and salt using the PBKDF2-HMAC algorithm with a digest function.
+pub fn pbkdf2_hmac(pass: &[u8],
+ salt: &[u8],
+ iter: usize,
+ hash: MessageDigest,
+ key: &mut [u8])
+ -> Result<(), ErrorStack> {
+ unsafe {
+ assert!(pass.len() <= c_int::max_value() as usize);
+ assert!(salt.len() <= c_int::max_value() as usize);
+ assert!(key.len() <= c_int::max_value() as usize);
+
+ ffi::init();
+ cvt(ffi::PKCS5_PBKDF2_HMAC(pass.as_ptr() as *const _,
+ pass.len() as c_int,
+ salt.as_ptr(),
+ salt.len() as c_int,
+ iter as c_int,
+ hash.as_ptr(),
+ key.len() as c_int,
+ key.as_mut_ptr()))
+ .map(|_| ())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use hash::MessageDigest;
+ use symm::Cipher;
+
+ // Test vectors from
+ // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c
+ #[test]
+ fn pbkdf2_hmac_sha256() {
+ let mut buf = [0; 16];
+
+ super::pbkdf2_hmac(b"passwd", b"salt", 1, MessageDigest::sha256(), &mut buf).unwrap();
+ assert_eq!(buf,
+ &[0x55_u8, 0xac_u8, 0x04_u8, 0x6e_u8, 0x56_u8, 0xe3_u8, 0x08_u8, 0x9f_u8,
+ 0xec_u8, 0x16_u8, 0x91_u8, 0xc2_u8, 0x25_u8, 0x44_u8, 0xb6_u8, 0x05_u8][..]);
+
+ super::pbkdf2_hmac(b"Password",
+ b"NaCl",
+ 80000,
+ MessageDigest::sha256(),
+ &mut buf)
+ .unwrap();
+ assert_eq!(buf,
+ &[0x4d_u8, 0xdc_u8, 0xd8_u8, 0xf6_u8, 0x0b_u8, 0x98_u8, 0xbe_u8, 0x21_u8,
+ 0x83_u8, 0x0c_u8, 0xee_u8, 0x5e_u8, 0xf2_u8, 0x27_u8, 0x01_u8, 0xf9_u8][..]);
+ }
+
+ // Test vectors from
+ // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c
+ #[test]
+ fn pbkdf2_hmac_sha512() {
+ let mut buf = [0; 64];
+
+ super::pbkdf2_hmac(b"password", b"NaCL", 1, MessageDigest::sha512(), &mut buf).unwrap();
+ assert_eq!(&buf[..],
+ &[0x73_u8, 0xde_u8, 0xcf_u8, 0xa5_u8, 0x8a_u8, 0xa2_u8, 0xe8_u8, 0x4f_u8,
+ 0x94_u8, 0x77_u8, 0x1a_u8, 0x75_u8, 0x73_u8, 0x6b_u8, 0xb8_u8, 0x8b_u8,
+ 0xd3_u8, 0xc7_u8, 0xb3_u8, 0x82_u8, 0x70_u8, 0xcf_u8, 0xb5_u8, 0x0c_u8,
+ 0xb3_u8, 0x90_u8, 0xed_u8, 0x78_u8, 0xb3_u8, 0x05_u8, 0x65_u8, 0x6a_u8,
+ 0xf8_u8, 0x14_u8, 0x8e_u8, 0x52_u8, 0x45_u8, 0x2b_u8, 0x22_u8, 0x16_u8,
+ 0xb2_u8, 0xb8_u8, 0x09_u8, 0x8b_u8, 0x76_u8, 0x1f_u8, 0xc6_u8, 0x33_u8,
+ 0x60_u8, 0x60_u8, 0xa0_u8, 0x9f_u8, 0x76_u8, 0x41_u8, 0x5e_u8, 0x9f_u8,
+ 0x71_u8, 0xea_u8, 0x47_u8, 0xf9_u8, 0xe9_u8, 0x06_u8, 0x43_u8, 0x06_u8][..]);
+
+ super::pbkdf2_hmac(b"pass\0word",
+ b"sa\0lt",
+ 1,
+ MessageDigest::sha512(),
+ &mut buf)
+ .unwrap();
+ assert_eq!(&buf[..],
+ &[0x71_u8, 0xa0_u8, 0xec_u8, 0x84_u8, 0x2a_u8, 0xbd_u8, 0x5c_u8, 0x67_u8,
+ 0x8b_u8, 0xcf_u8, 0xd1_u8, 0x45_u8, 0xf0_u8, 0x9d_u8, 0x83_u8, 0x52_u8,
+ 0x2f_u8, 0x93_u8, 0x36_u8, 0x15_u8, 0x60_u8, 0x56_u8, 0x3c_u8, 0x4d_u8,
+ 0x0d_u8, 0x63_u8, 0xb8_u8, 0x83_u8, 0x29_u8, 0x87_u8, 0x10_u8, 0x90_u8,
+ 0xe7_u8, 0x66_u8, 0x04_u8, 0xa4_u8, 0x9a_u8, 0xf0_u8, 0x8f_u8, 0xe7_u8,
+ 0xc9_u8, 0xf5_u8, 0x71_u8, 0x56_u8, 0xc8_u8, 0x79_u8, 0x09_u8, 0x96_u8,
+ 0xb2_u8, 0x0f_u8, 0x06_u8, 0xbc_u8, 0x53_u8, 0x5e_u8, 0x5a_u8, 0xb5_u8,
+ 0x44_u8, 0x0d_u8, 0xf7_u8, 0xe8_u8, 0x78_u8, 0x29_u8, 0x6f_u8, 0xa7_u8][..]);
+
+ super::pbkdf2_hmac(b"passwordPASSWORDpassword",
+ b"salt\0\0\0",
+ 50,
+ MessageDigest::sha512(),
+ &mut buf)
+ .unwrap();
+ assert_eq!(&buf[..],
+ &[0x01_u8, 0x68_u8, 0x71_u8, 0xa4_u8, 0xc4_u8, 0xb7_u8, 0x5f_u8, 0x96_u8,
+ 0x85_u8, 0x7f_u8, 0xd2_u8, 0xb9_u8, 0xf8_u8, 0xca_u8, 0x28_u8, 0x02_u8,
+ 0x3b_u8, 0x30_u8, 0xee_u8, 0x2a_u8, 0x39_u8, 0xf5_u8, 0xad_u8, 0xca_u8,
+ 0xc8_u8, 0xc9_u8, 0x37_u8, 0x5f_u8, 0x9b_u8, 0xda_u8, 0x1c_u8, 0xcd_u8,
+ 0x1b_u8, 0x6f_u8, 0x0b_u8, 0x2f_u8, 0xc3_u8, 0xad_u8, 0xda_u8, 0x50_u8,
+ 0x54_u8, 0x12_u8, 0xe7_u8, 0x9d_u8, 0x89_u8, 0x00_u8, 0x56_u8, 0xc6_u8,
+ 0x2e_u8, 0x52_u8, 0x4c_u8, 0x7d_u8, 0x51_u8, 0x15_u8, 0x4b_u8, 0x1a_u8,
+ 0x85_u8, 0x34_u8, 0x57_u8, 0x5b_u8, 0xd0_u8, 0x2d_u8, 0xee_u8, 0x39_u8][..]);
+ }
+ #[test]
+ fn bytes_to_key() {
+ let salt = [16_u8, 34_u8, 19_u8, 23_u8, 141_u8, 4_u8, 207_u8, 221_u8];
+
+ let data = [143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8, 241_u8, 242_u8, 31_u8,
+ 154_u8, 56_u8, 198_u8, 145_u8, 192_u8, 64_u8, 2_u8, 245_u8, 167_u8, 220_u8,
+ 55_u8, 119_u8, 233_u8, 136_u8, 139_u8, 27_u8, 71_u8, 242_u8, 119_u8, 175_u8,
+ 65_u8, 207_u8];
+
+
+
+ let expected_key = vec![249_u8, 115_u8, 114_u8, 97_u8, 32_u8, 213_u8, 165_u8, 146_u8,
+ 58_u8, 87_u8, 234_u8, 3_u8, 43_u8, 250_u8, 97_u8, 114_u8, 26_u8,
+ 98_u8, 245_u8, 246_u8, 238_u8, 177_u8, 229_u8, 161_u8, 183_u8,
+ 224_u8, 174_u8, 3_u8, 6_u8, 244_u8, 236_u8, 255_u8];
+ let expected_iv = vec![4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8,
+ 69_u8, 98_u8, 107_u8, 208_u8, 14_u8, 236_u8, 60_u8];
+
+ assert_eq!(super::bytes_to_key(Cipher::aes_256_cbc(),
+ MessageDigest::sha1(),
+ &data,
+ Some(&salt),
+ 1).unwrap(),
+ super::KeyIvPair {
+ key: expected_key,
+ iv: Some(expected_iv),
+ });
+ }
+}
diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs
new file mode 100644
index 00000000..a1ebd695
--- /dev/null
+++ b/openssl/src/pkey.rs
@@ -0,0 +1,178 @@
+use libc::{c_void, c_char, c_int};
+use std::ptr;
+use std::mem;
+use ffi;
+
+use {cvt, cvt_p};
+use bio::{MemBio, MemBioSlice};
+use dsa::Dsa;
+use rsa::Rsa;
+use error::ErrorStack;
+use util::{CallbackState, invoke_passwd_cb};
+use types::{OpenSslType, OpenSslTypeRef};
+
+type_!(PKey, PKeyRef, ffi::EVP_PKEY, ffi::EVP_PKEY_free);
+
+impl PKeyRef {
+ /// Get a reference to the interal RSA key for direct access to the key components
+ pub fn rsa(&self) -> Result<Rsa, ErrorStack> {
+ unsafe {
+ let rsa = try!(cvt_p(ffi::EVP_PKEY_get1_RSA(self.as_ptr())));
+ // this is safe as the ffi increments a reference counter to the internal key
+ Ok(Rsa::from_ptr(rsa))
+ }
+ }
+
+ /// Stores private key as a PEM
+ // FIXME: also add password and encryption
+ pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
+ unsafe {
+ try!(cvt(ffi::PEM_write_bio_PrivateKey(mem_bio.as_ptr(),
+ self.as_ptr(),
+ ptr::null(),
+ ptr::null_mut(),
+ -1,
+ None,
+ ptr::null_mut())));
+
+ }
+ Ok(mem_bio.get_buf().to_owned())
+ }
+
+ /// Encode public key in PEM format
+ pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
+ unsafe {
+ try!(cvt(ffi::PEM_write_bio_PUBKEY(mem_bio.as_ptr(), self.as_ptr())));
+ }
+ Ok(mem_bio.get_buf().to_owned())
+ }
+
+ /// Encode public key in DER format
+ pub fn public_key_to_der(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
+ unsafe {
+ try!(cvt(ffi::i2d_PUBKEY_bio(mem_bio.as_ptr(), self.as_ptr())));
+ }
+ Ok(mem_bio.get_buf().to_owned())
+ }
+
+ pub fn public_eq(&self, other: &PKeyRef) -> bool {
+ unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 }
+ }
+}
+
+unsafe impl Send for PKey {}
+unsafe impl Sync for PKey {}
+
+impl PKey {
+ /// Create a new `PKey` containing an RSA key.
+ pub fn from_rsa(rsa: Rsa) -> Result<PKey, ErrorStack> {
+ unsafe {
+ let evp = try!(cvt_p(ffi::EVP_PKEY_new()));
+ let pkey = PKey(evp);
+ try!(cvt(ffi::EVP_PKEY_assign(pkey.0, ffi::EVP_PKEY_RSA, rsa.as_ptr() as *mut _)));
+ mem::forget(rsa);
+ Ok(pkey)
+ }
+ }
+
+ /// Create a new `PKey` containing a DSA key.
+ pub fn from_dsa(dsa: Dsa) -> Result<PKey, ErrorStack> {
+ unsafe {
+ let evp = try!(cvt_p(ffi::EVP_PKEY_new()));
+ let pkey = PKey(evp);
+ try!(cvt(ffi::EVP_PKEY_assign(pkey.0, ffi::EVP_PKEY_DSA, dsa.as_ptr() as *mut _)));
+ mem::forget(dsa);
+ Ok(pkey)
+ }
+ }
+
+ /// Create a new `PKey` containing an HMAC key.
+ pub fn hmac(key: &[u8]) -> Result<PKey, ErrorStack> {
+ unsafe {
+ assert!(key.len() <= c_int::max_value() as usize);
+ let key = try!(cvt_p(ffi::EVP_PKEY_new_mac_key(ffi::EVP_PKEY_HMAC,
+ ptr::null_mut(),
+ key.as_ptr() as *const _,
+ key.len() as c_int)));
+ Ok(PKey(key))
+ }
+ }
+
+ /// Reads private key from PEM, takes ownership of handle
+ pub fn private_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
+ ffi::init();
+ let mem_bio = try!(MemBioSlice::new(buf));
+ unsafe {
+ let evp = try!(cvt_p(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ None,
+ ptr::null_mut())));
+ Ok(PKey::from_ptr(evp))
+ }
+ }
+
+ /// Read a private key from PEM, supplying a password callback to be invoked if the private key
+ /// is encrypted.
+ ///
+ /// The callback will be passed the password buffer and should return the number of characters
+ /// placed into the buffer.
+ pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<PKey, ErrorStack>
+ where F: FnOnce(&mut [c_char]) -> usize
+ {
+ ffi::init();
+ let mut cb = CallbackState::new(pass_cb);
+ let mem_bio = try!(MemBioSlice::new(buf));
+ unsafe {
+ let evp = try!(cvt_p(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ Some(invoke_passwd_cb::<F>),
+ &mut cb as *mut _ as *mut c_void)));
+ Ok(PKey::from_ptr(evp))
+ }
+ }
+
+ /// Reads public key from PEM, takes ownership of handle
+ pub fn public_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
+ ffi::init();
+ let mem_bio = try!(MemBioSlice::new(buf));
+ unsafe {
+ let evp = try!(cvt_p(ffi::PEM_read_bio_PUBKEY(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ None,
+ ptr::null_mut())));
+ Ok(PKey::from_ptr(evp))
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn test_private_key_from_pem() {
+ let key = include_bytes!("../test/key.pem");
+ super::PKey::private_key_from_pem(key).unwrap();
+ }
+
+ #[test]
+ fn test_public_key_from_pem() {
+ let key = include_bytes!("../test/key.pem.pub");
+ super::PKey::public_key_from_pem(key).unwrap();
+ }
+
+ #[test]
+ fn test_pem() {
+ let key = include_bytes!("../test/key.pem");
+ let key = super::PKey::private_key_from_pem(key).unwrap();
+
+ let priv_key = key.private_key_to_pem().unwrap();
+ let pub_key = key.public_key_to_pem().unwrap();
+
+ // As a super-simple verification, just check that the buffers contain
+ // the `PRIVATE KEY` or `PUBLIC KEY` strings.
+ assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY"));
+ assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY"));
+ }
+}
diff --git a/openssl/src/crypto/rand.rs b/openssl/src/rand.rs
index 519449e9..c1c49e7b 100644
--- a/openssl/src/crypto/rand.rs
+++ b/openssl/src/rand.rs
@@ -1,13 +1,14 @@
use libc::c_int;
use ffi;
+
+use cvt;
use error::ErrorStack;
pub fn rand_bytes(buf: &mut [u8]) -> Result<(), ErrorStack> {
unsafe {
ffi::init();
assert!(buf.len() <= c_int::max_value() as usize);
- try_ssl_if!(ffi::RAND_bytes(buf.as_mut_ptr(), buf.len() as c_int) != 1);
- Ok(())
+ cvt(ffi::RAND_bytes(buf.as_mut_ptr(), buf.len() as c_int)).map(|_| ())
}
}
diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs
new file mode 100644
index 00000000..bd1d16d3
--- /dev/null
+++ b/openssl/src/rsa.rs
@@ -0,0 +1,457 @@
+use ffi;
+use std::fmt;
+use std::ptr;
+use std::mem;
+use libc::{c_int, c_void, c_char};
+
+use {cvt, cvt_p, cvt_n};
+use bn::{BigNum, BigNumRef};
+use bio::{MemBio, MemBioSlice};
+use error::ErrorStack;
+use util::{CallbackState, invoke_passwd_cb};
+use types::OpenSslTypeRef;
+
+/// Type of encryption padding to use.
+#[derive(Copy, Clone)]
+pub struct Padding(c_int);
+
+pub const NO_PADDING: Padding = Padding(ffi::RSA_NO_PADDING);
+pub const PKCS1_PADDING: Padding = Padding(ffi::RSA_PKCS1_PADDING);
+pub const PKCS1_OAEP_PADDING: Padding = Padding(ffi::RSA_PKCS1_OAEP_PADDING);
+
+type_!(Rsa, RsaRef, ffi::RSA, ffi::RSA_free);
+
+impl RsaRef {
+ /// Writes an RSA private key as unencrypted PEM formatted data
+ pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
+
+ unsafe {
+ try!(cvt(ffi::PEM_write_bio_RSAPrivateKey(mem_bio.as_ptr(),
+ self.as_ptr(),
+ ptr::null(),
+ ptr::null_mut(),
+ 0,
+ None,
+ ptr::null_mut())));
+ }
+ Ok(mem_bio.get_buf().to_owned())
+ }
+
+ /// Writes an RSA public key as PEM formatted data
+ pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
+
+ unsafe {
+ try!(cvt(ffi::PEM_write_bio_RSA_PUBKEY(mem_bio.as_ptr(), self.as_ptr())));
+ }
+
+ Ok(mem_bio.get_buf().to_owned())
+ }
+
+ pub fn size(&self) -> usize {
+ unsafe {
+ assert!(self.n().is_some());
+
+ ffi::RSA_size(self.as_ptr()) as usize
+ }
+ }
+
+ /// Decrypts data using the private key, returning the number of decrypted bytes.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `self` has no private components, or if `to` is smaller
+ /// than `self.size()`.
+ pub fn private_decrypt(&self,
+ from: &[u8],
+ to: &mut [u8],
+ padding: Padding)
+ -> Result<usize, ErrorStack> {
+ assert!(self.d().is_some(), "private components missing");
+ assert!(from.len() <= i32::max_value() as usize);
+ assert!(to.len() >= self.size());
+
+ unsafe {
+ let len = try!(cvt_n(ffi::RSA_private_decrypt(from.len() as c_int,
+ from.as_ptr(),
+ to.as_mut_ptr(),
+ self.as_ptr(),
+ padding.0)));
+ Ok(len as usize)
+ }
+ }
+
+ /// Encrypts data using the private key, returning the number of encrypted bytes.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `self` has no private components, or if `to` is smaller
+ /// than `self.size()`.
+ pub fn private_encrypt(&self,
+ from: &[u8],
+ to: &mut [u8],
+ padding: Padding)
+ -> Result<usize, ErrorStack> {
+ assert!(self.d().is_some(), "private components missing");
+ assert!(from.len() <= i32::max_value() as usize);
+ assert!(to.len() >= self.size());
+
+ unsafe {
+ let len = try!(cvt_n(ffi::RSA_private_encrypt(from.len() as c_int,
+ from.as_ptr(),
+ to.as_mut_ptr(),
+ self.as_ptr(),
+ padding.0)));
+ Ok(len as usize)
+ }
+ }
+
+ /// Decrypts data using the public key, returning the number of decrypted bytes.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `to` is smaller than `self.size()`.
+ pub fn public_decrypt(&self,
+ from: &[u8],
+ to: &mut [u8],
+ padding: Padding)
+ -> Result<usize, ErrorStack> {
+ assert!(from.len() <= i32::max_value() as usize);
+ assert!(to.len() >= self.size());
+
+ unsafe {
+ let len = try!(cvt_n(ffi::RSA_public_decrypt(from.len() as c_int,
+ from.as_ptr(),
+ to.as_mut_ptr(),
+ self.as_ptr(),
+ padding.0)));
+ Ok(len as usize)
+ }
+ }
+
+ /// Encrypts data using the private key, returning the number of encrypted bytes.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `to` is smaller than `self.size()`.
+ pub fn public_encrypt(&self,
+ from: &[u8],
+ to: &mut [u8],
+ padding: Padding)
+ -> Result<usize, ErrorStack> {
+ assert!(from.len() <= i32::max_value() as usize);
+ assert!(to.len() >= self.size());
+
+ unsafe {
+ let len = try!(cvt_n(ffi::RSA_public_encrypt(from.len() as c_int,
+ from.as_ptr(),
+ to.as_mut_ptr(),
+ self.as_ptr(),
+ padding.0)));
+ Ok(len as usize)
+ }
+ }
+
+ pub fn n(&self) -> Option<&BigNumRef> {
+ unsafe {
+ let n = compat::key(self.as_ptr())[0];
+ if n.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr(n as *mut _))
+ }
+ }
+ }
+
+ pub fn d(&self) -> Option<&BigNumRef> {
+ unsafe {
+ let d = compat::key(self.as_ptr())[2];
+ if d.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr(d as *mut _))
+ }
+ }
+ }
+
+ pub fn e(&self) -> Option<&BigNumRef> {
+ unsafe {
+ let e = compat::key(self.as_ptr())[1];
+ if e.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr(e as *mut _))
+ }
+ }
+ }
+
+ pub fn p(&self) -> Option<&BigNumRef> {
+ unsafe {
+ let p = compat::factors(self.as_ptr())[0];
+ if p.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr(p as *mut _))
+ }
+ }
+ }
+
+ pub fn q(&self) -> Option<&BigNumRef> {
+ unsafe {
+ let q = compat::factors(self.as_ptr())[1];
+ if q.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr(q as *mut _))
+ }
+ }
+ }
+}
+
+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, ErrorStack> {
+ unsafe {
+ let rsa = Rsa(try!(cvt_p(ffi::RSA_new())));
+ try!(cvt(compat::set_key(rsa.0,
+ n.as_ptr(),
+ e.as_ptr(),
+ ptr::null_mut())));
+ mem::forget((n, e));
+ Ok(rsa)
+ }
+ }
+
+ pub fn from_private_components(n: BigNum,
+ e: BigNum,
+ d: BigNum,
+ p: BigNum,
+ q: BigNum,
+ dp: BigNum,
+ dq: BigNum,
+ qi: BigNum)
+ -> Result<Rsa, ErrorStack> {
+ unsafe {
+ let rsa = Rsa(try!(cvt_p(ffi::RSA_new())));
+ try!(cvt(compat::set_key(rsa.0, n.as_ptr(), e.as_ptr(), d.as_ptr())));
+ mem::forget((n, e, d));
+ try!(cvt(compat::set_factors(rsa.0, p.as_ptr(), q.as_ptr())));
+ mem::forget((p, q));
+ try!(cvt(compat::set_crt_params(rsa.0, dp.as_ptr(), dq.as_ptr(),
+ qi.as_ptr())));
+ mem::forget((dp, dq, qi));
+ Ok(rsa)
+ }
+ }
+
+ /// Generates a public/private key pair with the specified size.
+ ///
+ /// The public exponent will be 65537.
+ pub fn generate(bits: u32) -> Result<Rsa, ErrorStack> {
+ unsafe {
+ let rsa = Rsa(try!(cvt_p(ffi::RSA_new())));
+ let e = try!(BigNum::from_u32(ffi::RSA_F4 as u32));
+ try!(cvt(ffi::RSA_generate_key_ex(rsa.0, bits as c_int, e.as_ptr(), ptr::null_mut())));
+ Ok(rsa)
+ }
+ }
+
+ /// Reads an RSA private key from PEM formatted data.
+ pub fn private_key_from_pem(buf: &[u8]) -> Result<Rsa, ErrorStack> {
+ let mem_bio = try!(MemBioSlice::new(buf));
+ unsafe {
+ let rsa = try!(cvt_p(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ None,
+ ptr::null_mut())));
+ Ok(Rsa(rsa))
+ }
+ }
+
+ /// Reads an RSA private key from PEM formatted data and supplies a password callback.
+ pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<Rsa, ErrorStack>
+ where F: FnOnce(&mut [c_char]) -> usize
+ {
+ let mut cb = CallbackState::new(pass_cb);
+ let mem_bio = try!(MemBioSlice::new(buf));
+
+ unsafe {
+ let cb_ptr = &mut cb as *mut _ as *mut c_void;
+ let rsa = try!(cvt_p(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ Some(invoke_passwd_cb::<F>),
+ cb_ptr)));
+ Ok(Rsa(rsa))
+ }
+ }
+
+ /// Reads an RSA public key from PEM formatted data.
+ pub fn public_key_from_pem(buf: &[u8]) -> Result<Rsa, ErrorStack> {
+ let mem_bio = try!(MemBioSlice::new(buf));
+ unsafe {
+ let rsa = try!(cvt_p(ffi::PEM_read_bio_RSA_PUBKEY(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ None,
+ ptr::null_mut())));
+ Ok(Rsa(rsa))
+ }
+ }
+}
+
+impl fmt::Debug for Rsa {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Rsa")
+ }
+}
+
+#[cfg(ossl110)]
+mod compat {
+ use std::ptr;
+
+ use ffi::{self, BIGNUM, RSA};
+ use libc::c_int;
+
+ pub unsafe fn key(r: *const RSA) -> [*const BIGNUM; 3] {
+ let (mut n, mut e, mut d) = (ptr::null(), ptr::null(), ptr::null());
+ ffi::RSA_get0_key(r, &mut n, &mut e, &mut d);
+ [n, e, d]
+ }
+
+ pub unsafe fn factors(r: *const RSA) -> [*const BIGNUM; 2] {
+ let (mut p, mut q) = (ptr::null(), ptr::null());
+ ffi::RSA_get0_factors(r, &mut p, &mut q);
+ [p, q]
+ }
+
+ pub unsafe fn set_key(r: *mut RSA, n: *mut BIGNUM, e: *mut BIGNUM, d: *mut BIGNUM) -> c_int {
+ ffi::RSA_set0_key(r, n, e, d)
+ }
+
+ pub unsafe fn set_factors(r: *mut RSA, p: *mut BIGNUM, q: *mut BIGNUM) -> c_int {
+ ffi::RSA_set0_factors(r, p, q)
+ }
+
+ pub unsafe fn set_crt_params(r: *mut RSA,
+ dmp1: *mut BIGNUM,
+ dmq1: *mut BIGNUM,
+ iqmp: *mut BIGNUM)
+ -> c_int {
+ ffi::RSA_set0_crt_params(r, dmp1, dmq1, iqmp)
+ }
+}
+
+#[cfg(ossl10x)]
+mod compat {
+ use libc::c_int;
+ use ffi::{BIGNUM, RSA};
+
+ pub unsafe fn key(r: *const RSA) -> [*const BIGNUM; 3] {
+ [(*r).n, (*r).e, (*r).d]
+ }
+
+ pub unsafe fn factors(r: *const RSA) -> [*const BIGNUM; 2] {
+ [(*r).p, (*r).q]
+ }
+
+ pub unsafe fn set_key(r: *mut RSA, n: *mut BIGNUM, e: *mut BIGNUM, d: *mut BIGNUM) -> c_int {
+ (*r).n = n;
+ (*r).e = e;
+ (*r).d = d;
+ 1 // TODO: is this right? should it be 0? what's success?
+ }
+
+ pub unsafe fn set_factors(r: *mut RSA, p: *mut BIGNUM, q: *mut BIGNUM) -> c_int {
+ (*r).p = p;
+ (*r).q = q;
+ 1 // TODO: is this right? should it be 0? what's success?
+ }
+
+ pub unsafe fn set_crt_params(r: *mut RSA,
+ dmp1: *mut BIGNUM,
+ dmq1: *mut BIGNUM,
+ iqmp: *mut BIGNUM)
+ -> c_int {
+ (*r).dmp1 = dmp1;
+ (*r).dmq1 = dmq1;
+ (*r).iqmp = iqmp;
+ 1 // TODO: is this right? should it be 0? what's success?
+ }
+}
+
+
+#[cfg(test)]
+mod test {
+ use libc::c_char;
+
+ use super::*;
+
+ #[test]
+ pub fn test_password() {
+ let mut password_queried = false;
+ let key = include_bytes!("../test/rsa-encrypted.pem");
+ Rsa::private_key_from_pem_cb(key, |password| {
+ password_queried = true;
+ password[0] = b'm' as c_char;
+ password[1] = b'y' as c_char;
+ password[2] = b'p' as c_char;
+ password[3] = b'a' as c_char;
+ password[4] = b's' as c_char;
+ password[5] = b's' as c_char;
+ 6
+ })
+ .unwrap();
+
+ assert!(password_queried);
+ }
+
+ #[test]
+ pub fn test_public_encrypt_private_decrypt_with_padding() {
+ let key = include_bytes!("../test/rsa.pem.pub");
+ let public_key = Rsa::public_key_from_pem(key).unwrap();
+
+ let mut result = vec![0; public_key.size()];
+ let original_data = b"This is test";
+ let len = public_key.public_encrypt(original_data, &mut result, PKCS1_PADDING).unwrap();
+ assert_eq!(len, 256);
+
+ let pkey = include_bytes!("../test/rsa.pem");
+ let private_key = Rsa::private_key_from_pem(pkey).unwrap();
+ let mut dec_result = vec![0; private_key.size()];
+ let len = private_key.private_decrypt(&result, &mut dec_result, PKCS1_PADDING).unwrap();
+
+ assert_eq!(&dec_result[..len], original_data);
+ }
+
+ #[test]
+ fn test_private_encrypt() {
+ let k0 = super::Rsa::generate(512).unwrap();
+ let k0pkey = k0.public_key_to_pem().unwrap();
+ let k1 = super::Rsa::public_key_from_pem(&k0pkey).unwrap();
+
+ let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
+
+ let mut emesg = vec![0; k0.size()];
+ k0.private_encrypt(&msg, &mut emesg, PKCS1_PADDING).unwrap();
+ let mut dmesg = vec![0; k1.size()];
+ let len = k1.public_decrypt(&emesg, &mut dmesg, PKCS1_PADDING).unwrap();
+ assert_eq!(msg, &dmesg[..len]);
+ }
+
+ #[test]
+ fn test_public_encrypt() {
+ let k0 = super::Rsa::generate(512).unwrap();
+ let k0pkey = k0.private_key_to_pem().unwrap();
+ let k1 = super::Rsa::private_key_from_pem(&k0pkey).unwrap();
+
+ let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
+
+ let mut emesg = vec![0; k0.size()];
+ k0.public_encrypt(&msg, &mut emesg, PKCS1_PADDING).unwrap();
+ let mut dmesg = vec![0; k1.size()];
+ let len = k1.private_decrypt(&emesg, &mut dmesg, PKCS1_PADDING).unwrap();
+ assert_eq!(msg, &dmesg[..len]);
+ }
+
+}
diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs
new file mode 100644
index 00000000..4ca551b6
--- /dev/null
+++ b/openssl/src/sign.rs
@@ -0,0 +1,397 @@
+//! Message signatures.
+//!
+//! The `Signer` allows for the computation of cryptographic signatures of
+//! data given a private key. The `Verifier` can then be used with the
+//! corresponding public key to verify the integrity and authenticity of that
+//! data given the signature.
+//!
+//! # Examples
+//!
+//! Sign and verify data given an RSA keypair:
+//!
+//! ```rust
+//! use openssl::sign::{Signer, Verifier};
+//! use openssl::rsa::Rsa;
+//! use openssl::pkey::PKey;
+//! use openssl::hash::MessageDigest;
+//!
+//! // Generate a keypair
+//! let keypair = Rsa::generate(2048).unwrap();
+//! let keypair = PKey::from_rsa(keypair).unwrap();
+//!
+//! let data = b"hello, world!";
+//! let data2 = b"hola, mundo!";
+//!
+//! // Sign the data
+//! let mut signer = Signer::new(MessageDigest::sha256(), &keypair).unwrap();
+//! signer.update(data).unwrap();
+//! signer.update(data2).unwrap();
+//! let signature = signer.finish().unwrap();
+//!
+//! // Verify the data
+//! let mut verifier = Verifier::new(MessageDigest::sha256(), &keypair).unwrap();
+//! verifier.update(data).unwrap();
+//! verifier.update(data2).unwrap();
+//! assert!(verifier.finish(&signature).unwrap());
+//! ```
+//!
+//! Compute an HMAC (note that `Verifier` cannot be used with HMACs):
+//!
+//! ```rust
+//! use openssl::sign::Signer;
+//! use openssl::pkey::PKey;
+//! use openssl::hash::MessageDigest;
+//!
+//! // Create a PKey
+//! let key = PKey::hmac(b"my secret").unwrap();
+//!
+//! let data = b"hello, world!";
+//! let data2 = b"hola, mundo!";
+//!
+//! // Compute the HMAC
+//! let mut signer = Signer::new(MessageDigest::sha256(), &key).unwrap();
+//! signer.update(data).unwrap();
+//! signer.update(data2).unwrap();
+//! let hmac = signer.finish().unwrap();
+//! ```
+use ffi;
+use std::io::{self, Write};
+use std::marker::PhantomData;
+use std::ptr;
+
+use {cvt, cvt_p};
+use hash::MessageDigest;
+use pkey::PKeyRef;
+use error::ErrorStack;
+use types::OpenSslTypeRef;
+
+#[cfg(ossl110)]
+use ffi::{EVP_MD_CTX_new, EVP_MD_CTX_free};
+#[cfg(any(ossl101, ossl102))]
+use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free};
+
+pub struct Signer<'a>(*mut ffi::EVP_MD_CTX, PhantomData<&'a PKeyRef>);
+
+impl<'a> Drop for Signer<'a> {
+ fn drop(&mut self) {
+ unsafe {
+ EVP_MD_CTX_free(self.0);
+ }
+ }
+}
+
+impl<'a> Signer<'a> {
+ pub fn new(type_: MessageDigest, pkey: &'a PKeyRef) -> Result<Signer<'a>, ErrorStack> {
+ unsafe {
+ ffi::init();
+
+ let ctx = try!(cvt_p(EVP_MD_CTX_new()));
+ let r = ffi::EVP_DigestSignInit(ctx,
+ ptr::null_mut(),
+ type_.as_ptr(),
+ ptr::null_mut(),
+ pkey.as_ptr());
+ if r != 1 {
+ EVP_MD_CTX_free(ctx);
+ return Err(ErrorStack::get());
+ }
+ Ok(Signer(ctx, PhantomData))
+ }
+ }
+
+ pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::EVP_DigestUpdate(self.0, buf.as_ptr() as *const _, buf.len())).map(|_| ())
+ }
+ }
+
+ pub fn finish(&self) -> Result<Vec<u8>, ErrorStack> {
+ unsafe {
+ let mut len = 0;
+ try!(cvt(ffi::EVP_DigestSignFinal(self.0, ptr::null_mut(), &mut len)));
+ let mut buf = vec![0; len];
+ try!(cvt(ffi::EVP_DigestSignFinal(self.0, buf.as_mut_ptr() as *mut _, &mut len)));
+ // The advertised length is not always equal to the real length for things like DSA
+ buf.truncate(len);
+ Ok(buf)
+ }
+ }
+}
+
+impl<'a> Write for Signer<'a> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ try!(self.update(buf));
+ Ok(buf.len())
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+pub struct Verifier<'a>(*mut ffi::EVP_MD_CTX, PhantomData<&'a PKeyRef>);
+
+impl<'a> Drop for Verifier<'a> {
+ fn drop(&mut self) {
+ unsafe {
+ EVP_MD_CTX_free(self.0);
+ }
+ }
+}
+
+impl<'a> Verifier<'a> {
+ pub fn new(type_: MessageDigest, pkey: &'a PKeyRef) -> Result<Verifier<'a>, ErrorStack> {
+ unsafe {
+ ffi::init();
+
+ let ctx = try!(cvt_p(EVP_MD_CTX_new()));
+ let r = ffi::EVP_DigestVerifyInit(ctx,
+ ptr::null_mut(),
+ type_.as_ptr(),
+ ptr::null_mut(),
+ pkey.as_ptr());
+ if r != 1 {
+ EVP_MD_CTX_free(ctx);
+ return Err(ErrorStack::get());
+ }
+
+ Ok(Verifier(ctx, PhantomData))
+ }
+ }
+
+ pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::EVP_DigestUpdate(self.0, buf.as_ptr() as *const _, buf.len())).map(|_| ())
+ }
+ }
+
+ pub fn finish(&self, signature: &[u8]) -> Result<bool, ErrorStack> {
+ unsafe {
+ let r = EVP_DigestVerifyFinal(self.0, signature.as_ptr() as *const _, signature.len());
+ match r {
+ 1 => Ok(true),
+ 0 => {
+ ErrorStack::get(); // discard error stack
+ Ok(false)
+ }
+ _ => Err(ErrorStack::get()),
+ }
+ }
+ }
+}
+
+impl<'a> Write for Verifier<'a> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ try!(self.update(buf));
+ Ok(buf.len())
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+#[cfg(not(ossl101))]
+use ffi::EVP_DigestVerifyFinal;
+
+#[cfg(ossl101)]
+#[allow(bad_style)]
+unsafe fn EVP_DigestVerifyFinal(ctx: *mut ffi::EVP_MD_CTX,
+ sigret: *const ::libc::c_uchar,
+ siglen: ::libc::size_t)
+ -> ::libc::c_int {
+ ffi::EVP_DigestVerifyFinal(ctx, sigret as *mut _, siglen)
+}
+
+#[cfg(test)]
+mod test {
+ use serialize::hex::FromHex;
+ use std::iter;
+
+ use hash::MessageDigest;
+ use sign::{Signer, Verifier};
+ use rsa::Rsa;
+ use dsa::Dsa;
+ use pkey::PKey;
+
+ static INPUT: &'static [u8] =
+ &[101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 83, 85, 122, 73, 49, 78, 105, 74, 57,
+ 46, 101, 121, 74, 112, 99, 51, 77, 105, 79, 105, 74, 113, 98, 50, 85, 105, 76, 65, 48,
+ 75, 73, 67, 74, 108, 101, 72, 65, 105, 79, 106, 69, 122, 77, 68, 65, 52, 77, 84, 107,
+ 122, 79, 68, 65, 115, 68, 81, 111, 103, 73, 109, 104, 48, 100, 72, 65, 54, 76, 121, 57,
+ 108, 101, 71, 70, 116, 99, 71, 120, 108, 76, 109, 78, 118, 98, 83, 57, 112, 99, 49, 57,
+ 121, 98, 50, 57, 48, 73, 106, 112, 48, 99, 110, 86, 108, 102, 81];
+
+ static SIGNATURE: &'static [u8] =
+ &[112, 46, 33, 137, 67, 232, 143, 209, 30, 181, 216, 45, 191, 120, 69, 243, 65, 6, 174,
+ 27, 129, 255, 247, 115, 17, 22, 173, 209, 113, 125, 131, 101, 109, 66, 10, 253, 60, 150,
+ 238, 221, 115, 162, 102, 62, 81, 102, 104, 123, 0, 11, 135, 34, 110, 1, 135, 237, 16,
+ 115, 249, 69, 229, 130, 173, 252, 239, 22, 216, 90, 121, 142, 232, 198, 109, 219, 61,
+ 184, 151, 91, 23, 208, 148, 2, 190, 237, 213, 217, 217, 112, 7, 16, 141, 178, 129, 96,
+ 213, 248, 4, 12, 167, 68, 87, 98, 184, 31, 190, 127, 249, 217, 46, 10, 231, 111, 36,
+ 242, 91, 51, 187, 230, 244, 74, 230, 30, 177, 4, 10, 203, 32, 4, 77, 62, 249, 18, 142,
+ 212, 1, 48, 121, 91, 212, 189, 59, 65, 238, 202, 208, 102, 171, 101, 25, 129, 253, 228,
+ 141, 247, 127, 55, 45, 195, 139, 159, 175, 221, 59, 239, 177, 139, 93, 163, 204, 60, 46,
+ 176, 47, 158, 58, 65, 214, 18, 202, 173, 21, 145, 18, 115, 160, 95, 35, 185, 232, 56,
+ 250, 175, 132, 157, 105, 132, 41, 239, 90, 30, 136, 121, 130, 54, 195, 212, 14, 96, 69,
+ 34, 165, 68, 200, 242, 122, 122, 45, 184, 6, 99, 209, 108, 247, 202, 234, 86, 222, 64,
+ 92, 178, 33, 90, 69, 178, 194, 85, 102, 181, 90, 193, 167, 72, 160, 112, 223, 200, 163,
+ 42, 70, 149, 67, 208, 25, 238, 251, 71];
+
+ #[test]
+ fn rsa_sign() {
+ let key = include_bytes!("../test/rsa.pem");
+ let private_key = Rsa::private_key_from_pem(key).unwrap();
+ let pkey = PKey::from_rsa(private_key).unwrap();
+
+ let mut signer = Signer::new(MessageDigest::sha256(), &pkey).unwrap();
+ signer.update(INPUT).unwrap();
+ let result = signer.finish().unwrap();
+
+ assert_eq!(result, SIGNATURE);
+ }
+
+ #[test]
+ fn rsa_verify_ok() {
+ let key = include_bytes!("../test/rsa.pem");
+ let private_key = Rsa::private_key_from_pem(key).unwrap();
+ let pkey = PKey::from_rsa(private_key).unwrap();
+
+ let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap();
+ verifier.update(INPUT).unwrap();
+ assert!(verifier.finish(SIGNATURE).unwrap());
+ }
+
+ #[test]
+ fn rsa_verify_invalid() {
+ let key = include_bytes!("../test/rsa.pem");
+ let private_key = Rsa::private_key_from_pem(key).unwrap();
+ let pkey = PKey::from_rsa(private_key).unwrap();
+
+ let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap();
+ verifier.update(INPUT).unwrap();
+ verifier.update(b"foobar").unwrap();
+ assert!(!verifier.finish(SIGNATURE).unwrap());
+ }
+
+ #[test]
+ pub fn dsa_sign_verify() {
+ let input: Vec<u8> = (0..25).cycle().take(1024).collect();
+
+ let private_key = {
+ let key = include_bytes!("../test/dsa.pem");
+ PKey::from_dsa(Dsa::private_key_from_pem(key).unwrap()).unwrap()
+ };
+
+ let public_key = {
+ let key = include_bytes!("../test/dsa.pem.pub");
+ PKey::from_dsa(Dsa::public_key_from_pem(key).unwrap()).unwrap()
+ };
+
+ let mut signer = Signer::new(MessageDigest::sha1(), &private_key).unwrap();
+ signer.update(&input).unwrap();
+ let sig = signer.finish().unwrap();
+
+ let mut verifier = Verifier::new(MessageDigest::sha1(), &public_key).unwrap();
+ verifier.update(&input).unwrap();
+ assert!(verifier.finish(&sig).unwrap());
+ }
+
+ #[test]
+ pub fn dsa_sign_verify_fail() {
+ let input: Vec<u8> = (0..25).cycle().take(1024).collect();
+
+ let private_key = {
+ let key = include_bytes!("../test/dsa.pem");
+ PKey::from_dsa(Dsa::private_key_from_pem(key).unwrap()).unwrap()
+ };
+
+ let public_key = {
+ let key = include_bytes!("../test/dsa.pem.pub");
+ PKey::from_dsa(Dsa::public_key_from_pem(key).unwrap()).unwrap()
+ };
+
+ let mut signer = Signer::new(MessageDigest::sha1(), &private_key).unwrap();
+ signer.update(&input).unwrap();
+ let mut sig = signer.finish().unwrap();
+ sig[0] -= 1;
+
+ let mut verifier = Verifier::new(MessageDigest::sha1(), &public_key).unwrap();
+ verifier.update(&input).unwrap();
+ match verifier.finish(&sig) {
+ Ok(true) => panic!("unexpected success"),
+ Ok(false) | Err(_) => {}
+ }
+ }
+
+ fn test_hmac(ty: MessageDigest, tests: &[(Vec<u8>, Vec<u8>, Vec<u8>)]) {
+ for &(ref key, ref data, ref res) in tests.iter() {
+ let pkey = PKey::hmac(key).unwrap();
+ let mut signer = Signer::new(ty, &pkey).unwrap();
+ signer.update(data).unwrap();
+ assert_eq!(signer.finish().unwrap(), *res);
+ }
+ }
+
+ #[test]
+ fn hmac_md5() {
+ // test vectors from RFC 2202
+ let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 7] =
+ [(iter::repeat(0x0b_u8).take(16).collect(),
+ b"Hi There".to_vec(),
+ "9294727a3638bb1c13f48ef8158bfc9d".from_hex().unwrap()),
+ (b"Jefe".to_vec(),
+ b"what do ya want for nothing?".to_vec(),
+ "750c783e6ab0b503eaa86e310a5db738".from_hex().unwrap()),
+ (iter::repeat(0xaa_u8).take(16).collect(),
+ iter::repeat(0xdd_u8).take(50).collect(),
+ "56be34521d144c88dbb8c733f0e8b3f6".from_hex().unwrap()),
+ ("0102030405060708090a0b0c0d0e0f10111213141516171819".from_hex().unwrap(),
+ iter::repeat(0xcd_u8).take(50).collect(),
+ "697eaf0aca3a3aea3a75164746ffaa79".from_hex().unwrap()),
+ (iter::repeat(0x0c_u8).take(16).collect(),
+ b"Test With Truncation".to_vec(),
+ "56461ef2342edc00f9bab995690efd4c".from_hex().unwrap()),
+ (iter::repeat(0xaa_u8).take(80).collect(),
+ b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
+ "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap()),
+ (iter::repeat(0xaa_u8).take(80).collect(),
+ b"Test Using Larger Than Block-Size Key \
+ and Larger Than One Block-Size Data"
+ .to_vec(),
+ "6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())];
+
+ test_hmac(MessageDigest::md5(), &tests);
+ }
+
+ #[test]
+ fn hmac_sha1() {
+ // test vectors from RFC 2202
+ let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 7] =
+ [(iter::repeat(0x0b_u8).take(20).collect(),
+ b"Hi There".to_vec(),
+ "b617318655057264e28bc0b6fb378c8ef146be00".from_hex().unwrap()),
+ (b"Jefe".to_vec(),
+ b"what do ya want for nothing?".to_vec(),
+ "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79".from_hex().unwrap()),
+ (iter::repeat(0xaa_u8).take(20).collect(),
+ iter::repeat(0xdd_u8).take(50).collect(),
+ "125d7342b9ac11cd91a39af48aa17b4f63f175d3".from_hex().unwrap()),
+ ("0102030405060708090a0b0c0d0e0f10111213141516171819".from_hex().unwrap(),
+ iter::repeat(0xcd_u8).take(50).collect(),
+ "4c9007f4026250c6bc8414f9bf50c86c2d7235da".from_hex().unwrap()),
+ (iter::repeat(0x0c_u8).take(20).collect(),
+ b"Test With Truncation".to_vec(),
+ "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04".from_hex().unwrap()),
+ (iter::repeat(0xaa_u8).take(80).collect(),
+ b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
+ "aa4ae5e15272d00e95705637ce8a3b55ed402112".from_hex().unwrap()),
+ (iter::repeat(0xaa_u8).take(80).collect(),
+ b"Test Using Larger Than Block-Size Key \
+ and Larger Than One Block-Size Data"
+ .to_vec(),
+ "e8e99d0f45237d786d6bbaa7965c7808bbff1a91".from_hex().unwrap())];
+
+ test_hmac(MessageDigest::sha1(), &tests);
+ }
+}
diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs
index c5663eb1..486b4dba 100644
--- a/openssl/src/ssl/bio.rs
+++ b/openssl/src/ssl/bio.rs
@@ -1,14 +1,14 @@
use libc::{c_char, c_int, c_long, c_void, strlen};
-use ffi::{self, BIO, BIO_CTRL_FLUSH, BIO_TYPE_NONE, BIO_new, BIO_clear_retry_flags,
- BIO_set_retry_read, BIO_set_retry_write};
+use ffi::{BIO, BIO_CTRL_FLUSH, BIO_new, BIO_clear_retry_flags, BIO_set_retry_read,
+ BIO_set_retry_write};
use std::any::Any;
use std::io;
use std::io::prelude::*;
use std::mem;
use std::ptr;
use std::slice;
-use std::sync::Arc;
+use cvt_p;
use error::ErrorStack;
pub struct StreamState<S> {
@@ -18,29 +18,19 @@ pub struct StreamState<S> {
}
/// Safe wrapper for BIO_METHOD
-pub struct BioMethod(ffi::BIO_METHOD);
+pub struct BioMethod(compat::BIO_METHOD);
impl BioMethod {
- pub fn new<S: Read + Write>() -> BioMethod {
- BioMethod(ffi::BIO_METHOD {
- type_: BIO_TYPE_NONE,
- name: b"rust\0".as_ptr() as *const _,
- bwrite: Some(bwrite::<S>),
- bread: Some(bread::<S>),
- bputs: Some(bputs::<S>),
- bgets: None,
- ctrl: Some(ctrl::<S>),
- create: Some(create),
- destroy: Some(destroy::<S>),
- callback_ctrl: None,
- })
+ fn new<S: Read + Write>() -> BioMethod {
+ BioMethod(compat::BIO_METHOD::new::<S>())
}
}
+unsafe impl Sync for BioMethod {}
unsafe impl Send for BioMethod {}
-pub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, Arc<BioMethod>), ErrorStack> {
- let method = Arc::new(BioMethod::new::<S>());
+pub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, BioMethod), ErrorStack> {
+ let method = BioMethod::new::<S>();
let state = Box::new(StreamState {
stream: stream,
@@ -49,9 +39,9 @@ pub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, Arc<BioMethod>), Err
});
unsafe {
- let bio = try_ssl_null!(BIO_new(&method.0));
- (*bio).ptr = Box::into_raw(state) as *mut _;
- (*bio).init = 1;
+ let bio = try!(cvt_p(BIO_new(method.0.get())));
+ compat::BIO_set_data(bio, Box::into_raw(state) as *mut _);
+ compat::BIO_set_init(bio, 1);
return Ok((bio, method));
}
@@ -62,14 +52,13 @@ pub unsafe fn take_error<S>(bio: *mut BIO) -> Option<io::Error> {
state.error.take()
}
-#[cfg_attr(not(feature = "nightly"), allow(dead_code))]
pub unsafe fn take_panic<S>(bio: *mut BIO) -> Option<Box<Any + Send>> {
let state = state::<S>(bio);
state.panic.take()
}
pub unsafe fn get_ref<'a, S: 'a>(bio: *mut BIO) -> &'a S {
- let state: &'a StreamState<S> = mem::transmute((*bio).ptr);
+ let state: &'a StreamState<S> = mem::transmute(compat::BIO_get_data(bio));
&state.stream
}
@@ -78,23 +67,15 @@ pub unsafe fn get_mut<'a, S: 'a>(bio: *mut BIO) -> &'a mut S {
}
unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState<S> {
- mem::transmute((*bio).ptr)
+ mem::transmute(compat::BIO_get_data(bio))
}
-#[cfg(feature = "nightly")]
fn catch_unwind<F, T>(f: F) -> Result<T, Box<Any + Send>>
where F: FnOnce() -> T
{
::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(f))
}
-#[cfg(not(feature = "nightly"))]
-fn catch_unwind<F, T>(f: F) -> Result<T, Box<Any + Send>>
- where F: FnOnce() -> T
-{
- Ok(f())
-}
-
unsafe extern "C" fn bwrite<S: Write>(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int {
BIO_clear_retry_flags(bio);
@@ -176,10 +157,10 @@ unsafe extern "C" fn ctrl<S: Write>(bio: *mut BIO,
}
unsafe extern "C" fn create(bio: *mut BIO) -> c_int {
- (*bio).init = 0;
- (*bio).num = 0;
- (*bio).ptr = ptr::null_mut();
- (*bio).flags = 0;
+ compat::BIO_set_init(bio, 0);
+ compat::BIO_set_num(bio, 0);
+ compat::BIO_set_data(bio, ptr::null_mut());
+ compat::BIO_set_flags(bio, 0);
1
}
@@ -188,9 +169,115 @@ unsafe extern "C" fn destroy<S>(bio: *mut BIO) -> c_int {
return 0;
}
- assert!(!(*bio).ptr.is_null());
- Box::<StreamState<S>>::from_raw((*bio).ptr as *mut _);
- (*bio).ptr = ptr::null_mut();
- (*bio).init = 0;
+ let data = compat::BIO_get_data(bio);
+ assert!(!data.is_null());
+ Box::<StreamState<S>>::from_raw(data as *mut _);
+ compat::BIO_set_data(bio, ptr::null_mut());
+ compat::BIO_set_init(bio, 0);
1
}
+
+#[cfg(ossl110)]
+#[allow(bad_style)]
+mod compat {
+ use std::io::{Read, Write};
+
+ use libc::c_int;
+ use ffi;
+ pub use ffi::{BIO_set_init, BIO_set_flags, BIO_set_data, BIO_get_data};
+
+ pub unsafe fn BIO_set_num(_bio: *mut ffi::BIO, _num: c_int) {}
+
+ pub struct BIO_METHOD(*mut ffi::BIO_METHOD);
+
+ impl BIO_METHOD {
+ pub fn new<S: Read + Write>() -> BIO_METHOD {
+ unsafe {
+ let ptr = ffi::BIO_meth_new(ffi::BIO_TYPE_NONE, b"rust\0".as_ptr() as *const _);
+ assert!(!ptr.is_null());
+ let ret = BIO_METHOD(ptr);
+ assert!(ffi::BIO_meth_set_write(ptr, super::bwrite::<S>) != 0);
+ assert!(ffi::BIO_meth_set_read(ptr, super::bread::<S>) != 0);
+ assert!(ffi::BIO_meth_set_puts(ptr, super::bputs::<S>) != 0);
+ assert!(ffi::BIO_meth_set_ctrl(ptr, super::ctrl::<S>) != 0);
+ assert!(ffi::BIO_meth_set_create(ptr, super::create) != 0);
+ assert!(ffi::BIO_meth_set_destroy(ptr, super::destroy::<S>) != 0);
+ return ret;
+ }
+ }
+
+ pub fn get(&self) -> *mut ffi::BIO_METHOD {
+ self.0
+ }
+ }
+
+ impl Drop for BIO_METHOD {
+ fn drop(&mut self) {
+ unsafe {
+ ffi::BIO_meth_free(self.0);
+ }
+ }
+ }
+}
+
+#[cfg(ossl10x)]
+#[allow(bad_style)]
+mod compat {
+ use std::io::{Read, Write};
+
+ use ffi;
+ use libc::{c_int, c_void};
+
+ pub struct BIO_METHOD(*mut ffi::BIO_METHOD);
+
+ impl BIO_METHOD {
+ pub fn new<S: Read + Write>() -> BIO_METHOD {
+ let ptr = Box::new(ffi::BIO_METHOD {
+ type_: ffi::BIO_TYPE_NONE,
+ name: b"rust\0".as_ptr() as *const _,
+ bwrite: Some(super::bwrite::<S>),
+ bread: Some(super::bread::<S>),
+ bputs: Some(super::bputs::<S>),
+ bgets: None,
+ ctrl: Some(super::ctrl::<S>),
+ create: Some(super::create),
+ destroy: Some(super::destroy::<S>),
+ callback_ctrl: None,
+ });
+
+ BIO_METHOD(Box::into_raw(ptr))
+ }
+
+ pub fn get(&self) -> *mut ffi::BIO_METHOD {
+ self.0
+ }
+ }
+
+ impl Drop for BIO_METHOD {
+ fn drop(&mut self) {
+ unsafe {
+ Box::<ffi::BIO_METHOD>::from_raw(self.0);
+ }
+ }
+ }
+
+ pub unsafe fn BIO_set_init(bio: *mut ffi::BIO, init: c_int) {
+ (*bio).init = init;
+ }
+
+ pub unsafe fn BIO_set_flags(bio: *mut ffi::BIO, flags: c_int) {
+ (*bio).flags = flags;
+ }
+
+ pub unsafe fn BIO_get_data(bio: *mut ffi::BIO) -> *mut c_void {
+ (*bio).ptr
+ }
+
+ pub unsafe fn BIO_set_data(bio: *mut ffi::BIO, data: *mut c_void) {
+ (*bio).ptr = data;
+ }
+
+ pub unsafe fn BIO_set_num(bio: *mut ffi::BIO, num: c_int) {
+ (*bio).num = num;
+ }
+}
diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs
new file mode 100644
index 00000000..0d92529d
--- /dev/null
+++ b/openssl/src/ssl/connector.rs
@@ -0,0 +1,452 @@
+use std::io::{Read, Write};
+
+use dh::Dh;
+use error::ErrorStack;
+use ssl::{self, SslMethod, SslContextBuilder, SslContext, Ssl, SSL_VERIFY_PEER, SslStream,
+ HandshakeError};
+use pkey::PKeyRef;
+use x509::X509Ref;
+
+// Serialized form of DH_get_2048_256
+#[cfg(any(ossl101, all(test, any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))))]
+const DHPARAM_PEM: &'static str = r#"
+-----BEGIN DH PARAMETERS-----
+MIICCQKCAQEAh6jmHbS2Zjz/u9GcZRlZmYzu9ghmDdDyXSzu1ENeOwDgDfjx1hlX
+1Pr330VhsqowFsPZETQJb6o79Cltgw6afCCeDGSXUXq9WoqdMGvPZ+2R+eZyW0dY
+wCLgse9Cdb97bFv8EdRfkIi5QfVOseWbuLw5oL8SMH9cT9twxYGyP3a2Osrhyqa3
+kC1SUmc1SIoO8TxtmlG/pKs62DR3llJNjvahZ7WkGCXZZ+FE5RQFZCUcysuD5rSG
+9rPKP3lxUGAmwLhX9omWKFbe1AEKvQvmIcOjlgpU5xDDdfJjddcBQQOktUMwwZiv
+EmEW0iduEXFfaTh3+tfvCcrbCUrpHhoVlwKCAQA/syybcxNNCy53UGZg7b1ITKex
+jyHvIFQH9Hk6GguhJRDbwVB3vkY//0/tSqwLtVW+OmwbDGtHsbw3c79+jG9ikBIo
++MKMuxilWuMTQQAKZQGW+THHelfy3fRj5ensFEt3feYqqrioYorDdtKC1u04ZOZ5
+gkKOvIMdFDSPby+Rk7UEWvJ2cWTh38lnwfs/LlWkvRv/6DucgNBSuYXRguoK2yo7
+cxPT/hTISEseBSWIubfSu9LfAWGZ7NBuFVfNCRWzNTu7ZODsN3/QKDcN+StSx4kU
+KM3GfrYYS1I9HbJGwy9jB4SQ8A741kfRSNR5VFFeIyfP75jFgmZLTA9sxBZZ
+-----END DH PARAMETERS-----
+"#;
+
+fn ctx(method: SslMethod) -> Result<SslContextBuilder, ErrorStack> {
+ let mut ctx = try!(SslContextBuilder::new(method));
+
+ let mut opts = ssl::SSL_OP_ALL;
+ opts |= ssl::SSL_OP_NO_TICKET;
+ opts |= ssl::SSL_OP_NO_COMPRESSION;
+ opts &= !ssl::SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
+ opts &= !ssl::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+ opts |= ssl::SSL_OP_NO_SSLV2;
+ opts |= ssl::SSL_OP_NO_SSLV3;
+ opts |= ssl::SSL_OP_SINGLE_DH_USE;
+ opts |= ssl::SSL_OP_SINGLE_ECDH_USE;
+ opts |= ssl::SSL_OP_CIPHER_SERVER_PREFERENCE;
+ ctx.set_options(opts);
+
+ let mode = ssl::SSL_MODE_AUTO_RETRY | ssl::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
+ ssl::SSL_MODE_ENABLE_PARTIAL_WRITE;
+ ctx.set_mode(mode);
+
+ Ok(ctx)
+}
+
+/// A builder for `SslConnector`s.
+pub struct SslConnectorBuilder(SslContextBuilder);
+
+impl SslConnectorBuilder {
+ /// Creates a new builder for TLS connections.
+ ///
+ /// The default configuration is subject to change, and is currently derived from Python.
+ pub fn new(method: SslMethod) -> Result<SslConnectorBuilder, ErrorStack> {
+ let mut ctx = try!(ctx(method));
+ try!(ctx.set_default_verify_paths());
+ // From https://github.com/python/cpython/blob/c30098c8c6014f3340a369a31df9c74bdbacc269/Lib/ssl.py#L191
+ try!(ctx.set_cipher_list("ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:\
+ DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:RSA+AESGCM:\
+ RSA+AES:RSA+HIGH:!aNULL:!eNULL:!MD5:!3DES"));
+
+ Ok(SslConnectorBuilder(ctx))
+ }
+
+ /// Returns a shared reference to the inner `SslContextBuilder`.
+ pub fn builder(&self) -> &SslContextBuilder {
+ &self.0
+ }
+
+ /// Returns a mutable reference to the inner `SslContextBuilder`.
+ pub fn builder_mut(&mut self) -> &mut SslContextBuilder {
+ &mut self.0
+ }
+
+ /// Consumes the builder, returning a `SslConnector`.
+ pub fn build(self) -> SslConnector {
+ SslConnector(self.0.build())
+ }
+}
+
+/// A type which wraps client-side streams in a TLS session.
+///
+/// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL
+/// structures, configuring cipher suites, session options, hostname verification, and more.
+///
+/// OpenSSL's built in hostname verification is used when linking against OpenSSL 1.0.2 or 1.1.0,
+/// and a custom implementation is used when linking against OpenSSL 1.0.1.
+pub struct SslConnector(SslContext);
+
+impl SslConnector {
+ /// Initiates a client-side TLS session on a stream.
+ ///
+ /// The domain is used for SNI and hostname verification.
+ pub fn connect<S>(&self, domain: &str, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
+ where S: Read + Write
+ {
+ let mut ssl = try!(Ssl::new(&self.0));
+ try!(ssl.set_hostname(domain));
+ try!(setup_verify(&mut ssl, domain));
+
+ ssl.connect(stream)
+ }
+}
+
+/// A builder for `SslAcceptor`s.
+pub struct SslAcceptorBuilder(SslContextBuilder);
+
+impl SslAcceptorBuilder {
+ /// Creates a new builder configured to connect to non-legacy clients. This should generally be
+ /// considered a reasonable default choice.
+ ///
+ /// This corresponds to the intermediate configuration of Mozilla's server side TLS
+ /// recommendations. See its [documentation][docs] for more details on specifics.
+ ///
+ /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS
+ pub fn mozilla_intermediate<I>(method: SslMethod,
+ private_key: &PKeyRef,
+ certificate: &X509Ref,
+ chain: I)
+ -> Result<SslAcceptorBuilder, ErrorStack>
+ where I: IntoIterator,
+ I::Item: AsRef<X509Ref>
+ {
+ let mut ctx = try!(ctx(method));
+ let dh = try!(get_dh());
+ try!(ctx.set_tmp_dh(&dh));
+ try!(setup_curves(&mut ctx));
+ try!(ctx.set_cipher_list("ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\
+ ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\
+ ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\
+ DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:\
+ ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:\
+ ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:\
+ ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:\
+ ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:\
+ DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:\
+ DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:\
+ ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:\
+ EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:\
+ AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:\
+ DES-CBC3-SHA:!DSS"));
+ SslAcceptorBuilder::finish_setup(ctx, private_key, certificate, chain)
+ }
+
+ /// Creates a new builder configured to connect to modern clients.
+ ///
+ /// This corresponds to the modern configuration of Mozilla's server side TLS recommendations.
+ /// See its [documentation][docs] for more details on specifics.
+ ///
+ /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS
+ pub fn mozilla_modern<I>(method: SslMethod,
+ private_key: &PKeyRef,
+ certificate: &X509Ref,
+ chain: I)
+ -> Result<SslAcceptorBuilder, ErrorStack>
+ where I: IntoIterator,
+ I::Item: AsRef<X509Ref>
+ {
+ let mut ctx = try!(ctx(method));
+ try!(setup_curves(&mut ctx));
+ try!(ctx.set_cipher_list("ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\
+ ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\
+ ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\
+ ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:\
+ ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"));
+ SslAcceptorBuilder::finish_setup(ctx, private_key, certificate, chain)
+ }
+
+ fn finish_setup<I>(mut ctx: SslContextBuilder,
+ private_key: &PKeyRef,
+ certificate: &X509Ref,
+ chain: I)
+ -> Result<SslAcceptorBuilder, ErrorStack>
+ where I: IntoIterator,
+ I::Item: AsRef<X509Ref>
+ {
+ try!(ctx.set_private_key(private_key));
+ try!(ctx.set_certificate(certificate));
+ try!(ctx.check_private_key());
+ for cert in chain {
+ try!(ctx.add_extra_chain_cert(cert.as_ref().to_owned()));
+ }
+ Ok(SslAcceptorBuilder(ctx))
+ }
+
+ /// Returns a shared reference to the inner `SslContextBuilder`.
+ pub fn builder(&self) -> &SslContextBuilder {
+ &self.0
+ }
+
+ /// Returns a mutable reference to the inner `SslContextBuilder`.
+ pub fn builder_mut(&mut self) -> &mut SslContextBuilder {
+ &mut self.0
+ }
+
+ /// Consumes the builder, returning a `SslAcceptor`.
+ pub fn build(self) -> SslAcceptor {
+ SslAcceptor(self.0.build())
+ }
+}
+
+#[cfg(ossl101)]
+fn get_dh() -> Result<Dh, ErrorStack> {
+ Dh::from_pem(DHPARAM_PEM.as_bytes())
+}
+
+#[cfg(not(ossl101))]
+fn get_dh() -> Result<Dh, ErrorStack> {
+ use ffi;
+
+ use cvt_p;
+ use types::OpenSslType;
+
+ // manually call into ffi to avoid forcing the features
+ unsafe { cvt_p(ffi::DH_get_2048_256()).map(|p| Dh::from_ptr(p)) }
+}
+
+#[cfg(ossl101)]
+fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> {
+ use ec_key::EcKey;
+ use nid;
+
+ let curve = try!(EcKey::new_by_curve_name(nid::X9_62_PRIME256V1));
+ ctx.set_tmp_ecdh(&curve)
+}
+
+#[cfg(ossl102)]
+fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> {
+ ctx._set_ecdh_auto(true)
+}
+
+#[cfg(ossl110)]
+fn setup_curves(_: &mut SslContextBuilder) -> Result<(), ErrorStack> {
+ Ok(())
+}
+
+/// A type which wraps server-side streams in a TLS session.
+///
+/// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL
+/// structures, configuring cipher suites, session options, and more.
+pub struct SslAcceptor(SslContext);
+
+impl SslAcceptor {
+ /// Initiates a server-side TLS session on a stream.
+ pub fn accept<S>(&self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
+ where S: Read + Write
+ {
+ let ssl = try!(Ssl::new(&self.0));
+ ssl.accept(stream)
+ }
+}
+
+#[cfg(any(ossl102, ossl110))]
+fn setup_verify(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> {
+ ssl.set_verify(SSL_VERIFY_PEER);
+ let param = ssl._param_mut();
+ param.set_hostflags(::verify::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
+ param.set_host(domain)
+}
+
+#[cfg(ossl101)]
+fn setup_verify(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> {
+ let domain = domain.to_owned();
+ ssl.set_verify_callback(SSL_VERIFY_PEER,
+ move |p, x| verify::verify_callback(&domain, p, x));
+ Ok(())
+}
+
+#[cfg(ossl101)]
+mod verify {
+ use std::net::IpAddr;
+ use std::str;
+
+ use nid;
+ use x509::{X509StoreContextRef, X509Ref, X509NameRef, GeneralName};
+ use stack::Stack;
+ use types::OpenSslTypeRef;
+
+ pub fn verify_callback(domain: &str,
+ preverify_ok: bool,
+ x509_ctx: &X509StoreContextRef)
+ -> bool {
+ if !preverify_ok || x509_ctx.error_depth() != 0 {
+ return preverify_ok;
+ }
+
+ match x509_ctx.current_cert() {
+ Some(x509) => verify_hostname(domain, &x509),
+ None => true,
+ }
+ }
+
+ fn verify_hostname(domain: &str, cert: &X509Ref) -> bool {
+ match cert.subject_alt_names() {
+ Some(names) => verify_subject_alt_names(domain, names),
+ None => verify_subject_name(domain, &cert.subject_name()),
+ }
+ }
+
+ fn verify_subject_alt_names(domain: &str, names: Stack<GeneralName>) -> bool {
+ let ip = domain.parse();
+
+ for name in &names {
+ match ip {
+ Ok(ip) => {
+ if let Some(actual) = name.ipaddress() {
+ if matches_ip(&ip, actual) {
+ return true;
+ }
+ }
+ }
+ Err(_) => {
+ if let Some(pattern) = name.dnsname() {
+ if matches_dns(pattern, domain, false) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ false
+ }
+
+ fn verify_subject_name(domain: &str, subject_name: &X509NameRef) -> bool {
+ if let Some(pattern) = subject_name.entries_by_nid(nid::COMMONNAME).next() {
+ let pattern = match str::from_utf8(pattern.data().as_slice()) {
+ Ok(pattern) => pattern,
+ Err(_) => return false,
+ };
+
+ // Unlike with SANs, IP addresses in the subject name don't have a
+ // different encoding. We need to pass this down to matches_dns to
+ // disallow wildcard matches with bogus patterns like *.0.0.1
+ let is_ip = domain.parse::<IpAddr>().is_ok();
+
+ if matches_dns(&pattern, domain, is_ip) {
+ return true;
+ }
+ }
+
+ false
+ }
+
+ fn matches_dns(mut pattern: &str, mut hostname: &str, is_ip: bool) -> bool {
+ // first strip trailing . off of pattern and hostname to normalize
+ if pattern.ends_with('.') {
+ pattern = &pattern[..pattern.len() - 1];
+ }
+ if hostname.ends_with('.') {
+ hostname = &hostname[..hostname.len() - 1];
+ }
+
+ matches_wildcard(pattern, hostname, is_ip).unwrap_or_else(|| pattern == hostname)
+ }
+
+ fn matches_wildcard(pattern: &str, hostname: &str, is_ip: bool) -> Option<bool> {
+ // IP addresses and internationalized domains can't involved in wildcards
+ if is_ip || pattern.starts_with("xn--") {
+ return None;
+ }
+
+ let wildcard_location = match pattern.find('*') {
+ Some(l) => l,
+ None => return None,
+ };
+
+ let mut dot_idxs = pattern.match_indices('.').map(|(l, _)| l);
+ let wildcard_end = match dot_idxs.next() {
+ Some(l) => l,
+ None => return None,
+ };
+
+ // Never match wildcards if the pattern has less than 2 '.'s (no *.com)
+ //
+ // This is a bit dubious, as it doesn't disallow other TLDs like *.co.uk.
+ // Chrome has a black- and white-list for this, but Firefox (via NSS) does
+ // the same thing we do here.
+ //
+ // The Public Suffix (https://www.publicsuffix.org/) list could
+ // potentically be used here, but it's both huge and updated frequently
+ // enough that management would be a PITA.
+ if dot_idxs.next().is_none() {
+ return None;
+ }
+
+ // Wildcards can only be in the first component
+ if wildcard_location > wildcard_end {
+ return None;
+ }
+
+ let hostname_label_end = match hostname.find('.') {
+ Some(l) => l,
+ None => return None,
+ };
+
+ // check that the non-wildcard parts are identical
+ if pattern[wildcard_end..] != hostname[hostname_label_end..] {
+ return Some(false);
+ }
+
+ let wildcard_prefix = &pattern[..wildcard_location];
+ let wildcard_suffix = &pattern[wildcard_location + 1..wildcard_end];
+
+ let hostname_label = &hostname[..hostname_label_end];
+
+ // check the prefix of the first label
+ if !hostname_label.starts_with(wildcard_prefix) {
+ return Some(false);
+ }
+
+ // and the suffix
+ if !hostname_label[wildcard_prefix.len()..].ends_with(wildcard_suffix) {
+ return Some(false);
+ }
+
+ Some(true)
+ }
+
+ fn matches_ip(expected: &IpAddr, actual: &[u8]) -> bool {
+ match (expected, actual.len()) {
+ (&IpAddr::V4(ref addr), 4) => actual == addr.octets(),
+ (&IpAddr::V6(ref addr), 16) => {
+ let segments = [((actual[0] as u16) << 8) | actual[1] as u16,
+ ((actual[2] as u16) << 8) | actual[3] as u16,
+ ((actual[4] as u16) << 8) | actual[5] as u16,
+ ((actual[6] as u16) << 8) | actual[7] as u16,
+ ((actual[8] as u16) << 8) | actual[9] as u16,
+ ((actual[10] as u16) << 8) | actual[11] as u16,
+ ((actual[12] as u16) << 8) | actual[13] as u16,
+ ((actual[14] as u16) << 8) | actual[15] as u16];
+ segments == addr.segments()
+ }
+ _ => false,
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
+ #[test]
+ fn check_dhparam() {
+ use dh::Dh;
+
+ let expected = String::from_utf8(Dh::get_2048_256().unwrap().to_pem().unwrap()).unwrap();
+ assert_eq!(expected.trim(), super::DHPARAM_PEM.trim());
+ }
+}
diff --git a/openssl/src/ssl/error.rs b/openssl/src/ssl/error.rs
index 95213361..518ae90f 100644
--- a/openssl/src/ssl/error.rs
+++ b/openssl/src/ssl/error.rs
@@ -1,8 +1,11 @@
+use std::any::Any;
use std::error;
use std::error::Error as StdError;
use std::fmt;
use std::io;
+
use error::ErrorStack;
+use ssl::MidHandshakeSslStream;
/// An SSL error.
#[derive(Debug)]
@@ -62,3 +65,55 @@ impl From<ErrorStack> for Error {
Error::Ssl(e)
}
}
+
+/// An error or intermediate state after a TLS handshake attempt.
+#[derive(Debug)]
+pub enum HandshakeError<S> {
+ /// Setup failed.
+ SetupFailure(ErrorStack),
+ /// The handshake failed.
+ Failure(MidHandshakeSslStream<S>),
+ /// The handshake was interrupted midway through.
+ Interrupted(MidHandshakeSslStream<S>),
+}
+
+impl<S: Any + fmt::Debug> StdError for HandshakeError<S> {
+ fn description(&self) -> &str {
+ match *self {
+ HandshakeError::SetupFailure(_) => "stream setup failed",
+ HandshakeError::Failure(_) => "the handshake failed",
+ HandshakeError::Interrupted(_) => "the handshake was interrupted",
+ }
+ }
+
+ fn cause(&self) -> Option<&StdError> {
+ match *self {
+ HandshakeError::SetupFailure(ref e) => Some(e),
+ HandshakeError::Failure(ref s) |
+ HandshakeError::Interrupted(ref s) => Some(s.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::description(self)));
+ match *self {
+ HandshakeError::SetupFailure(ref e) => try!(write!(f, ": {}", e)),
+ HandshakeError::Failure(ref s) |
+ HandshakeError::Interrupted(ref s) => {
+ try!(write!(f, ": {}", s.error()));
+ if let Some(err) = s.ssl().verify_result() {
+ try!(write!(f, ": {}", err));
+ }
+ }
+ }
+ Ok(())
+ }
+}
+
+impl<S> From<ErrorStack> for HandshakeError<S> {
+ fn from(e: ErrorStack) -> HandshakeError<S> {
+ HandshakeError::SetupFailure(e)
+ }
+}
diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs
index 6e365af6..9a477993 100644
--- a/openssl/src/ssl/mod.rs
+++ b/openssl/src/ssl/mod.rs
@@ -1,49 +1,123 @@
-use libc::{c_int, c_void, c_long};
+//! SSL/TLS support.
+//!
+//! `SslConnector` and `SslAcceptor` should be used in most cases - they handle
+//! configuration of the OpenSSL primitives for you.
+//!
+//! # Examples
+//!
+//! To connect as a client to a remote server:
+//!
+//! ```
+//! use openssl::ssl::{SslMethod, SslConnectorBuilder};
+//! use std::io::{Read, Write};
+//! use std::net::TcpStream;
+//!
+//! let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build();
+//!
+//! let stream = TcpStream::connect("google.com:443").unwrap();
+//! let mut stream = connector.connect("google.com", stream).unwrap();
+//!
+//! stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
+//! let mut res = vec![];
+//! stream.read_to_end(&mut res).unwrap();
+//! println!("{}", String::from_utf8_lossy(&res));
+//! ```
+//!
+//! To accept connections as a server from remote clients:
+//!
+//! ```no_run
+//! use openssl::pkcs12::Pkcs12;
+//! use openssl::ssl::{SslMethod, SslAcceptorBuilder, SslStream};
+//! use std::fs::File;
+//! use std::io::{Read, Write};
+//! use std::net::{TcpListener, TcpStream};
+//! use std::sync::Arc;
+//! use std::thread;
+//!
+//! // In this example we retrieve our keypair and certificate chain from a PKCS #12 archive,
+//! // but but they can also be retrieved from, for example, individual PEM- or DER-formatted
+//! // files. See the documentation for the `PKey` and `X509` types for more details.
+//! let mut file = File::open("identity.pfx").unwrap();
+//! let mut pkcs12 = vec![];
+//! file.read_to_end(&mut pkcs12).unwrap();
+//! let pkcs12 = Pkcs12::from_der(&pkcs12).unwrap();
+//! let identity = pkcs12.parse("password123").unwrap();
+//!
+//! let acceptor = SslAcceptorBuilder::mozilla_intermediate(SslMethod::tls(),
+//! &identity.pkey,
+//! &identity.cert,
+//! &identity.chain)
+//! .unwrap()
+//! .build();
+//! let acceptor = Arc::new(acceptor);
+//!
+//! let listener = TcpListener::bind("0.0.0.0:8443").unwrap();
+//!
+//! fn handle_client(stream: SslStream<TcpStream>) {
+//! // ...
+//! }
+//!
+//! for stream in listener.incoming() {
+//! match stream {
+//! Ok(stream) => {
+//! let acceptor = acceptor.clone();
+//! thread::spawn(move || {
+//! let stream = acceptor.accept(stream).unwrap();
+//! handle_client(stream);
+//! });
+//! }
+//! Err(e) => { /* connection failed */ }
+//! }
+//! }
+//! ```
+use ffi;
+use libc::{c_int, c_void, c_long, c_ulong};
+use libc::{c_uchar, c_uint};
use std::any::Any;
use std::any::TypeId;
use std::cmp;
use std::collections::HashMap;
-use std::error as stderror;
use std::ffi::{CStr, CString};
use std::fmt;
use std::io;
use std::io::prelude::*;
+use std::marker::PhantomData;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::path::Path;
use std::ptr;
-use std::str;
-use std::sync::{Mutex, Arc};
-#[cfg(any(feature = "npn", feature = "alpn"))]
-use libc::{c_uchar, c_uint};
-#[cfg(any(feature = "npn", feature = "alpn"))]
use std::slice;
-use std::marker::PhantomData;
-use ffi;
-
-use init;
-use dh::DH;
-use x509::{X509StoreContext, X509FileType, X509, X509Ref};
-use crypto::pkey::PKey;
+use std::str;
+use std::sync::Mutex;
+
+use {init, cvt, cvt_p};
+use dh::DhRef;
+use ec_key::EcKeyRef;
+use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError};
+#[cfg(any(ossl102, ossl110))]
+use verify::X509VerifyParamRef;
+use pkey::PKeyRef;
use error::ErrorStack;
+use types::{OpenSslType, OpenSslTypeRef};
+use util::Opaque;
-pub mod error;
+mod error;
+mod connector;
mod bio;
#[cfg(test)]
mod tests;
use self::bio::BioMethod;
-#[doc(inline)]
-pub use ssl::error::Error;
+pub use ssl::connector::{SslConnectorBuilder, SslConnector, SslAcceptorBuilder, SslAcceptor};
+pub use ssl::error::{Error, HandshakeError};
bitflags! {
- pub flags SslContextOptions: c_long {
+ pub flags SslOption: c_ulong {
const SSL_OP_MICROSOFT_SESS_ID_BUG = ffi::SSL_OP_MICROSOFT_SESS_ID_BUG,
const SSL_OP_NETSCAPE_CHALLENGE_BUG = ffi::SSL_OP_NETSCAPE_CHALLENGE_BUG,
const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG =
ffi::SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG,
- const SSL_OP_TLSEXT_PADDING = ffi::SSL_OP_TLSEXT_PADDING,
const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = ffi::SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER,
const SSL_OP_SSLEAY_080_CLIENT_DH_BUG = ffi::SSL_OP_SSLEAY_080_CLIENT_DH_BUG,
const SSL_OP_TLS_D5_BUG = ffi::SSL_OP_TLS_D5_BUG,
@@ -66,80 +140,59 @@ bitflags! {
const SSL_OP_NO_SSLV2 = ffi::SSL_OP_NO_SSLv2,
const SSL_OP_NO_SSLV3 = ffi::SSL_OP_NO_SSLv3,
const SSL_OP_NO_TLSV1 = ffi::SSL_OP_NO_TLSv1,
+ const SSL_OP_NO_TLSV1_2 = ffi::SSL_OP_NO_TLSv1_2,
+ const SSL_OP_NO_TLSV1_1 = ffi::SSL_OP_NO_TLSv1_1,
+ /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
+ #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
+ const SSL_OP_NO_DTLSV1 = ffi::SSL_OP_NO_DTLSv1,
+ /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
+ #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
+ const SSL_OP_NO_DTLSV1_2 = ffi::SSL_OP_NO_DTLSv1_2,
+ /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
+ #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
+ const SSL_OP_NO_SSL_MASK = ffi::SSL_OP_NO_SSL_MASK,
}
}
-/// Determines the SSL method supported
-#[allow(non_camel_case_types)]
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum SslMethod {
- #[cfg(feature = "sslv2")]
- /// Only support the SSLv2 protocol, requires the `sslv2` feature.
- Sslv2,
- /// Support the SSLv2, SSLv3, TLSv1, TLSv1.1, and TLSv1.2 protocols depending on what the
- /// linked OpenSSL library supports.
- Sslv23,
- #[cfg(feature = "sslv3")]
- /// Only support the SSLv3 protocol.
- Sslv3,
- /// Only support the TLSv1 protocol.
- Tlsv1,
- #[cfg(feature = "tlsv1_1")]
- /// Support TLSv1.1 protocol, requires the `tlsv1_1` feature.
- Tlsv1_1,
- #[cfg(feature = "tlsv1_2")]
- /// Support TLSv1.2 protocol, requires the `tlsv1_2` feature.
- Tlsv1_2,
- #[cfg(feature = "dtlsv1")]
- /// Support DTLSv1 protocol, requires the `dtlsv1` feature.
- Dtlsv1,
- #[cfg(feature = "dtlsv1_2")]
- /// Support DTLSv1.2 protocol, requires the `dtlsv1_2` feature.
- Dtlsv1_2,
+bitflags! {
+ pub flags SslMode: c_long {
+ const SSL_MODE_ENABLE_PARTIAL_WRITE = ffi::SSL_MODE_ENABLE_PARTIAL_WRITE,
+ const SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER = ffi::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER,
+ const SSL_MODE_AUTO_RETRY = ffi::SSL_MODE_AUTO_RETRY,
+ const SSL_MODE_NO_AUTO_CHAIN = ffi::SSL_MODE_NO_AUTO_CHAIN,
+ const SSL_MODE_RELEASE_BUFFERS = ffi::SSL_MODE_RELEASE_BUFFERS,
+ const SSL_MODE_SEND_CLIENTHELLO_TIME = ffi::SSL_MODE_SEND_CLIENTHELLO_TIME,
+ const SSL_MODE_SEND_SERVERHELLO_TIME = ffi::SSL_MODE_SEND_SERVERHELLO_TIME,
+ const SSL_MODE_SEND_FALLBACK_SCSV = ffi::SSL_MODE_SEND_FALLBACK_SCSV,
+ }
}
+#[derive(Copy, Clone)]
+pub struct SslMethod(*const ffi::SSL_METHOD);
+
impl SslMethod {
- fn to_raw(&self) -> *const ffi::SSL_METHOD {
- unsafe {
- match *self {
- #[cfg(feature = "sslv2")]
- SslMethod::Sslv2 => ffi::SSLv2_method(),
- #[cfg(feature = "sslv3")]
- SslMethod::Sslv3 => ffi::SSLv3_method(),
- SslMethod::Tlsv1 => ffi::TLSv1_method(),
- SslMethod::Sslv23 => ffi::SSLv23_method(),
- #[cfg(feature = "tlsv1_1")]
- SslMethod::Tlsv1_1 => ffi::TLSv1_1_method(),
- #[cfg(feature = "tlsv1_2")]
- SslMethod::Tlsv1_2 => ffi::TLSv1_2_method(),
- #[cfg(feature = "dtlsv1")]
- SslMethod::Dtlsv1 => ffi::DTLSv1_method(),
- #[cfg(feature = "dtlsv1_2")]
- SslMethod::Dtlsv1_2 => ffi::DTLSv1_2_method(),
- }
- }
+ /// Support all versions of the TLS protocol.
+ ///
+ /// This corresponds to `TLS_method` on OpenSSL 1.1.0 and `SSLv23_method`
+ /// on OpenSSL 1.0.x.
+ pub fn tls() -> SslMethod {
+ SslMethod(compat::tls_method())
}
- fn from_raw(method: *const ffi::SSL_METHOD) -> Option<SslMethod> {
- unsafe {
- match method {
- #[cfg(feature = "sslv2")]
- x if x == ffi::SSLv2_method() => Some(SslMethod::Sslv2),
- #[cfg(feature = "sslv3")]
- x if x == ffi::SSLv3_method() => Some(SslMethod::Sslv3),
- x if x == ffi::TLSv1_method() => Some(SslMethod::Tlsv1),
- x if x == ffi::SSLv23_method() => Some(SslMethod::Sslv23),
- #[cfg(feature = "tlsv1_1")]
- x if x == ffi::TLSv1_1_method() => Some(SslMethod::Tlsv1_1),
- #[cfg(feature = "tlsv1_2")]
- x if x == ffi::TLSv1_2_method() => Some(SslMethod::Tlsv1_2),
- #[cfg(feature = "dtlsv1")]
- x if x == ffi::DTLSv1_method() => Some(SslMethod::Dtlsv1),
- #[cfg(feature = "dtlsv1_2")]
- x if x == ffi::DTLSv1_2_method() => Some(SslMethod::Dtlsv1_2),
- _ => None,
- }
- }
+ /// Support all versions of the DTLS protocol.
+ ///
+ /// This corresponds to `DTLS_method` on OpenSSL 1.1.0 and `DTLSv1_method`
+ /// on OpenSSL 1.0.x.
+ pub fn dtls() -> SslMethod {
+ SslMethod(compat::dtls_method())
+ }
+
+ pub unsafe fn from_ptr(ptr: *const ffi::SSL_METHOD) -> SslMethod {
+ SslMethod(ptr)
+ }
+
+ pub fn as_ptr(&self) -> *const ffi::SSL_METHOD {
+ self.0
}
}
@@ -172,85 +225,72 @@ fn get_ssl_verify_data_idx<T: Any + 'static>() -> c_int {
*SSL_INDEXES.lock().unwrap().entry(TypeId::of::<T>()).or_insert_with(|| get_new_ssl_idx::<T>())
}
-#[cfg(feature = "npn")]
lazy_static! {
static ref NPN_PROTOS_IDX: c_int = get_new_idx::<Vec<u8>>();
}
-#[cfg(feature = "alpn")]
+
+#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
lazy_static! {
static ref ALPN_PROTOS_IDX: c_int = get_new_idx::<Vec<u8>>();
}
+unsafe extern "C" fn free_data_box<T>(_parent: *mut c_void,
+ ptr: *mut c_void,
+ _ad: *mut ffi::CRYPTO_EX_DATA,
+ _idx: c_int,
+ _argl: c_long,
+ _argp: *mut c_void) {
+ if !ptr.is_null() {
+ Box::<T>::from_raw(ptr as *mut T);
+ }
+}
+
/// Determine a new index to use for SSL CTX ex data.
/// Registers a destruct for the data which will be called by openssl when the context is freed.
fn get_new_idx<T>() -> c_int {
- extern "C" fn free_data_box<T>(_parent: *mut c_void,
- ptr: *mut c_void,
- _ad: *mut ffi::CRYPTO_EX_DATA,
- _idx: c_int,
- _argl: c_long,
- _argp: *mut c_void) {
- if !ptr.is_null() {
- let _: Box<T> = unsafe { mem::transmute(ptr) };
- }
- }
-
unsafe {
- let f: ffi::CRYPTO_EX_free = free_data_box::<T>;
- let idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, Some(f));
+ let idx = compat::get_new_idx(free_data_box::<T>);
assert!(idx >= 0);
idx
}
}
fn get_new_ssl_idx<T>() -> c_int {
- extern "C" fn free_data_box<T>(_parent: *mut c_void,
- ptr: *mut c_void,
- _ad: *mut ffi::CRYPTO_EX_DATA,
- _idx: c_int,
- _argl: c_long,
- _argp: *mut c_void) {
- if !ptr.is_null() {
- let _: Box<T> = unsafe { mem::transmute(ptr) };
- }
- }
-
unsafe {
- let f: ffi::CRYPTO_EX_free = free_data_box::<T>;
- let idx = ffi::SSL_get_ex_new_index(0, ptr::null(), None, None, Some(f));
+ let idx = compat::get_new_ssl_idx(free_data_box::<T>);
assert!(idx >= 0);
idx
}
}
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
+ where F: Fn(bool, &X509StoreContextRef) -> 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 ssl_ctx = ffi::SSL_get_SSL_CTX(ssl as *const _);
let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::<F>());
- let verify: &F = mem::transmute(verify);
+ let verify: &F = &*(verify as *mut F);
- let ctx = X509StoreContext::new(x509_ctx);
+ let ctx = X509StoreContextRef::from_ptr(x509_ctx);
- verify(preverify_ok != 0, &ctx) as c_int
+ verify(preverify_ok != 0, ctx) as c_int
}
}
extern "C" fn ssl_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
+ where F: Fn(bool, &X509StoreContextRef) -> 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 verify = ffi::SSL_get_ex_data(ssl, get_ssl_verify_data_idx::<F>());
- let verify: &F = mem::transmute(verify);
+ let verify = ffi::SSL_get_ex_data(ssl as *const _, get_ssl_verify_data_idx::<F>());
+ let verify: &F = &*(verify as *mut F);
- let ctx = X509StoreContext::new(x509_ctx);
+ let ctx = X509StoreContextRef::from_ptr(x509_ctx);
- verify(preverify_ok != 0, &ctx) as c_int
+ verify(preverify_ok != 0, ctx) as c_int
}
}
@@ -260,10 +300,10 @@ extern "C" fn raw_sni<F>(ssl: *mut ffi::SSL, al: *mut c_int, _arg: *mut c_void)
unsafe {
let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::<F>());
- let callback: &F = mem::transmute(callback);
- let mut ssl = SslRef::from_ptr(ssl);
+ let callback: &F = &*(callback as *mut F);
+ let ssl = SslRef::from_ptr_mut(ssl);
- match callback(&mut ssl) {
+ match callback(ssl) {
Ok(()) => ffi::SSL_TLSEXT_ERR_OK,
Err(SniError::Fatal(e)) => {
*al = e;
@@ -278,7 +318,6 @@ extern "C" fn raw_sni<F>(ssl: *mut ffi::SSL, al: *mut c_int, _arg: *mut c_void)
}
}
-#[cfg(any(feature = "npn", feature = "alpn"))]
unsafe fn select_proto_using(ssl: *mut ffi::SSL,
out: *mut *mut c_uchar,
outlen: *mut c_uchar,
@@ -291,7 +330,7 @@ unsafe fn select_proto_using(ssl: *mut ffi::SSL,
// extra data.
let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
let protocols = ffi::SSL_CTX_get_ex_data(ssl_ctx, ex_data);
- let protocols: &Vec<u8> = mem::transmute(protocols);
+ let protocols: &Vec<u8> = &*(protocols as *mut Vec<u8>);
// Prepare the client list parameters to be passed to the OpenSSL function...
let client = protocols.as_ptr();
let client_len = protocols.len() as c_uint;
@@ -311,7 +350,6 @@ unsafe fn select_proto_using(ssl: *mut ffi::SSL,
/// supported by the server. It achieves this by delegating to the `SSL_select_next_proto`
/// function. The list of protocols supported by the client is found in the extra data of the
/// OpenSSL context.
-#[cfg(feature = "npn")]
extern "C" fn raw_next_proto_select_cb(ssl: *mut ffi::SSL,
out: *mut *mut c_uchar,
outlen: *mut c_uchar,
@@ -322,15 +360,15 @@ extern "C" fn raw_next_proto_select_cb(ssl: *mut ffi::SSL,
unsafe { select_proto_using(ssl, out, outlen, inbuf, inlen, *NPN_PROTOS_IDX) }
}
-#[cfg(feature = "alpn")]
+#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
extern "C" fn raw_alpn_select_cb(ssl: *mut ffi::SSL,
- out: *mut *mut c_uchar,
+ out: *mut *const c_uchar,
outlen: *mut c_uchar,
inbuf: *const c_uchar,
inlen: c_uint,
_arg: *mut c_void)
-> c_int {
- unsafe { select_proto_using(ssl, out, outlen, inbuf, inlen, *ALPN_PROTOS_IDX) }
+ unsafe { select_proto_using(ssl, out as *mut _, outlen, inbuf, inlen, *ALPN_PROTOS_IDX) }
}
/// The function is given as the callback to `SSL_CTX_set_next_protos_advertised_cb`.
@@ -340,7 +378,6 @@ extern "C" fn raw_alpn_select_cb(ssl: *mut ffi::SSL,
/// that it supports.
/// The list of supported protocols is found in the extra data of the OpenSSL
/// context.
-#[cfg(feature = "npn")]
extern "C" fn raw_next_protos_advertise_cb(ssl: *mut ffi::SSL,
out: *mut *const c_uchar,
outlen: *mut c_uint,
@@ -356,7 +393,7 @@ extern "C" fn raw_next_protos_advertise_cb(ssl: *mut ffi::SSL,
} else {
// If the pointer is valid, put the pointer to the actual byte array into the
// output parameter `out`, as well as its length into `outlen`.
- let protocols: &Vec<u8> = mem::transmute(protocols);
+ let protocols: &Vec<u8> = &*(protocols as *mut Vec<u8>);
*out = protocols.as_ptr();
*outlen = protocols.len() as c_uint;
}
@@ -367,7 +404,6 @@ extern "C" fn raw_next_protos_advertise_cb(ssl: *mut ffi::SSL,
/// Convert a set of byte slices into a series of byte strings encoded for SSL. Encoding is a byte
/// containing the length followed by the string.
-#[cfg(any(feature = "npn", feature = "alpn"))]
fn ssl_encode_byte_strings(strings: &[&[u8]]) -> Vec<u8> {
let mut enc = Vec::new();
for string in strings {
@@ -389,22 +425,30 @@ pub enum SniError {
NoAck,
}
-// FIXME: macro may be instead of inlining?
-#[inline]
-fn wrap_ssl_result(res: c_int) -> Result<(), ErrorStack> {
- if res == 0 {
- Err(ErrorStack::get())
- } else {
- Ok(())
+/// A builder for `SslContext`s.
+pub struct SslContextBuilder(*mut ffi::SSL_CTX);
+
+unsafe impl Sync for SslContextBuilder {}
+unsafe impl Send for SslContextBuilder {}
+
+impl Drop for SslContextBuilder {
+ fn drop(&mut self) {
+ unsafe { ffi::SSL_CTX_free(self.as_ptr()) }
}
}
-/// A borrowed SSL context object.
-pub struct SslContextRef<'a>(*mut ffi::SSL_CTX, PhantomData<&'a ()>);
+impl SslContextBuilder {
+ pub fn new(method: SslMethod) -> Result<SslContextBuilder, ErrorStack> {
+ unsafe {
+ init();
+ let ctx = try!(cvt_p(ffi::SSL_CTX_new(method.as_ptr())));
-impl<'a> SslContextRef<'a> {
- pub unsafe fn from_ptr(ctx: *mut ffi::SSL_CTX) -> SslContextRef<'a> {
- SslContextRef(ctx, PhantomData)
+ Ok(SslContextBuilder::from_ptr(ctx))
+ }
+ }
+
+ pub unsafe fn from_ptr(ctx: *mut ffi::SSL_CTX) -> SslContextBuilder {
+ SslContextBuilder(ctx)
}
pub fn as_ptr(&self) -> *mut ffi::SSL_CTX {
@@ -421,11 +465,13 @@ impl<'a> SslContextRef<'a> {
/// 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
+ where F: Fn(bool, &X509StoreContextRef) -> bool + Any + 'static + Sync + Send
{
unsafe {
let verify = Box::new(verify);
- ffi::SSL_CTX_set_ex_data(self.as_ptr(), get_verify_data_idx::<F>(), mem::transmute(verify));
+ ffi::SSL_CTX_set_ex_data(self.as_ptr(),
+ get_verify_data_idx::<F>(),
+ mem::transmute(verify));
ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, Some(raw_verify::<F>));
}
}
@@ -455,18 +501,25 @@ impl<'a> SslContextRef<'a> {
}
}
- pub fn set_read_ahead(&mut self, m: u32) {
+ pub fn set_read_ahead(&mut self, read_ahead: bool) {
unsafe {
- ffi::SSL_CTX_set_read_ahead(self.as_ptr(), m as c_long);
+ ffi::SSL_CTX_set_read_ahead(self.as_ptr(), read_ahead as c_long);
}
}
- fn set_mode(&mut self, mode: c_long) -> Result<(), ErrorStack> {
- wrap_ssl_result(unsafe { ffi::SSL_CTX_set_mode(self.as_ptr(), mode) as c_int })
+ pub fn set_mode(&mut self, mode: SslMode) -> SslMode {
+ unsafe {
+ let mode = ffi::SSL_CTX_set_mode(self.as_ptr(), mode.bits());
+ SslMode::from_bits(mode).unwrap()
+ }
+ }
+
+ pub fn set_tmp_dh(&mut self, dh: &DhRef) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::SSL_CTX_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) }
}
- pub fn set_tmp_dh(&mut self, dh: &DH) -> Result<(), ErrorStack> {
- wrap_ssl_result(unsafe { ffi::SSL_CTX_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as i32 })
+ pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::SSL_CTX_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) }
}
/// Use the default locations of trusted certificates for verification.
@@ -475,16 +528,18 @@ impl<'a> SslContextRef<'a> {
/// environment variables if present, or defaults specified at OpenSSL
/// build time otherwise.
pub fn set_default_verify_paths(&mut self) -> Result<(), ErrorStack> {
- wrap_ssl_result(unsafe { ffi::SSL_CTX_set_default_verify_paths(self.as_ptr()) })
+ unsafe { cvt(ffi::SSL_CTX_set_default_verify_paths(self.as_ptr())).map(|_| ()) }
}
- #[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<(), 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.as_ptr(), file.as_ptr() as *const _, ptr::null())
- })
+ 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().unwrap()).unwrap();
+ unsafe {
+ cvt(ffi::SSL_CTX_load_verify_locations(self.as_ptr(),
+ file.as_ptr() as *const _,
+ ptr::null()))
+ .map(|_| ())
+ }
}
/// Set the context identifier for sessions
@@ -496,9 +551,13 @@ impl<'a> SslContextRef<'a> {
/// 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<(), ErrorStack> {
- wrap_ssl_result(unsafe {
- ffi::SSL_CTX_set_session_id_context(self.as_ptr(), sid_ctx.as_ptr(), sid_ctx.len() as u32)
- })
+ unsafe {
+ assert!(sid_ctx.len() <= c_uint::max_value() as usize);
+ cvt(ffi::SSL_CTX_set_session_id_context(self.as_ptr(),
+ sid_ctx.as_ptr(),
+ sid_ctx.len() as c_uint))
+ .map(|_| ())
+ }
}
/// Specifies the file that contains certificate
@@ -506,43 +565,39 @@ impl<'a> SslContextRef<'a> {
file: P,
file_type: X509FileType)
-> 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.as_ptr(),
- file.as_ptr() as *const _,
- file_type as c_int)
- })
+ let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
+ unsafe {
+ cvt(ffi::SSL_CTX_use_certificate_file(self.as_ptr(),
+ file.as_ptr() as *const _,
+ file_type.as_raw()))
+ .map(|_| ())
+ }
}
/// Specifies the file that contains certificate chain
pub fn set_certificate_chain_file<P: AsRef<Path>>(&mut self,
- file: P,
- file_type: X509FileType)
+ 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_use_certificate_chain_file(self.as_ptr(),
- file.as_ptr() as *const _,
- file_type as c_int)
- })
+ let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
+ unsafe {
+ cvt(ffi::SSL_CTX_use_certificate_chain_file(self.as_ptr(), file.as_ptr() as *const _))
+ .map(|_| ())
+ }
}
/// Specifies the certificate
pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
- wrap_ssl_result(unsafe { ffi::SSL_CTX_use_certificate(self.as_ptr(), cert.as_ptr()) })
+ unsafe { cvt(ffi::SSL_CTX_use_certificate(self.as_ptr(), cert.as_ptr())).map(|_| ()) }
}
/// 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: &X509Ref) -> Result<(), ErrorStack> {
- // FIXME this should really just take an X509 by value
- let der = try!(cert.to_der());
- let cert = try!(X509::from_der(&der));
+ pub fn add_extra_chain_cert(&mut self, cert: X509) -> Result<(), ErrorStack> {
unsafe {
- try_ssl!(ffi::SSL_CTX_add_extra_chain_cert(self.as_ptr(), cert.as_ptr()));
+ try!(cvt(ffi::SSL_CTX_add_extra_chain_cert(self.as_ptr(), cert.as_ptr()) as c_int));
+ mem::forget(cert);
+ Ok(())
}
- mem::forget(cert);
- Ok(())
}
/// Specifies the file that contains private key
@@ -550,61 +605,61 @@ impl<'a> SslContextRef<'a> {
file: P,
file_type: X509FileType)
-> 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.as_ptr(),
- file.as_ptr() as *const _,
- file_type as c_int)
- })
+ let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
+ unsafe {
+ cvt(ffi::SSL_CTX_use_PrivateKey_file(self.as_ptr(),
+ file.as_ptr() as *const _,
+ file_type.as_raw()))
+ .map(|_| ())
+ }
}
/// Specifies the private key
- pub fn set_private_key(&mut self, key: &PKey) -> Result<(), ErrorStack> {
- wrap_ssl_result(unsafe { ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr()) })
- }
-
- /// Check consistency of private key and certificate
- pub fn check_private_key(&mut self) -> Result<(), ErrorStack> {
- wrap_ssl_result(unsafe { ffi::SSL_CTX_check_private_key(self.as_ptr()) })
+ pub fn set_private_key(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr())).map(|_| ()) }
}
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.as_ptr(), cipher_list.as_ptr() as *const _)
- })
+ let cipher_list = CString::new(cipher_list).unwrap();
+ unsafe {
+ cvt(ffi::SSL_CTX_set_cipher_list(self.as_ptr(), cipher_list.as_ptr() as *const _))
+ .map(|_| ())
+ }
}
- /// If `onoff` is set to `true`, enable ECDHE for key exchange with compatible
- /// clients, and automatically select an appropriate elliptic curve.
+ /// If `onoff` is set to `true`, enable ECDHE for key exchange with
+ /// compatible clients, and automatically select an appropriate elliptic
+ /// curve.
///
- /// This method requires OpenSSL >= 1.0.2 or LibreSSL and the `ecdh_auto` feature.
- #[cfg(feature = "ecdh_auto")]
+ /// Requires the `v102` feature and OpenSSL 1.0.2.
+ #[cfg(all(feature = "v102", ossl102))]
pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
- wrap_ssl_result(unsafe { ffi::SSL_CTX_set_ecdh_auto(self.as_ptr(), onoff as c_long) as c_int })
+ self._set_ecdh_auto(onoff)
+ }
+
+ #[cfg(ossl102)]
+ fn _set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::SSL_CTX_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) }
}
- pub fn set_options(&mut self, option: SslContextOptions) -> SslContextOptions {
- let ret = unsafe { ffi::SSL_CTX_set_options(self.as_ptr(), option.bits()) };
- SslContextOptions::from_bits(ret).unwrap()
+ pub fn set_options(&mut self, option: SslOption) -> SslOption {
+ let ret = unsafe { compat::SSL_CTX_set_options(self.as_ptr(), option.bits()) };
+ SslOption::from_bits(ret).unwrap()
}
- pub fn options(&self) -> SslContextOptions {
- let ret = unsafe { ffi::SSL_CTX_get_options(self.as_ptr()) };
- SslContextOptions::from_bits(ret).unwrap()
+ pub fn options(&self) -> SslOption {
+ let ret = unsafe { compat::SSL_CTX_get_options(self.as_ptr()) };
+ SslOption::from_bits(ret).unwrap()
}
- pub fn clear_options(&mut self, option: SslContextOptions) -> SslContextOptions {
- let ret = unsafe { ffi::SSL_CTX_clear_options(self.as_ptr(), option.bits()) };
- SslContextOptions::from_bits(ret).unwrap()
+ pub fn clear_options(&mut self, option: SslOption) -> SslOption {
+ let ret = unsafe { compat::SSL_CTX_clear_options(self.as_ptr(), option.bits()) };
+ SslOption::from_bits(ret).unwrap()
}
/// Set the protocols to be used during Next Protocol Negotiation (the protocols
/// supported by the application).
- ///
- /// This method needs the `npn` feature.
- #[cfg(feature = "npn")]
- pub fn set_npn_protocols(&mut self, protocols: &[&[u8]]) {
+ pub fn set_npn_protocols(&mut self, protocols: &[&[u8]]) -> Result<(), ErrorStack> {
// Firstly, convert the list of protocols to a byte-array that can be passed to OpenSSL
// APIs -- a list of length-prefixed strings.
let protocols: Box<Vec<u8>> = Box::new(ssl_encode_byte_strings(protocols));
@@ -612,7 +667,9 @@ impl<'a> SslContextRef<'a> {
unsafe {
// Attach the protocol list to the OpenSSL context structure,
// so that we can refer to it within the callback.
- ffi::SSL_CTX_set_ex_data(self.as_ptr(), *NPN_PROTOS_IDX, mem::transmute(protocols));
+ try!(cvt(ffi::SSL_CTX_set_ex_data(self.as_ptr(),
+ *NPN_PROTOS_IDX,
+ Box::into_raw(protocols) as *mut c_void)));
// Now register the callback that performs the default protocol
// matching based on the client-supported list of protocols that
// has been saved.
@@ -624,6 +681,7 @@ impl<'a> SslContextRef<'a> {
ffi::SSL_CTX_set_next_protos_advertised_cb(self.as_ptr(),
raw_next_protos_advertise_cb,
ptr::null_mut());
+ Ok(())
}
}
@@ -634,40 +692,58 @@ impl<'a> SslContextRef<'a> {
///
/// Note that ordering of the protocols controls the priority with which they are chosen.
///
- /// This method needs the `alpn` feature.
- #[cfg(feature = "alpn")]
- pub fn set_alpn_protocols(&mut self, protocols: &[&[u8]]) {
+ /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
+ #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
+ pub fn set_alpn_protocols(&mut self, protocols: &[&[u8]]) -> Result<(), ErrorStack> {
let protocols: Box<Vec<u8>> = Box::new(ssl_encode_byte_strings(protocols));
unsafe {
// Set the context's internal protocol list for use if we are a server
- ffi::SSL_CTX_set_alpn_protos(self.as_ptr(), protocols.as_ptr(), protocols.len() as c_uint);
+ let r = ffi::SSL_CTX_set_alpn_protos(self.as_ptr(),
+ protocols.as_ptr(),
+ protocols.len() as c_uint);
+ // fun fact, SSL_CTX_set_alpn_protos has a reversed return code D:
+ if r != 0 {
+ return Err(ErrorStack::get());
+ }
// Rather than use the argument to the callback to contain our data, store it in the
// ssl ctx's ex_data so that we can configure a function to free it later. In the
// future, it might make sense to pull this into our internal struct Ssl instead of
// leaning on openssl and using function pointers.
- ffi::SSL_CTX_set_ex_data(self.as_ptr(), *ALPN_PROTOS_IDX, mem::transmute(protocols));
+ try!(cvt(ffi::SSL_CTX_set_ex_data(self.as_ptr(),
+ *ALPN_PROTOS_IDX,
+ Box::into_raw(protocols) as *mut c_void)));
// Now register the callback that performs the default protocol
// matching based on the client-supported list of protocols that
// has been saved.
ffi::SSL_CTX_set_alpn_select_cb(self.as_ptr(), raw_alpn_select_cb, ptr::null_mut());
+
+ Ok(())
}
}
+
+ /// Checks consistency between the private key and certificate.
+ pub fn check_private_key(&self) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::SSL_CTX_check_private_key(self.as_ptr())).map(|_| ()) }
+ }
+
+ pub fn build(self) -> SslContext {
+ let ctx = SslContext(self.0);
+ mem::forget(self);
+ ctx
+ }
}
-/// An owned SSL context object.
-pub struct SslContext(SslContextRef<'static>);
+type_!(SslContext, SslContextRef, ffi::SSL_CTX, ffi::SSL_CTX_free);
unsafe impl Send for SslContext {}
unsafe impl Sync for SslContext {}
-#[cfg(feature = "ssl_context_clone")]
impl Clone for SslContext {
- /// Requires the `ssl_context_clone` feature.
fn clone(&self) -> Self {
unsafe {
- ::c_helpers::rust_0_8_SSL_CTX_clone(self.as_ptr());
+ compat::SSL_CTX_up_ref(self.as_ptr());
SslContext::from_ptr(self.as_ptr())
}
}
@@ -680,78 +756,57 @@ impl fmt::Debug for SslContext {
}
}
-impl Drop for SslContext {
- fn drop(&mut self) {
- unsafe { ffi::SSL_CTX_free(self.as_ptr()) }
+impl SslContext {
+ pub fn builder(method: SslMethod) -> Result<SslContextBuilder, ErrorStack> {
+ SslContextBuilder::new(method)
}
}
-impl Deref for SslContext {
- type Target = SslContextRef<'static>;
- fn deref(&self) -> &SslContextRef<'static> {
- &self.0
- }
-}
+pub struct CipherBits {
+ /// The number of secret bits used for the cipher.
+ pub secret: i32,
-impl DerefMut for SslContext {
- fn deref_mut(&mut self) -> &mut SslContextRef<'static> {
- &mut self.0
- }
+ /// The number of bits processed by the chosen algorithm.
+ pub algorithm: i32,
}
-impl SslContext {
- /// Creates a new SSL context.
- pub fn new(method: SslMethod) -> Result<SslContext, ErrorStack> {
- init();
+pub struct SslCipher(*mut ffi::SSL_CIPHER);
- let mut ctx = unsafe {
- let ctx = try_ssl_null!(ffi::SSL_CTX_new(method.to_raw()));
- SslContext::from_ptr(ctx)
- };
+impl OpenSslType for SslCipher {
+ type CType = ffi::SSL_CIPHER;
+ type Ref = SslCipherRef;
- match method {
- #[cfg(feature = "dtlsv1")]
- SslMethod::Dtlsv1 => ctx.set_read_ahead(1),
- #[cfg(feature = "dtlsv1_2")]
- SslMethod::Dtlsv1_2 => ctx.set_read_ahead(1),
- _ => {}
- }
- // this is a bit dubious (?)
- try!(ctx.set_mode(ffi::SSL_MODE_AUTO_RETRY | ffi::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER));
-
- Ok(ctx)
+ unsafe fn from_ptr(ptr: *mut ffi::SSL_CIPHER) -> SslCipher {
+ SslCipher(ptr)
}
+}
- pub unsafe fn from_ptr(ctx: *mut ffi::SSL_CTX) -> SslContext {
- SslContext(SslContextRef::from_ptr(ctx))
- }
+impl Deref for SslCipher {
+ type Target = SslCipherRef;
- pub fn as_ptr(&self) -> *mut ffi::SSL_CTX {
- (**self).as_ptr()
+ fn deref(&self) -> &SslCipherRef {
+ unsafe { SslCipherRef::from_ptr(self.0) }
}
}
-
-pub struct CipherBits {
- /// The number of secret bits used for the cipher.
- pub secret: i32,
- /// The number of bits processed by the chosen algorithm, if not None.
- pub algorithm: Option<i32>,
- _p: (),
+impl DerefMut for SslCipher {
+ fn deref_mut(&mut self) -> &mut SslCipherRef {
+ unsafe { SslCipherRef::from_ptr_mut(self.0) }
+ }
}
+pub struct SslCipherRef(Opaque);
-pub struct SslCipher<'a> {
- cipher: *const ffi::SSL_CIPHER,
- ph: PhantomData<&'a ()>,
+impl OpenSslTypeRef for SslCipherRef {
+ type CType = ffi::SSL_CIPHER;
}
-impl<'a> SslCipher<'a> {
+impl SslCipherRef {
/// Returns the name of cipher.
- pub fn name(&self) -> &'static str {
+ pub fn name(&self) -> &str {
let name = unsafe {
- let ptr = ffi::SSL_CIPHER_get_name(self.cipher);
+ let ptr = ffi::SSL_CIPHER_get_name(self.as_ptr());
CStr::from_ptr(ptr as *const _)
};
@@ -759,9 +814,9 @@ impl<'a> SslCipher<'a> {
}
/// Returns the SSL/TLS protocol version that first defined the cipher.
- pub fn version(&self) -> &'static str {
+ pub fn version(&self) -> &str {
let version = unsafe {
- let ptr = ffi::SSL_CIPHER_get_version(self.cipher);
+ let ptr = ffi::SSL_CIPHER_get_version(self.as_ptr());
CStr::from_ptr(ptr as *const _)
};
@@ -771,78 +826,44 @@ impl<'a> SslCipher<'a> {
/// Returns the number of bits used for the cipher.
pub fn bits(&self) -> CipherBits {
unsafe {
- let algo_bits: *mut c_int = ptr::null_mut();
- let secret_bits = ffi::SSL_CIPHER_get_bits(self.cipher, algo_bits);
- if !algo_bits.is_null() {
- CipherBits {
- secret: secret_bits,
- algorithm: Some(*algo_bits),
- _p: (),
- }
- } else {
- CipherBits {
- secret: secret_bits,
- algorithm: None,
- _p: (),
- }
+ let mut algo_bits = 0;
+ let secret_bits = ffi::SSL_CIPHER_get_bits(self.as_ptr(), &mut algo_bits);
+ CipherBits {
+ secret: secret_bits.into(),
+ algorithm: algo_bits.into(),
}
}
}
/// Returns a textual description of the cipher used
- pub fn description(&self) -> Option<String> {
+ pub fn description(&self) -> String {
unsafe {
// SSL_CIPHER_description requires a buffer of at least 128 bytes.
let mut buf = [0; 128];
- let desc_ptr = ffi::SSL_CIPHER_description(self.cipher, buf.as_mut_ptr(), 128);
-
- if !desc_ptr.is_null() {
- String::from_utf8(CStr::from_ptr(desc_ptr as *const _).to_bytes().to_vec()).ok()
- } else {
- None
- }
+ let ptr = ffi::SSL_CIPHER_description(self.as_ptr(), buf.as_mut_ptr(), 128);
+ String::from_utf8(CStr::from_ptr(ptr as *const _).to_bytes().to_vec()).unwrap()
}
}
}
-pub struct SslRef<'a>(*mut ffi::SSL, PhantomData<&'a ()>);
+type_!(Ssl, SslRef, ffi::SSL, ffi::SSL_free);
-unsafe impl<'a> Send for SslRef<'a> {}
-unsafe impl<'a> Sync for SslRef<'a> {}
-
-impl<'a> fmt::Debug for SslRef<'a> {
+impl fmt::Debug for SslRef {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- fmt.debug_struct("SslRef")
- .field("state", &self.state_string_long())
- .finish()
+ let mut builder = fmt.debug_struct("Ssl");
+ builder.field("state", &self.state_string_long());
+ if let Some(err) = self.verify_result() {
+ builder.field("verify_result", &err);
+ }
+ builder.finish()
}
}
-impl<'a> SslRef<'a> {
- pub unsafe fn from_ptr(ssl: *mut ffi::SSL) -> SslRef<'a> {
- SslRef(ssl, PhantomData)
- }
-
- pub fn as_ptr(&self) -> *mut ffi::SSL {
- self.0
- }
-
+impl SslRef {
fn get_raw_rbio(&self) -> *mut ffi::BIO {
unsafe { ffi::SSL_get_rbio(self.as_ptr()) }
}
- fn connect(&mut self) -> c_int {
- unsafe { ffi::SSL_connect(self.as_ptr()) }
- }
-
- fn accept(&mut self) -> c_int {
- unsafe { ffi::SSL_accept(self.as_ptr()) }
- }
-
- fn handshake(&mut self) -> c_int {
- unsafe { ffi::SSL_do_handshake(self.as_ptr()) }
- }
-
fn read(&mut self, buf: &mut [u8]) -> c_int {
let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
unsafe { ffi::SSL_read(self.as_ptr(), buf.as_ptr() as *mut c_void, len) }
@@ -872,7 +893,7 @@ impl<'a> SslRef<'a> {
/// to the certificate chain. It should return `true` if the certificate
/// chain is valid and `false` otherwise.
pub fn set_verify_callback<F>(&mut self, mode: SslVerifyMode, verify: F)
- where F: Fn(bool, &X509StoreContext) -> bool + Any + 'static + Sync + Send
+ where F: Fn(bool, &X509StoreContextRef) -> bool + Any + 'static + Sync + Send
{
unsafe {
let verify = Box::new(verify);
@@ -883,17 +904,14 @@ impl<'a> SslRef<'a> {
}
}
- pub fn current_cipher(&self) -> Option<SslCipher<'a>> {
+ pub fn current_cipher(&self) -> Option<&SslCipherRef> {
unsafe {
let ptr = ffi::SSL_get_current_cipher(self.as_ptr());
if ptr.is_null() {
None
} else {
- Some(SslCipher {
- cipher: ptr,
- ph: PhantomData,
- })
+ Some(SslCipherRef::from_ptr(ptr as *mut _))
}
}
}
@@ -919,15 +937,9 @@ impl<'a> SslRef<'a> {
/// Sets the host name to be used with SNI (Server Name Indication).
pub fn set_hostname(&mut self, hostname: &str) -> Result<(), ErrorStack> {
let cstr = CString::new(hostname).unwrap();
- let ret = unsafe {
- ffi::SSL_set_tlsext_host_name(self.as_ptr(), cstr.as_ptr() as *mut _)
- };
-
- // For this case, 0 indicates failure.
- if ret == 0 {
- Err(ErrorStack::get())
- } else {
- Ok(())
+ unsafe {
+ cvt(ffi::SSL_set_tlsext_host_name(self.as_ptr(), cstr.as_ptr() as *mut _) as c_int)
+ .map(|_| ())
}
}
@@ -957,9 +969,6 @@ impl<'a> SslRef<'a> {
///
/// The protocol's name is returned is an opaque sequence of bytes. It is up to the client
/// to interpret it.
- ///
- /// This method needs the `npn` feature.
- #[cfg(feature = "npn")]
pub fn selected_npn_protocol(&self) -> Option<&[u8]> {
unsafe {
let mut data: *const c_uchar = ptr::null();
@@ -981,8 +990,8 @@ impl<'a> SslRef<'a> {
/// The protocol's name is returned is an opaque sequence of bytes. It is up to the client
/// to interpret it.
///
- /// This method needs the `alpn` feature.
- #[cfg(feature = "alpn")]
+ /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
+ #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
pub fn selected_alpn_protocol(&self) -> Option<&[u8]> {
unsafe {
let mut data: *const c_uchar = ptr::null();
@@ -1009,139 +1018,99 @@ impl<'a> SslRef<'a> {
///
/// The result will be either None, indicating no compression is in use, or
/// a string with the compression name.
- pub fn compression(&self) -> Option<String> {
- let ptr = unsafe { ffi::SSL_get_current_compression(self.as_ptr()) };
- if ptr == ptr::null() {
- return None;
- }
-
- let meth = unsafe { ffi::SSL_COMP_get_name(ptr) };
- let s = unsafe {
- String::from_utf8(CStr::from_ptr(meth as *const _).to_bytes().to_vec()).unwrap()
- };
-
- Some(s)
+ pub fn compression(&self) -> Option<&str> {
+ self._compression()
}
- pub fn ssl_method(&self) -> SslMethod {
+ #[cfg(not(osslconf = "OPENSSL_NO_COMP"))]
+ fn _compression(&self) -> Option<&str> {
unsafe {
- let method = ffi::SSL_get_ssl_method(self.as_ptr());
- SslMethod::from_raw(method).unwrap()
+ let ptr = ffi::SSL_get_current_compression(self.as_ptr());
+ if ptr == ptr::null() {
+ return None;
+ }
+ let meth = ffi::SSL_COMP_get_name(ptr);
+ Some(str::from_utf8(CStr::from_ptr(meth as *const _).to_bytes()).unwrap())
}
}
+ #[cfg(osslconf = "OPENSSL_NO_COMP")]
+ fn _compression(&self) -> Option<&str> {
+ None
+ }
+
/// Returns the server's name for the current connection
- pub fn servername(&self) -> Option<String> {
- let name = unsafe { ffi::SSL_get_servername(self.as_ptr(), ffi::TLSEXT_NAMETYPE_host_name) };
- if name == ptr::null() {
- return None;
- }
+ pub fn servername(&self) -> Option<&str> {
+ unsafe {
+ let name = ffi::SSL_get_servername(self.as_ptr(), ffi::TLSEXT_NAMETYPE_host_name);
+ if name == ptr::null() {
+ return None;
+ }
- unsafe { String::from_utf8(CStr::from_ptr(name as *const _).to_bytes().to_vec()).ok() }
+ Some(str::from_utf8(CStr::from_ptr(name as *const _).to_bytes()).unwrap())
+ }
}
/// Changes the context corresponding to the current connection.
pub fn set_ssl_context(&mut self, ctx: &SslContextRef) -> Result<(), ErrorStack> {
- unsafe {
- try_ssl_null!(ffi::SSL_set_SSL_CTX(self.as_ptr(), ctx.as_ptr()));
- }
- Ok(())
+ unsafe { cvt_p(ffi::SSL_set_SSL_CTX(self.as_ptr(), ctx.as_ptr())).map(|_| ()) }
}
/// Returns the context corresponding to the current connection
- pub fn ssl_context(&self) -> SslContextRef<'a> {
+ pub fn ssl_context(&self) -> &SslContextRef {
unsafe {
let ssl_ctx = ffi::SSL_get_SSL_CTX(self.as_ptr());
SslContextRef::from_ptr(ssl_ctx)
}
}
-}
-pub struct Ssl(SslRef<'static>);
-
-impl fmt::Debug for Ssl {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- fmt.debug_struct("Ssl")
- .field("state", &self.state_string_long())
- .finish()
+ /// Returns the X509 verification configuration.
+ ///
+ /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or 1.1.0.
+ #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
+ pub fn param_mut(&mut self) -> &mut X509VerifyParamRef {
+ self._param_mut()
}
-}
-impl Drop for Ssl {
- fn drop(&mut self) {
- unsafe { ffi::SSL_free(self.as_ptr()) }
+ #[cfg(any(ossl102, ossl110))]
+ fn _param_mut(&mut self) -> &mut X509VerifyParamRef {
+ unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) }
}
-}
-
-impl Deref for Ssl {
- type Target = SslRef<'static>;
- fn deref(&self) -> &SslRef<'static> {
- &self.0
+ /// Returns the result of X509 certificate verification.
+ pub fn verify_result(&self) -> Option<X509VerifyError> {
+ unsafe { X509VerifyError::from_raw(ffi::SSL_get_verify_result(self.as_ptr())) }
}
}
-impl DerefMut for Ssl {
- fn deref_mut(&mut self) -> &mut SslRef<'static> {
- &mut self.0
+unsafe impl Sync for Ssl {}
+unsafe impl Send for Ssl {}
+
+impl fmt::Debug for Ssl {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&**self, fmt)
}
}
impl Ssl {
pub fn new(ctx: &SslContext) -> Result<Ssl, ErrorStack> {
unsafe {
- let ssl = try_ssl_null!(ffi::SSL_new(ctx.as_ptr()));
+ let ssl = try!(cvt_p(ffi::SSL_new(ctx.as_ptr())));
Ok(Ssl::from_ptr(ssl))
}
}
- pub unsafe fn from_ptr(ssl: *mut ffi::SSL) -> Ssl {
- Ssl(SslRef::from_ptr(ssl))
- }
-}
-
-/// A stream wrapper which handles SSL encryption for an underlying stream.
-pub struct SslStream<S> {
- ssl: Ssl,
- _method: Arc<BioMethod>, // NOTE: this *must* be after the Ssl field so things drop right
- _p: PhantomData<S>,
-}
-
-unsafe impl<S: Send> Send for SslStream<S> {}
-
-impl<S> fmt::Debug for SslStream<S>
- where S: fmt::Debug
-{
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- fmt.debug_struct("SslStream")
- .field("stream", &self.get_ref())
- .field("ssl", &self.ssl())
- .finish()
- }
-}
-
-impl<S: Read + Write> SslStream<S> {
- fn new_base(ssl: Ssl, stream: S) -> Self {
- unsafe {
- let (bio, method) = bio::new(stream).unwrap();
- ffi::SSL_set_bio(ssl.as_ptr(), bio, bio);
-
- SslStream {
- ssl: ssl,
- _method: method,
- _p: PhantomData,
- }
- }
- }
-
/// Creates an SSL/TLS client operating over the provided stream.
- 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();
+ ///
+ /// # Warning
+ ///
+ /// OpenSSL's default configuration is insecure. It is highly recommended to use
+ /// `SslConnector` rather than `Ssl` directly, as it manages that configuration.
+ pub fn connect<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
+ where S: Read + Write
+ {
+ let mut stream = SslStream::new_base(self, stream);
+ let ret = unsafe { ffi::SSL_connect(stream.ssl.as_ptr()) };
if ret > 0 {
Ok(stream)
} else {
@@ -1153,19 +1122,27 @@ impl<S: Read + Write> SslStream<S> {
error: e,
}))
}
- err => Err(HandshakeError::Failure(err)),
+ err => {
+ Err(HandshakeError::Failure(MidHandshakeSslStream {
+ stream: stream,
+ error: err,
+ }))
+ }
}
}
}
/// Creates an SSL/TLS server operating over the provided stream.
- 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();
+ ///
+ /// # Warning
+ ///
+ /// OpenSSL's default configuration is insecure. It is highly recommended to use
+ /// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration.
+ pub fn accept<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
+ where S: Read + Write
+ {
+ let mut stream = SslStream::new_base(self, stream);
+ let ret = unsafe { ffi::SSL_accept(stream.ssl.as_ptr()) };
if ret > 0 {
Ok(stream)
} else {
@@ -1177,71 +1154,15 @@ impl<S: Read + Write> SslStream<S> {
error: e,
}))
}
- err => Err(HandshakeError::Failure(err)),
+ err => {
+ Err(HandshakeError::Failure(MidHandshakeSslStream {
+ stream: stream,
+ error: err,
+ }))
+ }
}
}
}
-
- /// Like `read`, but returns an `ssl::Error` rather than an `io::Error`.
- ///
- /// This is particularly useful with a nonblocking socket, where the error
- /// value will identify if OpenSSL is waiting on read or write readiness.
- pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
- let ret = self.ssl.read(buf);
- if ret >= 0 {
- Ok(ret as usize)
- } else {
- Err(self.make_error(ret))
- }
- }
-
- /// Like `write`, but returns an `ssl::Error` rather than an `io::Error`.
- ///
- /// This is particularly useful with a nonblocking socket, where the error
- /// value will identify if OpenSSL is waiting on read or write readiness.
- pub fn ssl_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
- let ret = self.ssl.write(buf);
- if ret >= 0 {
- Ok(ret as usize)
- } else {
- Err(self.make_error(ret))
- }
- }
-}
-
-/// 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>),
-}
-
-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.
@@ -1263,7 +1184,7 @@ impl<S> MidHandshakeSslStream<S> {
}
/// Returns a shared reference to the `Ssl` of the stream.
- pub fn ssl(&self) -> &Ssl {
+ pub fn ssl(&self) -> &SslRef {
self.stream.ssl()
}
@@ -1272,9 +1193,14 @@ impl<S> MidHandshakeSslStream<S> {
&self.error
}
+ /// Consumes `self`, returning its error.
+ pub fn into_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();
+ let ret = unsafe { ffi::SSL_do_handshake(self.stream.ssl.as_ptr()) };
if ret > 0 {
Ok(self.stream)
} else {
@@ -1284,12 +1210,94 @@ impl<S> MidHandshakeSslStream<S> {
self.error = e;
Err(HandshakeError::Interrupted(self))
}
- err => Err(HandshakeError::Failure(err)),
+ err => {
+ self.error = err;
+ Err(HandshakeError::Failure(self))
+ }
}
}
}
}
+/// A stream wrapper which handles SSL encryption for an underlying stream.
+pub struct SslStream<S> {
+ ssl: Ssl,
+ _method: BioMethod, // NOTE: this *must* be after the Ssl field so things drop right
+ _p: PhantomData<S>,
+}
+
+impl<S> fmt::Debug for SslStream<S>
+ where S: fmt::Debug
+{
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("SslStream")
+ .field("stream", &self.get_ref())
+ .field("ssl", &self.ssl())
+ .finish()
+ }
+}
+
+impl<S: Read + Write> SslStream<S> {
+ fn new_base(ssl: Ssl, stream: S) -> Self {
+ unsafe {
+ let (bio, method) = bio::new(stream).unwrap();
+ ffi::SSL_set_bio(ssl.as_ptr(), bio, bio);
+
+ SslStream {
+ ssl: ssl,
+ _method: method,
+ _p: PhantomData,
+ }
+ }
+ }
+
+ /// Like `read`, but returns an `ssl::Error` rather than an `io::Error`.
+ ///
+ /// This is particularly useful with a nonblocking socket, where the error
+ /// value will identify if OpenSSL is waiting on read or write readiness.
+ pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
+ let ret = self.ssl.read(buf);
+ if ret >= 0 {
+ Ok(ret as usize)
+ } else {
+ Err(self.make_error(ret))
+ }
+ }
+
+ /// Like `write`, but returns an `ssl::Error` rather than an `io::Error`.
+ ///
+ /// This is particularly useful with a nonblocking socket, where the error
+ /// value will identify if OpenSSL is waiting on read or write readiness.
+ pub fn ssl_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
+ let ret = self.ssl.write(buf);
+ if ret >= 0 {
+ Ok(ret as usize)
+ } else {
+ Err(self.make_error(ret))
+ }
+ }
+
+ /// Shuts down the session.
+ ///
+ /// The shutdown process consists of two steps. The first step sends a
+ /// close notify message to the peer, after which `ShutdownResult::Sent`
+ /// is returned. The second step awaits the receipt of a close notify
+ /// message from the peer, after which `ShutdownResult::Received` is
+ /// returned.
+ ///
+ /// While the connection may be closed after the first step, it is
+ /// recommended to fully shut the session down. In particular, it must
+ /// be fully shut down if the connection is to be used for further
+ /// communication in the future.
+ pub fn shutdown(&mut self) -> Result<ShutdownResult, Error> {
+ match unsafe { ffi::SSL_shutdown(self.ssl.as_ptr()) } {
+ 0 => Ok(ShutdownResult::Sent),
+ 1 => Ok(ShutdownResult::Received),
+ n => Err(self.make_error(n)),
+ }
+ }
+}
+
impl<S> SslStream<S> {
fn make_error(&mut self, ret: c_int) -> Error {
self.check_panic();
@@ -1319,16 +1327,12 @@ impl<S> SslStream<S> {
}
}
- #[cfg(feature = "nightly")]
fn check_panic(&mut self) {
if let Some(err) = unsafe { bio::take_panic::<S>(self.ssl.get_raw_rbio()) } {
::std::panic::resume_unwind(err)
}
}
- #[cfg(not(feature = "nightly"))]
- fn check_panic(&mut self) {}
-
fn get_bio_error(&mut self) -> io::Error {
let error = unsafe { bio::take_error::<S>(self.ssl.get_raw_rbio()) };
match error {
@@ -1362,7 +1366,7 @@ impl<S> SslStream<S> {
}
/// Returns the OpenSSL `Ssl` object associated with this stream.
- pub fn ssl(&self) -> &Ssl {
+ pub fn ssl(&self) -> &SslRef {
&self.ssl
}
}
@@ -1397,18 +1401,101 @@ impl<S: Read + Write> Write for SslStream<S> {
}
}
-pub trait IntoSsl {
- fn into_ssl(self) -> Result<Ssl, ErrorStack>;
+/// The result of a shutdown request.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum ShutdownResult {
+ /// A close notify message has been sent to the peer.
+ Sent,
+
+ /// A close notify response message has been received from the peer.
+ Received,
}
-impl IntoSsl for Ssl {
- fn into_ssl(self) -> Result<Ssl, ErrorStack> {
- Ok(self)
+#[cfg(ossl110)]
+mod compat {
+ use std::ptr;
+
+ use ffi;
+ use libc::c_int;
+
+ pub use ffi::{SSL_CTX_get_options, SSL_CTX_set_options};
+ pub use ffi::{SSL_CTX_clear_options, SSL_CTX_up_ref};
+
+ pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
+ ffi::CRYPTO_get_ex_new_index(ffi::CRYPTO_EX_INDEX_SSL_CTX,
+ 0,
+ ptr::null_mut(),
+ None,
+ None,
+ Some(f))
+ }
+
+ pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int {
+ ffi::CRYPTO_get_ex_new_index(ffi::CRYPTO_EX_INDEX_SSL,
+ 0,
+ ptr::null_mut(),
+ None,
+ None,
+ Some(f))
+ }
+
+ pub fn tls_method() -> *const ffi::SSL_METHOD {
+ unsafe { ffi::TLS_method() }
+ }
+
+ pub fn dtls_method() -> *const ffi::SSL_METHOD {
+ unsafe { ffi::DTLS_method() }
}
}
-impl<'a> IntoSsl for &'a SslContext {
- fn into_ssl(self) -> Result<Ssl, ErrorStack> {
- Ssl::new(self)
+#[cfg(ossl10x)]
+#[allow(bad_style)]
+mod compat {
+ use std::ptr;
+
+ use ffi;
+ use libc::{self, c_long, c_ulong, c_int};
+
+ pub unsafe fn SSL_CTX_get_options(ctx: *const ffi::SSL_CTX) -> c_ulong {
+ ffi::SSL_CTX_ctrl(ctx as *mut _, ffi::SSL_CTRL_OPTIONS, 0, ptr::null_mut()) as c_ulong
+ }
+
+ pub unsafe fn SSL_CTX_set_options(ctx: *const ffi::SSL_CTX, op: c_ulong) -> c_ulong {
+ ffi::SSL_CTX_ctrl(ctx as *mut _,
+ ffi::SSL_CTRL_OPTIONS,
+ op as c_long,
+ ptr::null_mut()) as c_ulong
+ }
+
+ pub unsafe fn SSL_CTX_clear_options(ctx: *const ffi::SSL_CTX, op: c_ulong) -> c_ulong {
+ ffi::SSL_CTX_ctrl(ctx as *mut _,
+ ffi::SSL_CTRL_CLEAR_OPTIONS,
+ op as c_long,
+ ptr::null_mut()) as c_ulong
+ }
+
+ pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
+ ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f))
+ }
+
+ pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int {
+ ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f))
+ }
+
+ pub unsafe fn SSL_CTX_up_ref(ssl: *mut ffi::SSL_CTX) -> libc::c_int {
+ ffi::CRYPTO_add_lock(&mut (*ssl).references,
+ 1,
+ ffi::CRYPTO_LOCK_SSL_CTX,
+ "mod.rs\0".as_ptr() as *const _,
+ line!() as libc::c_int);
+ 0
+ }
+
+ pub fn tls_method() -> *const ffi::SSL_METHOD {
+ unsafe { ffi::SSLv23_method() }
+ }
+
+ pub fn dtls_method() -> *const ffi::SSL_METHOD {
+ unsafe { ffi::DTLSv1_method() }
}
}
diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs
index 3bbbed03..a84f6b25 100644
--- a/openssl/src/ssl/tests/mod.rs
+++ b/openssl/src/ssl/tests/mod.rs
@@ -1,5 +1,6 @@
#![allow(unused_imports)]
+use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::io::{self, BufReader};
@@ -11,31 +12,26 @@ use std::process::{Command, Child, Stdio, ChildStdin};
use std::thread;
use std::time::Duration;
-use net2::TcpStreamExt;
+use tempdir::TempDir;
-use crypto::hash::Type::SHA256;
+use hash::MessageDigest;
use ssl;
use ssl::SSL_VERIFY_PEER;
-use ssl::SslMethod::Sslv23;
use ssl::{SslMethod, HandshakeError};
-use ssl::error::Error;
-use ssl::{SslContext, SslStream};
-use x509::X509StoreContext;
-use x509::X509FileType;
-use x509::X509;
-use crypto::pkey::PKey;
-
-#[cfg(feature="dtlsv1")]
+use ssl::{SslContext, SslStream, Ssl, ShutdownResult, SslConnectorBuilder, SslAcceptorBuilder,
+ Error};
+use x509::{X509StoreContext, X509, X509_FILETYPE_PEM};
+#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
+use x509::verify::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS;
+use pkey::PKey;
+
use std::net::UdpSocket;
-#[cfg(feature="dtlsv1")]
-use ssl::SslMethod::Dtlsv1;
-#[cfg(feature="sslv2")]
-use ssl::SslMethod::Sslv2;
-#[cfg(feature="dtlsv1")]
-use net2::UdpSocketExt;
mod select;
+static CERT: &'static [u8] = include_bytes!("../../../test/cert.pem");
+static KEY: &'static [u8] = include_bytes!("../../../test/key.pem");
+
fn next_addr() -> SocketAddr {
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
static PORT: AtomicUsize = ATOMIC_USIZE_INIT;
@@ -46,32 +42,42 @@ fn next_addr() -> SocketAddr {
struct Server {
p: Child,
+ _temp: TempDir,
}
impl Server {
fn spawn(args: &[&str], input: Option<Box<FnMut(ChildStdin) + Send>>) -> (Server, SocketAddr) {
+ let td = TempDir::new("openssl").unwrap();
+ let cert = td.path().join("cert.pem");
+ let key = td.path().join("key.pem");
+ File::create(&cert).unwrap().write_all(CERT).unwrap();
+ File::create(&key).unwrap().write_all(KEY).unwrap();
+
let addr = next_addr();
let mut child = Command::new("openssl")
- .arg("s_server")
- .arg("-accept")
- .arg(addr.port().to_string())
- .args(args)
- .arg("-cert")
- .arg("cert.pem")
- .arg("-key")
- .arg("key.pem")
- .arg("-no_dhe")
- .current_dir("test")
- .stdout(Stdio::null())
- .stderr(Stdio::null())
- .stdin(Stdio::piped())
- .spawn()
- .unwrap();
+ .arg("s_server")
+ .arg("-accept")
+ .arg(addr.port().to_string())
+ .args(args)
+ .arg("-cert")
+ .arg(&cert)
+ .arg("-key")
+ .arg(&key)
+ .arg("-no_dhe")
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .stdin(Stdio::piped())
+ .spawn()
+ .unwrap();
let stdin = child.stdin.take().unwrap();
if let Some(mut input) = input {
thread::spawn(move || input(stdin));
}
- (Server { p: child }, addr)
+ (Server {
+ p: child,
+ _temp: td,
+ },
+ addr)
}
fn new_tcp(args: &[&str]) -> (Server, TcpStream) {
@@ -92,7 +98,6 @@ impl Server {
Server::new_tcp(&["-www"])
}
- #[cfg(any(feature = "alpn", feature = "npn"))]
fn new_alpn() -> (Server, TcpStream) {
Server::new_tcp(&["-www",
"-nextprotoneg",
@@ -101,7 +106,6 @@ impl Server {
"http/1.1,spdy/3.1"])
}
- #[cfg(feature = "dtlsv1")]
fn new_dtlsv1<I>(input: I) -> (Server, UdpConnected)
where I: IntoIterator<Item = &'static str>,
I::IntoIter: Send + 'static
@@ -109,17 +113,17 @@ impl Server {
let mut input = input.into_iter();
let (s, addr) = Server::spawn(&["-dtls1"],
Some(Box::new(move |mut io| {
- for s in input.by_ref() {
- if io.write_all(s.as_bytes()).is_err() {
- break;
- }
- }
- })));
+ for s in input.by_ref() {
+ if io.write_all(s.as_bytes()).is_err() {
+ break;
+ }
+ }
+ })));
// Need to wait for the UDP socket to get bound in our child process,
// but don't currently have a great way to do that so just wait for a
// bit.
thread::sleep(Duration::from_millis(100));
- let socket = UdpSocket::bind(next_addr()).unwrap();
+ let socket = UdpSocket::bind("127.0.0.1:0").unwrap();
socket.connect(&addr).unwrap();
(s, UdpConnected(socket))
}
@@ -132,51 +136,18 @@ impl Drop for Server {
}
}
-#[cfg(feature = "dtlsv1")]
#[derive(Debug)]
struct UdpConnected(UdpSocket);
-#[cfg(feature = "dtlsv1")]
impl Read for UdpConnected {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- self.0.recv_from(buf).map(|(s, _)| s)
+ self.0.recv(buf)
}
}
-#[cfg(feature = "dtlsv1")]
impl Write for UdpConnected {
- #[cfg(unix)]
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- use std::os::unix::prelude::*;
- use libc;
- let n = unsafe {
- libc::send(self.0.as_raw_fd(),
- buf.as_ptr() as *const _,
- buf.len() as libc::size_t,
- 0)
- };
- if n < 0 {
- Err(io::Error::last_os_error())
- } else {
- Ok(n as usize)
- }
- }
-
- #[cfg(windows)]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- use std::os::windows::prelude::*;
- use libc;
- let n = unsafe {
- libc::send(self.0.as_raw_socket(),
- buf.as_ptr() as *const _,
- buf.len() as libc::c_int,
- 0)
- };
- if n < 0 {
- Err(io::Error::last_os_error())
- } else {
- Ok(n as usize)
- }
+ self.0.send(buf)
}
fn flush(&mut self) -> io::Result<()> {
@@ -197,147 +168,139 @@ macro_rules! run_test(
use ssl::SslMethod;
use ssl::{SslContext, Ssl, SslStream};
use ssl::SSL_VERIFY_PEER;
- use crypto::hash::Type::{SHA1, SHA256};
+ use hash::MessageDigest;
use x509::X509StoreContext;
use serialize::hex::FromHex;
+ use types::OpenSslTypeRef;
use super::Server;
#[test]
fn sslv23() {
let (_s, stream) = Server::new();
- $blk(SslMethod::Sslv23, stream);
+ $blk(SslMethod::tls(), stream);
}
#[test]
- #[cfg(feature="dtlsv1")]
+ #[cfg_attr(any(windows, target_arch = "arm"), ignore)] // FIXME(#467)
fn dtlsv1() {
let (_s, stream) = Server::new_dtlsv1(Some("hello"));
- $blk(SslMethod::Dtlsv1, stream);
+ $blk(SslMethod::dtls(), stream);
}
}
);
);
run_test!(new_ctx, |method, _| {
- SslContext::new(method).unwrap();
-});
-
-run_test!(new_sslstream, |method, stream| {
- 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.ssl_method(), method);
+ SslContext::builder(method).unwrap();
});
run_test!(verify_untrusted, |method, stream| {
- let mut ctx = SslContext::new(method).unwrap();
+ let mut ctx = SslContext::builder(method).unwrap();
ctx.set_verify(SSL_VERIFY_PEER);
- match SslStream::connect(&ctx, stream) {
+ match Ssl::new(&ctx.build()).unwrap().connect(stream) {
Ok(_) => panic!("expected failure"),
Err(err) => println!("error {:?}", err),
}
});
run_test!(verify_trusted, |method, stream| {
- let mut ctx = SslContext::new(method).unwrap();
+ let mut ctx = SslContext::builder(method).unwrap();
ctx.set_verify(SSL_VERIFY_PEER);
- match ctx.set_CA_file(&Path::new("test/root-ca.pem")) {
+ match ctx.set_ca_file(&Path::new("test/root-ca.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
- match SslStream::connect(&ctx, stream) {
+ match Ssl::new(&ctx.build()).unwrap().connect(stream) {
Ok(_) => (),
Err(err) => panic!("Expected success, got {:?}", err),
}
});
run_test!(verify_untrusted_callback_override_ok, |method, stream| {
- let mut ctx = SslContext::new(method).unwrap();
+ let mut ctx = SslContext::builder(method).unwrap();
ctx.set_verify_callback(SSL_VERIFY_PEER, |_, _| true);
- match SslStream::connect(&ctx, stream) {
+ match Ssl::new(&ctx.build()).unwrap().connect(stream) {
Ok(_) => (),
Err(err) => panic!("Expected success, got {:?}", err),
}
});
run_test!(verify_untrusted_callback_override_bad, |method, stream| {
- let mut ctx = SslContext::new(method).unwrap();
+ let mut ctx = SslContext::builder(method).unwrap();
ctx.set_verify_callback(SSL_VERIFY_PEER, |_, _| false);
- assert!(SslStream::connect(&ctx, stream).is_err());
+ assert!(Ssl::new(&ctx.build()).unwrap().connect(stream).is_err());
});
run_test!(verify_trusted_callback_override_ok, |method, stream| {
- let mut ctx = SslContext::new(method).unwrap();
+ let mut ctx = SslContext::builder(method).unwrap();
ctx.set_verify_callback(SSL_VERIFY_PEER, |_, _| true);
- match ctx.set_CA_file(&Path::new("test/cert.pem")) {
+ match ctx.set_ca_file(&Path::new("test/cert.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
- match SslStream::connect(&ctx, stream) {
+ match Ssl::new(&ctx.build()).unwrap().connect(stream) {
Ok(_) => (),
Err(err) => panic!("Expected success, got {:?}", err),
}
});
run_test!(verify_trusted_callback_override_bad, |method, stream| {
- let mut ctx = SslContext::new(method).unwrap();
+ let mut ctx = SslContext::builder(method).unwrap();
ctx.set_verify_callback(SSL_VERIFY_PEER, |_, _| false);
- match ctx.set_CA_file(&Path::new("test/cert.pem")) {
+ match ctx.set_ca_file(&Path::new("test/cert.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
- assert!(SslStream::connect(&ctx, stream).is_err());
+ assert!(Ssl::new(&ctx.build()).unwrap().connect(stream).is_err());
});
run_test!(verify_callback_load_certs, |method, stream| {
- let mut ctx = SslContext::new(method).unwrap();
+ let mut ctx = SslContext::builder(method).unwrap();
ctx.set_verify_callback(SSL_VERIFY_PEER, |_, x509_ctx| {
assert!(x509_ctx.current_cert().is_some());
true
});
- assert!(SslStream::connect(&ctx, stream).is_ok());
+ assert!(Ssl::new(&ctx.build()).unwrap().connect(stream).is_ok());
});
run_test!(verify_trusted_get_error_ok, |method, stream| {
- let mut ctx = SslContext::new(method).unwrap();
+ let mut ctx = SslContext::builder(method).unwrap();
ctx.set_verify_callback(SSL_VERIFY_PEER, |_, x509_ctx| {
assert!(x509_ctx.error().is_none());
true
});
- match ctx.set_CA_file(&Path::new("test/root-ca.pem")) {
+ match ctx.set_ca_file(&Path::new("test/root-ca.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
- assert!(SslStream::connect(&ctx, stream).is_ok());
+ assert!(Ssl::new(&ctx.build()).unwrap().connect(stream).is_ok());
});
run_test!(verify_trusted_get_error_err, |method, stream| {
- let mut ctx = SslContext::new(method).unwrap();
+ let mut ctx = SslContext::builder(method).unwrap();
ctx.set_verify_callback(SSL_VERIFY_PEER, |_, x509_ctx| {
assert!(x509_ctx.error().is_some());
false
});
- assert!(SslStream::connect(&ctx, stream).is_err());
+ assert!(Ssl::new(&ctx.build()).unwrap().connect(stream).is_err());
});
run_test!(verify_callback_data, |method, stream| {
- let mut ctx = SslContext::new(method).unwrap();
+ let mut ctx = SslContext::builder(method).unwrap();
- // Node id was generated as SHA256 hash of certificate "test/cert.pem"
- // in DER format.
- // Command: openssl x509 -in test/cert.pem -outform DER | openssl dgst -sha256
- // Please update if "test/cert.pem" will ever change
+// Node id was generated as SHA256 hash of certificate "test/cert.pem"
+// in DER format.
+// Command: openssl x509 -in test/cert.pem -outform DER | openssl dgst -sha256
+// Please update if "test/cert.pem" will ever change
let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584";
let node_id = node_hash_str.from_hex().unwrap();
ctx.set_verify_callback(SSL_VERIFY_PEER, move |_preverify_ok, x509_ctx| {
@@ -345,14 +308,14 @@ run_test!(verify_callback_data, |method, stream| {
match cert {
None => false,
Some(cert) => {
- let fingerprint = cert.fingerprint(SHA1).unwrap();
+ let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap();
fingerprint == node_id
}
}
});
ctx.set_verify_depth(1);
- match SslStream::connect(&ctx, stream) {
+ match Ssl::new(&ctx.build()).unwrap().connect(stream) {
Ok(_) => (),
Err(err) => panic!("Expected success, got {:?}", err),
}
@@ -360,12 +323,11 @@ run_test!(verify_callback_data, |method, stream| {
run_test!(ssl_verify_callback, |method, stream| {
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
- use ssl::IntoSsl;
static CHECKED: AtomicUsize = ATOMIC_USIZE_INIT;
- let ctx = SslContext::new(method).unwrap();
- let mut ssl = ctx.into_ssl().unwrap();
+ let ctx = SslContext::builder(method).unwrap();
+ let mut ssl = Ssl::new(&ctx.build()).unwrap();
let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584";
let node_id = node_hash_str.from_hex().unwrap();
@@ -374,13 +336,13 @@ run_test!(ssl_verify_callback, |method, stream| {
match x509.current_cert() {
None => false,
Some(cert) => {
- let fingerprint = cert.fingerprint(SHA1).unwrap();
+ let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap();
fingerprint == node_id
}
}
});
- match SslStream::connect(ssl, stream) {
+ match ssl.connect(stream) {
Ok(_) => (),
Err(err) => panic!("Expected success, got {:?}", err),
}
@@ -391,24 +353,24 @@ run_test!(ssl_verify_callback, |method, stream| {
// Make sure every write call translates to a write call to the underlying socket.
#[test]
fn test_write_hits_stream() {
- let listener = TcpListener::bind(next_addr()).unwrap();
+ let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();
let guard = thread::spawn(move || {
- let ctx = SslContext::new(Sslv23).unwrap();
+ let ctx = SslContext::builder(SslMethod::tls()).unwrap();
let stream = TcpStream::connect(addr).unwrap();
- let mut stream = SslStream::connect(&ctx, stream).unwrap();
+ let mut stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap();
stream.write_all(b"hello").unwrap();
stream
});
- let mut ctx = SslContext::new(Sslv23).unwrap();
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
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();
+ ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM).unwrap();
+ ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM).unwrap();
let stream = listener.accept().unwrap().0;
- let mut stream = SslStream::accept(&ctx, stream).unwrap();
+ let mut stream = Ssl::new(&ctx.build()).unwrap().accept(stream).unwrap();
let mut buf = [0; 5];
assert_eq!(5, stream.read(&mut buf).unwrap());
@@ -423,7 +385,7 @@ fn test_set_certificate_and_private_key() {
let cert = include_bytes!("../../../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();
- let mut ctx = SslContext::new(Sslv23).unwrap();
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
ctx.set_private_key(&key).unwrap();
ctx.set_certificate(&cert).unwrap();
@@ -431,18 +393,18 @@ fn test_set_certificate_and_private_key() {
}
run_test!(get_ctx_options, |method, _| {
- let ctx = SslContext::new(method).unwrap();
+ let ctx = SslContext::builder(method).unwrap();
ctx.options();
});
run_test!(set_ctx_options, |method, _| {
- let mut ctx = SslContext::new(method).unwrap();
+ let mut ctx = SslContext::builder(method).unwrap();
let opts = ctx.set_options(ssl::SSL_OP_NO_TICKET);
assert!(opts.contains(ssl::SSL_OP_NO_TICKET));
});
run_test!(clear_ctx_options, |method, _| {
- let mut ctx = SslContext::new(method).unwrap();
+ let mut ctx = SslContext::builder(method).unwrap();
ctx.set_options(ssl::SSL_OP_ALL);
let opts = ctx.clear_options(ssl::SSL_OP_ALL);
assert!(!opts.contains(ssl::SSL_OP_ALL));
@@ -451,17 +413,8 @@ run_test!(clear_ctx_options, |method, _| {
#[test]
fn test_write() {
let (_s, stream) = Server::new();
- 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();
- stream.flush().unwrap();
-}
-
-#[test]
-fn test_write_direct() {
- let (_s, stream) = Server::new();
- let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), stream).unwrap();
+ let ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ let mut stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap();
stream.write_all("hello".as_bytes()).unwrap();
stream.flush().unwrap();
stream.write_all(" there".as_bytes()).unwrap();
@@ -469,20 +422,21 @@ fn test_write_direct() {
}
run_test!(get_peer_certificate, |method, stream| {
- let stream = SslStream::connect(&SslContext::new(method).unwrap(), stream).unwrap();
+ let ctx = SslContext::builder(method).unwrap();
+ let stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap();
let cert = stream.ssl().peer_certificate().unwrap();
- let fingerprint = cert.fingerprint(SHA1).unwrap();
+ let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap();
let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584";
let node_id = node_hash_str.from_hex().unwrap();
assert_eq!(node_id, fingerprint)
});
#[test]
-#[cfg(feature = "dtlsv1")]
+#[cfg_attr(any(windows, target_arch = "arm"), ignore)] // FIXME(#467)
fn test_write_dtlsv1() {
let (_s, stream) = Server::new_dtlsv1(iter::repeat("y\n"));
-
- let mut stream = SslStream::connect(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap();
+ let ctx = SslContext::builder(SslMethod::dtls()).unwrap();
+ let mut stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap();
stream.write_all(b"hello").unwrap();
stream.flush().unwrap();
stream.write_all(b" there").unwrap();
@@ -492,16 +446,8 @@ fn test_write_dtlsv1() {
#[test]
fn test_read() {
let (_s, tcp) = Server::new();
- 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");
-}
-
-#[test]
-fn test_read_direct() {
- let (_s, tcp) = Server::new();
- let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap();
+ let ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ let mut stream = Ssl::new(&ctx.build()).unwrap().connect(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");
@@ -510,7 +456,8 @@ fn test_read_direct() {
#[test]
fn test_pending() {
let (_s, tcp) = Server::new();
- let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap();
+ let ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ let mut stream = Ssl::new(&ctx.build()).unwrap().connect(tcp).unwrap();
stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap();
stream.flush().unwrap();
@@ -533,7 +480,8 @@ fn test_pending() {
#[test]
fn test_state() {
let (_s, tcp) = Server::new();
- let stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap();
+ let ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ let stream = Ssl::new(&ctx.build()).unwrap().connect(tcp).unwrap();
assert_eq!(stream.ssl().state_string(), "SSLOK ");
assert_eq!(stream.ssl().state_string_long(),
"SSL negotiation finished successfully");
@@ -542,17 +490,17 @@ fn test_state() {
/// Tests that connecting with the client using ALPN, but the server not does not
/// break the existing connection behavior.
#[test]
-#[cfg(feature = "alpn")]
+#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
fn test_connect_with_unilateral_alpn() {
let (_s, stream) = Server::new();
- let mut ctx = SslContext::new(Sslv23).unwrap();
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
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/root-ca.pem")) {
+ ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]).unwrap();
+ match ctx.set_ca_file(&Path::new("test/root-ca.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
- let stream = match SslStream::connect(&ctx, stream) {
+ let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) {
Ok(stream) => stream,
Err(err) => panic!("Expected success, got {:?}", err),
};
@@ -564,17 +512,16 @@ fn test_connect_with_unilateral_alpn() {
/// Tests that connecting with the client using NPN, but the server not does not
/// break the existing connection behavior.
#[test]
-#[cfg(feature = "npn")]
fn test_connect_with_unilateral_npn() {
let (_s, stream) = Server::new();
- let mut ctx = SslContext::new(Sslv23).unwrap();
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
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/root-ca.pem")) {
+ ctx.set_npn_protocols(&[b"http/1.1", b"spdy/3.1"]).unwrap();
+ match ctx.set_ca_file(&Path::new("test/root-ca.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
- let stream = match SslStream::connect(&ctx, stream) {
+ let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) {
Ok(stream) => stream,
Err(err) => panic!("Expected success, got {:?}", err),
};
@@ -586,17 +533,17 @@ fn test_connect_with_unilateral_npn() {
/// Tests that when both the client as well as the server use ALPN and their
/// lists of supported protocols have an overlap, the correct protocol is chosen.
#[test]
-#[cfg(feature = "alpn")]
+#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
fn test_connect_with_alpn_successful_multiple_matching() {
let (_s, stream) = Server::new_alpn();
- let mut ctx = SslContext::new(Sslv23).unwrap();
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
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/root-ca.pem")) {
+ ctx.set_alpn_protocols(&[b"spdy/3.1", b"http/1.1"]).unwrap();
+ match ctx.set_ca_file(&Path::new("test/root-ca.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
- let stream = match SslStream::connect(&ctx, stream) {
+ let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) {
Ok(stream) => stream,
Err(err) => panic!("Expected success, got {:?}", err),
};
@@ -608,17 +555,17 @@ fn test_connect_with_alpn_successful_multiple_matching() {
/// Tests that when both the client as well as the server use NPN and their
/// lists of supported protocols have an overlap, the correct protocol is chosen.
#[test]
-#[cfg(feature = "npn")]
+#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
fn test_connect_with_npn_successful_multiple_matching() {
let (_s, stream) = Server::new_alpn();
- let mut ctx = SslContext::new(Sslv23).unwrap();
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
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/root-ca.pem")) {
+ ctx.set_npn_protocols(&[b"spdy/3.1", b"http/1.1"]).unwrap();
+ match ctx.set_ca_file(&Path::new("test/root-ca.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
- let stream = match SslStream::connect(&ctx, stream) {
+ let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) {
Ok(stream) => stream,
Err(err) => panic!("Expected success, got {:?}", err),
};
@@ -631,17 +578,17 @@ fn test_connect_with_npn_successful_multiple_matching() {
/// lists of supported protocols have an overlap -- with only ONE protocol
/// being valid for both.
#[test]
-#[cfg(feature = "alpn")]
+#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
fn test_connect_with_alpn_successful_single_match() {
let (_s, stream) = Server::new_alpn();
- let mut ctx = SslContext::new(Sslv23).unwrap();
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
ctx.set_verify(SSL_VERIFY_PEER);
- ctx.set_alpn_protocols(&[b"spdy/3.1"]);
- match ctx.set_CA_file(&Path::new("test/root-ca.pem")) {
+ ctx.set_alpn_protocols(&[b"spdy/3.1"]).unwrap();
+ match ctx.set_ca_file(&Path::new("test/root-ca.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
- let stream = match SslStream::connect(&ctx, stream) {
+ let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) {
Ok(stream) => stream,
Err(err) => panic!("Expected success, got {:?}", err),
};
@@ -655,17 +602,17 @@ fn test_connect_with_alpn_successful_single_match() {
/// lists of supported protocols have an overlap -- with only ONE protocol
/// being valid for both.
#[test]
-#[cfg(feature = "npn")]
+#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
fn test_connect_with_npn_successful_single_match() {
let (_s, stream) = Server::new_alpn();
- let mut ctx = SslContext::new(Sslv23).unwrap();
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
ctx.set_verify(SSL_VERIFY_PEER);
- ctx.set_npn_protocols(&[b"spdy/3.1"]);
- match ctx.set_CA_file(&Path::new("test/root-ca.pem")) {
+ ctx.set_npn_protocols(&[b"spdy/3.1"]).unwrap();
+ match ctx.set_ca_file(&Path::new("test/root-ca.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
- let stream = match SslStream::connect(&ctx, stream) {
+ let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) {
Ok(stream) => stream,
Err(err) => panic!("Expected success, got {:?}", err),
};
@@ -677,37 +624,36 @@ fn test_connect_with_npn_successful_single_match() {
/// Tests that when the `SslStream` is created as a server stream, the protocols
/// are correctly advertised to the client.
#[test]
-#[cfg(feature = "npn")]
fn test_npn_server_advertise_multiple() {
- let listener = TcpListener::bind(next_addr()).unwrap();
+ let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let localhost = listener.local_addr().unwrap();
// We create a different context instance for the server...
let listener_ctx = {
- let mut ctx = SslContext::new(Sslv23).unwrap();
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
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)
+ ctx.set_npn_protocols(&[b"http/1.1", b"spdy/3.1"]).unwrap();
+ assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM)
.is_ok());
- ctx.set_private_key_file(&Path::new("test/key.pem"), X509FileType::PEM)
- .unwrap();
- ctx
+ ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM)
+ .unwrap();
+ ctx.build()
};
// Have the listener wait on the connection in a different thread.
thread::spawn(move || {
let (stream, _) = listener.accept().unwrap();
- let _ = SslStream::accept(&listener_ctx, stream).unwrap();
+ Ssl::new(&listener_ctx).unwrap().accept(stream).unwrap();
});
- let mut ctx = SslContext::new(Sslv23).unwrap();
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
ctx.set_verify(SSL_VERIFY_PEER);
- ctx.set_npn_protocols(&[b"spdy/3.1"]);
- match ctx.set_CA_file(&Path::new("test/root-ca.pem")) {
+ ctx.set_npn_protocols(&[b"spdy/3.1"]).unwrap();
+ match ctx.set_ca_file(&Path::new("test/root-ca.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
// Now connect to the socket and make sure the protocol negotiation works...
let stream = TcpStream::connect(localhost).unwrap();
- let stream = match SslStream::connect(&ctx, stream) {
+ let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) {
Ok(stream) => stream,
Err(err) => panic!("Expected success, got {:?}", err),
};
@@ -718,37 +664,37 @@ fn test_npn_server_advertise_multiple() {
/// Tests that when the `SslStream` is created as a server stream, the protocols
/// are correctly advertised to the client.
#[test]
-#[cfg(feature = "alpn")]
+#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
fn test_alpn_server_advertise_multiple() {
- let listener = TcpListener::bind(next_addr()).unwrap();
+ let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let localhost = listener.local_addr().unwrap();
// We create a different context instance for the server...
let listener_ctx = {
- let mut ctx = SslContext::new(Sslv23).unwrap();
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
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)
+ ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]).unwrap();
+ assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM)
.is_ok());
- ctx.set_private_key_file(&Path::new("test/key.pem"), X509FileType::PEM)
- .unwrap();
- ctx
+ ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM)
+ .unwrap();
+ ctx.build()
};
// Have the listener wait on the connection in a different thread.
thread::spawn(move || {
let (stream, _) = listener.accept().unwrap();
- let _ = SslStream::accept(&listener_ctx, stream).unwrap();
+ Ssl::new(&listener_ctx).unwrap().accept(stream).unwrap();
});
- let mut ctx = SslContext::new(Sslv23).unwrap();
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
ctx.set_verify(SSL_VERIFY_PEER);
- ctx.set_alpn_protocols(&[b"spdy/3.1"]);
- match ctx.set_CA_file(&Path::new("test/root-ca.pem")) {
+ ctx.set_alpn_protocols(&[b"spdy/3.1"]).unwrap();
+ match ctx.set_ca_file(&Path::new("test/root-ca.pem")) {
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
// Now connect to the socket and make sure the protocol negotiation works...
let stream = TcpStream::connect(localhost).unwrap();
- let stream = match SslStream::connect(&ctx, stream) {
+ let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) {
Ok(stream) => stream,
Err(err) => panic!("Expected success, got {:?}", err),
};
@@ -759,87 +705,82 @@ fn test_alpn_server_advertise_multiple() {
/// Test that Servers supporting ALPN don't report a protocol when none of their protocols match
/// the client's reported protocol.
#[test]
-#[cfg(feature = "alpn")]
+#[cfg(all(feature = "v102", ossl102))]
fn test_alpn_server_select_none() {
- let listener = TcpListener::bind(next_addr()).unwrap();
+ let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let localhost = listener.local_addr().unwrap();
// We create a different context instance for the server...
let listener_ctx = {
- let mut ctx = SslContext::new(Sslv23).unwrap();
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
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)
+ ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]).unwrap();
+ assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM)
.is_ok());
- ctx.set_private_key_file(&Path::new("test/key.pem"), X509FileType::PEM)
- .unwrap();
- ctx
+ ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM)
+ .unwrap();
+ ctx.build()
};
// Have the listener wait on the connection in a different thread.
thread::spawn(move || {
let (stream, _) = listener.accept().unwrap();
- let _ = SslStream::accept(&listener_ctx, stream).unwrap();
+ Ssl::new(&listener_ctx).unwrap().accept(stream).unwrap();
});
- let mut ctx = SslContext::new(Sslv23).unwrap();
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
ctx.set_verify(SSL_VERIFY_PEER);
- ctx.set_alpn_protocols(&[b"http/2"]);
- match ctx.set_CA_file(&Path::new("test/root-ca.pem")) {
- Ok(_) => {}
- Err(err) => panic!("Unexpected error {:?}", err),
- }
+ ctx.set_alpn_protocols(&[b"http/2"]).unwrap();
+ ctx.set_ca_file(&Path::new("test/root-ca.pem")).unwrap();
// Now connect to the socket and make sure the protocol negotiation works...
let stream = TcpStream::connect(localhost).unwrap();
- let stream = match SslStream::connect(&ctx, stream) {
- Ok(stream) => stream,
- Err(err) => panic!("Expected success, got {:?}", err),
- };
+ let stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap();
// Since the protocols from the server and client don't overlap at all, no protocol is selected
assert_eq!(None, stream.ssl().selected_alpn_protocol());
}
+// In 1.1.0, ALPN negotiation failure is a fatal error
+#[test]
+#[cfg(all(feature = "v110", ossl110))]
+fn test_alpn_server_select_none() {
+ let listener = TcpListener::bind("127.0.0.1:0").unwrap();
+ let localhost = listener.local_addr().unwrap();
+ // We create a different context instance for the server...
+ let listener_ctx = {
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ ctx.set_verify(SSL_VERIFY_PEER);
+ ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]).unwrap();
+ assert!(ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM)
+ .is_ok());
+ ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM)
+ .unwrap();
+ ctx.build()
+ };
+ // Have the listener wait on the connection in a different thread.
+ thread::spawn(move || {
+ let (stream, _) = listener.accept().unwrap();
+ assert!(Ssl::new(&listener_ctx).unwrap().accept(stream).is_err());
+ });
-#[cfg(feature="dtlsv1")]
-#[cfg(test)]
-mod dtlsv1 {
- use serialize::hex::FromHex;
- use std::net::TcpStream;
- use std::thread;
-
- use crypto::hash::Type::SHA256;
- use ssl::SslMethod;
- use ssl::SslMethod::Dtlsv1;
- use ssl::{SslContext, SslStream};
- use ssl::SSL_VERIFY_PEER;
- use x509::X509StoreContext;
-
- const PROTOCOL: SslMethod = Dtlsv1;
-
- #[test]
- fn test_new_ctx() {
- SslContext::new(PROTOCOL).unwrap();
- }
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ ctx.set_verify(SSL_VERIFY_PEER);
+ ctx.set_alpn_protocols(&[b"http/2"]).unwrap();
+ ctx.set_ca_file(&Path::new("test/root-ca.pem")).unwrap();
+ // Now connect to the socket and make sure the protocol negotiation works...
+ let stream = TcpStream::connect(localhost).unwrap();
+ assert!(Ssl::new(&ctx.build()).unwrap().connect(stream).is_err());
}
#[test]
-#[cfg(feature = "dtlsv1")]
+#[cfg_attr(any(windows, target_arch = "arm"), ignore)] // FIXME(#467)
fn test_read_dtlsv1() {
let (_s, stream) = Server::new_dtlsv1(Some("hello"));
- let mut stream = SslStream::connect(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap();
+ let ctx = SslContext::builder(SslMethod::dtls()).unwrap();
+ let mut stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap();
let mut buf = [0u8; 100];
assert!(stream.read(&mut buf).is_ok());
}
-#[test]
-#[cfg(feature = "sslv2")]
-fn test_sslv2_connect_failure() {
- let (_s, tcp) = Server::new_tcp(&["-no_ssl2", "-www"]);
- SslStream::connect(&SslContext::new(Sslv2).unwrap(), tcp)
- .err()
- .unwrap();
-}
-
fn wait_io(stream: &TcpStream, read: bool, timeout_ms: u32) -> bool {
unsafe {
let mut set: select::fd_set = mem::zeroed();
@@ -859,8 +800,7 @@ fn wait_io(stream: &TcpStream, read: bool, timeout_ms: u32) -> bool {
}
}
-fn handshake(res: Result<SslStream<TcpStream>, HandshakeError<TcpStream>>)
- -> SslStream<TcpStream> {
+fn handshake(res: Result<SslStream<TcpStream>, HandshakeError<TcpStream>>) -> SslStream<TcpStream> {
match res {
Ok(s) => s,
Err(HandshakeError::Interrupted(s)) => {
@@ -875,8 +815,8 @@ fn handshake(res: Result<SslStream<TcpStream>, HandshakeError<TcpStream>>)
fn test_write_nonblocking() {
let (_s, stream) = Server::new();
stream.set_nonblocking(true).unwrap();
- let cx = SslContext::new(Sslv23).unwrap();
- let mut stream = handshake(SslStream::connect(&cx, stream));
+ let cx = SslContext::builder(SslMethod::tls()).unwrap().build();
+ let mut stream = handshake(Ssl::new(&cx).unwrap().connect(stream));
let mut iterations = 0;
loop {
@@ -909,12 +849,12 @@ fn test_write_nonblocking() {
}
#[test]
-#[cfg_attr(windows, ignore)] // FIXME flickers on appveyor
+#[cfg_attr(any(windows, target_arch = "arm"), ignore)] // FIXME(#467)
fn test_read_nonblocking() {
let (_s, stream) = Server::new();
stream.set_nonblocking(true).unwrap();
- let cx = SslContext::new(Sslv23).unwrap();
- let mut stream = handshake(SslStream::connect(&cx, stream));
+ let cx = SslContext::builder(SslMethod::tls()).unwrap().build();
+ let mut stream = handshake(Ssl::new(&cx).unwrap().connect(stream));
let mut iterations = 0;
loop {
@@ -965,7 +905,6 @@ fn test_read_nonblocking() {
#[test]
#[should_panic(expected = "blammo")]
-#[cfg(feature = "nightly")]
fn write_panic() {
struct ExplodingStream(TcpStream);
@@ -988,13 +927,12 @@ fn write_panic() {
let (_s, stream) = Server::new();
let stream = ExplodingStream(stream);
- let ctx = SslContext::new(SslMethod::Sslv23).unwrap();
- let _ = SslStream::connect(&ctx, stream);
+ let ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ let _ = Ssl::new(&ctx.build()).unwrap().connect(stream);
}
#[test]
#[should_panic(expected = "blammo")]
-#[cfg(feature = "nightly")]
fn read_panic() {
struct ExplodingStream(TcpStream);
@@ -1017,13 +955,12 @@ fn read_panic() {
let (_s, stream) = Server::new();
let stream = ExplodingStream(stream);
- let ctx = SslContext::new(SslMethod::Sslv23).unwrap();
- let _ = SslStream::connect(&ctx, stream);
+ let ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ let _ = Ssl::new(&ctx.build()).unwrap().connect(stream);
}
#[test]
#[should_panic(expected = "blammo")]
-#[cfg(feature = "nightly")]
fn flush_panic() {
struct ExplodingStream(TcpStream);
@@ -1046,32 +983,31 @@ fn flush_panic() {
let (_s, stream) = Server::new();
let stream = ExplodingStream(stream);
- let ctx = SslContext::new(SslMethod::Sslv23).unwrap();
- let mut stream = SslStream::connect(&ctx, stream).unwrap();
+ let ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ let mut stream = Ssl::new(&ctx.build()).unwrap().connect(stream).ok().unwrap();
let _ = stream.flush();
}
#[test]
fn refcount_ssl_context() {
let mut ssl = {
- let ctx = SslContext::new(SslMethod::Sslv23).unwrap();
- ssl::Ssl::new(&ctx).unwrap()
+ let ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ ssl::Ssl::new(&ctx.build()).unwrap()
};
{
- let new_ctx_a = SslContext::new(SslMethod::Sslv23).unwrap();
+ let new_ctx_a = SslContext::builder(SslMethod::tls()).unwrap().build();
let _new_ctx_b = ssl.set_ssl_context(&new_ctx_a);
}
}
#[test]
-#[cfg_attr(windows, ignore)] // don't have a trusted CA list easily available :(
fn default_verify_paths() {
- let mut ctx = SslContext::new(SslMethod::Sslv23).unwrap();
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
ctx.set_default_verify_paths().unwrap();
ctx.set_verify(SSL_VERIFY_PEER);
let s = TcpStream::connect("google.com:443").unwrap();
- let mut socket = SslStream::connect(&ctx, s).unwrap();
+ let mut socket = Ssl::new(&ctx.build()).unwrap().connect(s).unwrap();
socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
let mut result = vec![];
@@ -1086,6 +1022,172 @@ fn default_verify_paths() {
fn add_extra_chain_cert() {
let cert = include_bytes!("../../../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();
- let mut ctx = SslContext::new(SslMethod::Sslv23).unwrap();
- ctx.add_extra_chain_cert(&cert).unwrap();
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ ctx.add_extra_chain_cert(cert).unwrap();
+}
+
+#[test]
+#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
+fn verify_valid_hostname() {
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ ctx.set_default_verify_paths().unwrap();
+ ctx.set_verify(SSL_VERIFY_PEER);
+
+ let mut ssl = Ssl::new(&ctx.build()).unwrap();
+ ssl.param_mut().set_hostflags(X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
+ ssl.param_mut().set_host("google.com").unwrap();
+
+ let s = TcpStream::connect("google.com:443").unwrap();
+ let mut socket = ssl.connect(s).unwrap();
+
+ socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
+ let mut result = vec![];
+ socket.read_to_end(&mut result).unwrap();
+
+ println!("{}", String::from_utf8_lossy(&result));
+ assert!(result.starts_with(b"HTTP/1.0"));
+ assert!(result.ends_with(b"</HTML>\r\n") || result.ends_with(b"</html>"));
+}
+
+#[test]
+#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
+fn verify_invalid_hostname() {
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ ctx.set_default_verify_paths().unwrap();
+ ctx.set_verify(SSL_VERIFY_PEER);
+
+ let mut ssl = Ssl::new(&ctx.build()).unwrap();
+ ssl.param_mut().set_hostflags(X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
+ ssl.param_mut().set_host("foobar.com").unwrap();
+
+ let s = TcpStream::connect("google.com:443").unwrap();
+ assert!(ssl.connect(s).is_err());
+}
+
+#[test]
+fn connector_valid_hostname() {
+ let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build();
+
+ let s = TcpStream::connect("google.com:443").unwrap();
+ let mut socket = connector.connect("google.com", s).unwrap();
+
+ socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
+ let mut result = vec![];
+ socket.read_to_end(&mut result).unwrap();
+
+ println!("{}", String::from_utf8_lossy(&result));
+ assert!(result.starts_with(b"HTTP/1.0"));
+ assert!(result.ends_with(b"</HTML>\r\n") || result.ends_with(b"</html>"));
+}
+
+#[test]
+fn connector_invalid_hostname() {
+ let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build();
+
+ let s = TcpStream::connect("google.com:443").unwrap();
+ assert!(connector.connect("foobar.com", s).is_err());
+}
+
+#[test]
+fn connector_client_server_mozilla_intermediate() {
+ let listener = TcpListener::bind("127.0.0.1:0").unwrap();
+ let port = listener.local_addr().unwrap().port();
+
+ let t = thread::spawn(move || {
+ let key = PKey::private_key_from_pem(KEY).unwrap();
+ let cert = X509::from_pem(CERT).unwrap();
+ let connector =
+ SslAcceptorBuilder::mozilla_intermediate(SslMethod::tls(), &key, &cert, None::<X509>)
+ .unwrap()
+ .build();
+ let stream = listener.accept().unwrap().0;
+ let mut stream = connector.accept(stream).unwrap();
+
+ stream.write_all(b"hello").unwrap();
+ });
+
+ let mut connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
+ connector.builder_mut().set_ca_file("test/root-ca.pem").unwrap();
+ let connector = connector.build();
+
+ let stream = TcpStream::connect(("127.0.0.1", port)).unwrap();
+ let mut stream = connector.connect("foobar.com", stream).unwrap();
+
+ let mut buf = [0; 5];
+ stream.read_exact(&mut buf).unwrap();
+ assert_eq!(b"hello", &buf);
+
+ t.join().unwrap();
+}
+
+#[test]
+fn connector_client_server_mozilla_modern() {
+ let listener = TcpListener::bind("127.0.0.1:0").unwrap();
+ let port = listener.local_addr().unwrap().port();
+
+ let t = thread::spawn(move || {
+ let key = PKey::private_key_from_pem(KEY).unwrap();
+ let cert = X509::from_pem(CERT).unwrap();
+ let connector =
+ SslAcceptorBuilder::mozilla_modern(SslMethod::tls(), &key, &cert, None::<X509>)
+ .unwrap()
+ .build();
+ let stream = listener.accept().unwrap().0;
+ let mut stream = connector.accept(stream).unwrap();
+
+ stream.write_all(b"hello").unwrap();
+ });
+
+ let mut connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
+ connector.builder_mut().set_ca_file("test/root-ca.pem").unwrap();
+ let connector = connector.build();
+
+ let stream = TcpStream::connect(("127.0.0.1", port)).unwrap();
+ let mut stream = connector.connect("foobar.com", stream).unwrap();
+
+ let mut buf = [0; 5];
+ stream.read_exact(&mut buf).unwrap();
+ assert_eq!(b"hello", &buf);
+
+ t.join().unwrap();
+}
+
+#[test]
+fn shutdown() {
+ let listener = TcpListener::bind("127.0.0.1:0").unwrap();
+ let port = listener.local_addr().unwrap().port();
+
+ thread::spawn(move || {
+ let stream = listener.accept().unwrap().0;
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM).unwrap();
+ ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM).unwrap();
+ let ssl = Ssl::new(&ctx.build()).unwrap();
+ let mut stream = ssl.accept(stream).unwrap();
+
+ stream.write_all(b"hello").unwrap();
+ let mut buf = [0; 1];
+ assert_eq!(stream.read(&mut buf).unwrap(), 0);
+ assert_eq!(stream.shutdown().unwrap(), ShutdownResult::Received);
+ });
+
+ let stream = TcpStream::connect(("127.0.0.1", port)).unwrap();
+ let ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ let ssl = Ssl::new(&ctx.build()).unwrap();
+ let mut stream = ssl.connect(stream).unwrap();
+
+ let mut buf = [0; 5];
+ stream.read_exact(&mut buf).unwrap();
+ assert_eq!(b"hello", &buf);
+
+ assert_eq!(stream.shutdown().unwrap(), ShutdownResult::Sent);
+ assert_eq!(stream.shutdown().unwrap(), ShutdownResult::Received);
+}
+
+fn _check_kinds() {
+ fn is_send<T: Send>() {}
+ fn is_sync<T: Sync>() {}
+
+ is_send::<SslStream<TcpStream>>();
+ is_sync::<SslStream<TcpStream>>();
}
diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs
new file mode 100644
index 00000000..dae42ca8
--- /dev/null
+++ b/openssl/src/stack.rs
@@ -0,0 +1,331 @@
+use std::ops::{Deref, DerefMut, Index, IndexMut};
+use std::iter;
+use std::borrow::Borrow;
+use std::convert::AsRef;
+use std::marker::PhantomData;
+use libc::c_int;
+use std::mem;
+
+use types::{OpenSslType, OpenSslTypeRef};
+use util::Opaque;
+
+#[cfg(ossl10x)]
+use ffi::{sk_pop as OPENSSL_sk_pop, sk_free as OPENSSL_sk_free, sk_num as OPENSSL_sk_num,
+ sk_value as OPENSSL_sk_value, _STACK as OPENSSL_STACK};
+#[cfg(ossl110)]
+use ffi::{OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value, OPENSSL_STACK};
+
+/// Trait implemented by types which can be placed in a stack.
+///
+/// Like `OpenSslType`, it should not be implemented for any type outside
+/// of this crate.
+pub trait Stackable: OpenSslType {
+ /// The C stack type for this element.
+ ///
+ /// Generally called `stack_st_{ELEMENT_TYPE}`, normally hidden by the
+ /// `STACK_OF(ELEMENT_TYPE)` macro in the OpenSSL API.
+ type StackType;
+}
+
+/// An owned stack of `T`.
+pub struct Stack<T: Stackable>(*mut T::StackType);
+
+impl<T: Stackable> Stack<T> {
+ /// Return a new Stack<T>, taking ownership of the handle
+ pub unsafe fn from_ptr(stack: *mut T::StackType) -> Stack<T> {
+ Stack(stack)
+ }
+}
+
+impl<T: Stackable> Drop for Stack<T> {
+ fn drop(&mut self) {
+ unsafe {
+ while let Some(_) = self.pop() {}
+ OPENSSL_sk_free(self.0 as *mut _);
+ }
+ }
+}
+
+impl<T: Stackable> iter::IntoIterator for Stack<T> {
+ type IntoIter = IntoIter<T>;
+ type Item = T;
+
+ fn into_iter(self) -> IntoIter<T> {
+ let it = IntoIter {
+ stack: self.0,
+ idx: 0,
+ };
+ mem::forget(self);
+ it
+ }
+}
+
+impl<T: Stackable> AsRef<StackRef<T>> for Stack<T> {
+ fn as_ref(&self) -> &StackRef<T> {
+ &*self
+ }
+}
+
+impl<T: Stackable> Borrow<StackRef<T>> for Stack<T> {
+ fn borrow(&self) -> &StackRef<T> {
+ &*self
+ }
+}
+
+impl<T: Stackable> OpenSslType for Stack<T> {
+ type CType = T::StackType;
+ type Ref = StackRef<T>;
+
+ unsafe fn from_ptr(ptr: *mut T::StackType) -> Stack<T> {
+ Stack(ptr)
+ }
+}
+
+impl<T: Stackable> Deref for Stack<T> {
+ type Target = StackRef<T>;
+
+ fn deref(&self) -> &StackRef<T> {
+ unsafe { StackRef::from_ptr(self.0) }
+ }
+}
+
+impl<T: Stackable> DerefMut for Stack<T> {
+ fn deref_mut(&mut self) -> &mut StackRef<T> {
+ unsafe { StackRef::from_ptr_mut(self.0) }
+ }
+}
+
+pub struct IntoIter<T: Stackable> {
+ stack: *mut T::StackType,
+ idx: c_int,
+}
+
+impl<T: Stackable> IntoIter<T> {
+ fn stack_len(&self) -> c_int {
+ unsafe { OPENSSL_sk_num(self.stack as *mut _) }
+ }
+}
+
+impl<T: Stackable> Drop for IntoIter<T> {
+ fn drop(&mut self) {
+ unsafe {
+ while let Some(_) = self.next() {}
+ OPENSSL_sk_free(self.stack as *mut _);
+ }
+ }
+}
+
+impl<T: Stackable> Iterator for IntoIter<T> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<T> {
+ unsafe {
+ if self.idx == self.stack_len() {
+ None
+ } else {
+ let ptr = OPENSSL_sk_value(self.stack as *mut _, self.idx);
+ self.idx += 1;
+ Some(T::from_ptr(ptr as *mut _))
+ }
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let size = (self.stack_len() - self.idx) as usize;
+ (size, Some(size))
+ }
+}
+
+impl<T: Stackable> ExactSizeIterator for IntoIter<T> {}
+
+pub struct StackRef<T: Stackable>(Opaque, PhantomData<T>);
+
+impl<T: Stackable> OpenSslTypeRef for StackRef<T> {
+ type CType = T::StackType;
+}
+
+impl<T: Stackable> StackRef<T> {
+ fn as_stack(&self) -> *mut OPENSSL_STACK {
+ self.as_ptr() as *mut _
+ }
+
+ /// Returns the number of items in the stack
+ pub fn len(&self) -> usize {
+ unsafe { OPENSSL_sk_num(self.as_stack()) as usize }
+ }
+
+ pub fn iter(&self) -> Iter<T> {
+ // Unfortunately we can't simply convert the stack into a
+ // slice and use that because OpenSSL 1.1.0 doesn't directly
+ // expose the stack data (we have to use `OPENSSL_sk_value`
+ // instead). We have to rewrite the entire iteration framework
+ // instead.
+
+ Iter {
+ stack: self,
+ pos: 0,
+ }
+ }
+
+ pub fn iter_mut(&mut self) -> IterMut<T> {
+ IterMut {
+ stack: self,
+ pos: 0,
+ }
+ }
+
+ /// Returns a reference to the element at the given index in the
+ /// stack or `None` if the index is out of bounds
+ pub fn get(&self, idx: usize) -> Option<&T::Ref> {
+ unsafe {
+ if idx >= self.len() {
+ return None;
+ }
+
+ Some(T::Ref::from_ptr(self._get(idx)))
+ }
+ }
+
+ /// Returns a mutable reference to the element at the given index in the
+ /// stack or `None` if the index is out of bounds
+ pub fn get_mut(&mut self, idx: usize) -> Option<&mut T::Ref> {
+ unsafe {
+ if idx >= self.len() {
+ return None;
+ }
+
+ Some(T::Ref::from_ptr_mut(self._get(idx)))
+ }
+ }
+
+ /// Removes the last element from the stack and returns it.
+ pub fn pop(&mut self) -> Option<T> {
+ unsafe {
+ let ptr = OPENSSL_sk_pop(self.as_stack());
+ if ptr.is_null() {
+ None
+ } else {
+ Some(T::from_ptr(ptr as *mut _))
+ }
+ }
+ }
+
+ unsafe fn _get(&self, idx: usize) -> *mut T::CType {
+ OPENSSL_sk_value(self.as_stack(), idx as c_int) as *mut _
+ }
+}
+
+impl<T: Stackable> Index<usize> for StackRef<T> {
+ type Output = T::Ref;
+
+ fn index(&self, index: usize) -> &T::Ref {
+ self.get(index).unwrap()
+ }
+}
+
+impl<T: Stackable> IndexMut<usize> for StackRef<T> {
+ fn index_mut(&mut self, index: usize) -> &mut T::Ref {
+ self.get_mut(index).unwrap()
+ }
+}
+
+impl<'a, T: Stackable> iter::IntoIterator for &'a StackRef<T> {
+ type Item = &'a T::Ref;
+ type IntoIter = Iter<'a, T>;
+
+ fn into_iter(self) -> Iter<'a, T> {
+ self.iter()
+ }
+}
+
+impl<'a, T: Stackable> iter::IntoIterator for &'a mut StackRef<T> {
+ type Item = &'a mut T::Ref;
+ type IntoIter = IterMut<'a, T>;
+
+ fn into_iter(self) -> IterMut<'a, T> {
+ self.iter_mut()
+ }
+}
+
+impl<'a, T: Stackable> iter::IntoIterator for &'a Stack<T> {
+ type Item = &'a T::Ref;
+ type IntoIter = Iter<'a, T>;
+
+ fn into_iter(self) -> Iter<'a, T> {
+ self.iter()
+ }
+}
+
+impl<'a, T: Stackable> iter::IntoIterator for &'a mut Stack<T> {
+ type Item = &'a mut T::Ref;
+ type IntoIter = IterMut<'a, T>;
+
+ fn into_iter(self) -> IterMut<'a, T> {
+ self.iter_mut()
+ }
+}
+
+/// An iterator over the stack's contents.
+pub struct Iter<'a, T: Stackable>
+ where T: 'a
+{
+ stack: &'a StackRef<T>,
+ pos: usize,
+}
+
+impl<'a, T: Stackable> iter::Iterator for Iter<'a, T> {
+ type Item = &'a T::Ref;
+
+ fn next(&mut self) -> Option<&'a T::Ref> {
+ let n = self.stack.get(self.pos);
+
+ if n.is_some() {
+ self.pos += 1;
+ }
+
+ n
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let rem = self.stack.len() - self.pos;
+
+ (rem, Some(rem))
+ }
+}
+
+impl<'a, T: Stackable> iter::ExactSizeIterator for Iter<'a, T> {}
+
+/// A mutable iterator over the stack's contents.
+pub struct IterMut<'a, T: Stackable + 'a> {
+ stack: &'a mut StackRef<T>,
+ pos: usize,
+}
+
+impl<'a, T: Stackable> iter::Iterator for IterMut<'a, T> {
+ type Item = &'a mut T::Ref;
+
+ fn next(&mut self) -> Option<&'a mut T::Ref> {
+ if self.pos >= self.stack.len() {
+ None
+ } else {
+ // Rust won't allow us to get a mutable reference into
+ // `stack` in this situation since it can't statically
+ // guarantee that we won't return several references to
+ // the same object, so we have to use unsafe code for
+ // mutable iterators.
+ let n = unsafe { Some(T::Ref::from_ptr_mut(self.stack._get(self.pos))) };
+
+ self.pos += 1;
+
+ n
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let rem = self.stack.len() - self.pos;
+
+ (rem, Some(rem))
+ }
+}
+
+impl<'a, T: Stackable> iter::ExactSizeIterator for IterMut<'a, T> {}
diff --git a/openssl/src/crypto/symm.rs b/openssl/src/symm.rs
index 93764e4d..d4b15f28 100644
--- a/openssl/src/crypto/symm.rs
+++ b/openssl/src/symm.rs
@@ -3,6 +3,7 @@ use std::ptr;
use libc::c_int;
use ffi;
+use {cvt, cvt_p};
use error::ErrorStack;
#[derive(Copy, Clone)]
@@ -11,90 +12,105 @@ pub enum Mode {
Decrypt,
}
-#[allow(non_camel_case_types)]
#[derive(Copy, Clone)]
-pub enum Type {
- AES_128_ECB,
- AES_128_CBC,
- /// Requires the `aes_xts` feature
- #[cfg(feature = "aes_xts")]
- AES_128_XTS,
- #[cfg(feature = "aes_ctr")]
- AES_128_CTR,
- // AES_128_GCM,
- AES_128_CFB1,
- AES_128_CFB128,
- AES_128_CFB8,
-
- AES_256_ECB,
- AES_256_CBC,
- /// Requires the `aes_xts` feature
- #[cfg(feature = "aes_xts")]
- AES_256_XTS,
- #[cfg(feature = "aes_ctr")]
- AES_256_CTR,
- // AES_256_GCM,
- AES_256_CFB1,
- AES_256_CFB128,
- AES_256_CFB8,
-
- DES_CBC,
- DES_ECB,
-
- RC4_128,
-}
+pub struct Cipher(*const ffi::EVP_CIPHER);
+
+impl Cipher {
+ pub fn aes_128_ecb() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_128_ecb()) }
+ }
+
+ pub fn aes_128_cbc() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_128_cbc()) }
+ }
+
+ pub fn aes_128_xts() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_128_xts()) }
+ }
+
+ pub fn aes_128_ctr() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_128_ctr()) }
+ }
+
+ pub fn aes_128_cfb1() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_128_cfb1()) }
+ }
+
+ pub fn aes_128_cfb128() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_128_cfb128()) }
+ }
+
+ pub fn aes_128_cfb8() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_128_cfb8()) }
+ }
+
+ pub fn aes_128_gcm() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_128_gcm()) }
+ }
+
+ pub fn aes_256_ecb() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_256_ecb()) }
+ }
+
+ pub fn aes_256_cbc() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_256_cbc()) }
+ }
+
+ pub fn aes_256_xts() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_256_xts()) }
+ }
+
+ pub fn aes_256_ctr() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_256_ctr()) }
+ }
+
+ pub fn aes_256_cfb1() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_256_cfb1()) }
+ }
+
+ pub fn aes_256_cfb128() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_256_cfb128()) }
+ }
+
+ pub fn aes_256_cfb8() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_256_cfb8()) }
+ }
+
+ pub fn aes_256_gcm() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_256_gcm()) }
+ }
+
+ pub fn des_cbc() -> Cipher {
+ unsafe { Cipher(ffi::EVP_des_cbc()) }
+ }
+
+ pub fn des_ecb() -> Cipher {
+ unsafe { Cipher(ffi::EVP_des_ecb()) }
+ }
+
+ pub fn rc4() -> Cipher {
+ unsafe { Cipher(ffi::EVP_rc4()) }
+ }
+
+ pub unsafe fn from_ptr(ptr: *const ffi::EVP_CIPHER) -> Cipher {
+ Cipher(ptr)
+ }
-impl Type {
pub fn as_ptr(&self) -> *const ffi::EVP_CIPHER {
- unsafe {
- match *self {
- Type::AES_128_ECB => ffi::EVP_aes_128_ecb(),
- Type::AES_128_CBC => ffi::EVP_aes_128_cbc(),
- #[cfg(feature = "aes_xts")]
- Type::AES_128_XTS => ffi::EVP_aes_128_xts(),
- #[cfg(feature = "aes_ctr")]
- Type::AES_128_CTR => ffi::EVP_aes_128_ctr(),
- // AES_128_GCM => (EVP_aes_128_gcm(), 16, 16),
- Type::AES_128_CFB1 => ffi::EVP_aes_128_cfb1(),
- Type::AES_128_CFB128 => ffi::EVP_aes_128_cfb128(),
- Type::AES_128_CFB8 => ffi::EVP_aes_128_cfb8(),
-
- Type::AES_256_ECB => ffi::EVP_aes_256_ecb(),
- Type::AES_256_CBC => ffi::EVP_aes_256_cbc(),
- #[cfg(feature = "aes_xts")]
- Type::AES_256_XTS => ffi::EVP_aes_256_xts(),
- #[cfg(feature = "aes_ctr")]
- Type::AES_256_CTR => ffi::EVP_aes_256_ctr(),
- // AES_256_GCM => (EVP_aes_256_gcm(), 32, 16),
- Type::AES_256_CFB1 => ffi::EVP_aes_256_cfb1(),
- Type::AES_256_CFB128 => ffi::EVP_aes_256_cfb128(),
- Type::AES_256_CFB8 => ffi::EVP_aes_256_cfb8(),
-
- Type::DES_CBC => ffi::EVP_des_cbc(),
- Type::DES_ECB => ffi::EVP_des_ecb(),
-
- Type::RC4_128 => ffi::EVP_rc4(),
- }
- }
+ self.0
}
/// Returns the length of keys used with this cipher.
pub fn key_len(&self) -> usize {
- unsafe {
- ffi::EVP_CIPHER_key_length(self.as_ptr()) as usize
- }
+ unsafe { EVP_CIPHER_key_length(self.0) as usize }
}
/// Returns the length of the IV used with this cipher, or `None` if the
/// cipher does not use an IV.
pub fn iv_len(&self) -> Option<usize> {
unsafe {
- let len = ffi::EVP_CIPHER_iv_length(self.as_ptr()) as usize;
- if len == 0 {
- None
- } else {
- Some(len)
- }
+ let len = EVP_CIPHER_iv_length(self.0) as usize;
+ if len == 0 { None } else { Some(len) }
}
}
@@ -104,9 +120,7 @@ impl Type {
///
/// Stream ciphers such as RC4 have a block size of 1.
pub fn block_size(&self) -> usize {
- unsafe {
- ffi::EVP_CIPHER_block_size(self.as_ptr()) as usize
- }
+ unsafe { EVP_CIPHER_block_size(self.0) as usize }
}
}
@@ -122,12 +136,16 @@ impl Crypter {
/// # Panics
///
/// Panics if an IV is required by the cipher but not provided, or if the
- /// IV's length does not match the expected length (see `Type::iv_len`).
- pub fn new(t: Type, mode: Mode, key: &[u8], iv: Option<&[u8]>) -> Result<Crypter, ErrorStack> {
+ /// IV's length does not match the expected length (see `Cipher::iv_len`).
+ pub fn new(t: Cipher,
+ mode: Mode,
+ key: &[u8],
+ iv: Option<&[u8]>)
+ -> Result<Crypter, ErrorStack> {
ffi::init();
unsafe {
- let ctx = try_ssl_null!(ffi::EVP_CIPHER_CTX_new());
+ let ctx = try!(cvt_p(ffi::EVP_CIPHER_CTX_new()));
let crypter = Crypter {
ctx: ctx,
block_size: t.block_size(),
@@ -138,15 +156,15 @@ impl Crypter {
Mode::Decrypt => 0,
};
- try_ssl!(ffi::EVP_CipherInit_ex(crypter.ctx,
- t.as_ptr(),
- ptr::null_mut(),
- ptr::null_mut(),
- ptr::null_mut(),
- mode));
+ try!(cvt(ffi::EVP_CipherInit_ex(crypter.ctx,
+ t.as_ptr(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ mode)));
assert!(key.len() <= c_int::max_value() as usize);
- try_ssl!(ffi::EVP_CIPHER_CTX_set_key_length(crypter.ctx, key.len() as c_int));
+ try!(cvt(ffi::EVP_CIPHER_CTX_set_key_length(crypter.ctx, key.len() as c_int)));
let key = key.as_ptr() as *mut _;
let iv = match (iv, t.iv_len()) {
@@ -157,12 +175,12 @@ impl Crypter {
(Some(_), None) | (None, None) => ptr::null_mut(),
(None, Some(_)) => panic!("an IV is required for this cipher"),
};
- try_ssl!(ffi::EVP_CipherInit_ex(crypter.ctx,
+ try!(cvt(ffi::EVP_CipherInit_ex(crypter.ctx,
ptr::null(),
ptr::null_mut(),
key,
iv,
- mode));
+ mode)));
Ok(crypter)
}
@@ -173,7 +191,9 @@ impl Crypter {
/// If padding is disabled, total amount of data encrypted/decrypted must
/// be a multiple of the cipher's block size.
pub fn pad(&mut self, padding: bool) {
- unsafe { ffi::EVP_CIPHER_CTX_set_padding(self.ctx, padding as c_int); }
+ unsafe {
+ ffi::EVP_CIPHER_CTX_set_padding(self.ctx, padding as c_int);
+ }
}
/// Feeds data from `input` through the cipher, writing encrypted/decrypted
@@ -185,7 +205,7 @@ impl Crypter {
/// # Panics
///
/// Panics if `output.len() < input.len() + block_size` where
- /// `block_size` is the block size of the cipher (see `Type::block_size`),
+ /// `block_size` is the block size of the cipher (see `Cipher::block_size`),
/// or if `output.len() > c_int::max_value()`.
pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result<usize, ErrorStack> {
unsafe {
@@ -194,11 +214,11 @@ impl Crypter {
let mut outl = output.len() as c_int;
let inl = input.len() as c_int;
- try_ssl!(ffi::EVP_CipherUpdate(self.ctx,
+ try!(cvt(ffi::EVP_CipherUpdate(self.ctx,
output.as_mut_ptr(),
&mut outl,
input.as_ptr(),
- inl));
+ inl)));
Ok(outl as usize)
}
@@ -219,7 +239,7 @@ impl Crypter {
assert!(output.len() >= self.block_size);
let mut outl = cmp::min(output.len(), c_int::max_value() as usize) as c_int;
- try_ssl!(ffi::EVP_CipherFinal(self.ctx, output.as_mut_ptr(), &mut outl));
+ try!(cvt(ffi::EVP_CipherFinal(self.ctx, output.as_mut_ptr(), &mut outl)));
Ok(outl as usize)
}
@@ -238,7 +258,7 @@ impl Drop for Crypter {
* Encrypts data, using the specified crypter type in encrypt mode with the
* specified key and iv; returns the resulting (encrypted) data.
*/
-pub fn encrypt(t: Type,
+pub fn encrypt(t: Cipher,
key: &[u8],
iv: Option<&[u8]>,
data: &[u8])
@@ -250,7 +270,7 @@ pub fn encrypt(t: Type,
* Decrypts data, using the specified crypter type in decrypt mode with the
* specified key and iv; returns the resulting (decrypted) data.
*/
-pub fn decrypt(t: Type,
+pub fn decrypt(t: Cipher,
key: &[u8],
iv: Option<&[u8]>,
data: &[u8])
@@ -258,7 +278,7 @@ pub fn decrypt(t: Type,
cipher(t, Mode::Decrypt, key, iv, data)
}
-fn cipher(t: Type,
+fn cipher(t: Cipher,
mode: Mode,
key: &[u8],
iv: Option<&[u8]>,
@@ -272,6 +292,30 @@ fn cipher(t: Type,
Ok(out)
}
+#[cfg(ossl110)]
+use ffi::{EVP_CIPHER_iv_length, EVP_CIPHER_block_size, EVP_CIPHER_key_length};
+
+#[cfg(ossl10x)]
+#[allow(bad_style)]
+mod compat {
+ use libc::c_int;
+ use ffi::EVP_CIPHER;
+
+ pub unsafe fn EVP_CIPHER_iv_length(ptr: *const EVP_CIPHER) -> c_int {
+ (*ptr).iv_len
+ }
+
+ pub unsafe fn EVP_CIPHER_block_size(ptr: *const EVP_CIPHER) -> c_int {
+ (*ptr).block_size
+ }
+
+ pub unsafe fn EVP_CIPHER_key_length(ptr: *const EVP_CIPHER) -> c_int {
+ (*ptr).key_len
+ }
+}
+#[cfg(ossl10x)]
+use self::compat::*;
+
#[cfg(test)]
mod tests {
use serialize::hex::{FromHex, ToHex};
@@ -288,23 +332,25 @@ mod tests {
0xaau8, 0xbbu8, 0xccu8, 0xddu8, 0xeeu8, 0xffu8];
let c0 = [0x8eu8, 0xa2u8, 0xb7u8, 0xcau8, 0x51u8, 0x67u8, 0x45u8, 0xbfu8, 0xeau8, 0xfcu8,
0x49u8, 0x90u8, 0x4bu8, 0x49u8, 0x60u8, 0x89u8];
- let mut c = super::Crypter::new(super::Type::AES_256_ECB,
+ let mut c = super::Crypter::new(super::Cipher::aes_256_ecb(),
super::Mode::Encrypt,
&k0,
- None).unwrap();
+ None)
+ .unwrap();
c.pad(false);
- let mut r0 = vec![0; c0.len() + super::Type::AES_256_ECB.block_size()];
+ let mut r0 = vec![0; c0.len() + super::Cipher::aes_256_ecb().block_size()];
let count = c.update(&p0, &mut r0).unwrap();
let rest = c.finalize(&mut r0[count..]).unwrap();
r0.truncate(count + rest);
assert_eq!(r0.to_hex(), c0.to_hex());
- let mut c = super::Crypter::new(super::Type::AES_256_ECB,
+ let mut c = super::Crypter::new(super::Cipher::aes_256_ecb(),
super::Mode::Decrypt,
&k0,
- None).unwrap();
+ None)
+ .unwrap();
c.pad(false);
- let mut p1 = vec![0; r0.len() + super::Type::AES_256_ECB.block_size()];
+ let mut p1 = vec![0; r0.len() + super::Cipher::aes_256_ecb().block_size()];
let count = c.update(&r0, &mut p1).unwrap();
let rest = c.finalize(&mut p1[count..]).unwrap();
p1.truncate(count + rest);
@@ -322,12 +368,13 @@ mod tests {
let ciphered_data = [0x4a_u8, 0x2e_u8, 0xe5_u8, 0x6_u8, 0xbf_u8, 0xcf_u8, 0xf2_u8,
0xd7_u8, 0xea_u8, 0x2d_u8, 0xb1_u8, 0x85_u8, 0x6c_u8, 0x93_u8,
0x65_u8, 0x6f_u8];
- let mut cr = super::Crypter::new(super::Type::AES_256_CBC,
+ let mut cr = super::Crypter::new(super::Cipher::aes_256_cbc(),
super::Mode::Decrypt,
&data,
- Some(&iv)).unwrap();
+ Some(&iv))
+ .unwrap();
cr.pad(false);
- let mut unciphered_data = vec![0; data.len() + super::Type::AES_256_CBC.block_size()];
+ let mut unciphered_data = vec![0; data.len() + super::Cipher::aes_256_cbc().block_size()];
let count = cr.update(&ciphered_data, &mut unciphered_data).unwrap();
let rest = cr.finalize(&mut unciphered_data[count..]).unwrap();
unciphered_data.truncate(count + rest);
@@ -337,7 +384,7 @@ mod tests {
assert_eq!(&unciphered_data, expected_unciphered_data);
}
- fn cipher_test(ciphertype: super::Type, pt: &str, ct: &str, key: &str, iv: &str) {
+ fn cipher_test(ciphertype: super::Cipher, pt: &str, ct: &str, key: &str, iv: &str) {
use serialize::hex::ToHex;
let pt = pt.from_hex().unwrap();
@@ -368,11 +415,10 @@ mod tests {
let key = "97CD440324DA5FD1F7955C1C13B6B466";
let iv = "";
- cipher_test(super::Type::RC4_128, pt, ct, key, iv);
+ cipher_test(super::Cipher::rc4(), pt, ct, key, iv);
}
#[test]
- #[cfg(feature = "aes_xts")]
fn test_aes256_xts() {
// Test case 174 from
// http://csrc.nist.gov/groups/STM/cavp/documents/aes/XTSTestVectors.zip
@@ -384,11 +430,10 @@ mod tests {
4180026ad640b74243b3133e7b9fae629403f6733423dae28";
let iv = "db200efb7eaaa737dbdf40babb68953f";
- cipher_test(super::Type::AES_256_XTS, pt, ct, key, iv);
+ cipher_test(super::Cipher::aes_256_xts(), pt, ct, key, iv);
}
#[test]
- #[cfg(feature = "aes_ctr")]
fn test_aes128_ctr() {
let pt = "6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411\
@@ -398,20 +443,9 @@ mod tests {
let key = "2B7E151628AED2A6ABF7158809CF4F3C";
let iv = "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF";
- cipher_test(super::Type::AES_128_CTR, pt, ct, key, iv);
+ cipher_test(super::Cipher::aes_128_ctr(), pt, ct, key, iv);
}
- // #[test]
- // fn test_aes128_gcm() {
- // Test case 3 in GCM spec
- // let pt = ~"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255";
- // let ct = ~"42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62cf35abd2ba6fab4";
- // let key = ~"feffe9928665731c6d6a8f9467308308";
- // let iv = ~"cafebabefacedbaddecaf888";
- //
- // cipher_test(super::AES_128_GCM, pt, ct, key, iv);
- // }
-
#[test]
fn test_aes128_cfb1() {
// Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
@@ -421,7 +455,7 @@ mod tests {
let key = "2b7e151628aed2a6abf7158809cf4f3c";
let iv = "000102030405060708090a0b0c0d0e0f";
- cipher_test(super::Type::AES_128_CFB1, pt, ct, key, iv);
+ cipher_test(super::Cipher::aes_128_cfb1(), pt, ct, key, iv);
}
#[test]
@@ -432,7 +466,7 @@ mod tests {
let key = "2b7e151628aed2a6abf7158809cf4f3c";
let iv = "000102030405060708090a0b0c0d0e0f";
- cipher_test(super::Type::AES_128_CFB128, pt, ct, key, iv);
+ cipher_test(super::Cipher::aes_128_cfb128(), pt, ct, key, iv);
}
#[test]
@@ -443,7 +477,7 @@ mod tests {
let key = "2b7e151628aed2a6abf7158809cf4f3c";
let iv = "000102030405060708090a0b0c0d0e0f";
- cipher_test(super::Type::AES_128_CFB8, pt, ct, key, iv);
+ cipher_test(super::Cipher::aes_128_cfb8(), pt, ct, key, iv);
}
#[test]
@@ -454,7 +488,7 @@ mod tests {
let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4";
let iv = "000102030405060708090a0b0c0d0e0f";
- cipher_test(super::Type::AES_256_CFB1, pt, ct, key, iv);
+ cipher_test(super::Cipher::aes_256_cfb1(), pt, ct, key, iv);
}
#[test]
@@ -465,7 +499,7 @@ mod tests {
let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4";
let iv = "000102030405060708090a0b0c0d0e0f";
- cipher_test(super::Type::AES_256_CFB128, pt, ct, key, iv);
+ cipher_test(super::Cipher::aes_256_cfb128(), pt, ct, key, iv);
}
#[test]
@@ -476,7 +510,7 @@ mod tests {
let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4";
let iv = "000102030405060708090a0b0c0d0e0f";
- cipher_test(super::Type::AES_256_CFB8, pt, ct, key, iv);
+ cipher_test(super::Cipher::aes_256_cfb8(), pt, ct, key, iv);
}
#[test]
@@ -487,7 +521,7 @@ mod tests {
let key = "7cb66337f3d3c0fe";
let iv = "0001020304050607";
- cipher_test(super::Type::DES_CBC, pt, ct, key, iv);
+ cipher_test(super::Cipher::des_cbc(), pt, ct, key, iv);
}
#[test]
@@ -498,6 +532,6 @@ mod tests {
let key = "7cb66337f3d3c0fe";
let iv = "0001020304050607";
- cipher_test(super::Type::DES_ECB, pt, ct, key, iv);
+ cipher_test(super::Cipher::des_ecb(), pt, ct, key, iv);
}
}
diff --git a/openssl/src/types.rs b/openssl/src/types.rs
new file mode 100644
index 00000000..2fadfd42
--- /dev/null
+++ b/openssl/src/types.rs
@@ -0,0 +1,40 @@
+//! Items used by other types.
+
+/// A type implemented by wrappers over OpenSSL types.
+///
+/// This should not be implemented by anything outside of this crate; new methods may be added at
+/// any time.
+pub trait OpenSslType: Sized {
+ /// The raw C type.
+ type CType;
+
+ /// The type representing a reference to this type.
+ type Ref: OpenSslTypeRef<CType = Self::CType>;
+
+ /// Constructs an instance of this type from its raw type.
+ unsafe fn from_ptr(ptr: *mut Self::CType) -> Self;
+}
+
+/// A trait implemented by types which reference borrowed OpenSSL types.
+///
+/// This should not be implemented by anything outside of this crate; new methods may be added at
+/// any time.
+pub trait OpenSslTypeRef: Sized {
+ /// The raw C type.
+ type CType;
+
+ /// Constructs a shared instance of this type from its raw type.
+ unsafe fn from_ptr<'a>(ptr: *mut Self::CType) -> &'a Self {
+ &*(ptr as *mut _)
+ }
+
+ /// Constructs a mutable reference of this type from its raw type.
+ unsafe fn from_ptr_mut<'a>(ptr: *mut Self::CType) -> &'a mut Self {
+ &mut *(ptr as *mut _)
+ }
+
+ /// Returns a raw pointer to the wrapped value.
+ fn as_ptr(&self) -> *mut Self::CType {
+ self as *const _ as *mut _
+ }
+}
diff --git a/openssl/src/crypto/util.rs b/openssl/src/util.rs
index c11285f8..302bd316 100644
--- a/openssl/src/crypto/util.rs
+++ b/openssl/src/util.rs
@@ -1,7 +1,7 @@
use libc::{c_int, c_char, c_void};
-
use std::any::Any;
-use std::panic;
+use std::cell::UnsafeCell;
+use std::panic::{self, AssertUnwindSafe};
use std::slice;
/// Wraps a user-supplied callback and a slot for panics thrown inside the callback (while FFI
@@ -36,23 +36,32 @@ impl<F> Drop for CallbackState<F> {
/// Password callback function, passed to private key loading functions.
///
/// `cb_state` is expected to be a pointer to a `CallbackState`.
-pub extern "C" fn invoke_passwd_cb<F>(buf: *mut c_char,
- size: c_int,
- _rwflag: c_int,
- cb_state: *mut c_void)
- -> c_int
- where F: FnOnce(&mut [c_char]) -> usize {
- let result = panic::catch_unwind(|| {
+pub unsafe extern "C" fn invoke_passwd_cb<F>(buf: *mut c_char,
+ size: c_int,
+ _rwflag: c_int,
+ cb_state: *mut c_void)
+ -> c_int
+ where F: FnOnce(&mut [c_char]) -> usize
+{
+ let callback = &mut *(cb_state as *mut CallbackState<F>);
+
+ let result = panic::catch_unwind(AssertUnwindSafe(|| {
// build a `i8` slice to pass to the user callback
- let pass_slice = unsafe { slice::from_raw_parts_mut(buf, size as usize) };
- let callback = unsafe { &mut *(cb_state as *mut CallbackState<F>) };
+ let pass_slice = slice::from_raw_parts_mut(buf, size as usize);
callback.cb.take().unwrap()(pass_slice)
- });
+ }));
- if let Ok(len) = result {
- return len as c_int;
- } else {
- return 0;
+ match result {
+ Ok(len) => len as c_int,
+ Err(err) => {
+ callback.panic = Some(err);
+ 0
+ }
}
}
+
+/// This is intended to be used as the inner type for `FooRef` types converted from raw C pointers.
+/// It has an `UnsafeCell` internally to inform the compiler about aliasability and doesn't
+/// implement `Copy`, so it can't be dereferenced.
+pub struct Opaque(UnsafeCell<()>);
diff --git a/openssl/src/verify.rs b/openssl/src/verify.rs
new file mode 100644
index 00000000..2f070fe5
--- /dev/null
+++ b/openssl/src/verify.rs
@@ -0,0 +1,39 @@
+use libc::c_uint;
+use ffi;
+
+use cvt;
+use error::ErrorStack;
+use types::OpenSslTypeRef;
+
+bitflags! {
+ pub flags X509CheckFlags: c_uint {
+ const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT,
+ const X509_CHECK_FLAG_NO_WILDCARDS = ffi::X509_CHECK_FLAG_NO_WILDCARDS,
+ const X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS = ffi::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS,
+ const X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS = ffi::X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS,
+ const X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS
+ = ffi::X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS,
+ /// Requires the `v110` feature and OpenSSL 1.1.0.
+ #[cfg(all(feature = "v110", ossl110))]
+ const X509_CHECK_FLAG_NEVER_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_NEVER_CHECK_SUBJECT,
+ }
+}
+
+type_!(X509VerifyParam, X509VerifyParamRef, ffi::X509_VERIFY_PARAM, ffi::X509_VERIFY_PARAM_free);
+
+impl X509VerifyParamRef {
+ pub fn set_hostflags(&mut self, hostflags: X509CheckFlags) {
+ unsafe {
+ ffi::X509_VERIFY_PARAM_set_hostflags(self.as_ptr(), hostflags.bits);
+ }
+ }
+
+ pub fn set_host(&mut self, host: &str) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::X509_VERIFY_PARAM_set1_host(self.as_ptr(),
+ host.as_ptr() as *const _,
+ host.len()))
+ .map(|_| ())
+ }
+ }
+}
diff --git a/openssl/src/version.rs b/openssl/src/version.rs
index 0e9f61d8..d7db39a7 100644
--- a/openssl/src/version.rs
+++ b/openssl/src/version.rs
@@ -11,9 +11,21 @@
// limitations under the License.
//
-use ffi;
use std::ffi::CStr;
+#[cfg(ossl10x)]
+use ffi::{SSLEAY_VERSION as OPENSSL_VERSION, SSLEAY_CFLAGS as OPENSSL_CFLAGS,
+ SSLEAY_BUILT_ON as OPENSSL_BUILT_ON, SSLEAY_PLATFORM as OPENSSL_PLATFORM,
+ SSLEAY_DIR as OPENSSL_DIR, SSLeay as OpenSSL_version_num,
+ SSLeay_version as OpenSSL_version};
+
+#[cfg(ossl110)]
+use ffi::{OPENSSL_VERSION, OPENSSL_CFLAGS};
+#[cfg(ossl110)]
+use ffi::{OPENSSL_BUILT_ON, OPENSSL_PLATFORM, OPENSSL_DIR};
+#[cfg(ossl110)]
+use ffi::{OpenSSL_version_num, OpenSSL_version};
+
/// OPENSSL_VERSION_NUMBER is a numeric release version identifier:
///
/// `MNNFFPPS: major minor fix patch status`
@@ -39,34 +51,34 @@ use std::ffi::CStr;
///
/// The return value of this function can be compared to the macro to make sure that the correct version of the library has been loaded, especially when using DLLs on Windows systems.
pub fn number() -> i64 {
- unsafe { ffi::SSLeay() as i64 }
+ unsafe { OpenSSL_version_num() as i64 }
}
/// The text variant of the version number and the release date. For example, "OpenSSL 0.9.5a 1 Apr 2000".
pub fn version() -> &'static str {
- unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_VERSION)).to_str().unwrap() }
+ unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_VERSION)).to_str().unwrap() }
}
/// The compiler flags set for the compilation process in the form "compiler: ..." if available or
/// "compiler: information not available" otherwise.
pub fn c_flags() -> &'static str {
- unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_CFLAGS)).to_str().unwrap() }
+ unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_CFLAGS)).to_str().unwrap() }
}
/// The date of the build process in the form "built on: ..." if available or "built on: date not available" otherwise.
pub fn built_on() -> &'static str {
- unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_BUILT_ON)).to_str().unwrap() }
+ unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_BUILT_ON)).to_str().unwrap() }
}
/// The "Configure" target of the library build in the form "platform: ..." if available or "platform: information not available" otherwise.
pub fn platform() -> &'static str {
- unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_PLATFORM)).to_str().unwrap() }
+ unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_PLATFORM)).to_str().unwrap() }
}
/// The "OPENSSLDIR" setting of the library build in the form "OPENSSLDIR: "..."" if available or "OPENSSLDIR: N/A" otherwise.
pub fn dir() -> &'static str {
- unsafe { CStr::from_ptr(ffi::SSLeay_version(ffi::SSLEAY_DIR)).to_str().unwrap() }
+ unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_DIR)).to_str().unwrap() }
}
/// This test ensures that we do not segfault when calling the functions of this module
diff --git a/openssl/src/x509/extension.rs b/openssl/src/x509/extension.rs
index 99ef62c1..398bbb3e 100644
--- a/openssl/src/x509/extension.rs
+++ b/openssl/src/x509/extension.rs
@@ -1,6 +1,6 @@
use std::fmt;
-use nid::Nid;
+use nid::{self, Nid};
/// Type-only version of the `Extension` enum.
///
@@ -36,10 +36,10 @@ pub enum Extension {
///
/// ```
/// use openssl::x509::extension::Extension::*;
- /// use openssl::nid::Nid;
+ /// use openssl::nid;
///
/// # let generator = openssl::x509::X509Generator::new();
- /// generator.add_extension(OtherNid(Nid::BasicConstraints,"critical,CA:TRUE".to_owned()));
+ /// generator.add_extension(OtherNid(nid::BASIC_CONSTRAINTS,"critical,CA:TRUE".to_owned()));
/// ```
OtherNid(Nid, String),
/// Arbitrary extensions by OID string. See `man ASN1_generate_nconf` for value syntax.
@@ -71,10 +71,10 @@ impl Extension {
impl ExtensionType {
pub fn get_nid(&self) -> Option<Nid> {
match self {
- &ExtensionType::KeyUsage => Some(Nid::KeyUsage),
- &ExtensionType::ExtKeyUsage => Some(Nid::ExtendedKeyUsage),
- &ExtensionType::SubjectAltName => Some(Nid::SubjectAltName),
- &ExtensionType::IssuerAltName => Some(Nid::IssuerAltName),
+ &ExtensionType::KeyUsage => Some(nid::KEY_USAGE),
+ &ExtensionType::ExtKeyUsage => Some(nid::EXT_KEY_USAGE),
+ &ExtensionType::SubjectAltName => Some(nid::SUBJECT_ALT_NAME),
+ &ExtensionType::IssuerAltName => Some(nid::ISSUER_ALT_NAME),
&ExtensionType::OtherNid(nid) => Some(nid),
&ExtensionType::OtherStr(_) => None,
}
diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs
index f5369447..eb517f80 100644
--- a/openssl/src/x509/mod.rs
+++ b/openssl/src/x509/mod.rs
@@ -1,100 +1,66 @@
-use libc::{c_char, c_int, c_long, c_ulong, c_void};
+use libc::{c_char, c_int, c_long, c_ulong};
+use std::borrow::Borrow;
use std::cmp;
-use std::ffi::CString;
+use std::collections::HashMap;
+use std::error::Error;
+use std::ffi::{CStr, CString};
+use std::fmt;
use std::mem;
use std::ptr;
-use std::ops::Deref;
-use std::fmt;
-use std::str;
use std::slice;
-use std::collections::HashMap;
-use std::marker::PhantomData;
-
-use HashTypeInternals;
-use asn1::Asn1Time;
-#[cfg(feature = "x509_expiry")]
-use asn1::Asn1TimeRef;
+use std::str;
+use {cvt, cvt_p};
+use asn1::{Asn1StringRef, Asn1Time, Asn1TimeRef};
use bio::{MemBio, MemBioSlice};
-use crypto::hash;
-use crypto::hash::Type as HashType;
-use crypto::pkey::PKey;
-use crypto::rand::rand_bytes;
+use hash::MessageDigest;
+use pkey::{PKey, PKeyRef};
+use rand::rand_bytes;
+use error::ErrorStack;
use ffi;
use nid::Nid;
-use error::ErrorStack;
+use types::{OpenSslType, OpenSslTypeRef};
+use stack::{Stack, StackRef, Stackable};
-pub mod extension;
+#[cfg(ossl10x)]
+use ffi::{X509_set_notBefore, X509_set_notAfter, ASN1_STRING_data, X509_STORE_CTX_get_chain};
+#[cfg(ossl110)]
+use ffi::{X509_set1_notBefore as X509_set_notBefore, X509_set1_notAfter as X509_set_notAfter,
+ ASN1_STRING_get0_data as ASN1_STRING_data,
+ X509_STORE_CTX_get0_chain as X509_STORE_CTX_get_chain};
-use self::extension::{ExtensionType, Extension};
+#[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
+pub mod verify;
-#[cfg(test)]
-mod tests;
+use x509::extension::{ExtensionType, Extension};
-pub struct SslString(&'static str);
+pub mod extension;
-impl<'s> Drop for SslString {
- fn drop(&mut self) {
- unsafe {
- ffi::CRYPTO_free(self.0.as_ptr() as *mut c_void);
- }
- }
-}
+#[cfg(test)]
+mod tests;
-impl Deref for SslString {
- type Target = str;
+pub struct X509FileType(c_int);
- fn deref(&self) -> &str {
+impl X509FileType {
+ pub fn as_raw(&self) -> c_int {
self.0
}
}
-impl SslString {
- unsafe fn new(buf: *const c_char, len: c_int) -> SslString {
- let slice = slice::from_raw_parts(buf as *const _, len as usize);
- SslString(str::from_utf8_unchecked(slice))
- }
-}
+pub const X509_FILETYPE_PEM: X509FileType = X509FileType(ffi::X509_FILETYPE_PEM);
+pub const X509_FILETYPE_ASN1: X509FileType = X509FileType(ffi::X509_FILETYPE_ASN1);
+pub const X509_FILETYPE_DEFAULT: X509FileType = X509FileType(ffi::X509_FILETYPE_DEFAULT);
-impl fmt::Display for SslString {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(self.0, f)
- }
-}
+type_!(X509StoreContext, X509StoreContextRef, ffi::X509_STORE_CTX, ffi::X509_STORE_CTX_free);
-impl fmt::Debug for SslString {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Debug::fmt(self.0, f)
+impl X509StoreContextRef {
+ pub fn error(&self) -> Option<X509VerifyError> {
+ unsafe { X509VerifyError::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr()) as c_long) }
}
-}
-#[derive(Copy, Clone)]
-#[repr(i32)]
-pub enum X509FileType {
- PEM = ffi::X509_FILETYPE_PEM,
- ASN1 = ffi::X509_FILETYPE_ASN1,
- Default = ffi::X509_FILETYPE_DEFAULT,
-}
-
-#[allow(missing_copy_implementations)]
-pub struct X509StoreContext {
- ctx: *mut ffi::X509_STORE_CTX,
-}
-
-impl X509StoreContext {
- pub fn new(ctx: *mut ffi::X509_STORE_CTX) -> X509StoreContext {
- X509StoreContext { ctx: ctx }
- }
-
- pub fn error(&self) -> Option<X509ValidationError> {
- let err = unsafe { ffi::X509_STORE_CTX_get_error(self.ctx) };
- X509ValidationError::from_raw(err)
- }
-
- pub fn current_cert<'a>(&'a self) -> Option<X509Ref<'a>> {
+ pub fn current_cert(&self) -> Option<&X509Ref> {
unsafe {
- let ptr = ffi::X509_STORE_CTX_get_current_cert(self.ctx);
-
+ let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr());
if ptr.is_null() {
None
} else {
@@ -104,7 +70,19 @@ impl X509StoreContext {
}
pub fn error_depth(&self) -> u32 {
- unsafe { ffi::X509_STORE_CTX_get_error_depth(self.ctx) as u32 }
+ unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 }
+ }
+
+ pub fn chain(&self) -> Option<&StackRef<X509>> {
+ unsafe {
+ let chain = X509_STORE_CTX_get_chain(self.as_ptr());
+
+ if chain.is_null() {
+ return None;
+ }
+
+ Some(StackRef::from_ptr(chain))
+ }
}
}
@@ -114,19 +92,19 @@ impl X509StoreContext {
/// # Example
///
/// ```
-/// use openssl::crypto::hash::Type;
-/// use openssl::crypto::pkey::PKey;
-/// use openssl::crypto::rsa::RSA;
+/// use openssl::hash::MessageDigest;
+/// use openssl::pkey::PKey;
+/// use openssl::rsa::Rsa;
/// use openssl::x509::X509Generator;
/// use openssl::x509::extension::{Extension, KeyUsageOption};
///
-/// let rsa = RSA::generate(2048).unwrap();
+/// let rsa = Rsa::generate(2048).unwrap();
/// let pkey = PKey::from_rsa(rsa).unwrap();
///
/// let gen = X509Generator::new()
/// .set_valid_period(365*2)
/// .add_name("CN".to_owned(), "SuperMegaCorp Inc.".to_owned())
-/// .set_sign_hash(Type::SHA256)
+/// .set_sign_hash(MessageDigest::sha256())
/// .add_extension(Extension::KeyUsage(vec![KeyUsageOption::DigitalSignature]));
///
/// let cert = gen.sign(&pkey).unwrap();
@@ -137,7 +115,7 @@ pub struct X509Generator {
days: u32,
names: Vec<(String, String)>,
extensions: Extensions,
- hash_type: HashType,
+ hash_type: MessageDigest,
}
impl X509Generator {
@@ -153,7 +131,7 @@ impl X509Generator {
days: 365,
names: vec![],
extensions: Extensions::new(),
- hash_type: HashType::SHA1,
+ hash_type: MessageDigest::sha1(),
}
}
@@ -224,7 +202,7 @@ impl X509Generator {
self
}
- pub fn set_sign_hash(mut self, hash_type: hash::Type) -> X509Generator {
+ pub fn set_sign_hash(mut self, hash_type: MessageDigest) -> X509Generator {
self.hash_type = hash_type;
self
}
@@ -239,25 +217,25 @@ impl X509Generator {
let value = CString::new(value.as_bytes()).unwrap();
let ext = match exttype.get_nid() {
Some(nid) => {
- ffi::X509V3_EXT_conf_nid(ptr::null_mut(),
- mem::transmute(&ctx),
- nid as c_int,
- value.as_ptr() as *mut c_char)
+ try!(cvt_p(ffi::X509V3_EXT_nconf_nid(ptr::null_mut(),
+ &mut ctx,
+ nid.as_raw(),
+ value.as_ptr() as *mut c_char)))
}
None => {
let name = CString::new(exttype.get_name().unwrap().as_bytes()).unwrap();
- ffi::X509V3_EXT_conf(ptr::null_mut(),
- mem::transmute(&ctx),
- name.as_ptr() as *mut c_char,
- value.as_ptr() as *mut c_char)
+ try!(cvt_p(ffi::X509V3_EXT_nconf(ptr::null_mut(),
+ &mut ctx,
+ name.as_ptr() as *mut c_char,
+ value.as_ptr() as *mut c_char)))
}
};
- let mut success = false;
- if ext != ptr::null_mut() {
- success = ffi::X509_add_ext(x509, ext, -1) != 0;
+ if ffi::X509_add_ext(x509, ext, -1) != 1 {
ffi::X509_EXTENSION_free(ext);
+ Err(ErrorStack::get())
+ } else {
+ Ok(())
}
- lift_ssl_if!(!success)
}
}
@@ -266,17 +244,18 @@ impl X509Generator {
value: &str)
-> Result<(), ErrorStack> {
let value_len = value.len() as c_int;
- lift_ssl!(unsafe {
+ unsafe {
let key = CString::new(key.as_bytes()).unwrap();
let value = CString::new(value.as_bytes()).unwrap();
- ffi::X509_NAME_add_entry_by_txt(name,
- key.as_ptr() as *const _,
- ffi::MBSTRING_UTF8,
- value.as_ptr() as *const _,
- value_len,
- -1,
- 0)
- })
+ cvt(ffi::X509_NAME_add_entry_by_txt(name,
+ key.as_ptr() as *const _,
+ ffi::MBSTRING_UTF8,
+ value.as_ptr() as *const _,
+ value_len,
+ -1,
+ 0))
+ .map(|_| ())
+ }
}
fn random_serial() -> Result<c_long, ErrorStack> {
@@ -296,32 +275,30 @@ 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(&self, p_key: &PKey) -> Result<X509, ErrorStack> {
+ pub fn sign(&self, p_key: &PKeyRef) -> Result<X509, ErrorStack> {
ffi::init();
unsafe {
- let x509 = try_ssl_null!(ffi::X509_new());
- let x509 = X509::from_ptr(x509);
+ let x509 = X509::from_ptr(try!(cvt_p(ffi::X509_new())));
- try_ssl!(ffi::X509_set_version(x509.as_ptr(), 2));
- try_ssl!(ffi::ASN1_INTEGER_set(ffi::X509_get_serialNumber(x509.as_ptr()),
- try!(X509Generator::random_serial())));
+ try!(cvt(ffi::X509_set_version(x509.as_ptr(), 2)));
+ try!(cvt(ffi::ASN1_INTEGER_set(ffi::X509_get_serialNumber(x509.as_ptr()),
+ try!(X509Generator::random_serial()))));
let not_before = try!(Asn1Time::days_from_now(0));
let not_after = try!(Asn1Time::days_from_now(self.days));
- try_ssl!(ffi::X509_set_notBefore(x509.as_ptr(), not_before.as_ptr() as *const _));
+ try!(cvt(X509_set_notBefore(x509.as_ptr(), not_before.as_ptr() as *const _)));
// If prev line succeded - ownership should go to cert
mem::forget(not_before);
- try_ssl!(ffi::X509_set_notAfter(x509.as_ptr(), not_after.as_ptr() as *const _));
+ try!(cvt(X509_set_notAfter(x509.as_ptr(), not_after.as_ptr() as *const _)));
// If prev line succeded - ownership should go to cert
mem::forget(not_after);
- try_ssl!(ffi::X509_set_pubkey(x509.as_ptr(), p_key.as_ptr()));
+ try!(cvt(ffi::X509_set_pubkey(x509.as_ptr(), p_key.as_ptr())));
- let name = try_ssl_null!(ffi::X509_get_subject_name(x509.as_ptr()));
+ let name = try!(cvt_p(ffi::X509_get_subject_name(x509.as_ptr())));
let default = [("CN", "rust-openssl")];
let default_iter = &mut default.iter().map(|&(k, v)| (k, v));
@@ -335,7 +312,7 @@ impl X509Generator {
for (key, val) in iter {
try!(X509Generator::add_name_internal(name, &key, &val));
}
- try_ssl!(ffi::X509_set_issuer_name(x509.as_ptr(), name));
+ try!(cvt(ffi::X509_set_issuer_name(x509.as_ptr(), name)));
for (exttype, ext) in self.extensions.iter() {
try!(X509Generator::add_extension_internal(x509.as_ptr(),
@@ -343,117 +320,95 @@ impl X509Generator {
&ext.to_string()));
}
- let hash_fn = self.hash_type.evp_md();
- try_ssl!(ffi::X509_sign(x509.as_ptr(), p_key.as_ptr(), hash_fn));
+ let hash_fn = self.hash_type.as_ptr();
+ try!(cvt(ffi::X509_sign(x509.as_ptr(), p_key.as_ptr(), hash_fn)));
Ok(x509)
}
}
/// Obtain a certificate signing request (CSR)
- ///
- /// Requries the `x509_generator_request` feature.
- #[cfg(feature = "x509_generator_request")]
- pub fn request(&self, p_key: &PKey) -> Result<X509Req, ErrorStack> {
+ pub fn request(&self, p_key: &PKeyRef) -> Result<X509Req, ErrorStack> {
let cert = match self.sign(p_key) {
Ok(c) => c,
Err(x) => return Err(x),
};
unsafe {
- let req = ffi::X509_to_X509_REQ(cert.as_ptr(), ptr::null_mut(), ptr::null());
- try_ssl_null!(req);
+ let req = try!(cvt_p(ffi::X509_to_X509_REQ(cert.as_ptr(),
+ ptr::null_mut(),
+ ptr::null())));
+ let req = X509Req::from_ptr(req);
- let exts = ::c_helpers::rust_0_8_X509_get_extensions(cert.as_ptr());
+ let exts = compat::X509_get0_extensions(cert.as_ptr());
if exts != ptr::null_mut() {
- try_ssl!(ffi::X509_REQ_add_extensions(req, exts));
+ try!(cvt(ffi::X509_REQ_add_extensions(req.as_ptr(), exts as *mut _)));
}
- let hash_fn = self.hash_type.evp_md();
- try_ssl!(ffi::X509_REQ_sign(req, p_key.as_ptr(), hash_fn));
+ let hash_fn = self.hash_type.as_ptr();
+ try!(cvt(ffi::X509_REQ_sign(req.as_ptr(), p_key.as_ptr(), hash_fn)));
- Ok(X509Req::new(req))
+ Ok(req)
}
}
}
-/// A borrowed public key certificate.
-pub struct X509Ref<'a>(*mut ffi::X509, PhantomData<&'a ()>);
+type_!(X509, X509Ref, ffi::X509, ffi::X509_free);
-impl<'a> X509Ref<'a> {
- /// Creates a new `X509Ref` wrapping the provided handle.
- pub unsafe fn from_ptr(x509: *mut ffi::X509) -> X509Ref<'a> {
- X509Ref(x509, PhantomData)
- }
-
- ///
- #[deprecated(note = "renamed to `X509::from_ptr`", since = "0.8.1")]
- pub unsafe fn new(x509: *mut ffi::X509) -> X509Ref<'a> {
- X509Ref::from_ptr(x509)
- }
-
- pub fn as_ptr(&self) -> *mut ffi::X509 {
- self.0
- }
-
- pub fn subject_name<'b>(&'b self) -> X509Name<'b> {
- let name = unsafe { ffi::X509_get_subject_name(self.0) };
- X509Name(name, PhantomData)
+impl X509Ref {
+ pub fn subject_name(&self) -> &X509NameRef {
+ unsafe {
+ let name = ffi::X509_get_subject_name(self.as_ptr());
+ X509NameRef::from_ptr(name)
+ }
}
/// Returns this certificate's SAN entries, if they exist.
- pub fn subject_alt_names<'b>(&'b self) -> Option<GeneralNames<'b>> {
+ pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> {
unsafe {
- let stack = ffi::X509_get_ext_d2i(self.0,
- Nid::SubjectAltName as c_int,
+ let stack = ffi::X509_get_ext_d2i(self.as_ptr(),
+ ffi::NID_subject_alt_name,
ptr::null_mut(),
ptr::null_mut());
if stack.is_null() {
return None;
}
- Some(GeneralNames {
- stack: stack as *mut _,
- m: PhantomData,
- })
+ Some(Stack::from_ptr(stack as *mut _))
}
}
pub fn public_key(&self) -> Result<PKey, ErrorStack> {
unsafe {
- let pkey = try_ssl_null!(ffi::X509_get_pubkey(self.0));
+ let pkey = try!(cvt_p(ffi::X509_get_pubkey(self.as_ptr())));
Ok(PKey::from_ptr(pkey))
}
}
/// Returns certificate fingerprint calculated using provided hash
- pub fn fingerprint(&self, hash_type: hash::Type) -> Result<Vec<u8>, ErrorStack> {
+ pub fn fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack> {
unsafe {
- let evp = hash_type.evp_md();
+ let evp = hash_type.as_ptr();
let mut len = ffi::EVP_MAX_MD_SIZE;
let mut buf = vec![0u8; len as usize];
- try_ssl!(ffi::X509_digest(self.0, evp, buf.as_mut_ptr() as *mut _, &mut len));
+ try!(cvt(ffi::X509_digest(self.as_ptr(), evp, buf.as_mut_ptr() as *mut _, &mut len)));
buf.truncate(len as usize);
Ok(buf)
}
}
/// Returns certificate Not After validity period.
- /// Requires the `x509_expiry` feature.
- #[cfg(feature = "x509_expiry")]
- pub fn not_after<'b>(&'b self) -> Asn1TimeRef<'b> {
+ pub fn not_after<'a>(&'a self) -> &'a Asn1TimeRef {
unsafe {
- let date = ::c_helpers::rust_0_8_X509_get_notAfter(self.0);
+ let date = compat::X509_get_notAfter(self.as_ptr());
assert!(!date.is_null());
Asn1TimeRef::from_ptr(date)
}
}
/// Returns certificate Not Before validity period.
- /// Requires the `x509_expiry` feature.
- #[cfg(feature = "x509_expiry")]
- pub fn not_before<'b>(&'b self) -> Asn1TimeRef<'b> {
+ pub fn not_before<'a>(&'a self) -> &'a Asn1TimeRef {
unsafe {
- let date = ::c_helpers::rust_0_8_X509_get_notBefore(self.0);
+ let date = compat::X509_get_notBefore(self.as_ptr());
assert!(!date.is_null());
Asn1TimeRef::from_ptr(date)
}
@@ -463,7 +418,7 @@ impl<'a> X509Ref<'a> {
pub fn to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
let mem_bio = try!(MemBio::new());
unsafe {
- try_ssl!(ffi::PEM_write_bio_X509(mem_bio.as_ptr(), self.0));
+ try!(cvt(ffi::PEM_write_bio_X509(mem_bio.as_ptr(), self.as_ptr())));
}
Ok(mem_bio.get_buf().to_owned())
}
@@ -472,33 +427,30 @@ impl<'a> X509Ref<'a> {
pub fn to_der(&self) -> Result<Vec<u8>, ErrorStack> {
let mem_bio = try!(MemBio::new());
unsafe {
- ffi::i2d_X509_bio(mem_bio.as_ptr(), self.0);
+ ffi::i2d_X509_bio(mem_bio.as_ptr(), self.as_ptr());
}
Ok(mem_bio.get_buf().to_owned())
}
}
-/// An owned public key certificate.
-pub struct X509(X509Ref<'static>);
-
-impl X509 {
- /// Returns a new `X509`, taking ownership of the handle.
- pub unsafe fn from_ptr(x509: *mut ffi::X509) -> X509 {
- X509(X509Ref::from_ptr(x509))
- }
+impl ToOwned for X509Ref {
+ type Owned = X509;
- ///
- #[deprecated(note = "renamed to `X509::from_ptr`", since = "0.8.1")]
- pub unsafe fn new(x509: *mut ffi::X509) -> X509 {
- X509::from_ptr(x509)
+ fn to_owned(&self) -> X509 {
+ unsafe {
+ compat::X509_up_ref(self.as_ptr());
+ X509::from_ptr(self.as_ptr())
+ }
}
+}
+impl X509 {
/// Reads a certificate from DER.
pub fn from_der(buf: &[u8]) -> Result<X509, ErrorStack> {
unsafe {
- let mut ptr = buf.as_ptr() as *mut _;
+ let mut ptr = buf.as_ptr();
let len = cmp::min(buf.len(), c_long::max_value() as usize) as c_long;
- let x509 = try_ssl_null!(ffi::d2i_X509(ptr::null_mut(), &mut ptr, len));
+ let x509 = try!(cvt_p(ffi::d2i_X509(ptr::null_mut(), &mut ptr, len)));
Ok(X509::from_ptr(x509))
}
}
@@ -507,103 +459,99 @@ impl X509 {
pub fn from_pem(buf: &[u8]) -> Result<X509, ErrorStack> {
let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
- let handle = try_ssl_null!(ffi::PEM_read_bio_X509(mem_bio.as_ptr(),
- ptr::null_mut(),
- None,
- ptr::null_mut()));
+ let handle = try!(cvt_p(ffi::PEM_read_bio_X509(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ None,
+ ptr::null_mut())));
Ok(X509::from_ptr(handle))
}
}
}
-impl Deref for X509 {
- type Target = X509Ref<'static>;
+impl Clone for X509 {
+ fn clone(&self) -> X509 {
+ self.to_owned()
+ }
+}
- fn deref(&self) -> &X509Ref<'static> {
- &self.0
+impl AsRef<X509Ref> for X509 {
+ fn as_ref(&self) -> &X509Ref {
+ &*self
}
}
-#[cfg(feature = "x509_clone")]
-impl Clone for X509 {
- /// Requires the `x509_clone` feature.
- fn clone(&self) -> X509 {
- unsafe {
- ::c_helpers::rust_0_8_X509_clone(self.as_ptr());
- X509::new(self.as_ptr())
- }
+impl AsRef<X509Ref> for X509Ref {
+ fn as_ref(&self) -> &X509Ref {
+ self
}
}
-impl Drop for X509 {
- fn drop(&mut self) {
- unsafe { ffi::X509_free(self.as_ptr()) };
+impl Borrow<X509Ref> for X509 {
+ fn borrow(&self) -> &X509Ref {
+ &*self
}
}
-pub struct X509Name<'x>(*mut ffi::X509_NAME, PhantomData<&'x ()>);
+impl Stackable for X509 {
+ type StackType = ffi::stack_st_X509;
+}
-impl<'x> X509Name<'x> {
- pub fn text_by_nid(&self, nid: Nid) -> Option<SslString> {
- unsafe {
- let loc = ffi::X509_NAME_get_index_by_NID(self.0, nid as c_int, -1);
- if loc == -1 {
- return None;
- }
+type_!(X509Name, X509NameRef, ffi::X509_NAME, ffi::X509_NAME_free);
- let ne = ffi::X509_NAME_get_entry(self.0, loc);
- if ne.is_null() {
- return None;
- }
+impl X509NameRef {
+ pub fn entries_by_nid<'a>(&'a self, nid: Nid) -> X509NameEntries<'a> {
+ X509NameEntries {
+ name: self,
+ nid: nid,
+ loc: -1,
+ }
+ }
+}
- let asn1_str = ffi::X509_NAME_ENTRY_get_data(ne);
- if asn1_str.is_null() {
- return None;
- }
+pub struct X509NameEntries<'a> {
+ name: &'a X509NameRef,
+ nid: Nid,
+ loc: c_int,
+}
- let mut str_from_asn1: *mut c_char = ptr::null_mut();
- let len = ffi::ASN1_STRING_to_UTF8(&mut str_from_asn1, asn1_str);
+impl<'a> Iterator for X509NameEntries<'a> {
+ type Item = &'a X509NameEntryRef;
+
+ fn next(&mut self) -> Option<&'a X509NameEntryRef> {
+ unsafe {
+ self.loc =
+ ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), self.nid.as_raw(), self.loc);
- if len < 0 {
+ if self.loc == -1 {
return None;
}
- assert!(!str_from_asn1.is_null());
+ let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
+ assert!(!entry.is_null());
- Some(SslString::new(str_from_asn1, len))
+ Some(X509NameEntryRef::from_ptr(entry))
}
}
}
-/// A certificate signing request
-pub struct X509Req(*mut ffi::X509_REQ);
+type_!(X509NameEntry, X509NameEntryRef, ffi::X509_NAME_ENTRY, ffi::X509_NAME_ENTRY_free);
-impl X509Req {
- /// Creates new from handle
- pub unsafe fn new(handle: *mut ffi::X509_REQ) -> X509Req {
- X509Req(handle)
- }
-
- pub fn as_ptr(&self) -> *mut ffi::X509_REQ {
- self.0
- }
-
- /// Reads CSR from PEM
- pub fn from_pem(buf: &[u8]) -> Result<X509Req, ErrorStack> {
- let mem_bio = try!(MemBioSlice::new(buf));
+impl X509NameEntryRef {
+ pub fn data(&self) -> &Asn1StringRef {
unsafe {
- let handle = try_ssl_null!(ffi::PEM_read_bio_X509_REQ(mem_bio.as_ptr(),
- ptr::null_mut(),
- None,
- ptr::null_mut()));
- Ok(X509Req::new(handle))
+ let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr());
+ Asn1StringRef::from_ptr(data)
}
}
+}
+
+type_!(X509Req, X509ReqRef, ffi::X509_REQ, ffi::X509_REQ_free);
+impl X509ReqRef {
/// Writes CSR as PEM
pub fn to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
let mem_bio = try!(MemBio::new());
- if unsafe { ffi::PEM_write_bio_X509_REQ(mem_bio.as_ptr(), self.0) } != 1 {
+ if unsafe { ffi::PEM_write_bio_X509_REQ(mem_bio.as_ptr(), self.as_ptr()) } != 1 {
return Err(ErrorStack::get());
}
Ok(mem_bio.get_buf().to_owned())
@@ -613,15 +561,23 @@ impl X509Req {
pub fn to_der(&self) -> Result<Vec<u8>, ErrorStack> {
let mem_bio = try!(MemBio::new());
unsafe {
- ffi::i2d_X509_REQ_bio(mem_bio.as_ptr(), self.0);
+ ffi::i2d_X509_REQ_bio(mem_bio.as_ptr(), self.as_ptr());
}
Ok(mem_bio.get_buf().to_owned())
}
}
-impl Drop for X509Req {
- fn drop(&mut self) {
- unsafe { ffi::X509_REQ_free(self.0) };
+impl X509Req {
+ /// Reads CSR from PEM
+ pub fn from_pem(buf: &[u8]) -> Result<X509Req, ErrorStack> {
+ let mem_bio = try!(MemBioSlice::new(buf));
+ unsafe {
+ let handle = try!(cvt_p(ffi::PEM_read_bio_X509_REQ(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ None,
+ ptr::null_mut())));
+ Ok(X509Req::from_ptr(handle))
+ }
}
}
@@ -694,184 +650,72 @@ impl<'a> Iterator for ExtensionsIter<'a> {
}
}
-macro_rules! make_validation_error(
- ($ok_val:ident, $($name:ident = $val:ident,)+) => (
- #[derive(Copy, Clone)]
- pub enum X509ValidationError {
- $($name,)+
- X509UnknownError(c_int)
- }
-
- impl X509ValidationError {
- #[doc(hidden)]
- pub fn from_raw(err: c_int) -> Option<X509ValidationError> {
- match err {
- ffi::$ok_val => None,
- $(ffi::$val => Some(X509ValidationError::$name),)+
- err => Some(X509ValidationError::X509UnknownError(err))
- }
- }
- }
- )
-);
-
-make_validation_error!(X509_V_OK,
- X509UnableToGetIssuerCert = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,
- X509UnableToGetCrl = X509_V_ERR_UNABLE_TO_GET_CRL,
- X509UnableToDecryptCertSignature = X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE,
- X509UnableToDecryptCrlSignature = X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE,
- X509UnableToDecodeIssuerPublicKey = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY,
- X509CertSignatureFailure = X509_V_ERR_CERT_SIGNATURE_FAILURE,
- X509CrlSignatureFailure = X509_V_ERR_CRL_SIGNATURE_FAILURE,
- X509CertNotYetValid = X509_V_ERR_CERT_NOT_YET_VALID,
- X509CertHasExpired = X509_V_ERR_CERT_HAS_EXPIRED,
- X509CrlNotYetValid = X509_V_ERR_CRL_NOT_YET_VALID,
- X509CrlHasExpired = X509_V_ERR_CRL_HAS_EXPIRED,
- X509ErrorInCertNotBeforeField = X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD,
- X509ErrorInCertNotAfterField = X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD,
- X509ErrorInCrlLastUpdateField = X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD,
- X509ErrorInCrlNextUpdateField = X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD,
- X509OutOfMem = X509_V_ERR_OUT_OF_MEM,
- X509DepthZeroSelfSignedCert = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT,
- X509SelfSignedCertInChain = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
- X509UnableToGetIssuerCertLocally = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
- X509UnableToVerifyLeafSignature = X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE,
- X509CertChainTooLong = X509_V_ERR_CERT_CHAIN_TOO_LONG,
- X509CertRevoked = X509_V_ERR_CERT_REVOKED,
- X509InvalidCA = X509_V_ERR_INVALID_CA,
- X509PathLengthExceeded = X509_V_ERR_PATH_LENGTH_EXCEEDED,
- X509InvalidPurpose = X509_V_ERR_INVALID_PURPOSE,
- X509CertUntrusted = X509_V_ERR_CERT_UNTRUSTED,
- X509CertRejected = X509_V_ERR_CERT_REJECTED,
- X509SubjectIssuerMismatch = X509_V_ERR_SUBJECT_ISSUER_MISMATCH,
- X509AkidSkidMismatch = X509_V_ERR_AKID_SKID_MISMATCH,
- X509AkidIssuerSerialMismatch = X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH,
- X509KeyusageNoCertsign = X509_V_ERR_KEYUSAGE_NO_CERTSIGN,
- X509UnableToGetCrlIssuer = X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER,
- X509UnhandledCriticalExtension = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION,
- X509KeyusageNoCrlSign = X509_V_ERR_KEYUSAGE_NO_CRL_SIGN,
- X509UnhandledCriticalCrlExtension = X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION,
- X509InvalidNonCA = X509_V_ERR_INVALID_NON_CA,
- X509ProxyPathLengthExceeded = X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED,
- X509KeyusageNoDigitalSignature = X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE,
- X509ProxyCertificatesNotAllowed = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED,
- X509InvalidExtension = X509_V_ERR_INVALID_EXTENSION,
- X509InavlidPolicyExtension = X509_V_ERR_INVALID_POLICY_EXTENSION,
- X509NoExplicitPolicy = X509_V_ERR_NO_EXPLICIT_POLICY,
- X509DifferentCrlScope = X509_V_ERR_DIFFERENT_CRL_SCOPE,
- X509UnsupportedExtensionFeature = X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE,
- X509UnnestedResource = X509_V_ERR_UNNESTED_RESOURCE,
- X509PermittedVolation = X509_V_ERR_PERMITTED_VIOLATION,
- X509ExcludedViolation = X509_V_ERR_EXCLUDED_VIOLATION,
- X509SubtreeMinmax = X509_V_ERR_SUBTREE_MINMAX,
- X509UnsupportedConstraintType = X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE,
- X509UnsupportedConstraintSyntax = X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX,
- X509UnsupportedNameSyntax = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX,
- X509CrlPathValidationError= X509_V_ERR_CRL_PATH_VALIDATION_ERROR,
- X509ApplicationVerification = X509_V_ERR_APPLICATION_VERIFICATION,
-);
-
-// FIXME remove lifetime param for 0.9
-/// A collection of OpenSSL `GENERAL_NAME`s.
-pub struct GeneralNames<'a> {
- stack: *mut ffi::stack_st_GENERAL_NAME,
- m: PhantomData<&'a ()>,
+pub struct X509VerifyError(c_long);
+
+impl fmt::Debug for X509VerifyError {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("X509VerifyError")
+ .field("code", &self.0)
+ .field("error", &self.error_string())
+ .finish()
+ }
}
-impl<'a> Drop for GeneralNames<'a> {
- fn drop(&mut self) {
- unsafe {
- // This transmute is dubious but it's what openssl itself does...
- let free: unsafe extern "C" fn(*mut ffi::GENERAL_NAME) = ffi::GENERAL_NAME_free;
- let free: unsafe extern "C" fn(*mut c_void) = mem::transmute(free);
- ffi::sk_pop_free(&mut (*self.stack).stack, Some(free));
- }
+impl fmt::Display for X509VerifyError {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.write_str(self.error_string())
}
}
-impl<'a> GeneralNames<'a> {
- /// Returns the number of `GeneralName`s in this structure.
- pub fn len(&self) -> usize {
- unsafe { (*self.stack).stack.num as usize }
+impl Error for X509VerifyError {
+ fn description(&self) -> &str {
+ "an X509 validation error"
}
+}
- /// Returns the specified `GeneralName`.
+impl X509VerifyError {
+ /// Creates an `X509VerifyError` from a raw error number.
///
- /// # Panics
+ /// `None` will be returned if `err` is `X509_V_OK`.
///
- /// Panics if `idx` is not less than `len()`.
- pub fn get(&self, idx: usize) -> GeneralName<'a> {
- unsafe {
- assert!(idx < self.len());
-
- GeneralName {
- name: *(*self.stack).stack.data.offset(idx as isize) as *const ffi::GENERAL_NAME,
- m: PhantomData,
- }
- }
- }
-
- /// Returns an iterator over the `GeneralName`s in this structure.
- pub fn iter(&self) -> GeneralNamesIter {
- GeneralNamesIter {
- names: self,
- idx: 0,
+ /// # Safety
+ ///
+ /// Some methods on `X509VerifyError` are not thread safe if the error
+ /// number is invalid.
+ pub unsafe fn from_raw(err: c_long) -> Option<X509VerifyError> {
+ if err == ffi::X509_V_OK as c_long {
+ None
+ } else {
+ Some(X509VerifyError(err))
}
}
-}
-
-impl<'a> IntoIterator for &'a GeneralNames<'a> {
- type Item = GeneralName<'a>;
- type IntoIter = GeneralNamesIter<'a>;
- fn into_iter(self) -> GeneralNamesIter<'a> {
- self.iter()
+ pub fn as_raw(&self) -> c_long {
+ self.0
}
-}
-/// An iterator over OpenSSL `GENERAL_NAME`s.
-pub struct GeneralNamesIter<'a> {
- names: &'a GeneralNames<'a>,
- idx: usize,
-}
-
-impl<'a> Iterator for GeneralNamesIter<'a> {
- type Item = GeneralName<'a>;
+ pub fn error_string(&self) -> &'static str {
+ ffi::init();
- fn next(&mut self) -> Option<Self::Item> {
- if self.idx < self.names.len() {
- let name = self.names.get(self.idx);
- self.idx += 1;
- Some(name)
- } else {
- None
+ unsafe {
+ let s = ffi::X509_verify_cert_error_string(self.0);
+ str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
}
}
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- let size = self.names.len() - self.idx;
- (size, Some(size))
- }
}
-impl<'a> ExactSizeIterator for GeneralNamesIter<'a> {}
+type_!(GeneralName, GeneralNameRef, ffi::GENERAL_NAME, ffi::GENERAL_NAME_free);
-/// An OpenSSL `GENERAL_NAME`.
-pub struct GeneralName<'a> {
- name: *const ffi::GENERAL_NAME,
- m: PhantomData<&'a ()>,
-}
-
-impl<'a> GeneralName<'a> {
+impl GeneralNameRef {
/// Returns the contents of this `GeneralName` if it is a `dNSName`.
pub fn dnsname(&self) -> Option<&str> {
unsafe {
- if (*self.name).type_ != ffi::GEN_DNS {
+ if (*self.as_ptr()).type_ != ffi::GEN_DNS {
return None;
}
- let ptr = ffi::ASN1_STRING_data((*self.name).d as *mut _);
- let len = ffi::ASN1_STRING_length((*self.name).d as *mut _);
+ let ptr = ASN1_STRING_data((*self.as_ptr()).d as *mut _);
+ let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _);
let slice = slice::from_raw_parts(ptr as *const u8, len as usize);
// dNSNames are stated to be ASCII (specifically IA5). Hopefully
@@ -884,18 +728,22 @@ impl<'a> GeneralName<'a> {
/// Returns the contents of this `GeneralName` if it is an `iPAddress`.
pub fn ipaddress(&self) -> Option<&[u8]> {
unsafe {
- if (*self.name).type_ != ffi::GEN_IPADD {
+ if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
return None;
}
- let ptr = ffi::ASN1_STRING_data((*self.name).d as *mut _);
- let len = ffi::ASN1_STRING_length((*self.name).d as *mut _);
+ let ptr = ASN1_STRING_data((*self.as_ptr()).d as *mut _);
+ let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _);
Some(slice::from_raw_parts(ptr as *const u8, len as usize))
}
}
}
+impl Stackable for GeneralName {
+ type StackType = ffi::stack_st_GENERAL_NAME;
+}
+
#[test]
fn test_negative_serial() {
// I guess that's enough to get a random negative number
@@ -904,3 +752,44 @@ fn test_negative_serial() {
"All serials should be positive");
}
}
+
+#[cfg(ossl110)]
+mod compat {
+ pub use ffi::X509_getm_notAfter as X509_get_notAfter;
+ pub use ffi::X509_getm_notBefore as X509_get_notBefore;
+ pub use ffi::X509_up_ref;
+ pub use ffi::X509_get0_extensions;
+}
+
+#[cfg(ossl10x)]
+#[allow(bad_style)]
+mod compat {
+ use libc::c_int;
+ use ffi;
+
+ pub unsafe fn X509_get_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
+ (*(*(*x).cert_info).validity).notAfter
+ }
+
+ pub unsafe fn X509_get_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
+ (*(*(*x).cert_info).validity).notBefore
+ }
+
+ pub unsafe fn X509_up_ref(x: *mut ffi::X509) {
+ ffi::CRYPTO_add_lock(&mut (*x).references,
+ 1,
+ ffi::CRYPTO_LOCK_X509,
+ "mod.rs\0".as_ptr() as *const _,
+ line!() as c_int);
+ }
+
+ pub unsafe fn X509_get0_extensions(cert: *const ffi::X509)
+ -> *const ffi::stack_st_X509_EXTENSION {
+ let info = (*cert).cert_info;
+ if info.is_null() {
+ 0 as *mut _
+ } else {
+ (*info).extensions
+ }
+ }
+}
diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs
index eac08941..2527d538 100644
--- a/openssl/src/x509/tests.rs
+++ b/openssl/src/x509/tests.rs
@@ -1,31 +1,31 @@
use serialize::hex::FromHex;
-use crypto::hash::Type::SHA1;
-use crypto::pkey::PKey;
-use crypto::rsa::RSA;
+use hash::MessageDigest;
+use pkey::PKey;
+use rsa::Rsa;
use x509::{X509, X509Generator};
use x509::extension::Extension::{KeyUsage, ExtKeyUsage, SubjectAltName, OtherNid, OtherStr};
use x509::extension::AltNameOption as SAN;
use x509::extension::KeyUsageOption::{DigitalSignature, KeyEncipherment};
use x509::extension::ExtKeyUsageOption::{self, ClientAuth, ServerAuth};
-use nid::Nid;
+use nid;
fn get_generator() -> X509Generator {
X509Generator::new()
.set_valid_period(365 * 2)
.add_name("CN".to_string(), "test_me".to_string())
- .set_sign_hash(SHA1)
+ .set_sign_hash(MessageDigest::sha1())
.add_extension(KeyUsage(vec![DigitalSignature, KeyEncipherment]))
.add_extension(ExtKeyUsage(vec![ClientAuth,
ServerAuth,
ExtKeyUsageOption::Other("2.999.1".to_owned())]))
.add_extension(SubjectAltName(vec![(SAN::DNS, "example.com".to_owned())]))
- .add_extension(OtherNid(Nid::BasicConstraints, "critical,CA:TRUE".to_owned()))
+ .add_extension(OtherNid(nid::BASIC_CONSTRAINTS, "critical,CA:TRUE".to_owned()))
.add_extension(OtherStr("2.999.2".to_owned(), "ASN1:UTF8:example value".to_owned()))
}
fn pkey() -> PKey {
- let rsa = RSA::generate(2048).unwrap();
+ let rsa = Rsa::generate(2048).unwrap();
PKey::from_rsa(rsa).unwrap()
}
@@ -48,8 +48,8 @@ fn test_cert_gen() {
fn test_cert_gen_extension_ordering() {
let pkey = pkey();
get_generator()
- .add_extension(OtherNid(Nid::SubjectKeyIdentifier, "hash".to_owned()))
- .add_extension(OtherNid(Nid::AuthorityKeyIdentifier, "keyid:always".to_owned()))
+ .add_extension(OtherNid(nid::SUBJECT_KEY_IDENTIFIER, "hash".to_owned()))
+ .add_extension(OtherNid(nid::AUTHORITY_KEY_IDENTIFIER, "keyid:always".to_owned()))
.sign(&pkey)
.expect("Failed to generate cert with order-dependent extensions");
}
@@ -60,16 +60,14 @@ fn test_cert_gen_extension_ordering() {
fn test_cert_gen_extension_bad_ordering() {
let pkey = pkey();
let result = get_generator()
- .add_extension(OtherNid(Nid::AuthorityKeyIdentifier,
- "keyid:always".to_owned()))
- .add_extension(OtherNid(Nid::SubjectKeyIdentifier, "hash".to_owned()))
- .sign(&pkey);
+ .add_extension(OtherNid(nid::AUTHORITY_KEY_IDENTIFIER, "keyid:always".to_owned()))
+ .add_extension(OtherNid(nid::SUBJECT_KEY_IDENTIFIER, "hash".to_owned()))
+ .sign(&pkey);
assert!(result.is_err());
}
#[test]
-#[cfg(feature = "x509_generator_request")]
fn test_req_gen() {
let pkey = pkey();
@@ -84,7 +82,7 @@ fn test_req_gen() {
fn test_cert_loading() {
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 fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap();
let hash_str = "59172d9313e84459bcff27f967e79e6e9217e584";
let hash_vec = hash_str.from_hex().unwrap();
@@ -93,7 +91,6 @@ fn test_cert_loading() {
}
#[test]
-#[cfg(feature = "x509_expiry")]
fn test_cert_issue_validity() {
let cert = include_bytes!("../../test/cert.pem");
let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
@@ -116,65 +113,49 @@ fn test_save_der() {
#[test]
fn test_subject_read_cn() {
let cert = include_bytes!("../../test/cert.pem");
- let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
+ let cert = X509::from_pem(cert).unwrap();
let subject = cert.subject_name();
- let cn = match subject.text_by_nid(Nid::CN) {
- Some(x) => x,
- None => panic!("Failed to read CN from cert"),
- };
-
- assert_eq!(&cn as &str, "foobar.com")
+ let cn = subject.entries_by_nid(nid::COMMONNAME).next().unwrap();
+ assert_eq!(cn.data().as_slice(), b"foobar.com")
}
#[test]
fn test_nid_values() {
let cert = include_bytes!("../../test/nid_test_cert.pem");
- let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
+ let cert = X509::from_pem(cert).unwrap();
let subject = cert.subject_name();
- let cn = match subject.text_by_nid(Nid::CN) {
- Some(x) => x,
- None => panic!("Failed to read CN from cert"),
- };
- assert_eq!(&cn as &str, "example.com");
-
- let email = match subject.text_by_nid(Nid::Email) {
- Some(x) => x,
- None => panic!("Failed to read subject email address from cert"),
- };
- assert_eq!(&email as &str, "[email protected]");
-
- let friendly = match subject.text_by_nid(Nid::FriendlyName) {
- Some(x) => x,
- None => panic!("Failed to read subject friendly name from cert"),
- };
- assert_eq!(&friendly as &str, "Example");
+ let cn = subject.entries_by_nid(nid::COMMONNAME).next().unwrap();
+ assert_eq!(cn.data().as_slice(), b"example.com");
+
+ let email = subject.entries_by_nid(nid::PKCS9_EMAILADDRESS).next().unwrap();
+ assert_eq!(email.data().as_slice(), b"[email protected]");
+
+ let friendly = subject.entries_by_nid(nid::FRIENDLYNAME).next().unwrap();
+ assert_eq!(&*friendly.data().as_utf8().unwrap(), "Example");
}
#[test]
fn test_nid_uid_value() {
let cert = include_bytes!("../../test/nid_uid_test_cert.pem");
- let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
+ let cert = X509::from_pem(cert).unwrap();
let subject = cert.subject_name();
- let cn = match subject.text_by_nid(Nid::UserId) {
- Some(x) => x,
- None => panic!("Failed to read UID from cert"),
- };
- assert_eq!(&cn as &str, "this is the userId");
+ let cn = subject.entries_by_nid(nid::USERID).next().unwrap();
+ assert_eq!(cn.data().as_slice(), b"this is the userId");
}
#[test]
fn test_subject_alt_name() {
let cert = include_bytes!("../../test/alt_name_cert.pem");
- let cert = X509::from_pem(cert).ok().expect("Failed to load PEM");
+ let cert = X509::from_pem(cert).unwrap();
let subject_alt_names = cert.subject_alt_names().unwrap();
assert_eq!(3, subject_alt_names.len());
- assert_eq!(Some("foobar.com"), subject_alt_names.get(0).dnsname());
- assert_eq!(subject_alt_names.get(1).ipaddress(),
+ assert_eq!(Some("foobar.com"), subject_alt_names[0].dnsname());
+ assert_eq!(subject_alt_names[1].ipaddress(),
Some(&[127, 0, 0, 1][..]));
- assert_eq!(subject_alt_names.get(2).ipaddress(),
+ assert_eq!(subject_alt_names[2].ipaddress(),
Some(&b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"[..]));
}
diff --git a/openssl/src/x509/verify.rs b/openssl/src/x509/verify.rs
new file mode 100644
index 00000000..8cb123e6
--- /dev/null
+++ b/openssl/src/x509/verify.rs
@@ -0,0 +1,5 @@
+//! X509 certificate verification
+//!
+//! Requires the `v102` or `v110` features and OpenSSL 1.0.2 or 1.1.0.
+
+pub use ::verify::*;