diff --git a/openssl/src/asn1/mod.rs b/openssl/src/asn1.rs similarity index 91% rename from openssl/src/asn1/mod.rs rename to openssl/src/asn1.rs index 1eab9f04..91f920a3 100644 --- a/openssl/src/asn1/mod.rs +++ b/openssl/src/asn1.rs @@ -2,9 +2,10 @@ use libc::c_long; use std::{ptr, fmt}; use std::marker::PhantomData; use std::ops::Deref; - -use bio::MemBio; use ffi; + +use {cvt, cvt_p}; +use bio::MemBio; use error::ErrorStack; /// Corresponds to the ASN.1 structure Time defined in RFC5280 @@ -20,7 +21,7 @@ impl Asn1Time { ffi::init(); unsafe { - let handle = try_ssl_null!(ffi::X509_gmtime_adj(ptr::null_mut(), period)); + let handle = try!(cvt_p(ffi::X509_gmtime_adj(ptr::null_mut(), period))); Ok(Asn1Time::from_ptr(handle)) } } @@ -58,7 +59,7 @@ 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)); + try!(cvt(ffi::ASN1_TIME_print(mem_bio.as_ptr(), self.0))); String::from_utf8_unchecked(mem_bio.get_buf().to_owned()) }; write!(f, "{}", as_str) diff --git a/openssl/src/bio.rs b/openssl/src/bio.rs index 22d2cee3..199fc0c8 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]>); @@ -22,7 +23,7 @@ impl<'a> MemBioSlice<'a> { assert!(buf.len() <= c_int::max_value() as usize); let bio = unsafe { - try_ssl_null!(BIO_new_mem_buf(buf.as_ptr() as *const _, buf.len() as c_int)) + try!(cvt_p(BIO_new_mem_buf(buf.as_ptr() as *const _, buf.len() as c_int))) }; Ok(MemBioSlice(bio, PhantomData)) @@ -48,7 +49,7 @@ impl MemBio { ffi::init(); let bio = unsafe { - try_ssl_null!(ffi::BIO_new(ffi::BIO_s_mem())) + try!(cvt_p(ffi::BIO_new(ffi::BIO_s_mem()))) }; Ok(MemBio(bio)) } diff --git a/openssl/src/bn.rs b/openssl/src/bn.rs new file mode 100644 index 00000000..512c58d3 --- /dev/null +++ b/openssl/src/bn.rs @@ -0,0 +1,908 @@ +use ffi; +use libc::{c_int, c_void}; +use std::cmp::Ordering; +use std::ffi::{CStr, CString}; +use std::{fmt, ptr}; +use std::marker::PhantomData; +use std::ops::{Add, Div, Mul, Neg, Rem, Shl, Shr, Sub, Deref, DerefMut}; + +use {cvt, cvt_p, cvt_n}; +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, +} + +/// A context object for `BigNum` operations. +pub struct BnCtx(*mut ffi::BN_CTX); + +impl Drop for BnCtx { + fn drop(&mut self) { + unsafe { + ffi::BN_CTX_free(self.0); + } + } +} + +impl BnCtx { + /// Returns a new `BnCtx`. + pub fn new() -> Result { + unsafe { + cvt_p(ffi::BN_CTX_new()).map(BnCtx) + } + } + + /// Places the result of `a * b` in `r`. + pub fn mul(&mut self, + r: &mut BigNumRef, + a: &BigNumRef, + b: &BigNumRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_mul(r.0, a.0, b.0, self.0)).map(|_| ()) + } + } + + /// Places the result of `a / b` in `dv` and `a mod b` in `rem`. + pub fn div(&mut self, + dv: Option<&mut BigNumRef>, + rem: Option<&mut BigNumRef>, + a: &BigNumRef, + b: &BigNumRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_div(dv.map(|b| b.0).unwrap_or(ptr::null_mut()), + rem.map(|b| b.0).unwrap_or(ptr::null_mut()), + a.0, + b.0, + self.0)) + .map(|_| ()) + } + } + + /// Places the result of `a²` in `r`. + pub fn sqr(&mut self, r: &mut BigNumRef, a: &BigNumRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_sqr(r.as_ptr(), a.as_ptr(), self.0)).map(|_| ()) + } + } + + /// Places the result of `a mod m` in `r`. + pub fn nnmod(&mut self, + r: &mut BigNumRef, + a: &BigNumRef, + m: &BigNumRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_nnmod(r.as_ptr(), a.as_ptr(), m.as_ptr(), self.0)).map(|_| ()) + } + } + + /// Places the result of `(a + b) mod m` in `r`. + pub fn mod_add(&mut self, + r: &mut BigNumRef, + a: &BigNumRef, + b: &BigNumRef, + m: &BigNumRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_mod_add(r.as_ptr(), a.as_ptr(), b.as_ptr(), m.as_ptr(), self.0)).map(|_| ()) + } + } + + /// Places the result of `(a - b) mod m` in `r`. + pub fn mod_sub(&mut self, + r: &mut BigNumRef, + a: &BigNumRef, + b: &BigNumRef, + m: &BigNumRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_mod_sub(r.as_ptr(), a.as_ptr(), b.as_ptr(), m.as_ptr(), self.0)).map(|_| ()) + } + } + + /// Places the result of `(a * b) mod m` in `r`. + pub fn mod_mul(&mut self, + r: &mut BigNumRef, + a: &BigNumRef, + b: &BigNumRef, + m: &BigNumRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_mod_mul(r.as_ptr(), a.as_ptr(), b.as_ptr(), m.as_ptr(), self.0)).map(|_| ()) + } + } + + /// Places the result of `a² mod m` in `r`. + pub fn mod_sqr(&mut self, + r: &mut BigNumRef, + a: &BigNumRef, + m: &BigNumRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_mod_sqr(r.as_ptr(), a.as_ptr(), m.as_ptr(), self.0)).map(|_| ()) + } + } + + /// Places the result of `a^p` in `r`. + pub fn exp(&mut self, + r: &mut BigNumRef, + a: &BigNumRef, + p: &BigNumRef) -> Result<(), ErrorStack> { + unsafe{ + cvt(ffi::BN_exp(r.as_ptr(), a.as_ptr(), p.as_ptr(), self.0)).map(|_| ()) + } + } + + /// Places the result of `a^p mod m` in `r`. + pub fn mod_exp(&mut self, + r: &mut BigNumRef, + a: &BigNumRef, + p: &BigNumRef, + m: &BigNumRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_mod_exp(r.as_ptr(), a.as_ptr(), p.as_ptr(), m.as_ptr(), self.0)).map(|_| ()) + } + } + + /// Places the inverse of `a` modulo `n` in `r`. + pub fn mod_inverse(&mut self, + r: &mut BigNumRef, + a: &BigNumRef, + n: &BigNumRef) -> Result<(), ErrorStack> { + unsafe { + cvt_p(ffi::BN_mod_inverse(r.0, a.0, n.0, self.0)).map(|_| ()) + } + } + + /// Places the greatest common denominator of `a` and `b` in `r`. + pub fn gcd(&mut self, + r: &mut BigNumRef, + a: &BigNumRef, + b: &BigNumRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_gcd(r.0, a.0, b.0, self.0)).map(|_| ()) + } + } + + /// Checks whether `p` is prime. + /// + /// Performs a Miller-Rabin probabilistic primality test with `checks` iterations. + /// + /// Returns `true` if `p` is prime with an error probability of less than `0.25 ^ checks`. + pub fn is_prime(&mut self, p: &BigNumRef, checks: i32) -> Result { + unsafe { + cvt_n(ffi::BN_is_prime_ex(p.0, checks.into(), self.0, ptr::null_mut())).map(|r| r != 0) + } + } + + /// Checks whether `p` 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 `p` is prime with an error probability of less than `0.25 ^ checks`. + pub fn is_prime_fasttest(&mut self, + p: &BigNumRef, + checks: i32, + do_trial_division: bool) -> Result { + unsafe { + cvt_n(ffi::BN_is_prime_fasttest_ex(p.0, + checks.into(), + self.0, + do_trial_division as c_int, + ptr::null_mut())) + .map(|r| r != 0) + } + } + + /// Generates a cryptographically strong pseudo-random `BigNum`, placing it in `r`. + /// + /// # 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 rand(r: &mut BigNumRef, + bits: i32, + prop: RNGProperty, + odd: bool) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_rand(r.0, bits.into(), prop as c_int, odd as c_int)).map(|_| ()) + } + } + + /// The cryptographically weak counterpart to `checked_new_random`. + pub fn pseudo_rand(r: &mut BigNumRef, + bits: i32, + prop: RNGProperty, + odd: bool) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_pseudo_rand(r.0, bits.into(), prop as c_int, odd as c_int)).map(|_| ()) + } + } +} + +/// 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) + } + + /// Adds a `u32` to `self`. + pub fn add_word(&mut self, w: u32) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_add_word(self.0, 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.0, 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.0, w as ffi::BN_ULONG)).map(|_| ()) + } + } + + /// Divides `self` by a `u32`, returning the remainder. + pub fn div_word(&mut self, w: u32) -> Result { + unsafe { + let r = ffi::BN_div_word(self.0, 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 { + unsafe { + let r = ffi::BN_mod_word(self.0, 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_in_range(&self, rnd: &mut BigNumRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_rand_range(self.0, rnd.0)).map(|_| ()) + } + } + + /// The cryptographically weak counterpart to `rand_in_range`. + pub fn pseudo_rand_in_range(&self, rnd: &mut BigNumRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_pseudo_rand_range(self.0, rnd.0)).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.0, 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.0, 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.0, 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.0, n.into())).map(|_| ()) + } + } + + /// Places `self << 1` in `r`. + pub fn lshift1(&self, r: &mut BigNumRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_lshift1(r.0, self.0)).map(|_| ()) + } + } + + /// Places `self >> 1` in `r`. + pub fn rshift1(&self, r: &mut BigNumRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_rshift1(r.0, self.0)).map(|_| ()) + } + } + + /// Places `self + b` in `r`. + pub fn add(&self, r: &mut BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_add(r.0, self.0, b.0)).map(|_| ()) + } + } + + /// Places `self - b` in `r`. + pub fn sub(&self, r: &mut BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_sub(r.0, self.0, b.0)).map(|_| ()) + } + } + + /// Places `self << n` in `r`. + pub fn lshift(&self, r: &mut BigNumRef, b: i32) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_lshift(r.0, self.0, b.into())).map(|_| ()) + } + } + + /// Places `self >> n` in `r`. + pub fn rshift(&self, r: &mut BigNumRef, n: i32) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_rshift(r.0, self.0, n.into())).map(|_| ()) + } + } + + pub fn to_owned(&self) -> Result { + unsafe { + cvt_p(ffi::BN_dup(self.0)).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.0, 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 { + let res = ffi::BN_ucmp(self.as_ptr(), oth.as_ptr()); + if res < 0 { + Ordering::Less + } else if res > 0 { + Ordering::Greater + } else { + Ordering::Equal + } + } + } + + 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 + } + + 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::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 { + 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 { + unsafe { + let buf = try!(cvt_p(ffi::BN_bn2dec(self.as_ptr()))); + let str = String::from_utf8(CStr::from_ptr(buf as *const _).to_bytes().to_vec()) + .unwrap(); + CRYPTO_free!(buf as *mut c_void); + Ok(str) + } + } + + /// 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 { + unsafe { + let buf = try!(cvt_p(ffi::BN_bn2hex(self.as_ptr()))); + let str = String::from_utf8(CStr::from_ptr(buf as *const _).to_bytes().to_vec()) + .unwrap(); + CRYPTO_free!(buf as *mut c_void); + Ok(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 { + 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::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 { + 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 { + 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)) + } + } + + 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::from_slice(&[0x12, 0x00, 0x34]).unwrap(); + /// + /// assert_eq!(bignum, BigNum::from_u32(0x120034).unwrap()); + /// ``` + pub fn from_slice(n: &[u8]) -> Result { + 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)) + } + } + + /// Generates a prime number, placing it in `r`. + /// + /// # 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(r: &mut BigNumRef, + bits: i32, + safe: bool, + add: Option<&BigNumRef>, + rem: Option<&BigNumRef>) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_generate_prime_ex(r.0, + bits as c_int, + safe as c_int, + add.map(|n| n.0).unwrap_or(ptr::null_mut()), + rem.map(|n| n.0).unwrap_or(ptr::null_mut()), + ptr::null_mut())) + .map(|_| ()) + } + } +} + +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> 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 { + 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<'a> fmt::Display for BigNumRef<'a> { + 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<'a, 'b> PartialEq> for BigNumRef<'a> { + fn eq(&self, oth: &BigNumRef) -> bool { + self.cmp(oth) == Ordering::Equal + } +} + +impl<'a> PartialEq 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> for BigNum { + fn eq(&self, oth: &BigNumRef) -> bool { + self.deref().eq(oth) + } +} + +impl Eq for BigNum {} + +impl<'a, 'b> PartialOrd> for BigNumRef<'a> { + fn partial_cmp(&self, oth: &BigNumRef) -> Option { + Some(self.cmp(oth)) + } +} + +impl<'a> PartialOrd for BigNumRef<'a> { + fn partial_cmp(&self, oth: &BigNum) -> Option { + 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 { + self.deref().partial_cmp(oth.deref()) + } +} + +impl<'a> PartialOrd> for BigNum { + fn partial_cmp(&self, oth: &BigNumRef) -> Option { + 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<'a> { + type Output = BigNum; + + fn $m(self, oth: &BigNum) -> BigNum { + $t::$m(self, oth.deref()) + } + } + + impl<'a, 'b> $t<&'b BigNumRef<'b>> 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<'b>> for &'a BigNumRef<'a> { + type Output = BigNum; + + fn add(self, oth: &BigNumRef) -> BigNum { + let mut r = BigNum::new().unwrap(); + self.add(&mut r, oth).unwrap(); + r + } +} + +delegate!(Add, add); + +impl<'a, 'b> Sub<&'b BigNumRef<'b>> for &'a BigNumRef<'a> { + type Output = BigNum; + + fn sub(self, oth: &BigNumRef) -> BigNum { + let mut r = BigNum::new().unwrap(); + self.sub(&mut r, oth).unwrap(); + r + } +} + +delegate!(Sub, sub); + +impl<'a, 'b> Mul<&'b BigNumRef<'b>> for &'a BigNumRef<'a> { + type Output = BigNum; + + fn mul(self, oth: &BigNumRef) -> BigNum { + let mut ctx = BnCtx::new().unwrap(); + let mut r = BigNum::new().unwrap(); + ctx.mul(&mut r, self, oth).unwrap(); + r + } +} + +delegate!(Mul, mul); + +impl<'a, 'b> Div<&'b BigNumRef<'b>> for &'a BigNumRef<'a> { + type Output = BigNum; + + fn div(self, oth: &'b BigNumRef<'b>) -> BigNum { + let mut ctx = BnCtx::new().unwrap(); + let mut dv = BigNum::new().unwrap(); + ctx.div(Some(&mut dv), None, self, oth).unwrap(); + dv + } +} + +delegate!(Div, div); + +impl<'a, 'b> Rem<&'b BigNumRef<'b>> for &'a BigNumRef<'a> { + type Output = BigNum; + + fn rem(self, oth: &'b BigNumRef<'b>) -> BigNum { + let mut ctx = BnCtx::new().unwrap(); + let mut rem = BigNum::new().unwrap(); + ctx.div(None, Some(&mut rem), self, oth).unwrap(); + rem + } +} + +delegate!(Rem, rem); + +impl<'a> Shl for &'a BigNumRef<'a> { + type Output = BigNum; + + fn shl(self, n: i32) -> BigNum { + let mut r = BigNum::new().unwrap(); + self.lshift(&mut r, n).unwrap(); + r + } +} + +impl<'a> Shl for &'a BigNum { + type Output = BigNum; + + fn shl(self, n: i32) -> BigNum { + self.deref().shl(n) + } +} + +impl<'a> Shr for &'a BigNumRef<'a> { + type Output = BigNum; + + fn shr(self, n: i32) -> BigNum { + let mut r = BigNum::new().unwrap(); + self.rshift(&mut r, n).unwrap(); + r + } +} + +impl<'a> Shr for &'a BigNum { + type Output = BigNum; + + fn shr(self, n: i32) -> BigNum { + self.deref().shl(n) + } +} + +impl<'a> Neg for &'a BigNumRef<'a> { + 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::{BnCtx, 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(); + BigNum::generate_prime(&mut p, 128, true, None, Some(&a)).unwrap(); + + let mut ctx = BnCtx::new().unwrap(); + assert!(ctx.is_prime(&p, 100).unwrap()); + assert!(ctx.is_prime_fasttest(&p, 100, true).unwrap()); + } +} diff --git a/openssl/src/bn/mod.rs b/openssl/src/bn/mod.rs deleted file mode 100644 index 7d1f5458..00000000 --- a/openssl/src/bn/mod.rs +++ /dev/null @@ -1,1037 +0,0 @@ -use libc::{c_int, 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - unsafe { - with_bn_in_ctx!(r, ctx, { - !ffi::BN_mod_inverse(r.as_ptr(), self.as_ptr(), n.as_ptr(), ctx).is_null() - }) - } - } - - /// Add a `u32` to `self`. This is more efficient than adding a - /// `BigNum`. - pub fn add_word(&mut self, w: u32) -> Result<(), ErrorStack> { - unsafe { - if ffi::BN_add_word(self.as_ptr(), w as ffi::BN_ULONG) == 1 { - Ok(()) - } else { - Err(ErrorStack::get()) - } - } - } - - pub fn sub_word(&mut self, w: u32) -> Result<(), ErrorStack> { - unsafe { - if ffi::BN_sub_word(self.as_ptr(), w as ffi::BN_ULONG) == 1 { - Ok(()) - } else { - Err(ErrorStack::get()) - } - } - } - - pub fn mul_word(&mut self, w: u32) -> Result<(), ErrorStack> { - unsafe { - if ffi::BN_mul_word(self.as_ptr(), w as ffi::BN_ULONG) == 1 { - Ok(()) - } else { - Err(ErrorStack::get()) - } - } - } - - pub fn div_word(&mut self, w: u32) -> Result { - unsafe { - let result = ffi::BN_div_word(self.as_ptr(), w as ffi::BN_ULONG); - if result != !0 { - Ok(result.into()) - } else { - Err(ErrorStack::get()) - } - } - } - - pub fn mod_word(&self, w: u32) -> Result { - unsafe { - let result = ffi::BN_mod_word(self.as_ptr(), w as ffi::BN_ULONG); - if result != !0 { - Ok(result as u64) - } else { - Err(ErrorStack::get()) - } - } - } - - /// Computes the greatest common denominator of `self` and `a`. - pub fn checked_gcd(&self, a: &BigNumRef) -> Result { - 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 { - unsafe { - with_ctx!(ctx, { - Ok(ffi::BN_is_prime_ex(self.as_ptr(), - checks as c_int, - ctx, - ptr::null_mut()) == 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 { - 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_mut()) == 1) - }) - } - } - - /// Generates a cryptographically strong pseudo-random `BigNum` `r` in the range - /// `0 <= r < self`. - pub fn checked_rand_in_range(&self) -> Result { - 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 { - 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 { - 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 { - unsafe { - with_bn!(r, { - ffi::BN_rshift1(r.as_ptr(), self.as_ptr()) == 1 - }) - } - } - - pub fn checked_add(&self, a: &BigNumRef) -> Result { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - unsafe { - with_bn!(r, { - ffi::BN_rshift(r.as_ptr(), self.as_ptr(), *a as c_int) == 1 - }) - } - } - - pub fn to_owned(&self) -> Result { - 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 { - 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 - } - - 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 { - 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(); - 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(); - 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 { - 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: u32) -> Result { - BigNum::new().and_then(|v| unsafe { - try_ssl!(ffi::BN_set_word(v.as_ptr(), n as ffi::BN_ULONG)); - Ok(v) - }) - } - - /// Creates a `BigNum` from a decimal string. - pub fn from_dec_str(s: &str) -> Result { - BigNum::new().and_then(|mut v| unsafe { - let c_str = CString::new(s.as_bytes()).unwrap(); - try_ssl!(ffi::BN_dec2bn(&mut (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::new().and_then(|mut v| unsafe { - let c_str = CString::new(s.as_bytes()).unwrap(); - try_ssl!(ffi::BN_hex2bn(&mut (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::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 { - 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_mut()) == 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 { - 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 { - 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> 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> for BigNumRef<'a> { - fn eq(&self, oth: &BigNumRef) -> bool { - unsafe { ffi::BN_cmp(self.as_ptr(), oth.as_ptr()) == 0 } - } -} - -impl<'a> PartialEq 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> for BigNum { - fn eq(&self, oth: &BigNumRef) -> bool { - self.deref().eq(oth) - } -} - -impl Eq for BigNum {} - -impl<'a, 'b> PartialOrd> for BigNumRef<'a> { - fn partial_cmp(&self, oth: &BigNumRef) -> Option { - Some(self.cmp(oth)) - } -} - -impl<'a> PartialOrd for BigNumRef<'a> { - fn partial_cmp(&self, oth: &BigNum) -> Option { - 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 { - self.deref().partial_cmp(oth.deref()) - } -} - -impl<'a> PartialOrd> for BigNum { - fn partial_cmp(&self, oth: &BigNumRef) -> Option { - 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 for &'a BigNumRef<'a> { - type Output = BigNum; - - fn shl(self, n: i32) -> BigNum { - self.checked_shl(&n).unwrap() - } -} - -impl<'a> Shl for &'a BigNum { - type Output = BigNum; - - fn shl(self, n: i32) -> BigNum { - self.checked_shl(&n).unwrap() - } -} - -impl<'a> Shr for &'a BigNumRef<'a> { - type Output = BigNum; - - fn shr(self, n: i32) -> BigNum { - self.checked_shr(&n).unwrap() - } -} - -impl<'a> Shr 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/crypto/dsa.rs b/openssl/src/crypto/dsa.rs index addaae2f..f9044661 100644 --- a/openssl/src/crypto/dsa.rs +++ b/openssl/src/crypto/dsa.rs @@ -4,26 +4,25 @@ use error::ErrorStack; use std::ptr; use libc::{c_int, c_char, c_void}; +use {cvt, cvt_p}; use bn::BigNumRef; use bio::{MemBio, MemBioSlice}; use crypto::util::{CallbackState, invoke_passwd_cb}; - /// Builder for upfront DSA parameter generation pub struct DSAParams(*mut ffi::DSA); impl DSAParams { pub fn with_size(size: u32) -> Result { 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, + let dsa = DSAParams(try!(cvt_p(ffi::DSA_new()))); + try!(cvt(ffi::DSA_generate_parameters_ex(dsa.0, size as c_int, ptr::null(), 0, ptr::null_mut(), ptr::null_mut(), - ptr::null_mut())); + ptr::null_mut()))); Ok(dsa) } } @@ -31,7 +30,7 @@ impl DSAParams { /// Generate a key pair from the initialized parameters pub fn generate(self) -> Result { unsafe { - try_ssl!(ffi::DSA_generate_key(self.0)); + try!(cvt(ffi::DSA_generate_key(self.0))); let dsa = DSA(self.0); ::std::mem::forget(self); Ok(dsa) @@ -75,13 +74,11 @@ impl DSA { 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) + let dsa = try!(cvt_p(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(), + ptr::null_mut(), + None, + ptr::null_mut()))); + Ok(DSA(dsa)) } } @@ -99,13 +96,11 @@ impl DSA { 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::), - cb_ptr)); - let dsa = DSA(dsa); - assert!(dsa.has_private_key()); - Ok(dsa) + let dsa = try!(cvt_p(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(), + ptr::null_mut(), + Some(invoke_passwd_cb::), + cb_ptr))); + Ok(DSA(dsa)) } } @@ -116,9 +111,9 @@ impl DSA { 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())) + try!(cvt(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()) @@ -131,10 +126,10 @@ impl DSA { 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())); + 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)) } } @@ -142,7 +137,9 @@ impl DSA { /// Writes an DSA public key as PEM formatted data pub fn public_key_to_pem(&self) -> Result, ErrorStack> { let mem_bio = try!(MemBio::new()); - unsafe { try_ssl!(ffi::PEM_write_bio_DSA_PUBKEY(mem_bio.as_ptr(), self.0)) }; + unsafe { + try!(cvt(ffi::PEM_write_bio_DSA_PUBKEY(mem_bio.as_ptr(), self.0))); + } Ok(mem_bio.get_buf().to_owned()) } @@ -239,11 +236,9 @@ impl fmt::Debug for DSA { #[cfg(test)] mod test { - use std::io::Write; use libc::c_char; use super::*; - use crypto::hash::*; #[test] pub fn test_generate() { diff --git a/openssl/src/crypto/hash.rs b/openssl/src/crypto/hash.rs index 2fa75807..ec265631 100644 --- a/openssl/src/crypto/hash.rs +++ b/openssl/src/crypto/hash.rs @@ -1,6 +1,5 @@ use std::io::prelude::*; use std::io; -use std::ptr; use ffi; #[cfg(ossl110)] @@ -8,6 +7,7 @@ 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; #[derive(Copy, Clone)] @@ -116,7 +116,7 @@ impl Hasher { pub fn new(ty: MessageDigest) -> Result { ffi::init(); - let ctx = unsafe { try_ssl_null!(EVP_MD_CTX_new()) }; + let ctx = unsafe { try!(cvt_p(EVP_MD_CTX_new())) }; let mut h = Hasher { ctx: ctx, @@ -136,7 +136,7 @@ impl Hasher { } Finalized => (), } - unsafe { try_ssl!(ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *mut _)); } + unsafe { try!(cvt(ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *mut _))); } self.state = Reset; Ok(()) } @@ -147,9 +147,9 @@ impl Hasher { try!(self.init()); } unsafe { - try_ssl!(ffi::EVP_DigestUpdate(self.ctx, + try!(cvt(ffi::EVP_DigestUpdate(self.ctx, data.as_ptr() as *mut _, - data.len())); + data.len()))); } self.state = Updated; Ok(()) @@ -164,7 +164,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) diff --git a/openssl/src/crypto/pkcs12.rs b/openssl/src/crypto/pkcs12.rs index b028f29d..846b7baf 100644 --- a/openssl/src/crypto/pkcs12.rs +++ b/openssl/src/crypto/pkcs12.rs @@ -6,6 +6,7 @@ use std::cmp; use std::ptr; use std::ffi::CString; +use {cvt, cvt_p}; use crypto::pkey::PKey; use error::ErrorStack; use x509::X509; @@ -26,7 +27,7 @@ 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)) } } @@ -40,7 +41,7 @@ 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.0, pass.as_ptr(), &mut pkey, &mut cert, &mut chain))); let pkey = PKey::from_ptr(pkey); let cert = X509::from_ptr(cert); diff --git a/openssl/src/crypto/pkcs5.rs b/openssl/src/crypto/pkcs5.rs index 9d348b89..8bcb9b31 100644 --- a/openssl/src/crypto/pkcs5.rs +++ b/openssl/src/crypto/pkcs5.rs @@ -2,6 +2,7 @@ use libc::c_int; use std::ptr; use ffi; +use cvt; use crypto::hash::MessageDigest; use crypto::symm::Cipher; use error::ErrorStack; @@ -9,26 +10,27 @@ use error::ErrorStack; #[derive(Clone, Eq, PartialEq, Hash, Debug)] pub struct KeyIvPair { pub key: Vec, - pub iv: Vec, + pub iv: Option>, } /// Derives a key and an IV from various parameters. /// -/// If specified `salt` must be 8 bytes in length. +/// 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(cipher: Cipher, - digest: MessageDigest, - data: &[u8], - salt: Option<&[u8]>, - count: u32) - -> Result { +/// 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 { 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); @@ -39,78 +41,58 @@ pub fn evp_bytes_to_key_pbkdf1_compatible(cipher: Cipher, 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 = ffi::EVP_BytesToKey(cipher, - digest, - 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 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 mut iv = vec![0; len as usize]; + let iv_ptr = iv.as_mut().map(|v| v.as_mut_ptr()).unwrap_or(ptr::null_mut()); - try_ssl!(ffi::EVP_BytesToKey(cipher, + 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.as_mut_ptr())); + iv_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, ErrorStack> { - unsafe { - let mut out = vec![0; keylen]; - - ffi::init(); - - try_ssl!(ffi::PKCS5_PBKDF2_HMAC_SHA1(pass.as_ptr() as *const _, - 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. pub fn pbkdf2_hmac(pass: &[u8], salt: &[u8], iter: usize, hash: MessageDigest, - keylen: usize) - -> Result, ErrorStack> { + key: &mut [u8]) + -> Result<(), ErrorStack> { unsafe { - let mut out = vec![0; keylen]; + 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(); - try_ssl!(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(), - keylen as c_int, - out.as_mut_ptr())); - Ok(out) + 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(|_| ()) } } @@ -120,96 +102,67 @@ mod tests { use crypto::symm::Cipher; // Test vectors from - // http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06 + // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c #[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]); + fn pbkdf2_hmac_sha256() { + let mut buf = [0; 16]; - 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]); + 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][..]); - 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]); + 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 test_pbkdf2_hmac_sha256() { - assert_eq!(super::pbkdf2_hmac(b"passwd", b"salt", 1, MessageDigest::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]); + fn pbkdf2_hmac_sha512() { + let mut buf = [0; 64]; - assert_eq!(super::pbkdf2_hmac(b"Password", b"NaCl", 80000, MessageDigest::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]); - } + 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][..]); - // Test vectors from - // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c - #[test] - fn test_pbkdf2_hmac_sha512() { - assert_eq!(super::pbkdf2_hmac(b"password", b"NaCL", 1, MessageDigest::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]); + 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][..]); - assert_eq!(super::pbkdf2_hmac(b"pass\0word", b"sa\0lt", 1, MessageDigest::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, - MessageDigest::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]); + 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 test_evp_bytes_to_key_pbkdf1_compatible() { + 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, @@ -224,18 +177,16 @@ mod tests { 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]; + 69_u8, 98_u8, 107_u8, 208_u8, 14_u8, 236_u8, 60_u8]; - assert_eq!(super::evp_bytes_to_key_pbkdf1_compatible(Cipher::aes_256_cbc(), - MessageDigest::sha1(), - &data, - Some(&salt), - 1).unwrap(), + assert_eq!(super::bytes_to_key(Cipher::aes_256_cbc(), + MessageDigest::sha1(), + &data, + Some(&salt), + 1).unwrap(), super::KeyIvPair { key: expected_key, - iv: expected_iv, + iv: Some(expected_iv), }); } } diff --git a/openssl/src/crypto/pkey.rs b/openssl/src/crypto/pkey.rs index 67ff7520..1d062cfa 100644 --- a/openssl/src/crypto/pkey.rs +++ b/openssl/src/crypto/pkey.rs @@ -3,6 +3,7 @@ use std::ptr; use std::mem; use ffi; +use {cvt, cvt_p}; use bio::{MemBio, MemBioSlice}; use crypto::dsa::DSA; use crypto::rsa::RSA; @@ -19,9 +20,9 @@ impl PKey { /// Create a new `PKey` containing an RSA key. pub fn from_rsa(rsa: RSA) -> Result { unsafe { - let evp = try_ssl_null!(ffi::EVP_PKEY_new()); + let evp = try!(cvt_p(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 _)); + try!(cvt(ffi::EVP_PKEY_assign(pkey.0, ffi::EVP_PKEY_RSA, rsa.as_ptr() as *mut _))); mem::forget(rsa); Ok(pkey) } @@ -30,9 +31,9 @@ impl PKey { /// Create a new `PKey` containing a DSA key. pub fn from_dsa(dsa: DSA) -> Result { unsafe { - let evp = try_ssl_null!(ffi::EVP_PKEY_new()); + let evp = try!(cvt_p(ffi::EVP_PKEY_new())); let pkey = PKey(evp); - try_ssl!(ffi::EVP_PKEY_assign(pkey.0, ffi::EVP_PKEY_DSA, dsa.as_ptr() as *mut _)); + try!(cvt(ffi::EVP_PKEY_assign(pkey.0, ffi::EVP_PKEY_DSA, dsa.as_ptr() as *mut _))); mem::forget(dsa); Ok(pkey) } @@ -42,10 +43,10 @@ impl PKey { pub fn hmac(key: &[u8]) -> Result { unsafe { assert!(key.len() <= c_int::max_value() as usize); - let key = try_ssl_null!(ffi::EVP_PKEY_new_mac_key(ffi::EVP_PKEY_HMAC, - ptr::null_mut(), - key.as_ptr() as *const _, - key.len() as c_int)); + 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)) } } @@ -59,10 +60,10 @@ impl PKey { 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())); + 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)) } } @@ -79,10 +80,10 @@ impl PKey { 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::), - &mut cb as *mut _ as *mut c_void)); + let evp = try!(cvt_p(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(), + ptr::null_mut(), + Some(invoke_passwd_cb::), + &mut cb as *mut _ as *mut c_void))); Ok(PKey::from_ptr(evp)) } } @@ -92,10 +93,10 @@ impl PKey { 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())); + 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)) } } @@ -105,15 +106,15 @@ impl PKey { 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)); + try!(cvt(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 { + pub fn rsa(&self) -> Result { unsafe { - let rsa = try_ssl_null!(ffi::EVP_PKEY_get1_RSA(self.0)); + let rsa = try!(cvt_p(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)) } @@ -124,13 +125,13 @@ impl PKey { pub fn private_key_to_pem(&self) -> Result, ErrorStack> { let mem_bio = try!(MemBio::new()); unsafe { - try_ssl!(ffi::PEM_write_bio_PrivateKey(mem_bio.as_ptr(), + try!(cvt(ffi::PEM_write_bio_PrivateKey(mem_bio.as_ptr(), self.0, ptr::null(), ptr::null_mut(), -1, None, - ptr::null_mut())); + ptr::null_mut()))); } Ok(mem_bio.get_buf().to_owned()) @@ -139,7 +140,9 @@ impl PKey { /// Stores public key as a PEM pub fn public_key_to_pem(&self) -> Result, ErrorStack> { let mem_bio = try!(MemBio::new()); - unsafe { try_ssl!(ffi::PEM_write_bio_PUBKEY(mem_bio.as_ptr(), self.0)) } + unsafe { + try!(cvt(ffi::PEM_write_bio_PUBKEY(mem_bio.as_ptr(), self.0))); + } Ok(mem_bio.get_buf().to_owned()) } diff --git a/openssl/src/crypto/rand.rs b/openssl/src/crypto/rand.rs index 519449e9..c1c49e7b 100644 --- a/openssl/src/crypto/rand.rs +++ b/openssl/src/crypto/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/crypto/rsa.rs b/openssl/src/crypto/rsa.rs index 1212ee3a..a6a4f2b7 100644 --- a/openssl/src/crypto/rsa.rs +++ b/openssl/src/crypto/rsa.rs @@ -4,6 +4,7 @@ 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; @@ -42,11 +43,11 @@ impl RSA { /// the supplied load and save methods for DER formatted keys. pub fn from_public_components(n: BigNum, e: BigNum) -> Result { unsafe { - let rsa = RSA(try_ssl_null!(ffi::RSA_new())); - try_ssl!(compat::set_key(rsa.0, + 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())); + ptr::null_mut()))); mem::forget((n, e)); Ok(rsa) } @@ -62,13 +63,13 @@ impl RSA { qi: BigNum) -> Result { unsafe { - let rsa = RSA(try_ssl_null!(ffi::RSA_new())); - try_ssl!(compat::set_key(rsa.0, n.as_ptr(), e.as_ptr(), d.as_ptr())); + 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_ssl!(compat::set_factors(rsa.0, p.as_ptr(), q.as_ptr())); + try!(cvt(compat::set_factors(rsa.0, p.as_ptr(), q.as_ptr()))); mem::forget((p, q)); - try_ssl!(compat::set_crt_params(rsa.0, dp.as_ptr(), dq.as_ptr(), - qi.as_ptr())); + try!(cvt(compat::set_crt_params(rsa.0, dp.as_ptr(), dq.as_ptr(), + qi.as_ptr()))); mem::forget((dp, dq, qi)); Ok(rsa) } @@ -83,12 +84,9 @@ impl RSA { /// The public exponent will be 65537. pub fn generate(bits: u32) -> Result { unsafe { - let rsa = try_ssl_null!(ffi::RSA_new()); - let rsa = RSA(rsa); - let e = try!(BigNum::new_from(ffi::RSA_F4 as u32)); - - try_ssl!(ffi::RSA_generate_key_ex(rsa.0, bits as c_int, e.as_ptr(), ptr::null_mut())); - + 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) } } @@ -97,10 +95,10 @@ impl RSA { pub fn private_key_from_pem(buf: &[u8]) -> Result { 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())); + let rsa = try!(cvt_p(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(), + ptr::null_mut(), + None, + ptr::null_mut()))); Ok(RSA(rsa)) } } @@ -114,11 +112,10 @@ impl RSA { 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::), - cb_ptr)); - + let rsa = try!(cvt_p(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(), + ptr::null_mut(), + Some(invoke_passwd_cb::), + cb_ptr))); Ok(RSA(rsa)) } } @@ -127,10 +124,10 @@ impl RSA { pub fn public_key_from_pem(buf: &[u8]) -> Result { 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())); + 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)) } } @@ -140,13 +137,13 @@ impl RSA { 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())); + try!(cvt(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()) } @@ -156,93 +153,113 @@ impl RSA { let mem_bio = try!(MemBio::new()); unsafe { - try_ssl!(ffi::PEM_write_bio_RSA_PUBKEY(mem_bio.as_ptr(), self.0)) - }; + try!(cvt(ffi::PEM_write_bio_RSA_PUBKEY(mem_bio.as_ptr(), self.0))); + } Ok(mem_bio.get_buf().to_owned()) } - pub fn size(&self) -> Option { - if self.n().is_some() { - unsafe { Some(ffi::RSA_size(self.0) as u32) } - } else { - None + pub fn size(&self) -> usize { + unsafe { + assert!(self.n().is_some()); + + ffi::RSA_size(self.0) as usize } } - /** - * Decrypts data with the private key, using provided padding, returning the decrypted data. - */ - pub fn private_decrypt(&self, from: &[u8], padding: Padding) -> Result, ErrorStack> { + /// 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 { assert!(self.d().is_some(), "private components missing"); - let k_len = self.size().expect("RSA missing an n"); - let mut to: Vec = vec![0; k_len as usize]; + assert!(from.len() <= i32::max_value() as usize); + assert!(to.len() >= self.size()); unsafe { - let enc_len = try_ssl_returns_size!(ffi::RSA_private_decrypt(from.len() as i32, - from.as_ptr(), - to.as_mut_ptr(), - self.0, - padding.0)); - to.truncate(enc_len as usize); - Ok(to) + let len = try!(cvt_n(ffi::RSA_private_decrypt(from.len() as c_int, + from.as_ptr(), + to.as_mut_ptr(), + self.0, + padding.0))); + Ok(len as usize) } } - /** - * Encrypts data with the private key, using provided padding, returning the encrypted data. - */ - pub fn private_encrypt(&self, from: &[u8], padding: Padding) -> Result, ErrorStack> { + /// 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 { assert!(self.d().is_some(), "private components missing"); - let k_len = self.size().expect("RSA missing an n"); - let mut to:Vec = vec![0; k_len as usize]; + assert!(from.len() <= i32::max_value() as usize); + assert!(to.len() >= self.size()); unsafe { - let enc_len = try_ssl_returns_size!(ffi::RSA_private_encrypt(from.len() as c_int, - from.as_ptr(), - to.as_mut_ptr(), - self.0, - padding.0)); - assert!(enc_len as u32 == k_len); - - Ok(to) + let len = try!(cvt_n(ffi::RSA_private_encrypt(from.len() as c_int, + from.as_ptr(), + to.as_mut_ptr(), + self.0, + padding.0))); + Ok(len as usize) } } - /** - * Decrypts data with the public key, using provided padding, returning the decrypted data. - */ - pub fn public_decrypt(&self, from: &[u8], padding: Padding) -> Result, ErrorStack> { - let k_len = self.size().expect("RSA missing an n"); - let mut to: Vec = vec![0; k_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 { + assert!(from.len() <= i32::max_value() as usize); + assert!(to.len() >= self.size()); unsafe { - let enc_len = try_ssl_returns_size!(ffi::RSA_public_decrypt(from.len() as i32, - from.as_ptr(), - to.as_mut_ptr(), - self.0, - padding.0)); - to.truncate(enc_len as usize); - Ok(to) + let len = try!(cvt_n(ffi::RSA_public_decrypt(from.len() as c_int, + from.as_ptr(), + to.as_mut_ptr(), + self.0, + padding.0))); + Ok(len as usize) } } - /** - * Encrypts data with the public key, using provided padding, returning the encrypted data. - */ - pub fn public_encrypt(&self, from: &[u8], padding: Padding) -> Result, ErrorStack> { - let k_len = self.size().expect("RSA missing an n"); - let mut to:Vec = vec![0; k_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 { + assert!(from.len() <= i32::max_value() as usize); + assert!(to.len() >= self.size()); unsafe { - let enc_len = try_ssl_returns_size!(ffi::RSA_public_encrypt(from.len() as c_int, - from.as_ptr(), - to.as_mut_ptr(), - self.0, - padding.0)); - assert!(enc_len as u32 == k_len); - - Ok(to) + let len = try!(cvt_n(ffi::RSA_public_encrypt(from.len() as c_int, + from.as_ptr(), + to.as_mut_ptr(), + self.0, + padding.0))); + Ok(len as usize) } } @@ -424,55 +441,47 @@ mod test { let key = include_bytes!("../../test/rsa.pem.pub"); let public_key = RSA::public_key_from_pem(key).unwrap(); - let original_data: Vec = "This is test".to_string().into_bytes(); - let result = public_key.public_encrypt(&original_data, Padding::pkcs1()).unwrap(); - - assert_eq!(result.len(), 256); + 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, Padding::pkcs1()).unwrap(); + assert_eq!(len, 256); let pkey = include_bytes!("../../test/rsa.pem"); let private_key = RSA::private_key_from_pem(pkey).unwrap(); - let dec_result = private_key.private_decrypt(&result, Padding::pkcs1()).unwrap(); + let mut dec_result = vec![0; private_key.size()]; + let len = private_key.private_decrypt(&result, &mut dec_result, Padding::pkcs1()).unwrap(); - assert_eq!(dec_result, original_data); + 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 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 msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8]; - let emsg = k0.private_encrypt(&msg, Padding::pkcs1()).unwrap(); - let dmsg = k1.public_decrypt(&emsg, Padding::pkcs1()).unwrap(); - assert!(msg == dmsg); + let mut emesg = vec![0; k0.size()]; + k0.private_encrypt(&msg, &mut emesg, Padding::pkcs1()).unwrap(); + let mut dmesg = vec![0; k1.size()]; + let len = k1.public_decrypt(&emesg, &mut dmesg, Padding::pkcs1()).unwrap(); + assert_eq!(msg, &dmesg[..len]); } #[test] fn test_public_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 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 msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8]; - let emsg = k1.public_encrypt(&msg, Padding::pkcs1_oaep()).unwrap(); - let dmsg = k0.private_decrypt(&emsg, Padding::pkcs1_oaep()).unwrap(); - assert!(msg == dmsg); - } - - #[test] - fn test_public_encrypt_pkcs() { - 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 emsg = k1.public_encrypt(&msg, super::Padding::pkcs1()).unwrap(); - let dmsg = k0.private_decrypt(&emsg, super::Padding::pkcs1()).unwrap(); - assert!(msg == dmsg); + let mut emesg = vec![0; k0.size()]; + k0.public_encrypt(&msg, &mut emesg, Padding::pkcs1()).unwrap(); + let mut dmesg = vec![0; k1.size()]; + let len = k1.private_decrypt(&emesg, &mut dmesg, Padding::pkcs1()).unwrap(); + assert_eq!(msg, &dmesg[..len]); } } diff --git a/openssl/src/crypto/sign.rs b/openssl/src/crypto/sign.rs index fdedd4d5..41009149 100644 --- a/openssl/src/crypto/sign.rs +++ b/openssl/src/crypto/sign.rs @@ -59,6 +59,7 @@ use std::io::{self, Write}; use std::marker::PhantomData; use std::ptr; +use {cvt, cvt_p}; use crypto::hash::MessageDigest; use crypto::pkey::PKey; use error::ErrorStack; @@ -83,7 +84,7 @@ impl<'a> Signer<'a> { unsafe { ffi::init(); - let ctx = try_ssl_null!(EVP_MD_CTX_new()); + let ctx = try!(cvt_p(EVP_MD_CTX_new())); let r = ffi::EVP_DigestSignInit(ctx, ptr::null_mut(), type_.as_ptr(), @@ -93,25 +94,22 @@ impl<'a> Signer<'a> { EVP_MD_CTX_free(ctx); return Err(ErrorStack::get()); } - Ok(Signer(ctx, PhantomData)) } } pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> { unsafe { - try_ssl_if!(ffi::EVP_DigestUpdate(self.0, buf.as_ptr() as *const _, buf.len()) != 1); - Ok(()) + cvt(ffi::EVP_DigestUpdate(self.0, buf.as_ptr() as *const _, buf.len())).map(|_| ()) } } pub fn finish(&self) -> Result, ErrorStack> { unsafe { let mut len = 0; - try_ssl_if!(ffi::EVP_DigestSignFinal(self.0, ptr::null_mut(), &mut len) != 1); + try!(cvt(ffi::EVP_DigestSignFinal(self.0, ptr::null_mut(), &mut len))); let mut buf = vec![0; len]; - try_ssl_if!(ffi::EVP_DigestSignFinal(self.0, buf.as_mut_ptr() as *mut _, &mut len) - != 1); + 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) @@ -145,7 +143,7 @@ impl<'a> Verifier<'a> { unsafe { ffi::init(); - let ctx = try_ssl_null!(EVP_MD_CTX_new()); + let ctx = try!(cvt_p(EVP_MD_CTX_new())); let r = ffi::EVP_DigestVerifyInit(ctx, ptr::null_mut(), type_.as_ptr(), @@ -162,8 +160,7 @@ impl<'a> Verifier<'a> { pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> { unsafe { - try_ssl_if!(ffi::EVP_DigestUpdate(self.0, buf.as_ptr() as *const _, buf.len()) != 1); - Ok(()) + cvt(ffi::EVP_DigestUpdate(self.0, buf.as_ptr() as *const _, buf.len())).map(|_| ()) } } diff --git a/openssl/src/crypto/symm.rs b/openssl/src/crypto/symm.rs index 8ac6b7cf..65f0addb 100644 --- a/openssl/src/crypto/symm.rs +++ b/openssl/src/crypto/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)] @@ -170,7 +171,7 @@ impl Crypter { 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(), @@ -181,15 +182,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()) { @@ -200,12 +201,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) } @@ -237,11 +238,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) } @@ -262,7 +263,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) } diff --git a/openssl/src/dh/mod.rs b/openssl/src/dh.rs similarity index 84% rename from openssl/src/dh/mod.rs rename to openssl/src/dh.rs index 83807f39..fec6bd98 100644 --- a/openssl/src/dh/mod.rs +++ b/openssl/src/dh.rs @@ -3,6 +3,7 @@ use error::ErrorStack; use bio::MemBioSlice; use std::ptr; +use {cvt, cvt_p}; use bn::BigNum; use std::mem; @@ -11,11 +12,11 @@ pub struct DH(*mut ffi::DH); impl DH { pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result { unsafe { - let dh = DH(try_ssl_null!(ffi::DH_new())); - try_ssl!(compat::DH_set0_pqg(dh.0, + 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())); + g.as_ptr()))); mem::forget((p, g, q)); Ok(dh) } @@ -23,34 +24,38 @@ impl DH { pub fn from_pem(buf: &[u8]) -> Result { 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)) + unsafe { + cvt_p(ffi::PEM_read_bio_DHparams(mem_bio.as_ptr(), + ptr::null_mut(), + None, + ptr::null_mut())) + .map(DH) + } } #[cfg(feature = "openssl-102")] pub fn get_1024_160() -> Result { - let dh = try_ssl_null!(unsafe { ffi::DH_get_1024_160() }); - Ok(DH(dh)) + unsafe { + cvt_p(ffi::DH_get_1024_160()).map(DH) + } } #[cfg(feature = "openssl-102")] pub fn get_2048_224() -> Result { - let dh = try_ssl_null!(unsafe { ffi::DH_get_2048_224() }); - Ok(DH(dh)) + unsafe { + cvt_p(ffi::DH_get_2048_224()).map(DH) + } } #[cfg(feature = "openssl-102")] pub fn get_2048_256() -> Result { - let dh = try_ssl_null!(unsafe { ffi::DH_get_2048_256() }); - Ok(DH(dh)) + unsafe { + cvt_p(ffi::DH_get_2048_256()).map(DH) + } } pub unsafe fn as_ptr(&self) -> *mut ffi::DH { - let DH(n) = *self; - n + self.0 } } @@ -135,7 +140,7 @@ mod tests { #[test] fn test_dh_from_pem() { let mut ctx = SslContext::new(SslMethod::tls()).unwrap(); - let params = include_bytes!("../../test/dhparams.pem"); + 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/lib.rs b/openssl/src/lib.rs index 62968742..39c9fffe 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -16,6 +16,10 @@ extern crate tempdir; #[doc(inline)] pub use ffi::init; +use libc::c_int; + +use error::ErrorStack; + mod macros; pub mod asn1; @@ -28,3 +32,27 @@ pub mod nid; pub mod ssl; pub mod version; pub mod x509; + +pub fn cvt_p(r: *mut T) -> Result<*mut T, ErrorStack> { + if r.is_null() { + Err(ErrorStack::get()) + } else { + Ok(r) + } +} + +pub fn cvt(r: c_int) -> Result { + if r <= 0 { + Err(ErrorStack::get()) + } else { + Ok(r) + } +} + +pub fn cvt_n(r: c_int) -> Result { + if r < 0 { + Err(ErrorStack::get()) + } else { + Ok(r) + } +} diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs index 31c298fa..85175445 100644 --- a/openssl/src/macros.rs +++ b/openssl/src/macros.rs @@ -1,86 +1,5 @@ #![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 - }) -} - -/// Shortcut return with SSL error if last error result is -1 -/// (default for size) -macro_rules! try_ssl_returns_size{ - ($e:expr) => ( - if $e == -1 { - return Err(::error::ErrorStack::get().into()) - } else { - $e - } - ) -} - -/// 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)) -} - -/// Lifts current SSL error code into Result<(), Error> -/// if SSL returned -1 (default size error indication) -macro_rules! lift_ssl_returns_size { - ($e:expr) => ( { - if $e == -1 { - Err(::error::ErrorStack::get().into()) - } else { - Ok($e) - } - }) -} - #[cfg(ossl10x)] macro_rules! CRYPTO_free { ($e:expr) => (::ffi::CRYPTO_free($e)) diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs index ccf3a472..968aad10 100644 --- a/openssl/src/ssl/bio.rs +++ b/openssl/src/ssl/bio.rs @@ -9,6 +9,7 @@ use std::ptr; use std::slice; use std::sync::Arc; +use cvt_p; use error::ErrorStack; pub struct StreamState { @@ -38,7 +39,7 @@ pub fn new(stream: S) -> Result<(*mut BIO, Arc), Err }); unsafe { - let bio = try_ssl_null!(BIO_new(method.0.get())); + 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); diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 7b4f831b..ad21e563 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -19,7 +19,7 @@ use std::slice; use std::marker::PhantomData; use ffi; -use init; +use {init, cvt, cvt_p}; use dh::DH; use x509::{X509StoreContext, X509FileType, X509, X509Ref}; #[cfg(feature = "openssl-102")] @@ -341,16 +341,6 @@ 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 borrowed SSL context object. pub struct SslContextRef<'a>(*mut ffi::SSL_CTX, PhantomData<&'a ()>); @@ -414,11 +404,15 @@ impl<'a> SslContextRef<'a> { } 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 }) + unsafe { + cvt(ffi::SSL_CTX_set_mode(self.as_ptr(), mode) 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 }) + unsafe { + cvt(ffi::SSL_CTX_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as i32).map(|_| ()) + } } /// Use the default locations of trusted certificates for verification. @@ -427,16 +421,21 @@ 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>(&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()) - }) + 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 @@ -448,9 +447,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 @@ -458,40 +461,41 @@ 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 c_int)) + .map(|_| ()) + } } /// Specifies the file that contains certificate chain pub fn set_certificate_chain_file>(&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_use_certificate_chain_file(self.as_ptr(), - file.as_ptr() as *const _) - }) + 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 @@ -499,29 +503,35 @@ 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 c_int)) + .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()) }) + unsafe { + cvt(ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr())).map(|_| ()) + } } /// 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()) }) + unsafe { + cvt(ffi::SSL_CTX_check_private_key(self.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 @@ -539,12 +549,13 @@ impl<'a> SslContextRef<'a> { #[cfg(all(feature = "openssl-102", ossl102))] fn _set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { - wrap_ssl_result(unsafe { - ffi::SSL_CTX_ctrl(self.as_ptr(), - ffi::SSL_CTRL_SET_ECDH_AUTO, - onoff as c_long, - ptr::null_mut()) as c_int - }) + unsafe { + cvt(ffi::SSL_CTX_ctrl(self.as_ptr(), + ffi::SSL_CTRL_SET_ECDH_AUTO, + onoff as c_long, + ptr::null_mut()) as c_int) + .map(|_| ()) + } } #[cfg(all(feature = "openssl-102", ossl110))] @@ -669,11 +680,10 @@ impl SslContext { init(); let mut ctx = unsafe { - let ctx = try_ssl_null!(ffi::SSL_CTX_new(method.as_ptr())); + let ctx = try!(cvt_p(ffi::SSL_CTX_new(method.as_ptr()))); SslContext::from_ptr(ctx) }; - // this is a bit dubious (?) try!(ctx.set_mode(ffi::SSL_MODE_AUTO_RETRY | ffi::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)); Ok(ctx) @@ -692,11 +702,10 @@ impl SslContext { 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, - _p: (), -} + /// The number of bits processed by the chosen algorithm. + pub algorithm: i32, +} pub struct SslCipher<'a> { cipher: *const ffi::SSL_CIPHER, @@ -727,20 +736,11 @@ 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.cipher, &mut algo_bits); + CipherBits { + secret: secret_bits.into(), + algorithm: algo_bits.into(), } } } @@ -875,15 +875,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(|_| ()) } } @@ -999,9 +993,8 @@ impl<'a> SslRef<'a> { /// 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())); + cvt_p(ffi::SSL_set_SSL_CTX(self.as_ptr(), ctx.as_ptr())).map(|_| ()) } - Ok(()) } /// Returns the context corresponding to the current connection @@ -1056,7 +1049,7 @@ impl DerefMut for Ssl { impl Ssl { pub fn new(ctx: &SslContext) -> Result { 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)) } } diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index ac7505f8..2dd49cb0 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1061,7 +1061,7 @@ 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::tls()).unwrap(); - ctx.add_extra_chain_cert(&cert).unwrap(); + ctx.add_extra_chain_cert(cert).unwrap(); } #[test] diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index c429b486..1cd7471f 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -10,6 +10,7 @@ use std::slice; use std::collections::HashMap; use std::marker::PhantomData; +use {cvt, cvt_p}; use asn1::Asn1Time; use asn1::Asn1TimeRef; use bio::{MemBio, MemBioSlice}; @@ -251,25 +252,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_conf_nid(ptr::null_mut(), + mem::transmute(&ctx), + nid as c_int, + value.as_ptr() as *mut c_char))) } None => { let name = CString::new(exttype.get_name().unwrap().as_bytes()).unwrap(); - ffi::X509V3_EXT_conf(ptr::null_mut(), - mem::transmute(&ctx), - name.as_ptr() as *mut c_char, - value.as_ptr() as *mut c_char) + try!(cvt_p(ffi::X509V3_EXT_conf(ptr::null_mut(), + mem::transmute(&ctx), + name.as_ptr() as *mut c_char, + value.as_ptr() as *mut c_char))) } }; - let mut success = false; - if ext != ptr::null_mut() { - success = ffi::X509_add_ext(x509, ext, -1) != 0; + if ffi::X509_add_ext(x509, ext, -1) != 1 { ffi::X509_EXTENSION_free(ext); + Err(ErrorStack::get()) + } else { + Ok(()) } - lift_ssl_if!(!success) } } @@ -278,17 +279,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 { @@ -308,32 +310,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 { 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!(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!(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)); @@ -347,7 +347,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(), @@ -356,7 +356,7 @@ impl X509Generator { } let hash_fn = self.hash_type.as_ptr(); - try_ssl!(ffi::X509_sign(x509.as_ptr(), p_key.as_ptr(), hash_fn)); + try!(cvt(ffi::X509_sign(x509.as_ptr(), p_key.as_ptr(), hash_fn))); Ok(x509) } } @@ -369,18 +369,20 @@ impl X509Generator { }; 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 = compat::X509_get0_extensions(cert.as_ptr()); if exts != ptr::null_mut() { - try_ssl!(ffi::X509_REQ_add_extensions(req, exts as *mut _)); + try!(cvt(ffi::X509_REQ_add_extensions(req.as_ptr(), exts as *mut _))); } let hash_fn = self.hash_type.as_ptr(); - try_ssl!(ffi::X509_REQ_sign(req, p_key.as_ptr(), hash_fn)); + try!(cvt(ffi::X509_REQ_sign(req.as_ptr(), p_key.as_ptr(), hash_fn))); - Ok(X509Req::new(req)) + Ok(req) } } } @@ -394,12 +396,6 @@ impl<'a> 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 } @@ -429,7 +425,7 @@ impl<'a> X509Ref<'a> { pub fn public_key(&self) -> Result { unsafe { - let pkey = try_ssl_null!(ffi::X509_get_pubkey(self.0)); + let pkey = try!(cvt_p(ffi::X509_get_pubkey(self.0))); Ok(PKey::from_ptr(pkey)) } } @@ -440,7 +436,7 @@ impl<'a> X509Ref<'a> { 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.0, evp, buf.as_mut_ptr() as *mut _, &mut len))); buf.truncate(len as usize); Ok(buf) } @@ -468,7 +464,7 @@ impl<'a> X509Ref<'a> { pub fn to_pem(&self) -> Result, 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.0))); } Ok(mem_bio.get_buf().to_owned()) } @@ -492,18 +488,12 @@ impl X509 { X509(X509Ref::from_ptr(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) - } - /// Reads a certificate from DER. pub fn from_der(buf: &[u8]) -> Result { unsafe { 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)) } } @@ -512,10 +502,10 @@ impl X509 { pub fn from_pem(buf: &[u8]) -> Result { 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)) } } @@ -582,8 +572,7 @@ impl<'x> X509Name<'x> { pub struct X509Req(*mut ffi::X509_REQ); impl X509Req { - /// Creates new from handle - pub unsafe fn new(handle: *mut ffi::X509_REQ) -> X509Req { + pub unsafe fn from_ptr(handle: *mut ffi::X509_REQ) -> X509Req { X509Req(handle) } @@ -595,11 +584,11 @@ impl X509Req { pub fn from_pem(buf: &[u8]) -> Result { let mem_bio = try!(MemBioSlice::new(buf)); 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 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)) } } diff --git a/openssl/src/x509/verify.rs b/openssl/src/x509/verify.rs index 0fc1df3a..5cce9bd7 100644 --- a/openssl/src/x509/verify.rs +++ b/openssl/src/x509/verify.rs @@ -2,6 +2,7 @@ use std::marker::PhantomData; use libc::c_uint; use ffi; +use cvt; use error::ErrorStack; bitflags! { @@ -32,11 +33,10 @@ impl<'a> X509VerifyParamRef<'a> { pub fn set_host(&mut self, host: &str) -> Result<(), ErrorStack> { unsafe { - try_ssl!(ffi::X509_VERIFY_PARAM_set1_host(self.0, - host.as_ptr() as *const _, - host.len())) + cvt(ffi::X509_VERIFY_PARAM_set1_host(self.0, + host.as_ptr() as *const _, + host.len())) + .map(|_| ()) } - - Ok(()) } }