Some serialization support for EcKey

This commit is contained in:
Steven Fackler 2016-11-13 15:02:38 +00:00
parent 85c1474ce6
commit 08e0c4ca90
8 changed files with 161 additions and 120 deletions

View File

@ -1513,11 +1513,19 @@ extern {
user_data: *mut c_void) -> c_int;
pub fn PEM_write_bio_DSA_PUBKEY(bp: *mut BIO, dsa: *mut DSA) -> c_int;
pub fn PEM_write_bio_X509(bio: *mut BIO, x509: *mut X509) -> c_int;
pub fn PEM_write_bio_X509_REQ(bio: *mut BIO, x509: *mut X509_REQ) -> c_int;
pub fn PEM_write_bio_ECPrivateKey(bio: *mut BIO,
key: *mut EC_KEY,
cipher: *const EVP_CIPHER,
kstr: *mut c_uchar,
klen: c_int,
callback: Option<PasswordCallback>,
user_data: *mut c_void)
-> c_int;
pub fn PEM_read_bio_ECPrivateKey(bio: *mut BIO, key: *mut *mut EC_KEY, callback: Option<PasswordCallback>, user_data: *mut c_void) -> *mut EC_KEY;
pub fn PKCS5_PBKDF2_HMAC_SHA1(pass: *const c_char, passlen: c_int,
salt: *const u8, saltlen: c_int,
iter: c_int, keylen: c_int,
@ -1744,6 +1752,9 @@ extern {
pub fn d2i_DSAPrivateKey(a: *mut *mut DSA, pp: *mut *const c_uchar, length: c_long) -> *mut DSA;
pub fn i2d_DSAPrivateKey(a: *const DSA, pp: *mut *mut c_uchar) -> c_int;
pub fn d2i_ECPrivateKey(k: *mut *mut EC_KEY, pp: *mut *const c_uchar, length: c_long) -> *mut EC_KEY;
pub fn i2d_ECPrivateKey(ec_key: *mut EC_KEY, pp: *mut *mut c_uchar) -> c_int;
pub fn d2i_X509(a: *mut *mut X509, pp: *mut *const c_uchar, length: c_long) -> *mut X509;
pub fn i2d_X509_bio(b: *mut BIO, x: *mut X509) -> c_int;
pub fn i2d_X509_REQ_bio(b: *mut BIO, x: *mut X509_REQ) -> c_int;

View File

@ -9,7 +9,7 @@ use bio::{MemBio, MemBioSlice};
use bn::BigNumRef;
use {cvt, cvt_p};
use types::OpenSslTypeRef;
use util::{CallbackState, invoke_passwd_cb};
use util::{CallbackState, invoke_passwd_cb_old};
type_!(Dsa, DsaRef, ffi::DSA, ffi::DSA_free);
@ -125,25 +125,9 @@ impl Dsa {
}
}
/// Reads a DSA private key from PEM formatted data.
pub fn private_key_from_pem(buf: &[u8]) -> Result<Dsa, ErrorStack> {
ffi::init();
let mem_bio = try!(MemBioSlice::new(buf));
private_key_from_pem!(Dsa, ffi::PEM_read_bio_DSAPrivateKey);
unsafe {
let dsa = try!(cvt_p(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(),
ptr::null_mut(),
None,
ptr::null_mut())));
Ok(Dsa(dsa))
}
}
/// Read a private key from PEM supplying a password callback to be invoked if the private key
/// is encrypted.
///
/// The callback will be passed the password buffer and should return the number of characters
/// placed into the buffer.
#[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")]
pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<Dsa, ErrorStack>
where F: FnOnce(&mut [c_char]) -> usize
{
@ -155,7 +139,7 @@ impl Dsa {
let cb_ptr = &mut cb as *mut _ as *mut c_void;
let dsa = try!(cvt_p(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(),
ptr::null_mut(),
Some(invoke_passwd_cb::<F>),
Some(invoke_passwd_cb_old::<F>),
cb_ptr)));
Ok(Dsa(dsa))
}
@ -235,8 +219,6 @@ mod compat {
#[cfg(test)]
mod test {
use libc::c_char;
use super::*;
#[test]
@ -248,14 +230,9 @@ mod test {
pub fn test_password() {
let mut password_queried = false;
let key = include_bytes!("../test/dsa-encrypted.pem");
Dsa::private_key_from_pem_cb(key, |password| {
Dsa::private_key_from_pem_callback(key, |password| {
password_queried = true;
password[0] = b'm' as c_char;
password[1] = b'y' as c_char;
password[2] = b'p' as c_char;
password[3] = b'a' as c_char;
password[4] = b's' as c_char;
password[5] = b's' as c_char;
password[..6].copy_from_slice(b"mypass");
6
})
.unwrap();

View File

@ -1,11 +1,27 @@
use ffi;
use std::cmp;
use libc::c_long;
use std::ptr;
use {cvt_p, init};
use {cvt, cvt_p, init};
use error::ErrorStack;
use nid::Nid;
use types::OpenSslTypeRef;
type_!(EcKey, EcKeyRef, ffi::EC_KEY, ffi::EC_KEY_free);
impl EcKeyRef {
/// Serializes the private key components to DER.
pub fn private_key_to_der(&self) -> Result<Vec<u8>, ErrorStack> {
unsafe {
let len = try!(cvt(ffi::i2d_ECPrivateKey(self.as_ptr(), ptr::null_mut())));
let mut buf = vec![0; len as usize];
try!(cvt(ffi::i2d_ECPrivateKey(self.as_ptr(), &mut buf.as_mut_ptr())));
Ok(buf)
}
}
}
impl EcKey {
pub fn new_by_curve_name(nid: Nid) -> Result<EcKey, ErrorStack> {
unsafe {
@ -13,6 +29,16 @@ impl EcKey {
cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(EcKey)
}
}
/// Deserializes a DER-encoded private key.
pub fn private_key_from_der(der: &[u8]) -> Result<EcKey, ErrorStack> {
unsafe {
init();
let len = cmp::min(der.len(), c_long::max_value() as usize) as c_long;
cvt_p(ffi::d2i_ECPrivateKey(ptr::null_mut(), &mut der.as_ptr(), len)).map(EcKey)
}
}
private_key_from_pem!(EcKey, ffi::PEM_read_bio_ECPrivateKey);
}
#[cfg(test)]

View File

@ -19,46 +19,8 @@ use libc::c_int;
use error::ErrorStack;
macro_rules! type_ {
($n:ident, $r:ident, $c:path, $d:path) => {
pub struct $n(*mut $c);
impl ::types::OpenSslType for $n {
type CType = $c;
type Ref = $r;
unsafe fn from_ptr(ptr: *mut $c) -> $n {
$n(ptr)
}
}
impl Drop for $n {
fn drop(&mut self) {
unsafe { $d(self.0) }
}
}
impl ::std::ops::Deref for $n {
type Target = $r;
fn deref(&self) -> &$r {
unsafe { ::types::OpenSslTypeRef::from_ptr(self.0) }
}
}
impl ::std::ops::DerefMut for $n {
fn deref_mut(&mut self) -> &mut $r {
unsafe { ::types::OpenSslTypeRef::from_ptr_mut(self.0) }
}
}
pub struct $r(::util::Opaque);
impl ::types::OpenSslTypeRef for $r {
type CType = $c;
}
}
}
#[macro_use]
mod macros;
mod bio;
mod util;

77
openssl/src/macros.rs Normal file
View File

@ -0,0 +1,77 @@
macro_rules! type_ {
($n:ident, $r:ident, $c:path, $d:path) => {
pub struct $n(*mut $c);
impl ::types::OpenSslType for $n {
type CType = $c;
type Ref = $r;
unsafe fn from_ptr(ptr: *mut $c) -> $n {
$n(ptr)
}
}
impl Drop for $n {
fn drop(&mut self) {
unsafe { $d(self.0) }
}
}
impl ::std::ops::Deref for $n {
type Target = $r;
fn deref(&self) -> &$r {
unsafe { ::types::OpenSslTypeRef::from_ptr(self.0) }
}
}
impl ::std::ops::DerefMut for $n {
fn deref_mut(&mut self) -> &mut $r {
unsafe { ::types::OpenSslTypeRef::from_ptr_mut(self.0) }
}
}
pub struct $r(::util::Opaque);
impl ::types::OpenSslTypeRef for $r {
type CType = $c;
}
}
}
macro_rules! private_key_from_pem {
($t:ident, $f:path) => {
/// Deserializes a PEM-formatted private key.
pub fn private_key_from_pem(pem: &[u8]) -> Result<$t, ::error::ErrorStack> {
unsafe {
::init();
let bio = try!(::bio::MemBioSlice::new(pem));
cvt_p($f(bio.as_ptr(), ::std::ptr::null_mut(), None, ::std::ptr::null_mut()))
.map($t)
}
}
/// Deserializes a PEM-formatted private key, using a callback to retrieve a password if the
/// key is encrypted.
///
/// The callback should copy the password into the provided buffer and return the number of
/// bytes written.
pub fn private_key_from_pem_callback<F>(pem: &[u8],
callback: F)
-> Result<$t, ::error::ErrorStack>
where F: FnOnce(&mut [u8]) -> usize
{
unsafe {
ffi::init();
let mut cb = ::util::CallbackState::new(callback);
let bio = try!(::bio::MemBioSlice::new(pem));
cvt_p($f(bio.as_ptr(),
ptr::null_mut(),
Some(::util::invoke_passwd_cb::<F>),
&mut cb as *mut _ as *mut ::libc::c_void))
.map($t)
}
}
}
}

View File

@ -10,7 +10,7 @@ use dsa::Dsa;
use ec_key::EcKey;
use rsa::Rsa;
use error::ErrorStack;
use util::{CallbackState, invoke_passwd_cb};
use util::{CallbackState, invoke_passwd_cb_old};
use types::{OpenSslType, OpenSslTypeRef};
type_!(PKey, PKeyRef, ffi::EVP_PKEY, ffi::EVP_PKEY_free);
@ -166,24 +166,9 @@ impl PKey {
}
}
/// Reads a private key from PEM.
pub fn private_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
ffi::init();
let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let evp = try!(cvt_p(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(),
ptr::null_mut(),
None,
ptr::null_mut())));
Ok(PKey::from_ptr(evp))
}
}
private_key_from_pem!(PKey, ffi::PEM_read_bio_PrivateKey);
/// Read a private key from PEM, supplying a password callback to be invoked if the private key
/// is encrypted.
///
/// The callback will be passed the password buffer and should return the number of characters
/// placed into the buffer.
#[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")]
pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<PKey, ErrorStack>
where F: FnOnce(&mut [c_char]) -> usize
{
@ -193,7 +178,7 @@ impl PKey {
unsafe {
let evp = try!(cvt_p(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(),
ptr::null_mut(),
Some(invoke_passwd_cb::<F>),
Some(invoke_passwd_cb_old::<F>),
&mut cb as *mut _ as *mut c_void)));
Ok(PKey::from_ptr(evp))
}

View File

@ -9,7 +9,7 @@ use {cvt, cvt_p, cvt_n};
use bn::{BigNum, BigNumRef};
use bio::{MemBio, MemBioSlice};
use error::ErrorStack;
use util::{CallbackState, invoke_passwd_cb};
use util::{CallbackState, invoke_passwd_cb_old};
use types::OpenSslTypeRef;
/// Type of encryption padding to use.
@ -281,20 +281,9 @@ impl Rsa {
}
}
/// Reads an RSA private key from PEM formatted data.
pub fn private_key_from_pem(buf: &[u8]) -> Result<Rsa, ErrorStack> {
ffi::init();
let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
let rsa = try!(cvt_p(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(),
ptr::null_mut(),
None,
ptr::null_mut())));
Ok(Rsa(rsa))
}
}
private_key_from_pem!(Rsa, ffi::PEM_read_bio_RSAPrivateKey);
/// Reads an RSA private key from PEM formatted data and supplies a password callback.
#[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")]
pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<Rsa, ErrorStack>
where F: FnOnce(&mut [c_char]) -> usize
{
@ -306,7 +295,7 @@ impl Rsa {
let cb_ptr = &mut cb as *mut _ as *mut c_void;
let rsa = try!(cvt_p(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(),
ptr::null_mut(),
Some(invoke_passwd_cb::<F>),
Some(invoke_passwd_cb_old::<F>),
cb_ptr)));
Ok(Rsa(rsa))
}
@ -429,22 +418,15 @@ mod compat {
#[cfg(test)]
mod test {
use libc::c_char;
use super::*;
#[test]
pub fn test_password() {
let mut password_queried = false;
let key = include_bytes!("../test/rsa-encrypted.pem");
Rsa::private_key_from_pem_cb(key, |password| {
Rsa::private_key_from_pem_callback(key, |password| {
password_queried = true;
password[0] = b'm' as c_char;
password[1] = b'y' as c_char;
password[2] = b'p' as c_char;
password[3] = b'a' as c_char;
password[4] = b's' as c_char;
password[5] = b's' as c_char;
password[..6].copy_from_slice(b"mypass");
6
})
.unwrap();

View File

@ -33,10 +33,7 @@ impl<F> Drop for CallbackState<F> {
}
}
/// Password callback function, passed to private key loading functions.
///
/// `cb_state` is expected to be a pointer to a `CallbackState`.
pub unsafe extern "C" fn invoke_passwd_cb<F>(buf: *mut c_char,
pub unsafe extern fn invoke_passwd_cb_old<F>(buf: *mut c_char,
size: c_int,
_rwflag: c_int,
cb_state: *mut c_void)
@ -46,9 +43,33 @@ pub unsafe extern "C" fn invoke_passwd_cb<F>(buf: *mut c_char,
let callback = &mut *(cb_state as *mut CallbackState<F>);
let result = panic::catch_unwind(AssertUnwindSafe(|| {
// build a `i8` slice to pass to the user callback
let pass_slice = slice::from_raw_parts_mut(buf, size as usize);
callback.cb.take().unwrap()(pass_slice)
}));
match result {
Ok(len) => len as c_int,
Err(err) => {
callback.panic = Some(err);
0
}
}
}
/// Password callback function, passed to private key loading functions.
///
/// `cb_state` is expected to be a pointer to a `CallbackState`.
pub unsafe extern fn invoke_passwd_cb<F>(buf: *mut c_char,
size: c_int,
_rwflag: c_int,
cb_state: *mut c_void)
-> c_int
where F: FnOnce(&mut [u8]) -> usize
{
let callback = &mut *(cb_state as *mut CallbackState<F>);
let result = panic::catch_unwind(AssertUnwindSafe(|| {
let pass_slice = slice::from_raw_parts_mut(buf as *mut u8, size as usize);
callback.cb.take().unwrap()(pass_slice)
}));