Some serialization support for EcKey
This commit is contained in:
parent
85c1474ce6
commit
08e0c4ca90
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}));
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue