summaryrefslogtreecommitdiff
path: root/openssl/src/pkey.rs
diff options
context:
space:
mode:
authorSteven Fackler <sfackler@gmail.com>2017-02-14 19:37:25 -0800
committerSteven Fackler <sfackler@gmail.com>2017-02-14 19:37:25 -0800
commit19f3b8a11acc576135e94741975cd1d27e64794f (patch)
tree5c0cc8fdc522b2e2db7d9e93a2a03277e8d1e14b /openssl/src/pkey.rs
parent06065ddcee2abd5304a0aacb9643b925d504bb8b (diff)
downloadrust-openssl-19f3b8a11acc576135e94741975cd1d27e64794f.zip
Support PKCS#8 private key deserialization
Closes #581
Diffstat (limited to 'openssl/src/pkey.rs')
-rw-r--r--openssl/src/pkey.rs63
1 files changed, 62 insertions, 1 deletions
diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs
index 5608dd51..6dbe8ec7 100644
--- a/openssl/src/pkey.rs
+++ b/openssl/src/pkey.rs
@@ -1,6 +1,7 @@
use libc::{c_void, c_char, c_int};
use std::ptr;
use std::mem;
+use std::ffi::CString;
use ffi;
use foreign_types::{Opaque, ForeignType, ForeignTypeRef};
@@ -11,7 +12,7 @@ use dsa::Dsa;
use ec::EcKey;
use rsa::{Rsa, Padding};
use error::ErrorStack;
-use util::{CallbackState, invoke_passwd_cb_old};
+use util::{CallbackState, invoke_passwd_cb, invoke_passwd_cb_old};
foreign_type! {
type CType = ffi::EVP_PKEY;
@@ -140,6 +141,47 @@ impl PKey {
private_key_from_pem!(PKey, ffi::PEM_read_bio_PrivateKey);
public_key_from_pem!(PKey, ffi::PEM_read_bio_PUBKEY);
+ /// Deserializes a DER-formatted PKCS#8 private key, using a callback to retrieve the password
+ /// if the key is encrpyted.
+ ///
+ /// The callback should copy the password into the provided buffer and return the number of
+ /// bytes written.
+ pub fn private_key_from_pkcs8_callback<F>(der: &[u8], callback: F) -> Result<PKey, ErrorStack>
+ where F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>
+ {
+ unsafe {
+ ffi::init();
+ let mut cb = CallbackState::new(callback);
+ let bio = try!(MemBioSlice::new(der));
+ cvt_p(ffi::d2i_PKCS8PrivateKey_bio(bio.as_ptr(),
+ ptr::null_mut(),
+ Some(invoke_passwd_cb::<F>),
+ &mut cb as *mut _ as *mut _))
+ .map(PKey)
+ }
+ }
+
+ /// Deserializes a DER-formatted PKCS#8 private key, using the supplied password if the key is
+ /// encrypted.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `passphrase` contains an embedded null.
+ pub fn private_key_from_pkcs8_passphrase(der: &[u8],
+ passphrase: &[u8])
+ -> Result<PKey, ErrorStack> {
+ unsafe {
+ ffi::init();
+ let bio = try!(MemBioSlice::new(der));
+ let passphrase = CString::new(passphrase).unwrap();
+ cvt_p(ffi::d2i_PKCS8PrivateKey_bio(bio.as_ptr(),
+ ptr::null_mut(),
+ None,
+ passphrase.as_ptr() as *const _ as *mut _))
+ .map(PKey)
+ }
+ }
+
#[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
@@ -201,6 +243,25 @@ mod tests {
}
#[test]
+ fn test_encrypted_pkcs8_passphrase() {
+ let key = include_bytes!("../test/pkcs8.der");
+ PKey::private_key_from_pkcs8_passphrase(key, b"mypass").unwrap();
+ }
+
+ #[test]
+ fn test_encrypted_pkcs8_callback() {
+ let mut password_queried = false;
+ let key = include_bytes!("../test/pkcs8.der");
+ PKey::private_key_from_pkcs8_callback(key, |password| {
+ password_queried = true;
+ password[..6].copy_from_slice(b"mypass");
+ Ok(6)
+ })
+ .unwrap();
+ assert!(password_queried);
+ }
+
+ #[test]
fn test_private_key_from_pem() {
let key = include_bytes!("../test/key.pem");
PKey::private_key_from_pem(key).unwrap();