aboutsummaryrefslogtreecommitdiff
path: root/openssl/src/pkey.rs
diff options
context:
space:
mode:
authorSteven Fackler <[email protected]>2017-02-11 10:13:00 -0800
committerSteven Fackler <[email protected]>2017-02-11 10:13:00 -0800
commitf2c69ae7e9e9ab6c843c1de842551bb624e7eb2c (patch)
treeb507d4f207a37720d118bb75d86665d2d9a5da2d /openssl/src/pkey.rs
parentDocs (diff)
parentMerge pull request #568 from mredlek/x509_req_version_subject (diff)
downloadrust-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.rs209
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());
+ }
}