From 08e27f31ed851873f7684ac806b837e8cff4a28f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 2 Aug 2016 20:48:42 -0700 Subject: [PATCH] Restructure PEM input/output methods Dealing with byte buffers directly avoids error handling weirdness and we were loading it all into memory before anyway. --- openssl-sys/src/lib.rs | 7 +++ openssl/src/bio.rs | 67 ++++++++++++++++++++ openssl/src/bio/mod.rs | 107 -------------------------------- openssl/src/crypto/dsa.rs | 75 +++++++++-------------- openssl/src/crypto/pkey.rs | 114 ++++++++++------------------------- openssl/src/crypto/rsa.rs | 58 ++++++------------ openssl/src/dh/mod.rs | 20 ++---- openssl/src/lib.rs | 2 +- openssl/src/ssl/tests/mod.rs | 15 ++--- openssl/src/x509/mod.rs | 70 ++++++--------------- openssl/src/x509/tests.rs | 57 ++++++------------ 11 files changed, 201 insertions(+), 391 deletions(-) create mode 100644 openssl/src/bio.rs delete mode 100644 openssl/src/bio/mod.rs diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 3c31f671..2deef976 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -269,6 +269,7 @@ pub type PasswordCallback = extern "C" fn(buf: *mut c_char, size: c_int, pub const BIO_TYPE_NONE: c_int = 0; pub const BIO_CTRL_EOF: c_int = 2; +pub const BIO_CTRL_INFO: c_int = 3; pub const BIO_CTRL_FLUSH: c_int = 11; pub const BIO_C_SET_BUF_MEM_EOF_RETURN: c_int = 130; @@ -453,6 +454,11 @@ fn set_id_callback() { #[cfg(not(unix))] fn set_id_callback() {} +// macros +pub unsafe fn BIO_get_mem_data(b: *mut BIO, pp: *mut *mut c_char) -> c_long { + BIO_ctrl(b, BIO_CTRL_INFO, 0, pp as *mut c_void) +} + // True functions extern "C" { pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; @@ -466,6 +472,7 @@ extern "C" { pub fn BIO_read(b: *mut BIO, buf: *mut c_void, len: c_int) -> c_int; pub fn BIO_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int; pub fn BIO_s_mem() -> *const BIO_METHOD; + pub fn BIO_new_mem_buf(buf: *const c_void, len: c_int) -> *mut BIO; pub fn BN_new() -> *mut BIGNUM; pub fn BN_dup(n: *mut BIGNUM) -> *mut BIGNUM; diff --git a/openssl/src/bio.rs b/openssl/src/bio.rs new file mode 100644 index 00000000..841aca0e --- /dev/null +++ b/openssl/src/bio.rs @@ -0,0 +1,67 @@ +use std::marker::PhantomData; +use std::ptr; +use std::slice; +use libc::c_int; +use ffi; + +use error::ErrorStack; + +pub struct MemBioSlice<'a>(*mut ffi::BIO, PhantomData<&'a [u8]>); + +impl<'a> Drop for MemBioSlice<'a> { + fn drop(&mut self) { + unsafe { + ffi::BIO_free_all(self.0); + } + } +} + +impl<'a> MemBioSlice<'a> { + pub fn new(buf: &'a [u8]) -> Result, ErrorStack> { + ffi::init(); + + assert!(buf.len() <= c_int::max_value() as usize); + let bio = unsafe { + try_ssl_null!(ffi::BIO_new_mem_buf(buf.as_ptr() as *const _, buf.len() as c_int)) + }; + + Ok(MemBioSlice(bio, PhantomData)) + } + + pub fn get_handle(&self) -> *mut ffi::BIO { + self.0 + } +} + +pub struct MemBio(*mut ffi::BIO); + +impl Drop for MemBio { + fn drop(&mut self) { + unsafe { + ffi::BIO_free_all(self.0); + } + } +} + +impl MemBio { + pub fn new() -> Result { + ffi::init(); + + let bio = unsafe { + try_ssl_null!(ffi::BIO_new(ffi::BIO_s_mem())) + }; + Ok(MemBio(bio)) + } + + pub fn get_handle(&self) -> *mut ffi::BIO { + self.0 + } + + pub fn get_buf(&self) -> &[u8] { + unsafe { + let mut ptr = ptr::null_mut(); + let len = ffi::BIO_get_mem_data(self.0, &mut ptr); + slice::from_raw_parts(ptr as *const _ as *const _, len as usize) + } + } +} diff --git a/openssl/src/bio/mod.rs b/openssl/src/bio/mod.rs deleted file mode 100644 index 2e99284f..00000000 --- a/openssl/src/bio/mod.rs +++ /dev/null @@ -1,107 +0,0 @@ -use libc::{c_void, c_int}; -use std::io; -use std::io::prelude::*; -use std::ptr; -use std::cmp; - -use ffi; -use ffi_extras; -use error::ErrorStack; - -pub struct MemBio { - bio: *mut ffi::BIO, - owned: bool, -} - -impl Drop for MemBio { - fn drop(&mut self) { - if self.owned { - unsafe { - ffi::BIO_free_all(self.bio); - } - } - } -} - -impl MemBio { - /// Creates a new owned memory based BIO - pub fn new() -> Result { - ffi::init(); - - let bio = unsafe { ffi::BIO_new(ffi::BIO_s_mem()) }; - try_ssl_null!(bio); - - Ok(MemBio { - bio: bio, - owned: true, - }) - } - - /// Returns a "borrow", i.e. it has no ownership - pub fn borrowed(bio: *mut ffi::BIO) -> MemBio { - MemBio { - bio: bio, - owned: false, - } - } - - /// Consumes current bio and returns wrapped value - /// Note that data ownership is lost and - /// should be managed manually - pub unsafe fn unwrap(mut self) -> *mut ffi::BIO { - self.owned = false; - self.bio - } - - /// Temporarily gets wrapped value - pub unsafe fn get_handle(&self) -> *mut ffi::BIO { - self.bio - } - - /// Sets the BIO's EOF state. - pub fn set_eof(&self, eof: bool) { - let v = if eof { - 0 - } else { - -1 - }; - unsafe { - ffi_extras::BIO_set_mem_eof_return(self.bio, v); - } - } -} - -impl Read for MemBio { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int; - let ret = unsafe { ffi::BIO_read(self.bio, buf.as_ptr() as *mut c_void, len) }; - - if ret <= 0 { - let is_eof = unsafe { ffi_extras::BIO_eof(self.bio) }; - if is_eof != 0 { - Ok(0) - } else { - Err(io::Error::new(io::ErrorKind::Other, ErrorStack::get())) - } - } else { - Ok(ret as usize) - } - } -} - -impl Write for MemBio { - fn write(&mut self, buf: &[u8]) -> io::Result { - let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int; - let ret = unsafe { ffi::BIO_write(self.bio, buf.as_ptr() as *const c_void, len) }; - - if ret < 0 { - Err(io::Error::new(io::ErrorKind::Other, ErrorStack::get())) - } else { - Ok(ret as usize) - } - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} diff --git a/openssl/src/crypto/dsa.rs b/openssl/src/crypto/dsa.rs index a1e4572a..de35893b 100644 --- a/openssl/src/crypto/dsa.rs +++ b/openssl/src/crypto/dsa.rs @@ -2,11 +2,10 @@ use ffi; use std::fmt; use error::ErrorStack; use std::ptr; -use std::io::{self, Read, Write}; use libc::{c_uint, c_int, c_char, c_void}; use bn::BigNum; -use bio::MemBio; +use bio::{MemBio, MemBioSlice}; use crypto::hash; use crypto::HashTypeInternals; use crypto::util::{CallbackState, invoke_passwd_cb}; @@ -69,11 +68,9 @@ impl DSA { } /// Reads a DSA private key from PEM formatted data. - pub fn private_key_from_pem(reader: &mut R) -> io::Result - where R: Read - { - let mut mem_bio = try!(MemBio::new()); - try!(io::copy(reader, &mut mem_bio)); + pub fn private_key_from_pem(buf: &[u8]) -> Result { + ffi::init(); + let mem_bio = try!(MemBioSlice::new(buf)); unsafe { let dsa = try_ssl_null!(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.get_handle(), @@ -91,12 +88,12 @@ impl DSA { /// /// The callback will be passed the password buffer and should return the number of characters /// placed into the buffer. - pub fn private_key_from_pem_cb(reader: &mut R, pass_cb: F) -> io::Result - where R: Read, F: FnOnce(&mut [c_char]) -> usize + pub fn private_key_from_pem_cb(buf: &[u8], pass_cb: F) -> Result + where F: FnOnce(&mut [c_char]) -> usize { + ffi::init(); let mut cb = CallbackState::new(pass_cb); - let mut mem_bio = try!(MemBio::new()); - try!(io::copy(reader, &mut mem_bio)); + let mem_bio = try!(MemBioSlice::new(buf)); unsafe { let cb_ptr = &mut cb as *mut _ as *mut c_void; @@ -111,11 +108,10 @@ impl DSA { } /// Writes an DSA private key as unencrypted PEM formatted data - pub fn private_key_to_pem(&self, writer: &mut W) -> io::Result<()> - where W: Write + pub fn private_key_to_pem(&self) -> Result, ErrorStack> { assert!(self.has_private_key()); - let mut mem_bio = try!(MemBio::new()); + let mem_bio = try!(MemBio::new()); unsafe { try_ssl!(ffi::PEM_write_bio_DSAPrivateKey(mem_bio.get_handle(), self.0, @@ -123,18 +119,15 @@ impl DSA { None, ptr::null_mut())) }; - - try!(io::copy(&mut mem_bio, writer)); - Ok(()) + Ok(mem_bio.get_buf().to_owned()) } /// Reads an DSA public key from PEM formatted data. - pub fn public_key_from_pem(reader: &mut R) -> io::Result - where R: Read + pub fn public_key_from_pem(buf: &[u8]) -> Result { - let mut mem_bio = try!(MemBio::new()); - try!(io::copy(reader, &mut mem_bio)); + ffi::init(); + let mem_bio = try!(MemBioSlice::new(buf)); unsafe { let dsa = try_ssl_null!(ffi::PEM_read_bio_DSA_PUBKEY(mem_bio.get_handle(), ptr::null_mut(), @@ -145,15 +138,10 @@ impl DSA { } /// Writes an DSA public key as PEM formatted data - pub fn public_key_to_pem(&self, writer: &mut W) -> io::Result<()> - where W: Write - { - let mut mem_bio = try!(MemBio::new()); - + pub fn public_key_to_pem(&self) -> Result, ErrorStack> { + let mem_bio = try!(MemBio::new()); unsafe { try_ssl!(ffi::PEM_write_bio_DSA_PUBKEY(mem_bio.get_handle(), self.0)) }; - - try!(io::copy(&mut mem_bio, writer)); - Ok(()) + Ok(mem_bio.get_buf().to_owned()) } pub fn size(&self) -> Option { @@ -243,8 +231,7 @@ impl fmt::Debug for DSA { #[cfg(test)] mod test { - use std::fs::File; - use std::io::{Write, Cursor}; + use std::io::Write; use libc::c_char; use super::*; @@ -253,11 +240,9 @@ mod test { #[test] pub fn test_generate() { let key = DSA::generate(1024).unwrap(); - let mut priv_buf = Cursor::new(vec![]); - let mut pub_buf = Cursor::new(vec![]); - key.public_key_to_pem(&mut pub_buf).unwrap(); - key.private_key_to_pem(&mut priv_buf).unwrap(); + key.public_key_to_pem().unwrap(); + key.private_key_to_pem().unwrap(); let input: Vec = (0..25).cycle().take(1024).collect(); @@ -277,13 +262,13 @@ mod test { let input: Vec = (0..25).cycle().take(1024).collect(); let private_key = { - let mut buffer = File::open("test/dsa.pem").unwrap(); - DSA::private_key_from_pem(&mut buffer).unwrap() + let key = include_bytes!("../../test/dsa.pem"); + DSA::private_key_from_pem(key).unwrap() }; let public_key = { - let mut buffer = File::open("test/dsa.pem.pub").unwrap(); - DSA::public_key_from_pem(&mut buffer).unwrap() + let key = include_bytes!("../../test/dsa.pem.pub"); + DSA::public_key_from_pem(key).unwrap() }; let digest = { @@ -301,13 +286,13 @@ mod test { pub fn test_sign_verify_fail() { let input: Vec = (0..25).cycle().take(128).collect(); let private_key = { - let mut buffer = File::open("test/dsa.pem").unwrap(); - DSA::private_key_from_pem(&mut buffer).unwrap() + let key = include_bytes!("../../test/dsa.pem"); + DSA::private_key_from_pem(key).unwrap() }; let public_key = { - let mut buffer = File::open("test/dsa.pem.pub").unwrap(); - DSA::public_key_from_pem(&mut buffer).unwrap() + let key = include_bytes!("../../test/dsa.pem.pub"); + DSA::public_key_from_pem(key).unwrap() }; let digest = { @@ -329,8 +314,8 @@ mod test { #[test] pub fn test_password() { let mut password_queried = false; - let mut buffer = File::open("test/dsa-encrypted.pem").unwrap(); - DSA::private_key_from_pem_cb(&mut buffer, |password| { + let key = include_bytes!("../../test/dsa-encrypted.pem"); + DSA::private_key_from_pem_cb(key, |password| { password_queried = true; password[0] = b'm' as c_char; password[1] = b'y' as c_char; diff --git a/openssl/src/crypto/pkey.rs b/openssl/src/crypto/pkey.rs index 29feb016..ab9a4a95 100644 --- a/openssl/src/crypto/pkey.rs +++ b/openssl/src/crypto/pkey.rs @@ -1,10 +1,8 @@ use libc::{c_int, c_uint, c_ulong, c_void, c_char}; -use std::io; -use std::io::prelude::*; use std::iter::repeat; use std::mem; use std::ptr; -use bio::MemBio; +use bio::{MemBio, MemBioSlice}; use crypto::HashTypeInternals; use crypto::hash; @@ -76,12 +74,8 @@ impl PKey { } /// Reads private key from PEM, takes ownership of handle - pub fn private_key_from_pem(reader: &mut R) -> io::Result - where R: Read - { - let mut mem_bio = try!(MemBio::new()); - try!(io::copy(reader, &mut mem_bio)); - + pub fn private_key_from_pem(buf: &[u8]) -> Result { + let mem_bio = try!(MemBioSlice::new(buf)); unsafe { let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.get_handle(), ptr::null_mut(), @@ -100,14 +94,11 @@ impl PKey { /// /// The callback will be passed the password buffer and should return the number of characters /// placed into the buffer. - pub fn private_key_from_pem_cb(reader: &mut R, pass_cb: F) -> io::Result - where R: Read, F: FnOnce(&mut [c_char]) -> usize + pub fn private_key_from_pem_cb(buf: &[u8], pass_cb: F) -> Result + where F: FnOnce(&mut [c_char]) -> usize { let mut cb = CallbackState::new(pass_cb); - - let mut mem_bio = try!(MemBio::new()); - try!(io::copy(reader, &mut mem_bio)); - + let mem_bio = try!(MemBioSlice::new(buf)); unsafe { let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.get_handle(), ptr::null_mut(), @@ -122,12 +113,8 @@ impl PKey { } /// Reads public key from PEM, takes ownership of handle - pub fn public_key_from_pem(reader: &mut R) -> io::Result - where R: Read - { - let mut mem_bio = try!(MemBio::new()); - try!(io::copy(reader, &mut mem_bio)); - + pub fn public_key_from_pem(buf: &[u8]) -> Result { + let mem_bio = try!(MemBioSlice::new(buf)); unsafe { let evp = try_ssl_null!(ffi::PEM_read_bio_PUBKEY(mem_bio.get_handle(), ptr::null_mut(), @@ -141,14 +128,12 @@ impl PKey { } /// Reads an RSA private key from PEM, takes ownership of handle - pub fn private_rsa_key_from_pem(reader: &mut R) -> io::Result - where R: Read - { - let rsa = try!(RSA::private_key_from_pem(reader)); + pub fn private_rsa_key_from_pem(buf: &[u8]) -> Result { + let rsa = try!(RSA::private_key_from_pem(buf)); unsafe { let evp = try_ssl_null!(ffi::EVP_PKEY_new()); if ffi::EVP_PKEY_set1_RSA(evp, rsa.as_ptr()) == 0 { - return Err(io::Error::new(io::ErrorKind::Other, ErrorStack::get())); + return Err(ErrorStack::get()); } Ok(PKey { @@ -159,14 +144,12 @@ impl PKey { } /// Reads an RSA public key from PEM, takes ownership of handle - pub fn public_rsa_key_from_pem(reader: &mut R) -> io::Result - where R: Read - { - let rsa = try!(RSA::public_key_from_pem(reader)); + pub fn public_rsa_key_from_pem(buf: &[u8]) -> Result { + let rsa = try!(RSA::public_key_from_pem(buf)); unsafe { let evp = try_ssl_null!(ffi::EVP_PKEY_new()); if ffi::EVP_PKEY_set1_RSA(evp, rsa.as_ptr()) == 0 { - return Err(io::Error::new(io::ErrorKind::Other, ErrorStack::get())); + return Err(ErrorStack::get()); } Ok(PKey { @@ -280,10 +263,8 @@ impl PKey { /// Stores private key as a PEM // FIXME: also add password and encryption - pub fn write_pem(&self, - writer: &mut W /* , password: Option */) - -> io::Result<()> { - let mut mem_bio = try!(MemBio::new()); + pub fn write_pem(&self) -> Result, ErrorStack> { + let mem_bio = try!(MemBio::new()); unsafe { try_ssl!(ffi::PEM_write_bio_PrivateKey(mem_bio.get_handle(), self.evp, @@ -294,20 +275,14 @@ impl PKey { ptr::null_mut())); } - let mut buf = vec![]; - try!(mem_bio.read_to_end(&mut buf)); - writer.write_all(&buf) + Ok(mem_bio.get_buf().to_owned()) } /// Stores public key as a PEM - pub fn write_pub_pem(&self, - writer: &mut W /* , password: Option */) - -> io::Result<()> { - let mut mem_bio = try!(MemBio::new()); + pub fn write_pub_pem(&self) -> Result, ErrorStack> { + let mem_bio = try!(MemBio::new()); unsafe { try_ssl!(ffi::PEM_write_bio_PUBKEY(mem_bio.get_handle(), self.evp)) } - let mut buf = vec![]; - try!(mem_bio.read_to_end(&mut buf)); - writer.write_all(&buf) + Ok(mem_bio.get_buf().to_owned()) } /** @@ -648,8 +623,6 @@ impl Clone for PKey { #[cfg(test)] mod tests { - use std::path::Path; - use std::fs::File; use crypto::hash::Type::{MD5, SHA1}; use crypto::rsa::RSA; @@ -693,42 +666,26 @@ mod tests { #[test] fn test_private_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_key_from_pem(&mut file).unwrap(); + let key = include_bytes!("../../test/key.pem"); + super::PKey::private_key_from_pem(key).unwrap(); } #[test] fn test_public_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_key_from_pem(&mut file).unwrap(); + let key = include_bytes!("../../test/key.pem.pub"); + super::PKey::public_key_from_pem(key).unwrap(); } #[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(); + let key = include_bytes!("../../test/key.pem"); + super::PKey::private_rsa_key_from_pem(key).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(); + let key = include_bytes!("../../test/key.pem.pub"); + super::PKey::public_rsa_key_from_pem(key).unwrap(); } #[test] @@ -819,18 +776,11 @@ mod tests { #[test] fn test_pem() { - let key_path = Path::new("test/key.pem"); - let mut file = File::open(&key_path) - .ok() - .expect("Failed to open `test/key.pem`"); + let key = include_bytes!("../../test/key.pem"); + let key = super::PKey::private_key_from_pem(key).unwrap(); - let key = super::PKey::private_key_from_pem(&mut file).unwrap(); - - let mut priv_key = Vec::new(); - let mut pub_key = Vec::new(); - - key.write_pem(&mut priv_key).unwrap(); - key.write_pub_pem(&mut pub_key).unwrap(); + let priv_key = key.write_pem().unwrap(); + let pub_key = key.write_pub_pem().unwrap(); // As a super-simple verification, just check that the buffers contain // the `PRIVATE KEY` or `PUBLIC KEY` strings. diff --git a/openssl/src/crypto/rsa.rs b/openssl/src/crypto/rsa.rs index 05c1c774..226b2aab 100644 --- a/openssl/src/crypto/rsa.rs +++ b/openssl/src/crypto/rsa.rs @@ -1,11 +1,10 @@ use ffi; use std::fmt; use std::ptr; -use std::io::{self, Read, Write}; use libc::{c_int, c_void, c_char}; use bn::BigNum; -use bio::MemBio; +use bio::{MemBio, MemBioSlice}; use error::ErrorStack; use crypto::HashTypeInternals; use crypto::hash; @@ -62,12 +61,8 @@ impl RSA { } /// Reads an RSA private key from PEM formatted data. - pub fn private_key_from_pem(reader: &mut R) -> io::Result - where R: Read - { - let mut mem_bio = try!(MemBio::new()); - try!(io::copy(reader, &mut mem_bio)); - + pub fn private_key_from_pem(buf: &[u8]) -> Result { + let mem_bio = try!(MemBioSlice::new(buf)); unsafe { let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.get_handle(), ptr::null_mut(), @@ -78,13 +73,11 @@ impl RSA { } /// Reads an RSA private key from PEM formatted data and supplies a password callback. - pub fn private_key_from_pem_cb(reader: &mut R, pass_cb: F) -> io::Result - where R: Read, F: FnOnce(&mut [c_char]) -> usize + pub fn private_key_from_pem_cb(buf: &[u8], pass_cb: F) -> Result + where F: FnOnce(&mut [c_char]) -> usize { let mut cb = CallbackState::new(pass_cb); - - let mut mem_bio = try!(MemBio::new()); - try!(io::copy(reader, &mut mem_bio)); + let mem_bio = try!(MemBioSlice::new(buf)); unsafe { let cb_ptr = &mut cb as *mut _ as *mut c_void; @@ -98,10 +91,8 @@ impl RSA { } /// Writes an RSA private key as unencrypted PEM formatted data - pub fn private_key_to_pem(&self, writer: &mut W) -> io::Result<()> - where W: Write - { - let mut mem_bio = try!(MemBio::new()); + pub fn private_key_to_pem(&self) -> Result, ErrorStack> { + let mem_bio = try!(MemBio::new()); unsafe { try_ssl!(ffi::PEM_write_bio_RSAPrivateKey(mem_bio.get_handle(), @@ -112,17 +103,12 @@ impl RSA { None, ptr::null_mut())); } - try!(io::copy(&mut mem_bio, writer)); - Ok(()) + Ok(mem_bio.get_buf().to_owned()) } /// Reads an RSA public key from PEM formatted data. - pub fn public_key_from_pem(reader: &mut R) -> io::Result - where R: Read - { - let mut mem_bio = try!(MemBio::new()); - try!(io::copy(reader, &mut mem_bio)); - + pub fn public_key_from_pem(buf: &[u8]) -> Result { + let mem_bio = try!(MemBioSlice::new(buf)); unsafe { let rsa = try_ssl_null!(ffi::PEM_read_bio_RSA_PUBKEY(mem_bio.get_handle(), ptr::null_mut(), @@ -133,17 +119,14 @@ impl RSA { } /// Writes an RSA public key as PEM formatted data - pub fn public_key_to_pem(&self, writer: &mut W) -> io::Result<()> - where W: Write - { - let mut mem_bio = try!(MemBio::new()); + pub fn public_key_to_pem(&self) -> Result, ErrorStack> { + let mem_bio = try!(MemBio::new()); unsafe { try_ssl!(ffi::PEM_write_bio_RSA_PUBKEY(mem_bio.get_handle(), self.0)) }; - try!(io::copy(&mut mem_bio, writer)); - Ok(()) + Ok(mem_bio.get_buf().to_owned()) } pub fn size(&self) -> Option { @@ -236,7 +219,6 @@ impl fmt::Debug for RSA { #[cfg(test)] mod test { - use std::fs::File; use std::io::Write; use libc::c_char; @@ -271,8 +253,8 @@ mod test { #[test] pub fn test_sign() { - let mut buffer = File::open("test/rsa.pem").unwrap(); - let private_key = RSA::private_key_from_pem(&mut buffer).unwrap(); + let key = include_bytes!("../../test/rsa.pem"); + let private_key = RSA::private_key_from_pem(key).unwrap(); let mut sha = Hasher::new(Type::SHA256); sha.write_all(&signing_input_rs256()).unwrap(); @@ -285,8 +267,8 @@ mod test { #[test] pub fn test_verify() { - let mut buffer = File::open("test/rsa.pem.pub").unwrap(); - let public_key = RSA::public_key_from_pem(&mut buffer).unwrap(); + let key = include_bytes!("../../test/rsa.pem.pub"); + let public_key = RSA::public_key_from_pem(key).unwrap(); let mut sha = Hasher::new(Type::SHA256); sha.write_all(&signing_input_rs256()).unwrap(); @@ -300,8 +282,8 @@ mod test { #[test] pub fn test_password() { let mut password_queried = false; - let mut buffer = File::open("test/rsa-encrypted.pem").unwrap(); - RSA::private_key_from_pem_cb(&mut buffer, |password| { + let key = include_bytes!("../../test/rsa-encrypted.pem"); + RSA::private_key_from_pem_cb(key, |password| { password_queried = true; password[0] = b'm' as c_char; password[1] = b'y' as c_char; diff --git a/openssl/src/dh/mod.rs b/openssl/src/dh/mod.rs index bf1ca73e..df6f1b0a 100644 --- a/openssl/src/dh/mod.rs +++ b/openssl/src/dh/mod.rs @@ -1,8 +1,6 @@ use ffi; -use std::io; -use std::io::prelude::*; use error::ErrorStack; -use bio::MemBio; +use bio::MemBioSlice; use bn::BigNum; use std::mem; use std::ptr; @@ -18,11 +16,8 @@ impl DH { Ok(DH(dh)) } - pub fn from_pem(reader: &mut R) -> io::Result - where R: Read - { - let mut mem_bio = try!(MemBio::new()); - try!(io::copy(reader, &mut mem_bio)); + pub fn from_pem(buf: &[u8]) -> Result { + let mem_bio = try!(MemBioSlice::new(buf)); let dh = unsafe { ffi::PEM_read_bio_DHparams(mem_bio.get_handle(), ptr::null_mut(), None, ptr::null_mut()) }; @@ -71,8 +66,6 @@ impl Drop for DH { #[cfg(test)] mod tests { - use std::fs::File; - use std::path::Path; use super::DH; use bn::BigNum; use ssl::SslContext; @@ -123,11 +116,8 @@ mod tests { #[test] fn test_dh_from_pem() { let mut ctx = SslContext::new(Sslv23).unwrap(); - let pem_path = Path::new("test/dhparams.pem"); - let mut file = File::open(&pem_path) - .ok() - .expect("Failed to open `test/dhparams.pem`"); - let dh = DH::from_pem(&mut file).ok().expect("Failed to load PEM"); + let params = include_bytes!("../../test/dhparams.pem"); + let dh = DH::from_pem(params).ok().expect("Failed to load PEM"); ctx.set_tmp_dh(dh).unwrap(); } } diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index d12af41c..4cd76613 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -17,7 +17,7 @@ extern crate net2; mod macros; pub mod asn1; -pub mod bio; +mod bio; pub mod bn; pub mod crypto; pub mod dh; diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 0b638546..b774b383 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -418,17 +418,10 @@ fn test_write_hits_stream() { #[test] fn test_set_certificate_and_private_key() { - let key_path = Path::new("test/key.pem"); - let cert_path = Path::new("test/cert.pem"); - let mut key_file = File::open(&key_path) - .ok() - .expect("Failed to open `test/key.pem`"); - let mut cert_file = File::open(&cert_path) - .ok() - .expect("Failed to open `test/cert.pem`"); - - let key = PKey::private_key_from_pem(&mut key_file).unwrap(); - let cert = X509::from_pem(&mut cert_file).unwrap(); + let key = include_bytes!("../../../test/key.pem"); + let key = PKey::private_key_from_pem(key).unwrap(); + let cert = include_bytes!("../../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap(); ctx.set_private_key(&key).unwrap(); diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 05d8221e..64a61df0 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -1,6 +1,4 @@ use libc::{c_char, c_int, c_long, c_ulong, c_uint, c_void}; -use std::io; -use std::io::prelude::*; use std::cmp::Ordering; use std::ffi::CString; use std::iter::repeat; @@ -14,7 +12,7 @@ use std::collections::HashMap; use std::marker::PhantomData; use asn1::Asn1Time; -use bio::MemBio; +use bio::{MemBio, MemBioSlice}; use crypto::hash; use crypto::hash::Type as HashType; use crypto::pkey::{PKey, Parts}; @@ -116,13 +114,6 @@ impl X509StoreContext { /// # Example /// /// ``` -/// # #[allow(unstable)] -/// # fn main() { -/// use std::fs; -/// use std::fs::File; -/// use std::io::prelude::*; -/// use std::path::Path; -/// /// use openssl::crypto::hash::Type; /// use openssl::x509::X509Generator; /// use openssl::x509::extension::{Extension, KeyUsageOption}; @@ -135,17 +126,8 @@ impl X509StoreContext { /// .add_extension(Extension::KeyUsage(vec![KeyUsageOption::DigitalSignature])); /// /// let (cert, pkey) = gen.generate().unwrap(); -/// -/// let cert_path = "doc_cert.pem"; -/// let mut file = File::create(cert_path).unwrap(); -/// assert!(cert.write_pem(&mut file).is_ok()); -/// # let _ = fs::remove_file(cert_path); -/// -/// let pkey_path = "doc_key.pem"; -/// let mut file = File::create(pkey_path).unwrap(); -/// assert!(pkey.write_pem(&mut file).is_ok()); -/// # let _ = fs::remove_file(pkey_path); -/// # } +/// let cert_pem = cert.write_pem().unwrap(); +/// let pkey_pem = pkey.write_pem().unwrap(); /// ``` pub struct X509Generator { bits: u32, @@ -444,12 +426,8 @@ impl<'ctx> X509<'ctx> { } /// Reads certificate from PEM, takes ownership of handle - pub fn from_pem(reader: &mut R) -> io::Result> - where R: Read - { - let mut mem_bio = try!(MemBio::new()); - try!(io::copy(reader, &mut mem_bio)); - + pub fn from_pem(buf: &[u8]) -> Result, ErrorStack> { + let mem_bio = try!(MemBioSlice::new(buf)); unsafe { let handle = try_ssl_null!(ffi::PEM_read_bio_X509(mem_bio.get_handle(), ptr::null_mut(), @@ -523,25 +501,21 @@ impl<'ctx> X509<'ctx> { } /// Writes certificate as PEM - pub fn write_pem(&self, writer: &mut W) -> io::Result<()> - where W: Write - { - let mut mem_bio = try!(MemBio::new()); + pub fn write_pem(&self) -> Result, ErrorStack> { + let mem_bio = try!(MemBio::new()); unsafe { try_ssl!(ffi::PEM_write_bio_X509(mem_bio.get_handle(), self.handle)); } - io::copy(&mut mem_bio, writer).map(|_| ()) + Ok(mem_bio.get_buf().to_owned()) } /// Returns a DER serialized form of the certificate pub fn save_der(&self) -> Result, ErrorStack> { - let mut mem_bio = try!(MemBio::new()); + let mem_bio = try!(MemBio::new()); unsafe { ffi::i2d_X509_bio(mem_bio.get_handle(), self.handle); } - let mut v = Vec::new(); - drop(io::copy(&mut mem_bio, &mut v)); - Ok(v) + Ok(mem_bio.get_buf().to_owned()) } } @@ -627,12 +601,8 @@ impl X509Req { } /// Reads CSR from PEM - pub fn from_pem(reader: &mut R) -> io::Result - where R: Read - { - let mut mem_bio = try!(MemBio::new()); - try!(io::copy(reader, &mut mem_bio)); - + pub fn from_pem(buf: &[u8]) -> Result { + let mem_bio = try!(MemBioSlice::new(buf)); unsafe { let handle = try_ssl_null!(ffi::PEM_read_bio_X509_REQ(mem_bio.get_handle(), ptr::null_mut(), @@ -643,25 +613,21 @@ impl X509Req { } /// Writes CSR as PEM - pub fn write_pem(&self, writer: &mut W) -> io::Result<()> - where W: Write - { - let mut mem_bio = try!(MemBio::new()); + pub fn write_pem(&self) -> Result, ErrorStack> { + let mem_bio = try!(MemBio::new()); if unsafe { ffi::PEM_write_bio_X509_REQ(mem_bio.get_handle(), self.handle) } != 1 { - return Err(io::Error::new(io::ErrorKind::Other, ErrorStack::get())); + return Err(ErrorStack::get()); } - io::copy(&mut mem_bio, writer).map(|_| ()) + Ok(mem_bio.get_buf().to_owned()) } /// Returns a DER serialized form of the CSR pub fn save_der(&self) -> Result, ErrorStack> { - let mut mem_bio = try!(MemBio::new()); + let mem_bio = try!(MemBio::new()); unsafe { ffi::i2d_X509_REQ_bio(mem_bio.get_handle(), self.handle); } - let mut v = Vec::new(); - drop(io::copy(&mut mem_bio, &mut v)); - Ok(v) + Ok(mem_bio.get_buf().to_owned()) } } diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index 5d9b30ab..167ca8cf 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -1,7 +1,4 @@ use serialize::hex::FromHex; -use std::io; -use std::path::Path; -use std::fs::File; use crypto::hash::Type::SHA1; use crypto::pkey::PKey; @@ -30,8 +27,8 @@ fn get_generator() -> X509Generator { #[test] fn test_cert_gen() { let (cert, pkey) = get_generator().generate().unwrap(); - cert.write_pem(&mut io::sink()).unwrap(); - pkey.write_pem(&mut io::sink()).unwrap(); + cert.write_pem().unwrap(); + pkey.write_pem().unwrap(); // FIXME: check data in result to be correct, needs implementation // of X509 getters @@ -70,7 +67,7 @@ fn test_req_gen() { pkey.gen(512); let req = get_generator().request(&pkey).unwrap(); - req.write_pem(&mut io::sink()).unwrap(); + req.write_pem().unwrap(); // FIXME: check data in result to be correct, needs implementation // of X509_REQ getters @@ -78,12 +75,8 @@ fn test_req_gen() { #[test] fn test_cert_loading() { - let cert_path = Path::new("test/cert.pem"); - let mut file = File::open(&cert_path) - .ok() - .expect("Failed to open `test/cert.pem`"); - - let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM"); + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let fingerprint = cert.fingerprint(SHA1).unwrap(); let hash_str = "E19427DAC79FBE758394945276A6E4F15F0BEBE6"; @@ -94,12 +87,8 @@ fn test_cert_loading() { #[test] fn test_save_der() { - let cert_path = Path::new("test/cert.pem"); - let mut file = File::open(&cert_path) - .ok() - .expect("Failed to open `test/cert.pem`"); - - let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM"); + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let der = cert.save_der().unwrap(); assert!(!der.is_empty()); @@ -107,12 +96,8 @@ fn test_save_der() { #[test] fn test_subject_read_cn() { - let cert_path = Path::new("test/cert.pem"); - let mut file = File::open(&cert_path) - .ok() - .expect("Failed to open `test/cert.pem`"); - - let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM"); + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let subject = cert.subject_name(); let cn = match subject.text_by_nid(Nid::CN) { Some(x) => x, @@ -124,12 +109,8 @@ fn test_subject_read_cn() { #[test] fn test_nid_values() { - let cert_path = Path::new("test/nid_test_cert.pem"); - let mut file = File::open(&cert_path) - .ok() - .expect("Failed to open `test/nid_test_cert.pem`"); - - let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM"); + let cert = include_bytes!("../../test/nid_test_cert.pem"); + let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let subject = cert.subject_name(); let cn = match subject.text_by_nid(Nid::CN) { @@ -153,12 +134,8 @@ fn test_nid_values() { #[test] fn test_nid_uid_value() { - let cert_path = Path::new("test/nid_uid_test_cert.pem"); - let mut file = File::open(&cert_path) - .ok() - .expect("Failed to open `test/nid_uid_test_cert.pem`"); - - let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM"); + let cert = include_bytes!("../../test/nid_uid_test_cert.pem"); + let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let subject = cert.subject_name(); let cn = match subject.text_by_nid(Nid::UserId) { @@ -170,8 +147,8 @@ fn test_nid_uid_value() { #[test] fn test_subject_alt_name() { - let mut file = File::open("test/alt_name_cert.pem").unwrap(); - let cert = X509::from_pem(&mut file).unwrap(); + let cert = include_bytes!("../../test/alt_name_cert.pem"); + let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let subject_alt_names = cert.subject_alt_names().unwrap(); assert_eq!(3, subject_alt_names.len()); @@ -184,8 +161,8 @@ fn test_subject_alt_name() { #[test] fn test_subject_alt_name_iter() { - let mut file = File::open("test/alt_name_cert.pem").unwrap(); - let cert = X509::from_pem(&mut file).unwrap(); + let cert = include_bytes!("../../test/alt_name_cert.pem"); + let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let subject_alt_names = cert.subject_alt_names().unwrap(); let mut subject_alt_names_iter = subject_alt_names.iter();