Commit 4fd169a1 authored by Valerii Hiora's avatar Valerii Hiora
Browse files

Certificate/pkey generation & PEM export

Required quite a lot of refactoring
parent fa53c79e
Loading
Loading
Loading
Loading

src/asn1/mod.rs

0 → 100644
+23 −0
Original line number Diff line number Diff line
pub mod ffi {
    #![allow(dead_code)]
    #![allow(non_camel_case_types)]
    use libc::{c_int, c_long, c_void};

    pub type ASN1_INTEGER = c_void;
    pub type ASN1_TIME = c_void;
    pub type ASN1_STRING = c_void;

    pub static MBSTRING_FLAG: c_int = 0x1000;
    pub static MBSTRING_UTF8: c_int = MBSTRING_FLAG;
    pub static MBSTRING_ASC:  c_int = MBSTRING_FLAG | 1;
    pub static MBSTRING_BMP:  c_int = MBSTRING_FLAG | 2;
    pub static MBSTRING_UNIV: c_int = MBSTRING_FLAG | 4;

    pub static V_ASN1_UTCTIME:         c_int = 23;
    pub static V_ASN1_GENERALIZEDTIME: c_int = 24;

    extern "C" {
        pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING;
        pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int;
    }
}

src/bio/mod.rs

0 → 100644
+106 −0
Original line number Diff line number Diff line
use libc::{c_void, c_int};
use std::io::{IoResult, IoError, OtherIoError};
use std::io::{Reader, Writer};
use std::ptr;

use ssl::error::{SslError};

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, SslError> {
        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 handled manually
    pub unsafe fn unwrap(self) -> *mut ffi::BIO {
        let mut t = self;
        t.owned = false;
        t.bio
    }

    /// Temporarily gets wrapped value
    pub unsafe fn get_handle(&self) -> *mut ffi::BIO {
        self.bio
    }
}

impl Reader for MemBio {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        // FIXME: merge with read
        let ret = unsafe {
            ffi::BIO_read(self.bio, buf.as_ptr() as *mut c_void,
                          buf.len() as c_int)
        };

        if ret < 0 {
            // FIXME: provide details from OpenSSL
            Err(IoError{kind: OtherIoError, desc: "mem bio read error", detail: None})
        } else {
            Ok(ret as uint)
        }
    }
}

impl Writer for MemBio {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        // FIXME: merge with write
        let ret = unsafe {
            ffi::BIO_write(self.bio, buf.as_ptr() as *const c_void,
                           buf.len() as c_int)
        };
        if buf.len() != ret as uint {
            // FIXME: provide details from OpenSSL
            Err(IoError{kind: OtherIoError, desc: "mem bio write error", detail: None})
        } else {
            Ok(())
        }
    }
}

pub mod ffi {
    #![allow(non_camel_case_types)]

    use libc::{c_int, c_void};

    pub type BIO = c_void;
    pub type BIO_METHOD = c_void;

    extern "C" {
        pub fn BIO_s_mem() -> *const BIO_METHOD;
        pub fn BIO_new(type_: *const BIO_METHOD) -> *mut BIO;
        pub fn BIO_free_all(a: *mut BIO);
        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;
    }
}
+28 −1
Original line number Diff line number Diff line
use libc::{c_char, c_int, c_uint};
use libc::{c_char, c_int, c_uint, c_void};
use libc;
use std::mem;
use std::ptr;
use bio::{mod, MemBio};
use crypto::hash::{HashType, MD5, SHA1, SHA224, SHA256, SHA384, SHA512, RIPEMD160};
use crypto::symm::{EVP_CIPHER};
use ssl::error::{SslError, StreamError};

#[allow(non_camel_case_types)]
pub type EVP_PKEY = *mut libc::c_void;
@@ -10,6 +13,8 @@ pub type EVP_PKEY = *mut libc::c_void;
#[allow(non_camel_case_types)]
pub type RSA = *mut libc::c_void;

