Support serialization of encrypted private keys

Switch to PEM_write_bio_PKCS8PrivateKey since the other function outputs
nonstandard PEM when encrypting.
This commit is contained in:
Steven Fackler 2016-11-13 16:09:52 +00:00
parent 7d411c7975
commit 387e78257b
5 changed files with 58 additions and 4 deletions

View File

@ -1496,6 +1496,10 @@ extern {
kstr: *mut c_uchar, klen: c_int, kstr: *mut c_uchar, klen: c_int,
callback: Option<PasswordCallback>, callback: Option<PasswordCallback>,
user_data: *mut c_void) -> c_int; user_data: *mut c_void) -> c_int;
pub fn PEM_write_bio_PKCS8PrivateKey(bio: *mut BIO, pkey: *mut EVP_PKEY, cipher: *const EVP_CIPHER,
kstr: *mut c_char, klen: c_int,
callback: Option<PasswordCallback>,
user_data: *mut c_void) -> c_int;
pub fn PEM_write_bio_PUBKEY(bp: *mut BIO, x: *mut EVP_PKEY) -> c_int; pub fn PEM_write_bio_PUBKEY(bp: *mut BIO, x: *mut EVP_PKEY) -> c_int;
pub fn PEM_write_bio_RSAPrivateKey(bp: *mut BIO, rsa: *mut RSA, cipher: *const EVP_CIPHER, pub fn PEM_write_bio_RSAPrivateKey(bp: *mut BIO, rsa: *mut RSA, cipher: *const EVP_CIPHER,
kstr: *mut c_uchar, klen: c_int, kstr: *mut c_uchar, klen: c_int,

View File

@ -207,6 +207,8 @@ mod compat {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use symm::Cipher;
use super::*; use super::*;
#[test] #[test]
@ -220,6 +222,14 @@ mod test {
Dsa::private_key_from_pem_passphrase(key, b"mypass").unwrap(); Dsa::private_key_from_pem_passphrase(key, b"mypass").unwrap();
} }
#[test]
fn test_to_password() {
let key = Dsa::generate(2048).unwrap();
let pem = key.private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar").unwrap();
Dsa::private_key_from_pem_passphrase(&pem, b"foobar").unwrap();
assert!(Dsa::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err());
}
#[test] #[test]
pub fn test_password_callback() { pub fn test_password_callback() {
let mut password_queried = false; let mut password_queried = false;

View File

@ -113,5 +113,25 @@ macro_rules! private_key_to_pem {
Ok(bio.get_buf().to_owned()) Ok(bio.get_buf().to_owned())
} }
} }
/// Serializes the private key to PEM, encrypting it with the specified symmetric cipher and
/// passphrase.
pub fn private_key_to_pem_passphrase(&self,
cipher: ::symm::Cipher,
passphrase: &[u8])
-> Result<Vec<u8>, ::error::ErrorStack> {
unsafe {
let bio = try!(::bio::MemBio::new());
assert!(passphrase.len() <= ::libc::c_int::max_value() as usize);
try!(cvt($f(bio.as_ptr(),
self.as_ptr(),
cipher.as_ptr(),
passphrase.as_ptr() as *const _ as *mut _,
passphrase.len() as ::libc::c_int,
None,
ptr::null_mut())));
Ok(bio.get_buf().to_owned())
}
}
} }
} }

View File

@ -48,7 +48,7 @@ impl PKeyRef {
} }
} }
private_key_to_pem!(ffi::PEM_write_bio_PrivateKey); private_key_to_pem!(ffi::PEM_write_bio_PKCS8PrivateKey);
/// Encodes the public key in the PEM format. /// Encodes the public key in the PEM format.
pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> { pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
@ -185,6 +185,7 @@ impl PKey {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use symm::Cipher;
use dh::Dh; use dh::Dh;
use dsa::Dsa; use dsa::Dsa;
use ec_key::EcKey; use ec_key::EcKey;
@ -193,6 +194,15 @@ mod tests {
use super::*; use super::*;
#[test]
fn test_to_password() {
let rsa = Rsa::generate(2048).unwrap();
let pkey = PKey::from_rsa(rsa).unwrap();
let pem = pkey.private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar").unwrap();
PKey::private_key_from_pem_passphrase(&pem, b"foobar").unwrap();
assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err());
}
#[test] #[test]
fn test_private_key_from_pem() { fn test_private_key_from_pem() {
let key = include_bytes!("../test/key.pem"); let key = include_bytes!("../test/key.pem");

View File

@ -404,16 +404,18 @@ mod compat {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use symm::Cipher;
use super::*; use super::*;
#[test] #[test]
pub fn test_password() { fn test_from_password() {
let key = include_bytes!("../test/rsa-encrypted.pem"); let key = include_bytes!("../test/rsa-encrypted.pem");
Rsa::private_key_from_pem_passphrase(key, b"mypass").unwrap(); Rsa::private_key_from_pem_passphrase(key, b"mypass").unwrap();
} }
#[test] #[test]
pub fn test_password_callback() { fn test_from_password_callback() {
let mut password_queried = false; let mut password_queried = false;
let key = include_bytes!("../test/rsa-encrypted.pem"); let key = include_bytes!("../test/rsa-encrypted.pem");
Rsa::private_key_from_pem_callback(key, |password| { Rsa::private_key_from_pem_callback(key, |password| {
@ -427,7 +429,15 @@ mod test {
} }
#[test] #[test]
pub fn test_public_encrypt_private_decrypt_with_padding() { fn test_to_password() {
let key = Rsa::generate(2048).unwrap();
let pem = key.private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar").unwrap();
Rsa::private_key_from_pem_passphrase(&pem, b"foobar").unwrap();
assert!(Rsa::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err());
}
#[test]
fn test_public_encrypt_private_decrypt_with_padding() {
let key = include_bytes!("../test/rsa.pem.pub"); let key = include_bytes!("../test/rsa.pem.pub");
let public_key = Rsa::public_key_from_pem(key).unwrap(); let public_key = Rsa::public_key_from_pem(key).unwrap();