diff options
| author | Steven Fackler <[email protected]> | 2017-02-11 10:13:00 -0800 |
|---|---|---|
| committer | Steven Fackler <[email protected]> | 2017-02-11 10:13:00 -0800 |
| commit | f2c69ae7e9e9ab6c843c1de842551bb624e7eb2c (patch) | |
| tree | b507d4f207a37720d118bb75d86665d2d9a5da2d /openssl/src/pkey.rs | |
| parent | Docs (diff) | |
| parent | Merge pull request #568 from mredlek/x509_req_version_subject (diff) | |
| download | rust-openssl-f2c69ae7e9e9ab6c843c1de842551bb624e7eb2c.tar.xz rust-openssl-f2c69ae7e9e9ab6c843c1de842551bb624e7eb2c.zip | |
Merge remote-tracking branch 'origin/master' into x509-builder
Diffstat (limited to 'openssl/src/pkey.rs')
| -rw-r--r-- | openssl/src/pkey.rs | 209 |
1 files changed, 146 insertions, 63 deletions
diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index a1ebd695..5608dd51 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -2,62 +2,73 @@ use libc::{c_void, c_char, c_int}; use std::ptr; use std::mem; use ffi; +use foreign_types::{Opaque, ForeignType, ForeignTypeRef}; use {cvt, cvt_p}; -use bio::{MemBio, MemBioSlice}; +use bio::MemBioSlice; +use dh::Dh; use dsa::Dsa; -use rsa::Rsa; +use ec::EcKey; +use rsa::{Rsa, Padding}; use error::ErrorStack; -use util::{CallbackState, invoke_passwd_cb}; -use types::{OpenSslType, OpenSslTypeRef}; +use util::{CallbackState, invoke_passwd_cb_old}; -type_!(PKey, PKeyRef, ffi::EVP_PKEY, ffi::EVP_PKEY_free); +foreign_type! { + type CType = ffi::EVP_PKEY; + fn drop = ffi::EVP_PKEY_free; + + pub struct PKey; + pub struct PKeyRef; +} impl PKeyRef { - /// Get a reference to the interal RSA key for direct access to the key components + /// Returns a copy of the internal RSA key. pub fn rsa(&self) -> Result<Rsa, ErrorStack> { unsafe { let rsa = try!(cvt_p(ffi::EVP_PKEY_get1_RSA(self.as_ptr()))); - // this is safe as the ffi increments a reference counter to the internal key Ok(Rsa::from_ptr(rsa)) } } - /// Stores private key as a PEM - // FIXME: also add password and encryption - pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> { - let mem_bio = try!(MemBio::new()); + /// Returns a copy of the internal DSA key. + pub fn dsa(&self) -> Result<Dsa, ErrorStack> { unsafe { - try!(cvt(ffi::PEM_write_bio_PrivateKey(mem_bio.as_ptr(), - self.as_ptr(), - ptr::null(), - ptr::null_mut(), - -1, - None, - ptr::null_mut()))); - + let dsa = try!(cvt_p(ffi::EVP_PKEY_get1_DSA(self.as_ptr()))); + Ok(Dsa::from_ptr(dsa)) } - Ok(mem_bio.get_buf().to_owned()) } - /// Encode public key in PEM format - pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> { - let mem_bio = try!(MemBio::new()); + /// Returns a copy of the internal DH key. + pub fn dh(&self) -> Result<Dh, ErrorStack> { unsafe { - try!(cvt(ffi::PEM_write_bio_PUBKEY(mem_bio.as_ptr(), self.as_ptr()))); + let dh = try!(cvt_p(ffi::EVP_PKEY_get1_DH(self.as_ptr()))); + Ok(Dh::from_ptr(dh)) } - Ok(mem_bio.get_buf().to_owned()) } - /// Encode public key in DER format - pub fn public_key_to_der(&self) -> Result<Vec<u8>, ErrorStack> { - let mem_bio = try!(MemBio::new()); + /// Returns a copy of the internal elliptic curve key. + pub fn ec_key(&self) -> Result<EcKey, ErrorStack> { unsafe { - try!(cvt(ffi::i2d_PUBKEY_bio(mem_bio.as_ptr(), self.as_ptr()))); + let ec_key = try!(cvt_p(ffi::EVP_PKEY_get1_EC_KEY(self.as_ptr()))); + Ok(EcKey::from_ptr(ec_key)) } - Ok(mem_bio.get_buf().to_owned()) } + public_key_to_pem!(ffi::PEM_write_bio_PUBKEY); + private_key_to_pem!(ffi::PEM_write_bio_PKCS8PrivateKey); + + private_key_to_der!(ffi::i2d_PrivateKey); + public_key_to_der!(ffi::i2d_PUBKEY); + + /// Returns the size of the key. + /// + /// This corresponds to the bit length of the modulus of an RSA key, and the bit length of the + /// group order for an elliptic curve key, for example. + pub fn bits(&self) -> u32 { + unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as u32 } + } + + /// Compares the public component of this key with another. pub fn public_eq(&self, other: &PKeyRef) -> bool { unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 } } @@ -67,7 +78,7 @@ unsafe impl Send for PKey {} unsafe impl Sync for PKey {} impl PKey { - /// Create a new `PKey` containing an RSA key. + /// Creates a new `PKey` containing an RSA key. pub fn from_rsa(rsa: Rsa) -> Result<PKey, ErrorStack> { unsafe { let evp = try!(cvt_p(ffi::EVP_PKEY_new())); @@ -78,7 +89,7 @@ impl PKey { } } - /// Create a new `PKey` containing a DSA key. + /// Creates a new `PKey` containing a DSA key. pub fn from_dsa(dsa: Dsa) -> Result<PKey, ErrorStack> { unsafe { let evp = try!(cvt_p(ffi::EVP_PKEY_new())); @@ -89,7 +100,32 @@ impl PKey { } } - /// Create a new `PKey` containing an HMAC key. + /// Creates a new `PKey` containing a Diffie-Hellman key. + pub fn from_dh(dh: Dh) -> Result<PKey, ErrorStack> { + unsafe { + let evp = try!(cvt_p(ffi::EVP_PKEY_new())); + let pkey = PKey(evp); + try!(cvt(ffi::EVP_PKEY_assign(pkey.0, ffi::EVP_PKEY_DH, dh.as_ptr() as *mut _))); + mem::forget(dh); + Ok(pkey) + } + } + + /// Creates a new `PKey` containing an elliptic curve key. + pub fn from_ec_key(ec_key: EcKey) -> Result<PKey, ErrorStack> { + unsafe { + let evp = try!(cvt_p(ffi::EVP_PKEY_new())); + let pkey = PKey(evp); + try!(cvt(ffi::EVP_PKEY_assign(pkey.0, ffi::EVP_PKEY_EC, ec_key.as_ptr() as *mut _))); + mem::forget(ec_key); + Ok(pkey) + } + } + + /// Creates a new `PKey` containing an HMAC key. + /// + /// # Note + /// To compute HMAC values, use the `sign` module. pub fn hmac(key: &[u8]) -> Result<PKey, ErrorStack> { unsafe { assert!(key.len() <= c_int::max_value() as usize); @@ -101,24 +137,10 @@ impl PKey { } } - /// Reads private key from PEM, takes ownership of handle - 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); + public_key_from_pem!(PKey, ffi::PEM_read_bio_PUBKEY); - /// 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 { @@ -128,44 +150,72 @@ 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)) } } +} - /// Reads public key from PEM, takes ownership of handle - pub fn public_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> { - ffi::init(); - let mem_bio = try!(MemBioSlice::new(buf)); +pub struct PKeyCtxRef(Opaque); + +impl PKeyCtxRef { + pub fn set_rsa_padding(&mut self, pad: Padding) -> Result<(), ErrorStack> { unsafe { - let evp = try!(cvt_p(ffi::PEM_read_bio_PUBKEY(mem_bio.as_ptr(), - ptr::null_mut(), - None, - ptr::null_mut()))); - Ok(PKey::from_ptr(evp)) + try!(cvt(ffi::EVP_PKEY_CTX_set_rsa_padding(self.as_ptr(), pad.as_raw()))); } + Ok(()) } + + pub fn rsa_padding(&self) -> Result<Padding, ErrorStack> { + let mut pad: c_int = 0; + unsafe { + try!(cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.as_ptr(), &mut pad))); + }; + Ok(Padding::from_raw(pad)) + } +} + +impl ForeignTypeRef for PKeyCtxRef { + type CType = ffi::EVP_PKEY_CTX; } #[cfg(test)] mod tests { + use symm::Cipher; + use dh::Dh; + use dsa::Dsa; + use ec::EcKey; + use rsa::Rsa; + use nid; + + 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"); - super::PKey::private_key_from_pem(key).unwrap(); + PKey::private_key_from_pem(key).unwrap(); } #[test] fn test_public_key_from_pem() { let key = include_bytes!("../test/key.pem.pub"); - super::PKey::public_key_from_pem(key).unwrap(); + PKey::public_key_from_pem(key).unwrap(); } #[test] fn test_pem() { let key = include_bytes!("../test/key.pem"); - let key = super::PKey::private_key_from_pem(key).unwrap(); + let key = PKey::private_key_from_pem(key).unwrap(); let priv_key = key.private_key_to_pem().unwrap(); let pub_key = key.public_key_to_pem().unwrap(); @@ -175,4 +225,37 @@ mod tests { assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY")); assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY")); } + + #[test] + fn test_rsa_accessor() { + let rsa = Rsa::generate(2048).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + pkey.rsa().unwrap(); + assert!(pkey.dsa().is_err()); + } + + #[test] + fn test_dsa_accessor() { + let dsa = Dsa::generate(2048).unwrap(); + let pkey = PKey::from_dsa(dsa).unwrap(); + pkey.dsa().unwrap(); + assert!(pkey.rsa().is_err()); + } + + #[test] + fn test_dh_accessor() { + let dh = include_bytes!("../test/dhparams.pem"); + let dh = Dh::from_pem(dh).unwrap(); + let pkey = PKey::from_dh(dh).unwrap(); + pkey.dh().unwrap(); + assert!(pkey.rsa().is_err()); + } + + #[test] + fn test_ec_key_accessor() { + let ec_key = EcKey::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let pkey = PKey::from_ec_key(ec_key).unwrap(); + pkey.ec_key().unwrap(); + assert!(pkey.rsa().is_err()); + } } |