From 8f89f0bfa98ac69582f22244dae0f5cc923046e1 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 16 Oct 2016 15:54:09 -0700 Subject: [PATCH 1/9] Start on error + BN refactor --- openssl/src/{asn1/mod.rs => asn1.rs} | 9 +- openssl/src/{bn/mod.rs => bn.rs} | 386 ++++++++++++--------------- openssl/src/{dh/mod.rs => dh.rs} | 2 +- openssl/src/lib.rs | 28 ++ 4 files changed, 210 insertions(+), 215 deletions(-) rename openssl/src/{asn1/mod.rs => asn1.rs} (91%) rename openssl/src/{bn/mod.rs => bn.rs} (74%) rename openssl/src/{dh/mod.rs => dh.rs} (98%) 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/bn/mod.rs b/openssl/src/bn.rs similarity index 74% rename from openssl/src/bn/mod.rs rename to openssl/src/bn.rs index 7d1f5458..22924e67 100644 --- a/openssl/src/bn/mod.rs +++ b/openssl/src/bn.rs @@ -1,11 +1,12 @@ +use ffi; use libc::{c_int, c_void}; -use std::ffi::{CStr, CString}; 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 ffi; +use {cvt, cvt_p, cvt_n}; use error::ErrorStack; /// Specifies the desired properties of a randomly generated `BigNum`. @@ -74,199 +75,141 @@ macro_rules! with_bn_in_ctx( }); ); -/// A borrowed, signed, arbitrary-precision integer. -#[derive(Copy, Clone)] -pub struct BigNumRef<'a>(*mut ffi::BIGNUM, PhantomData<&'a ()>); +/// A context object for `BigNum` operations. +pub struct BnCtx(*mut ffi::BN_CTX); - -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 { +impl Drop for BnCtx { + fn drop(&mut self) { unsafe { - with_bn_in_ctx!(r, ctx, { - ffi::BN_sqr(r.as_ptr(), self.as_ptr(), ctx) == 1 - }) + 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) } } - /// Returns the unsigned remainder of the division `self / n`. - pub fn checked_nnmod(&self, n: &BigNumRef) -> Result { + /// Places the result of `a²` in `r`. + pub fn sqr(&mut self, r: &mut BigNumRef, a: &BigNumRef) -> Result<(), ErrorStack> { unsafe { - with_bn_in_ctx!(r, ctx, { - ffi::BN_nnmod(r.as_ptr(), self.as_ptr(), n.as_ptr(), ctx) == 1 - }) + cvt(ffi::BN_sqr(r.as_ptr(), a.as_ptr(), self.0)).map(|_| ()) } } - /// 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 { + /// Places the result of `a mod m` in `r`. + pub fn nnmod(&mut self, + r: &mut BigNumRef, + a: &BigNumRef, + m: &BigNumRef) -> Result<(), ErrorStack> { unsafe { - with_bn_in_ctx!(r, ctx, { - ffi::BN_mod_add(r.as_ptr(), self.as_ptr(), a.as_ptr(), n.as_ptr(), ctx) == 1 - }) + cvt(ffi::BN_nnmod(r.as_ptr(), a.as_ptr(), m.as_ptr(), self.0)).map(|_| ()) } } - /// Equivalent to `(self - a) mod n`. - pub fn checked_mod_sub(&self, a: &BigNumRef, n: &BigNumRef) -> Result { + /// 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 { - with_bn_in_ctx!(r, ctx, { - ffi::BN_mod_sub(r.as_ptr(), self.as_ptr(), a.as_ptr(), n.as_ptr(), ctx) == 1 - }) + cvt(ffi::BN_mod_add(r.as_ptr(), a.as_ptr(), b.as_ptr(), m.as_ptr(), self.0)).map(|_| ()) } } - /// Equivalent to `(self * a) mod n`. - pub fn checked_mod_mul(&self, a: &BigNumRef, n: &BigNumRef) -> Result { + /// 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 { - with_bn_in_ctx!(r, ctx, { - ffi::BN_mod_mul(r.as_ptr(), self.as_ptr(), a.as_ptr(), n.as_ptr(), ctx) == 1 - }) + cvt(ffi::BN_mod_sub(r.as_ptr(), a.as_ptr(), b.as_ptr(), m.as_ptr(), self.0)).map(|_| ()) } } - /// Equivalent to `self² mod n`. - pub fn checked_mod_sqr(&self, n: &BigNumRef) -> Result { + /// 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 { - with_bn_in_ctx!(r, ctx, { - ffi::BN_mod_sqr(r.as_ptr(), self.as_ptr(), n.as_ptr(), ctx) == 1 - }) + cvt(ffi::BN_mod_mul(r.as_ptr(), a.as_ptr(), b.as_ptr(), m.as_ptr(), self.0)).map(|_| ()) } } - /// Raises `self` to the `p`th power. - pub fn checked_exp(&self, p: &BigNumRef) -> Result { + /// 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 { - with_bn_in_ctx!(r, ctx, { - ffi::BN_exp(r.as_ptr(), self.as_ptr(), p.as_ptr(), ctx) == 1 - }) + cvt(ffi::BN_mod_sqr(r.as_ptr(), a.as_ptr(), m.as_ptr(), self.0)).map(|_| ()) } } - /// 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 - }) + /// 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(|_| ()) } } - /// 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 { + /// 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 { - with_bn_in_ctx!(r, ctx, { - !ffi::BN_mod_inverse(r.as_ptr(), self.as_ptr(), n.as_ptr(), ctx).is_null() - }) + cvt(ffi::BN_mod_exp(r.as_ptr(), a.as_ptr(), p.as_ptr(), m.as_ptr(), self.0)).map(|_| ()) } } - /// Add a `u32` to `self`. This is more efficient than adding a - /// `BigNum`. - pub fn add_word(&mut self, w: u32) -> Result<(), ErrorStack> { + /// 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 { - if ffi::BN_add_word(self.as_ptr(), w as ffi::BN_ULONG) == 1 { - Ok(()) - } else { - Err(ErrorStack::get()) - } + cvt_p(ffi::BN_mod_inverse(r.0, a.0, n.0, self.0)).map(|_| ()) } } - pub fn sub_word(&mut self, w: u32) -> Result<(), ErrorStack> { + /// 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 { - if ffi::BN_sub_word(self.as_ptr(), w as ffi::BN_ULONG) == 1 { - Ok(()) - } else { - Err(ErrorStack::get()) - } + cvt(ffi::BN_gcd(r.0, a.0, b.0, self.0)).map(|_| ()) } } - 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. + /// Checks whether `p` 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 { + /// 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 { - with_ctx!(ctx, { - Ok(ffi::BN_is_prime_ex(self.as_ptr(), - checks as c_int, - ctx, - ptr::null_mut()) == 1) - }) + cvt_n(ffi::BN_is_prime_ex(p.0, checks.into(), self.0, ptr::null_mut())).map(|r| r != 0) } } - /// Checks whether `self` is prime with optional trial division. + /// 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` @@ -274,35 +217,88 @@ impl<'a> BigNumRef<'a> { /// /// # 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 { + /// 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 { - 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) - }) + 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) + } + } +} + +/// 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(|_| ()) } } - /// Generates a cryptographically strong pseudo-random `BigNum` `r` in the range - /// `0 <= r < self`. - pub fn checked_rand_in_range(&self) -> Result { + /// Subtracts a `u32` from `self`. + pub fn sub_word(&mut self, w: u32) -> Result<(), ErrorStack> { unsafe { - with_bn_in_ctx!(r, ctx, { - ffi::BN_rand_range(r.as_ptr(), self.as_ptr()) == 1 - }) + cvt(ffi::BN_sub_word(self.0, w as ffi::BN_ULONG)).map(|_| ()) } } - /// The cryptographically weak counterpart to `checked_rand_in_range`. - pub fn checked_pseudo_rand_in_range(&self) -> Result { + /// Multiplies a `u32` by `self`. + pub fn mul_word(&mut self, w: u32) -> Result<(), ErrorStack> { unsafe { - with_bn_in_ctx!(r, ctx, { - ffi::BN_pseudo_rand_range(r.as_ptr(), self.as_ptr()) == 1 - }) + 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(|_| ()) } } @@ -311,11 +307,7 @@ impl<'a> BigNumRef<'a> { /// 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()) - } + cvt(ffi::BN_set_bit(self.0, n.into())).map(|_| ()) } } @@ -324,17 +316,15 @@ impl<'a> BigNumRef<'a> { /// 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()) - } + 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.as_ptr(), n as c_int) == 1 } + unsafe { + ffi::BN_is_bit_set(self.0, n.into()) == 1 + } } /// Truncates `self` to the lowest `n` bits. @@ -342,46 +332,21 @@ impl<'a> BigNumRef<'a> { /// 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()) - } + cvt(ffi::BN_mask_bits(self.0, n.into())).map(|_| ()) } } - /// 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 { + /// Places `self << 1` in `r`. + pub fn lshift1(&self, r: &mut BigNumRef) -> Result<(), ErrorStack> { unsafe { - with_bn!(r, { - ffi::BN_lshift1(r.as_ptr(), self.as_ptr()) == 1 - }) + cvt(ffi::BN_lshift1(r.0, self.0)).map(|_| ()) } } - /// Returns `self`, shifted right by 1 bit. `self` may be negative. - pub fn checked_shr1(&self) -> Result { + /// Places `self >> 1` in `r`. + pub fn rshift1(&self, r: &mut BigNumRef) -> Result<(), ErrorStack> { unsafe { - with_bn!(r, { - ffi::BN_rshift1(r.as_ptr(), self.as_ptr()) == 1 - }) + cvt(ffi::BN_rshift1(r.0, self.0)).map(|_| ()) } } @@ -1006,7 +971,7 @@ impl Neg for BigNum { #[cfg(test)] mod tests { - use bn::BigNum; + use bn::{BnCtx, BigNum}; #[test] fn test_to_from_slice() { @@ -1031,7 +996,8 @@ mod tests { 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()); + 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/dh/mod.rs b/openssl/src/dh.rs similarity index 98% rename from openssl/src/dh/mod.rs rename to openssl/src/dh.rs index 83807f39..6d0800a1 100644 --- a/openssl/src/dh/mod.rs +++ b/openssl/src/dh.rs @@ -135,7 +135,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) + } +} From 73ccfe7a29f55d4823fe9530e3c326d0b3099d6b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 16 Oct 2016 16:42:56 -0700 Subject: [PATCH 2/9] Continue error handling cleanup Also overhaul/clean up pkcs5 internals --- openssl/src/crypto/dsa.rs | 53 ++++---- openssl/src/crypto/hash.rs | 12 +- openssl/src/crypto/pkcs5.rs | 239 ++++++++++++++---------------------- 3 files changed, 126 insertions(+), 178 deletions(-) diff --git a/openssl/src/crypto/dsa.rs b/openssl/src/crypto/dsa.rs index addaae2f..e0f31766 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()) } 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/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), }); } } From 19440c298143aa311578ead17c8949312f4b94af Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 16 Oct 2016 19:06:02 -0700 Subject: [PATCH 3/9] More error cleanup Also allocation free RSA --- openssl/src/crypto/dsa.rs | 2 - openssl/src/crypto/pkcs12.rs | 5 +- openssl/src/crypto/pkey.rs | 55 ++++---- openssl/src/crypto/rand.rs | 5 +- openssl/src/crypto/rsa.rs | 261 ++++++++++++++++++----------------- 5 files changed, 170 insertions(+), 158 deletions(-) diff --git a/openssl/src/crypto/dsa.rs b/openssl/src/crypto/dsa.rs index e0f31766..f9044661 100644 --- a/openssl/src/crypto/dsa.rs +++ b/openssl/src/crypto/dsa.rs @@ -236,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/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/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..95675abe 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 rsa = RSA(try!(cvt_p(ffi::RSA_new()))); 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())); - + 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]); } } From 89a366d9f7558489fe321fef81a88b1919d10032 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 16 Oct 2016 19:24:04 -0700 Subject: [PATCH 4/9] Finish crypto error cleanup --- openssl/src/crypto/sign.rs | 17 +++++++---------- openssl/src/crypto/symm.rs | 27 ++++++++++++++------------- 2 files changed, 21 insertions(+), 23 deletions(-) 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) } From 78daed2d5875eee9807aaf5377b632a55f3f93a8 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 16 Oct 2016 20:14:04 -0700 Subject: [PATCH 5/9] ssl error handling cleanup --- openssl/src/ssl/bio.rs | 3 +- openssl/src/ssl/mod.rs | 170 +++++++++++++++++------------------ openssl/src/ssl/tests/mod.rs | 2 +- 3 files changed, 85 insertions(+), 90 deletions(-) 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..55955753 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,9 +702,9 @@ 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. + + /// The number of bits processed by the chosen algorithm. pub algorithm: Option, - _p: (), } @@ -727,20 +737,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 +876,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 +994,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 +1050,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] From 7ec015325b0d900ddaf375b62f5a52d4231dc9a2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 16 Oct 2016 21:07:17 -0700 Subject: [PATCH 6/9] Finish error overhaul --- openssl/src/bio.rs | 5 +- openssl/src/bn.rs | 35 ++++++----- openssl/src/dh.rs | 37 +++++++----- openssl/src/macros.rs | 81 ------------------------- openssl/src/x509/mod.rs | 119 +++++++++++++++++-------------------- openssl/src/x509/verify.rs | 9 ++- 6 files changed, 101 insertions(+), 185 deletions(-) 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 index 22924e67..62b30d96 100644 --- a/openssl/src/bn.rs +++ b/openssl/src/bn.rs @@ -408,7 +408,7 @@ impl<'a> BigNumRef<'a> { pub fn to_owned(&self) -> Result { unsafe { - let r = try_ssl_null!(ffi::BN_dup(self.as_ptr())); + let r = try!(cvt_p(ffi::BN_dup(self.as_ptr()))); Ok(BigNum::from_ptr(r)) } } @@ -553,7 +553,7 @@ impl BigNum { pub fn new() -> Result { unsafe { ffi::init(); - let v = try_ssl_null!(ffi::BN_new()); + let v = try!(cvt_p(ffi::BN_new())); Ok(BigNum::from_ptr(v)) } } @@ -561,27 +561,28 @@ impl BigNum { /// 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) + cvt(ffi::BN_set_word(v.as_ptr(), n as ffi::BN_ULONG)).map(|_| v) }) } /// Creates a `BigNum` from a decimal string. pub fn from_dec_str(s: &str) -> Result { - BigNum::new().and_then(|mut v| unsafe { + 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) - }) + let mut bn = ptr::null_mut(); + try!(cvt(ffi::BN_dec2bn(&mut bn, c_str.as_ptr() as *const _))); + Ok(BigNum::from_ptr(bn)) + } } /// Creates a `BigNum` from a hexadecimal string. pub fn from_hex_str(s: &str) -> Result { - BigNum::new().and_then(|mut v| unsafe { + 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) - }) + 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 { @@ -597,11 +598,13 @@ impl BigNum { /// 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) - }) + 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. /// /// # Parameters diff --git a/openssl/src/dh.rs b/openssl/src/dh.rs index 6d0800a1..fec6bd98 100644 --- a/openssl/src/dh.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 } } 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/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..87287875 100644 --- a/openssl/src/x509/verify.rs +++ b/openssl/src/x509/verify.rs @@ -32,11 +32,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(()) } } From 68954cfc51fac79d71ab9a3c2de5de23616f5626 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 16 Oct 2016 23:13:00 -0700 Subject: [PATCH 7/9] Finish BN overhaul --- openssl/src/bn.rs | 488 +++++++++++++++----------------------- openssl/src/crypto/rsa.rs | 2 +- 2 files changed, 196 insertions(+), 294 deletions(-) diff --git a/openssl/src/bn.rs b/openssl/src/bn.rs index 62b30d96..512c58d3 100644 --- a/openssl/src/bn.rs +++ b/openssl/src/bn.rs @@ -22,59 +22,6 @@ pub enum RNGProperty { 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 context object for `BigNum` operations. pub struct BnCtx(*mut ffi::BN_CTX); @@ -94,6 +41,34 @@ impl 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 { @@ -231,6 +206,34 @@ impl BnCtx { .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. @@ -350,82 +353,45 @@ impl<'a> BigNumRef<'a> { } } - pub fn checked_add(&self, a: &BigNumRef) -> Result { + /// Places `self + b` in `r`. + pub fn add(&self, r: &mut BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> { unsafe { - with_bn!(r, { - ffi::BN_add(r.as_ptr(), self.as_ptr(), a.as_ptr()) == 1 - }) + cvt(ffi::BN_add(r.0, self.0, b.0)).map(|_| ()) } } - pub fn checked_sub(&self, a: &BigNumRef) -> Result { + /// Places `self - b` in `r`. + pub fn sub(&self, r: &mut BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> { unsafe { - with_bn!(r, { - ffi::BN_sub(r.as_ptr(), self.as_ptr(), a.as_ptr()) == 1 - }) + cvt(ffi::BN_sub(r.0, self.0, b.0)).map(|_| ()) } } - pub fn checked_mul(&self, a: &BigNumRef) -> Result { + /// Places `self << n` in `r`. + pub fn lshift(&self, r: &mut BigNumRef, b: i32) -> Result<(), ErrorStack> { unsafe { - with_bn_in_ctx!(r, ctx, { - ffi::BN_mul(r.as_ptr(), self.as_ptr(), a.as_ptr(), ctx) == 1 - }) + cvt(ffi::BN_lshift(r.0, self.0, b.into())).map(|_| ()) } } - pub fn checked_div(&self, a: &BigNumRef) -> Result { + /// Places `self >> n` in `r`. + pub fn rshift(&self, r: &mut BigNumRef, n: i32) -> Result<(), ErrorStack> { unsafe { - with_bn_in_ctx!(r, ctx, { - ffi::BN_div(r.as_ptr(), ptr::null_mut(), self.as_ptr(), a.as_ptr(), ctx) == 1 - }) - } - } - - pub fn checked_mod(&self, a: &BigNumRef) -> Result { - 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 - }) + cvt(ffi::BN_rshift(r.0, self.0, n.into())).map(|_| ()) } } pub fn to_owned(&self) -> Result { unsafe { - let r = try!(cvt_p(ffi::BN_dup(self.as_ptr()))); - Ok(BigNum::from_ptr(r)) + cvt_p(ffi::BN_dup(self.0)).map(|b| BigNum::from_ptr(b)) } } - /// 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) } + /// 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`. @@ -433,14 +399,14 @@ impl<'a> BigNumRef<'a> { /// ``` /// # use openssl::bn::BigNum; /// # use std::cmp::Ordering; - /// let s = -BigNum::new_from(8).unwrap(); - /// let o = BigNum::new_from(8).unwrap(); + /// let s = -BigNum::from_u32(8).unwrap(); + /// let o = BigNum::from_u32(8).unwrap(); /// - /// assert_eq!(s.abs_cmp(&o), Ordering::Equal); + /// assert_eq!(s.ucmp(&o), Ordering::Equal); /// ``` - pub fn abs_cmp(&self, oth: &BigNumRef) -> Ordering { + pub fn ucmp(&self, oth: &BigNumRef) -> Ordering { unsafe { - let res = ffi::BN_ucmp(self.as_ptr(), oth.as_ptr()) as i32; + let res = ffi::BN_ucmp(self.as_ptr(), oth.as_ptr()); if res < 0 { Ordering::Less } else if res > 0 { @@ -485,11 +451,11 @@ impl<'a> BigNumRef<'a> { /// /// ``` /// # use openssl::bn::BigNum; - /// let s = -BigNum::new_from(4543).unwrap(); - /// let r = BigNum::new_from(4543).unwrap(); + /// let s = -BigNum::from_u32(4543).unwrap(); + /// let r = BigNum::from_u32(4543).unwrap(); /// /// let s_vec = s.to_vec(); - /// assert_eq!(BigNum::new_from_slice(&s_vec).unwrap(), r); + /// assert_eq!(BigNum::from_slice(&s_vec).unwrap(), r); /// ``` pub fn to_vec(&self) -> Vec { let size = self.num_bytes() as usize; @@ -505,18 +471,17 @@ impl<'a> BigNumRef<'a> { /// /// ``` /// # use openssl::bn::BigNum; - /// let s = -BigNum::new_from(12345).unwrap(); + /// let s = -BigNum::from_u32(12345).unwrap(); /// - /// assert_eq!(s.to_dec_str(), "-12345"); + /// assert_eq!(s.to_dec_str().unwrap(), "-12345"); /// ``` - pub fn to_dec_str(&self) -> String { + pub fn to_dec_str(&self) -> Result { unsafe { - let buf = ffi::BN_bn2dec(self.as_ptr()); - assert!(!buf.is_null()); + 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); - str + Ok(str) } } @@ -524,18 +489,17 @@ impl<'a> BigNumRef<'a> { /// /// ``` /// # use openssl::bn::BigNum; - /// let s = -BigNum::new_from(0x99ff).unwrap(); + /// let s = -BigNum::from_u32(0x99ff).unwrap(); /// - /// assert_eq!(s.to_hex_str(), "-99FF"); + /// assert_eq!(s.to_hex_str().unwrap(), "-99FF"); /// ``` - pub fn to_hex_str(&self) -> String { + pub fn to_hex_str(&self) -> Result { unsafe { - let buf = ffi::BN_bn2hex(self.as_ptr()); - assert!(!buf.is_null()); + 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); - str + Ok(str) } } } @@ -559,7 +523,7 @@ impl BigNum { } /// Creates a new `BigNum` with the given value. - pub fn new_from(n: u32) -> Result { + 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) }) @@ -593,11 +557,11 @@ impl BigNum { /// /// ``` /// # use openssl::bn::BigNum; - /// let bignum = BigNum::new_from_slice(&[0x12, 0x00, 0x34]).unwrap(); + /// let bignum = BigNum::from_slice(&[0x12, 0x00, 0x34]).unwrap(); /// - /// assert_eq!(bignum, BigNum::new_from(0x120034).unwrap()); + /// assert_eq!(bignum, BigNum::from_u32(0x120034).unwrap()); /// ``` - pub fn new_from_slice(n: &[u8]) -> Result { + 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())) @@ -605,7 +569,7 @@ impl BigNum { } } - /// Generates a prime number. + /// Generates a prime number, placing it in `r`. /// /// # Parameters /// @@ -613,50 +577,20 @@ impl BigNum { /// * `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 { + pub fn generate_prime(r: &mut BigNumRef, + bits: i32, + safe: bool, + add: Option<&BigNumRef>, + rem: Option<&BigNumRef>) + -> Result<(), ErrorStack> { unsafe { - with_bn_in_ctx!(r, ctx, { - let add_arg = add.map(|a| a.as_ptr()).unwrap_or(ptr::null_mut()); - let rem_arg = rem.map(|r| r.as_ptr()).unwrap_or(ptr::null_mut()); - - ffi::BN_generate_prime_ex(r.as_ptr(), + cvt(ffi::BN_generate_prime_ex(r.0, 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 - }) + add.map(|n| n.0).unwrap_or(ptr::null_mut()), + rem.map(|n| n.0).unwrap_or(ptr::null_mut()), + ptr::null_mut())) + .map(|_| ()) } } } @@ -689,31 +623,43 @@ impl AsRef> for BigNum { impl<'a> fmt::Debug for BigNumRef<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.to_dec_str()) + 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 { - write!(f, "{}", self.to_dec_str()) + 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 { - write!(f, "{}", self.to_dec_str()) + 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 { - write!(f, "{}", self.to_dec_str()) + 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 { - unsafe { ffi::BN_cmp(self.as_ptr(), oth.as_ptr()) == 0 } + self.cmp(oth) == Ordering::Equal } } @@ -775,147 +721,104 @@ impl Ord for BigNum { } } +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 { - self.checked_add(oth).unwrap() + 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 { - self.checked_sub(oth).unwrap() + let mut r = BigNum::new().unwrap(); + self.sub(&mut r, oth).unwrap(); + r } } -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() - } -} +delegate!(Sub, sub); 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() + let mut ctx = BnCtx::new().unwrap(); + let mut r = BigNum::new().unwrap(); + ctx.mul(&mut r, self, oth).unwrap(); + r } } -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() - } -} +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 { - self.checked_div(oth).unwrap() + let mut ctx = BnCtx::new().unwrap(); + let mut dv = BigNum::new().unwrap(); + ctx.div(Some(&mut dv), None, self, oth).unwrap(); + dv } } -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() - } -} +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 { - self.checked_mod(oth).unwrap() + let mut ctx = BnCtx::new().unwrap(); + let mut rem = BigNum::new().unwrap(); + ctx.div(None, Some(&mut rem), self, oth).unwrap(); + rem } } -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() - } -} +delegate!(Rem, rem); impl<'a> Shl for &'a BigNumRef<'a> { type Output = BigNum; fn shl(self, n: i32) -> BigNum { - self.checked_shl(&n).unwrap() + let mut r = BigNum::new().unwrap(); + self.lshift(&mut r, n).unwrap(); + r } } @@ -923,7 +826,7 @@ impl<'a> Shl for &'a BigNum { type Output = BigNum; fn shl(self, n: i32) -> BigNum { - self.checked_shl(&n).unwrap() + self.deref().shl(n) } } @@ -931,7 +834,9 @@ impl<'a> Shr for &'a BigNumRef<'a> { type Output = BigNum; fn shr(self, n: i32) -> BigNum { - self.checked_shr(&n).unwrap() + let mut r = BigNum::new().unwrap(); + self.rshift(&mut r, n).unwrap(); + r } } @@ -939,7 +844,7 @@ impl<'a> Shr for &'a BigNum { type Output = BigNum; fn shr(self, n: i32) -> BigNum { - self.checked_shr(&n).unwrap() + self.deref().shl(n) } } @@ -947,9 +852,7 @@ impl<'a> Neg for &'a BigNumRef<'a> { type Output = BigNum; fn neg(self) -> BigNum { - let mut n = self.to_owned().unwrap(); - n.negate(); - n + self.to_owned().unwrap().neg() } } @@ -957,9 +860,7 @@ impl<'a> Neg for &'a BigNum { type Output = BigNum; fn neg(self) -> BigNum { - let mut n = self.deref().to_owned().unwrap(); - n.negate(); - n + self.deref().neg() } } @@ -967,7 +868,8 @@ impl Neg for BigNum { type Output = BigNum; fn neg(mut self) -> BigNum { - self.negate(); + let negative = self.is_negative(); + self.set_negative(!negative); self } } @@ -978,26 +880,26 @@ mod tests { #[test] fn test_to_from_slice() { - let v0 = BigNum::new_from(10203004).unwrap(); + let v0 = BigNum::from_u32(10203004).unwrap(); let vec = v0.to_vec(); - let v1 = BigNum::new_from_slice(&vec).unwrap(); + let v1 = BigNum::from_slice(&vec).unwrap(); assert!(v0 == v1); } #[test] fn test_negation() { - let a = BigNum::new_from(909829283).unwrap(); + let a = BigNum::from_u32(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(); + 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()); diff --git a/openssl/src/crypto/rsa.rs b/openssl/src/crypto/rsa.rs index 95675abe..a6a4f2b7 100644 --- a/openssl/src/crypto/rsa.rs +++ b/openssl/src/crypto/rsa.rs @@ -85,7 +85,7 @@ impl RSA { pub fn generate(bits: u32) -> Result { unsafe { let rsa = RSA(try!(cvt_p(ffi::RSA_new()))); - let e = try!(BigNum::new_from(ffi::RSA_F4 as u32)); + 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) } From b7400d56e885d61e33da31f0d11286615692ca21 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 16 Oct 2016 23:22:00 -0700 Subject: [PATCH 8/9] Fix algorithm field --- openssl/src/ssl/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 55955753..ad21e563 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -704,10 +704,9 @@ pub struct CipherBits { pub secret: i32, /// The number of bits processed by the chosen algorithm. - pub algorithm: Option, + pub algorithm: i32, } - pub struct SslCipher<'a> { cipher: *const ffi::SSL_CIPHER, ph: PhantomData<&'a ()>, From a938a001a7f64a9934b88e24f9c4115b1d0bebf6 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 16 Oct 2016 23:26:38 -0700 Subject: [PATCH 9/9] Fix missing import --- openssl/src/x509/verify.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/openssl/src/x509/verify.rs b/openssl/src/x509/verify.rs index 87287875..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! {