pub type PrivateKeyWriteCallback = extern "C" fn(buf: *mut c_char, size: c_int, rwflag: c_int, user_data: *mut c_void) -> c_int;

#[link(name = "crypto")]
extern {
    fn EVP_PKEY_new() -> *mut EVP_PKEY;
@@ -34,6 +39,11 @@ extern {
                k: *mut RSA) -> c_int;
    fn RSA_verify(t: c_int, m: *const u8, mlen: c_uint, sig: *const u8, siglen: c_uint,
                  k: *mut RSA) -> c_int;

    fn PEM_write_bio_PrivateKey(bio: *mut bio::ffi::BIO, pkey: *mut EVP_PKEY, cipher: *const EVP_CIPHER,
                                kstr: *mut c_char, klen: c_int,
                                callback: *mut c_void,
                                user_data: *mut c_void) -> c_int;
}

enum Parts {
@@ -163,6 +173,19 @@ impl PKey {
        self.parts = Both;
    }

    /// Stores private key as a PEM
    // FIXME: also add password and encryption
    pub fn write_pem(&self, writer: &mut Writer/*, password: Option<String>*/) -> Result<(), SslError> {
        let mut mem_bio = try!(MemBio::new());
        unsafe {
            try_ssl!(PEM_write_bio_PrivateKey(mem_bio.get_handle(), self.evp, ptr::null(),
                                              ptr::null_mut(), -1, ptr::null_mut(), ptr::null_mut()));

        }
        let buf = try!(mem_bio.read_to_end().map_err(StreamError));
        writer.write(buf.as_slice()).map_err(StreamError)
    }

    /**
     * Returns the size of the public key modulus.
     */
@@ -326,6 +349,10 @@ impl PKey {
            rv == 1 as c_int
        }
    }

    pub unsafe fn get_handle(&self) -> *mut EVP_PKEY {
        return self.evp
    }
}

impl Drop for PKey {

src/lib.rs

100644 → 100755
+7 −2
Original line number Diff line number Diff line
@@ -9,6 +9,11 @@ extern crate libc;
extern crate serialize;
extern crate sync;

pub mod ssl;
pub mod crypto;
mod macros;

mod asn1;
pub mod bn;
pub mod bio;
pub mod crypto;
pub mod ssl;
pub mod x509;

src/macros.rs

0 → 100755
+61 −0
Original line number Diff line number Diff line
#![macro_escape]

#[macro_export]
macro_rules! try_ssl_stream {
    ($e:expr) => (
        match $e {
            Ok(ok) => ok,
            Err(err) => return Err(StreamError(err))
        }
    )
}

/// Shortcut return with SSL error if something went wrong
#[macro_export]
macro_rules! try_ssl_if {
    ($e:expr) => (
        if $e {
            return Err(SslError::get())
        }
    )
}

/// Shortcut return with SSL error if last error result is 0
/// (default)
#[macro_export]
macro_rules! try_ssl{
    ($e:expr) => (try_ssl_if!($e == 0))
}

/// Shortcut return with SSL if got a null result
#[macro_export]
macro_rules! try_ssl_null{
    ($e:expr) => (try_ssl_if!($e == ptr::null_mut()))
}


/// Lifts current SSL error code into Result<(), Error>
/// if expression is true
/// Lifting is actually a shortcut of the following form:
///
/// ```ignore
/// let _ = try!(something)
/// Ok(())
/// ```
#[macro_export]
macro_rules! lift_ssl_if{
    ($e:expr) => ( {
        if $e {
            Err(SslError::get())
        } else {
            Ok(())
        }
    })
}

/// Lifts current SSL error code into Result<(), Error>
/// if SSL returned 0 (default error indication)
#[macro_export]
macro_rules! lift_ssl {
    ($e:expr) => (lift_ssl_if!($e == 0))
}
Loading