Commit 08e27f31 authored by Steven Fackler's avatar Steven Fackler
Browse files

Restructure PEM input/output methods

Dealing with byte buffers directly avoids error handling weirdness and
we were loading it all into memory before anyway.
parent 92abf49b
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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;

openssl/src/bio.rs

0 → 100644
+67 −0
Original line number Diff line number Diff line
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<MemBioSlice<'a>, 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<MemBio, ErrorStack> {
        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)
        }
    }
}

openssl/src/bio/mod.rs

deleted100644 → 0
+0 −107
Original line number Diff line number Diff line
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<MemBio, ErrorStack> {
        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<usize> {
        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<usize> {
        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(())
    }
}
+30 −45
Original line number Diff line number Diff line
@@ -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<R>(reader: &mut R) -> io::Result<DSA>
        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<DSA, ErrorStack> {
        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<R, F>(reader: &mut R, pass_cb: F) -> io::Result<DSA>
        where R: Read, F: FnOnce(&mut [c_char]) -> usize
    pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<DSA, ErrorStack>
        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<W>(&self, writer: &mut W) -> io::Result<()>
        where W: Write
    pub fn private_key_to_pem(&self) -> Result<Vec<u8>, 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<R>(reader: &mut R) -> io::Result<DSA>
        where R: Read
    pub fn public_key_from_pem(buf: &[u8]) -> Result<DSA, ErrorStack>
    {
        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<W>(&self, writer: &mut W) -> io::Result<()>
        where W: Write
    {
        let mut mem_bio = try!(MemBio::new());

    pub fn public_key_to_pem(&self) -> Result<Vec<u8>, 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<u32> {
@@ -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<u8> = (0..25).cycle().take(1024).collect();

@@ -277,13 +262,13 @@ mod test {
        let input: Vec<u8> = (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<u8> = (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;
+32 −82
Original line number Diff line number Diff line
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<R>(reader: &mut R) -> io::Result<PKey>
        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<PKey, ErrorStack> {
        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<R, F>(reader: &mut R, pass_cb: F) -> io::Result<PKey>
        where R: Read, F: FnOnce(&mut [c_char]) -> usize
    pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<PKey, ErrorStack>
        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<R>(reader: &mut R) -> io::Result<PKey>
        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<PKey, ErrorStack> {
        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<R>(reader: &mut R) -> io::Result<PKey>
        where R: Read
    {
        let rsa = try!(RSA::private_key_from_pem(reader));
    pub fn private_rsa_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
        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<R>(reader: &mut R) -> io::Result<PKey>
        where R: Read
    {
        let rsa = try!(RSA::public_key_from_pem(reader));
    pub fn public_rsa_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
        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<W: Write>(&self,
                               writer: &mut W /* , password: Option<String> */)
                               -> io::Result<()> {
        let mut mem_bio = try!(MemBio::new());
    pub fn write_pem(&self) -> Result<Vec<u8>, 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<W: Write>(&self,
                                   writer: &mut W /* , password: Option<String> */)
                                   -> io::Result<()> {
        let mut mem_bio = try!(MemBio::new());
    pub fn write_pub_pem(&self) -> Result<Vec<u8>, 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 = super::PKey::private_key_from_pem(&mut file).unwrap();

        let mut priv_key = Vec::new();
        let mut pub_key = Vec::new();
        let key = include_bytes!("../../test/key.pem");
        let key = super::PKey::private_key_from_pem(key).unwrap();

        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.
Loading