diff options
author | Steven Fackler <sfackler@gmail.com> | 2017-02-14 19:37:25 -0800 |
---|---|---|
committer | Steven Fackler <sfackler@gmail.com> | 2017-02-14 19:37:25 -0800 |
commit | 19f3b8a11acc576135e94741975cd1d27e64794f (patch) | |
tree | 5c0cc8fdc522b2e2db7d9e93a2a03277e8d1e14b /openssl/src/pkey.rs | |
parent | 06065ddcee2abd5304a0aacb9643b925d504bb8b (diff) | |
download | rust-openssl-19f3b8a11acc576135e94741975cd1d27e64794f.zip |
Support PKCS#8 private key deserialization
Closes #581
Diffstat (limited to 'openssl/src/pkey.rs')
-rw-r--r-- | openssl/src/pkey.rs | 63 |
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(); |