From 8119f06ca5ca50a677cf584cbe816500153ce783 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 14 Jun 2016 18:12:50 +0200 Subject: [PATCH] Move into utility module --- openssl/src/crypto/mod.rs | 1 + openssl/src/crypto/pkey.rs | 43 +++------------------------- openssl/src/crypto/util.rs | 58 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 39 deletions(-) create mode 100644 openssl/src/crypto/util.rs diff --git a/openssl/src/crypto/mod.rs b/openssl/src/crypto/mod.rs index 95b27022..9d79b8b0 100644 --- a/openssl/src/crypto/mod.rs +++ b/openssl/src/crypto/mod.rs @@ -24,6 +24,7 @@ pub mod rand; pub mod symm; pub mod memcmp; pub mod rsa; +mod util; mod symm_internal; diff --git a/openssl/src/crypto/pkey.rs b/openssl/src/crypto/pkey.rs index 8ae9aa20..605aed42 100644 --- a/openssl/src/crypto/pkey.rs +++ b/openssl/src/crypto/pkey.rs @@ -1,12 +1,9 @@ -use libc::{c_int, c_uint, c_ulong, c_char, c_void}; -use std::any::Any; +use libc::{c_int, c_uint, c_ulong, c_void}; use std::io; use std::io::prelude::*; use std::iter::repeat; use std::mem; -use std::panic; use std::ptr; -use std::slice; use bio::MemBio; use crypto::HashTypeInternals; @@ -15,6 +12,7 @@ use crypto::hash::Type as HashType; use ffi; use ssl::error::{SslError, StreamError}; use crypto::rsa::RSA; +use crypto::util::{CallbackState, invoke_passwd_cb}; #[derive(Copy, Clone)] pub enum Parts { @@ -104,36 +102,7 @@ impl PKey { pub fn private_key_from_pem_cb(reader: &mut R, pass_cb: F) -> Result where R: Read, F: FnMut(&mut [i8]) -> usize { - struct CallbackState usize> { - cb: F, - panic: Option>, - } - - extern "C" fn user_cb_wrapper(buf: *mut c_char, - size: c_int, - _rwflag: c_int, - user_cb: *mut c_void) - -> c_int - where F: FnMut(&mut [i8]) -> usize { - let result = panic::catch_unwind(|| { - // build a `i8` slice to pass to the user callback - let pass_slice = unsafe { slice::from_raw_parts_mut(buf, size as usize) }; - let callback = unsafe { &mut *(user_cb as *mut CallbackState) }; - - (callback.cb)(pass_slice) - }); - - if let Ok(len) = result { - return len as c_int; - } else { - return 0; - } - } - - let mut cb = CallbackState { - cb: pass_cb, - panic: None, - }; + let mut cb = CallbackState::new(pass_cb); let mut mem_bio = try!(MemBio::new()); try!(io::copy(reader, &mut mem_bio).map_err(StreamError)); @@ -141,13 +110,9 @@ impl PKey { unsafe { let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.get_handle(), ptr::null_mut(), - Some(user_cb_wrapper::), + Some(invoke_passwd_cb::), &mut cb as *mut _ as *mut c_void)); - if let Some(panic) = cb.panic { - panic::resume_unwind(panic); - } - Ok(PKey { evp: evp as *mut ffi::EVP_PKEY, parts: Parts::Both, diff --git a/openssl/src/crypto/util.rs b/openssl/src/crypto/util.rs new file mode 100644 index 00000000..85df86b7 --- /dev/null +++ b/openssl/src/crypto/util.rs @@ -0,0 +1,58 @@ +use libc::{c_int, c_char, c_void}; + +use std::any::Any; +use std::panic; +use std::slice; + +/// Wraps a user-supplied callback and a slot for panics thrown inside the callback (while FFI +/// frames are on the stack). +/// +/// When dropped, checks if the callback has panicked, and resumes unwinding if so. +pub struct CallbackState { + /// The user callback. Taken out of the `Option` when called. + cb: Option, + /// If the callback panics, we place the panic object here, to be re-thrown once OpenSSL + /// returns. + panic: Option>, +} + +impl CallbackState { + pub fn new(callback: F) -> Self { + CallbackState { + cb: Some(callback), + panic: None, + } + } +} + +impl Drop for CallbackState { + fn drop(&mut self) { + if let Some(panic) = self.panic.take() { + panic::resume_unwind(panic); + } + } +} + +/// Password callback function, passed to private key loading functions. +/// +/// `cb_state` is expected to be a pointer to a `CallbackState`. +pub extern "C" fn invoke_passwd_cb(buf: *mut c_char, + size: c_int, + _rwflag: c_int, + cb_state: *mut c_void) + -> c_int + where F: FnMut(&mut [i8]) -> usize { + let result = panic::catch_unwind(|| { + // build a `i8` slice to pass to the user callback + let pass_slice = unsafe { slice::from_raw_parts_mut(buf, size as usize) }; + let callback = unsafe { &mut *(cb_state as *mut CallbackState) }; + + callback.cb.take().unwrap()(pass_slice) + }); + + if let Ok(len) = result { + return len as c_int; + } else { + return 0; + } +}