aboutsummaryrefslogtreecommitdiff
path: root/openssl/src/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'openssl/src/crypto')
-rw-r--r--openssl/src/crypto/mod.rs1
-rw-r--r--openssl/src/crypto/pkey.rs117
-rw-r--r--openssl/src/crypto/rsa.rs121
3 files changed, 238 insertions, 1 deletions
diff --git a/openssl/src/crypto/mod.rs b/openssl/src/crypto/mod.rs
index 0868ee95..bb77453f 100644
--- a/openssl/src/crypto/mod.rs
+++ b/openssl/src/crypto/mod.rs
@@ -21,5 +21,6 @@ pub mod pkey;
pub mod rand;
pub mod symm;
pub mod memcmp;
+pub mod rsa;
mod symm_internal;
diff --git a/openssl/src/crypto/pkey.rs b/openssl/src/crypto/pkey.rs
index 10891224..cafd50ad 100644
--- a/openssl/src/crypto/pkey.rs
+++ b/openssl/src/crypto/pkey.rs
@@ -9,6 +9,7 @@ use crypto::hash;
use crypto::hash::Type as HashType;
use ffi;
use ssl::error::{SslError, StreamError};
+use crypto::rsa::RSA;
#[derive(Copy, Clone)]
pub enum Parts {
@@ -52,11 +53,18 @@ fn openssl_hash_nid(hash: HashType) -> c_int {
}
}
+extern "C" {
+ fn rust_EVP_PKEY_clone(pkey: *mut ffi::EVP_PKEY);
+}
+
pub struct PKey {
evp: *mut ffi::EVP_PKEY,
parts: Parts,
}
+unsafe impl Send for PKey {}
+unsafe impl Sync for PKey {}
+
/// Represents a public key, optionally with a private key attached.
impl PKey {
pub fn new() -> PKey {
@@ -93,7 +101,7 @@ impl PKey {
None,
ptr::null_mut()));
Ok(PKey {
- evp: evp,
+ evp: evp as *mut ffi::EVP_PKEY,
parts: Parts::Both,
})
}
@@ -112,6 +120,38 @@ impl PKey {
None,
ptr::null_mut()));
Ok(PKey {
+ evp: evp as *mut ffi::EVP_PKEY,
+ parts: Parts::Public,
+ })
+ }
+ }
+
+ /// Reads an RSA private key from PEM, takes ownership of handle
+ pub fn private_rsa_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError>
+ where R: Read
+ {
+ let rsa = try!(RSA::private_key_from_pem(reader));
+ unsafe {
+ let evp = try_ssl_null!(ffi::EVP_PKEY_new());
+ try_ssl!(ffi::EVP_PKEY_set1_RSA(evp, rsa.as_ptr()));
+
+ Ok(PKey {
+ evp: evp,
+ parts: Parts::Public,
+ })
+ }
+ }
+
+ /// Reads an RSA public key from PEM, takes ownership of handle
+ pub fn public_rsa_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError>
+ where R: Read
+ {
+ let rsa = try!(RSA::public_key_from_pem(reader));
+ unsafe {
+ let evp = try_ssl_null!(ffi::EVP_PKEY_new());
+ try_ssl!(ffi::EVP_PKEY_set1_RSA(evp, rsa.as_ptr()));
+
+ Ok(PKey {
evp: evp,
parts: Parts::Public,
})
@@ -165,6 +205,28 @@ impl PKey {
}
}
+ /// assign RSA key to this pkey
+ pub fn set_rsa(&mut self, rsa: &RSA) {
+ unsafe {
+ // this needs to be a reference as the set1_RSA ups the reference count
+ let rsa_ptr = rsa.as_ptr();
+ if ffi::EVP_PKEY_set1_RSA(self.evp, rsa_ptr) == 1 {
+ if rsa.has_e() && rsa.has_n() {
+ self.parts = Parts::Public;
+ }
+ }
+ }
+ }
+
+ /// get a reference to the interal RSA key for direct access to the key components
+ pub fn get_rsa(&self) -> RSA {
+ unsafe {
+ let evp_pkey: *mut ffi::EVP_PKEY = self.evp;
+ // this is safe as the ffi increments a reference counter to the internal key
+ RSA::from_raw(ffi::EVP_PKEY_get1_RSA(evp_pkey))
+ }
+ }
+
/**
* Returns a DER serialized form of the public key, suitable for load_pub().
*/
@@ -549,11 +611,22 @@ impl Drop for PKey {
}
}
+impl Clone for PKey {
+ fn clone(&self) -> Self {
+ unsafe {
+ rust_EVP_PKEY_clone(self.evp);
+ }
+
+ PKey::from_handle(self.evp, self.parts)
+ }
+}
+
#[cfg(test)]
mod tests {
use std::path::Path;
use std::fs::File;
use crypto::hash::Type::{MD5, SHA1};
+ use crypto::rsa::RSA;
#[test]
fn test_gen_pub() {
@@ -614,6 +687,26 @@ mod tests {
}
#[test]
+ fn test_private_rsa_key_from_pem() {
+ let key_path = Path::new("test/key.pem");
+ let mut file = File::open(&key_path)
+ .ok()
+ .expect("Failed to open `test/key.pem`");
+
+ super::PKey::private_rsa_key_from_pem(&mut file).unwrap();
+ }
+
+ #[test]
+ fn test_public_rsa_key_from_pem() {
+ let key_path = Path::new("test/key.pem.pub");
+ let mut file = File::open(&key_path)
+ .ok()
+ .expect("Failed to open `test/key.pem.pub`");
+
+ super::PKey::public_rsa_key_from_pem(&mut file).unwrap();
+ }
+
+ #[test]
fn test_private_encrypt() {
let mut k0 = super::PKey::new();
let mut k1 = super::PKey::new();
@@ -721,6 +814,28 @@ mod tests {
}
#[test]
+ fn test_public_key_from_raw() {
+ let mut k0 = super::PKey::new();
+ let mut k1 = super::PKey::new();
+ let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
+
+ k0.gen(512);
+ let sig = k0.sign(&msg);
+
+ let r0 = k0.get_rsa();
+ let r1 = RSA::from_public_components(r0.n().expect("n"), r0.e().expect("e")).expect("r1");
+ k1.set_rsa(&r1);
+
+ assert!(k1.can(super::Role::Encrypt));
+ assert!(!k1.can(super::Role::Decrypt));
+ assert!(k1.can(super::Role::Verify));
+ assert!(!k1.can(super::Role::Sign));
+
+ let rv = k1.verify(&msg, &sig);
+ assert!(rv == true);
+ }
+
+ #[test]
#[should_panic(expected = "Could not get RSA key for encryption")]
fn test_nokey_encrypt() {
let mut pkey = super::PKey::new();
diff --git a/openssl/src/crypto/rsa.rs b/openssl/src/crypto/rsa.rs
new file mode 100644
index 00000000..6fcb5b07
--- /dev/null
+++ b/openssl/src/crypto/rsa.rs
@@ -0,0 +1,121 @@
+use ffi;
+use std::fmt;
+use ssl::error::{SslError, StreamError};
+use std::ptr;
+use std::io::{self, Read};
+
+use bn::BigNum;
+use bio::MemBio;
+
+pub struct RSA(*mut ffi::RSA);
+
+impl Drop for RSA {
+ fn drop(&mut self) {
+ unsafe {
+ ffi::RSA_free(self.0);
+ }
+ }
+}
+
+impl RSA {
+ /// only useful for associating the key material directly with the key, it's safer to use
+ /// the supplied load and save methods for DER formatted keys.
+ pub fn from_public_components(n: BigNum, e: BigNum) -> Result<RSA, SslError> {
+ unsafe {
+ let rsa = try_ssl_null!(ffi::RSA_new());
+ (*rsa).n = n.into_raw();
+ (*rsa).e = e.into_raw();
+ Ok(RSA(rsa))
+ }
+ }
+
+ /// the caller should assert that the rsa pointer is valid.
+ pub unsafe fn from_raw(rsa: *mut ffi::RSA) -> RSA {
+ RSA(rsa)
+ }
+
+ /// Reads an RSA private key from PEM formatted data.
+ pub fn private_key_from_pem<R>(reader: &mut R) -> Result<RSA, SslError>
+ where R: Read
+ {
+ let mut mem_bio = try!(MemBio::new());
+ try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
+
+ unsafe {
+ let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.get_handle(),
+ ptr::null_mut(),
+ None,
+ ptr::null_mut()));
+ Ok(RSA(rsa))
+ }
+ }
+
+ /// Reads an RSA public key from PEM formatted data.
+ pub fn public_key_from_pem<R>(reader: &mut R) -> Result<RSA, SslError>
+ where R: Read
+ {
+ let mut mem_bio = try!(MemBio::new());
+ try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
+
+ unsafe {
+ let rsa = try_ssl_null!(ffi::PEM_read_bio_RSA_PUBKEY(mem_bio.get_handle(),
+ ptr::null_mut(),
+ None,
+ ptr::null_mut()));
+ Ok(RSA(rsa))
+ }
+ }
+
+ pub fn as_ptr(&self) -> *mut ffi::RSA {
+ self.0
+ }
+
+ // The following getters are unsafe, since BigNum::new_from_ffi fails upon null pointers
+ pub fn n(&self) -> Result<BigNum, SslError> {
+ unsafe {
+ BigNum::new_from_ffi((*self.0).n)
+ }
+ }
+
+ pub fn has_n(&self) -> bool {
+ unsafe {
+ !(*self.0).n.is_null()
+ }
+ }
+
+ pub fn d(&self) -> Result<BigNum, SslError> {
+ unsafe {
+ BigNum::new_from_ffi((*self.0).d)
+ }
+ }
+
+ pub fn e(&self) -> Result<BigNum, SslError> {
+ unsafe {
+ BigNum::new_from_ffi((*self.0).e)
+ }
+ }
+
+ pub fn has_e(&self) -> bool {
+ unsafe {
+ !(*self.0).e.is_null()
+ }
+ }
+
+ pub fn p(&self) -> Result<BigNum, SslError> {
+ unsafe {
+ BigNum::new_from_ffi((*self.0).p)
+ }
+ }
+
+ pub fn q(&self) -> Result<BigNum, SslError> {
+ unsafe {
+ BigNum::new_from_ffi((*self.0).q)
+ }
+ }
+}
+
+impl fmt::Debug for RSA {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "RSA")
+ }
+}