Commit 387e7825 authored by Steven Fackler's avatar Steven Fackler
Browse files

Support serialization of encrypted private keys

Switch to PEM_write_bio_PKCS8PrivateKey since the other function outputs
nonstandard PEM when encrypting.
parent 7d411c79
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -1496,6 +1496,10 @@ extern {
                                    kstr: *mut c_uchar, klen: c_int,
                                    callback: Option<PasswordCallback>,
                                    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_RSAPrivateKey(bp: *mut BIO, rsa: *mut RSA, cipher: *const EVP_CIPHER,
                                        kstr: *mut c_uchar, klen: c_int,
+10 −0
Original line number Diff line number Diff line
@@ -207,6 +207,8 @@ mod compat {

#[cfg(test)]
mod test {
    use symm::Cipher;

    use super::*;

    #[test]
@@ -220,6 +222,14 @@ mod test {
        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]
    pub fn test_password_callback() {
        let mut password_queried = false;
+20 −0
Original line number Diff line number Diff line
@@ -113,5 +113,25 @@ macro_rules! private_key_to_pem {
                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())
            }
        }
    }
}
+11 −1
Original line number Diff line number Diff line
@@ -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.
    pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
@@ -185,6 +185,7 @@ impl PKey {

#[cfg(test)]
mod tests {
    use symm::Cipher;
    use dh::Dh;
    use dsa::Dsa;
    use ec_key::EcKey;
@@ -193,6 +194,15 @@ mod tests {

    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]
    fn test_private_key_from_pem() {
        let key = include_bytes!("../test/key.pem");
+13 −3
Original line number Diff line number Diff line
@@ -404,16 +404,18 @@ mod compat {

#[cfg(test)]
mod test {
    use symm::Cipher;

    use super::*;

    #[test]
    pub fn test_password() {
    fn test_from_password() {
        let key = include_bytes!("../test/rsa-encrypted.pem");
        Rsa::private_key_from_pem_passphrase(key, b"mypass").unwrap();
    }

    #[test]
    pub fn test_password_callback() {
    fn test_from_password_callback() {
        let mut password_queried = false;
        let key = include_bytes!("../test/rsa-encrypted.pem");
        Rsa::private_key_from_pem_callback(key, |password| {
@@ -427,7 +429,15 @@ mod 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 public_key = Rsa::public_key_from_pem(key).unwrap();