Commit 632d8398 authored by Manuel Schölling's avatar Manuel Schölling
Browse files

Add ability to load private keys from files and use raw keys and certificates for SslContext

parent b42202b8
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -435,6 +435,9 @@ extern "C" {

    pub fn PEM_read_bio_X509(bio: *mut BIO, out: *mut *mut X509, callback: Option<PasswordCallback>,
                             user_data: *mut c_void) -> *mut X509;
    pub fn PEM_read_bio_PrivateKey(bio: *mut BIO, out: *mut *mut EVP_PKEY, callback: Option<PasswordCallback>,
                             user_data: *mut c_void) -> *mut X509;

    pub fn PEM_write_bio_PrivateKey(bio: *mut BIO, pkey: *mut EVP_PKEY, cipher: *const EVP_CIPHER,
                                    kstr: *mut c_char, klen: c_int,
                                    callback: Option<PasswordCallback>,
@@ -510,7 +513,10 @@ extern "C" {
    pub fn SSL_CTX_get_ex_data(ctx: *mut SSL_CTX, idx: c_int) -> *mut c_void;

    pub fn SSL_CTX_use_certificate_file(ctx: *mut SSL_CTX, cert_file: *const c_char, file_type: c_int) -> c_int;
    pub fn SSL_CTX_use_certificate(ctx: *mut SSL_CTX, cert_file: *mut X509) -> c_int;
    pub fn SSL_CTX_use_PrivateKey_file(ctx: *mut SSL_CTX, key_file: *const c_char, file_type: c_int) -> c_int;
    pub fn SSL_CTX_use_PrivateKey(ctx: *mut SSL_CTX, key: *mut EVP_PKEY) -> c_int;
    pub fn SSL_CTX_check_private_key(ctx: *mut SSL_CTX) -> c_int;

    pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int;

+30 −0
Original line number Diff line number Diff line
use libc::{c_int, c_uint, c_ulong};
use std::io;
use std::io::prelude::*;
use std::iter::repeat;
use std::mem;
@@ -69,6 +70,22 @@ impl PKey {
        }
    }

    /// Reads private key from PEM, takes ownership of handle
    pub fn private_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError> where R: Read {
        let mut mem_bio = try!(MemBio::new());
        try!(io::copy(reader, &mut mem_bio).map_err(StreamError));

        unsafe {
            let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.get_handle(),
                                                                 ptr::null_mut(),
                                                                 None, ptr::null_mut()));
            Ok(PKey {
                evp:   evp,
                parts: Parts::Both,
            })
        }
    }

    fn _tostr(&self, f: unsafe extern "C" fn(*mut ffi::RSA, *const *mut u8) -> c_int) -> Vec<u8> {
        unsafe {
            let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
@@ -335,6 +352,9 @@ impl Drop for PKey {

#[cfg(test)]
mod tests {
    use std::io;
    use std::path::Path;
    use std::fs::File;
    use crypto::hash::Type::{MD5, SHA1};

    #[test]
@@ -373,6 +393,16 @@ mod tests {
        assert!(k1.can(super::Role::Sign));
    }

    #[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();
    }

    #[test]
    fn test_encrypt() {
        let mut k0 = super::PKey::new();
+25 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ use bio::{MemBio};
use ffi;
use ssl::error::{SslError, SslSessionClosed, StreamError, OpenSslErrors};
use x509::{X509StoreContext, X509FileType, X509};
use crypto::pkey::PKey;

pub mod error;
#[cfg(test)]
@@ -400,6 +401,14 @@ impl SslContext {
            })
    }

    /// Specifies the certificate
    pub fn set_certificate(&mut self, cert: &X509) -> Option<SslError> {
        wrap_ssl_result(
            unsafe {
                ffi::SSL_CTX_use_certificate(*self.ctx, cert.get_handle())
            })
    }

    /// Specifies the file that contains private key
    pub fn set_private_key_file(&mut self, file: &Path,
                                file_type: X509FileType) -> Option<SslError> {
@@ -410,6 +419,22 @@ impl SslContext {
            })
    }

    /// Specifies the private key
    pub fn set_private_key(&mut self, key: &PKey) -> Option<SslError> {
        wrap_ssl_result(
            unsafe {
                ffi::SSL_CTX_use_PrivateKey(*self.ctx, key.get_handle())
            })
    }

    /// Check consistency of private key and certificate
    pub fn check_private_key(&mut self) -> Option<SslError> {
        wrap_ssl_result(
            unsafe {
                ffi::SSL_CTX_check_private_key(*self.ctx)
            })
    }

    pub fn set_cipher_list(&mut self, cipher_list: &str) -> Option<SslError> {
        wrap_ssl_result(
            unsafe {
+24 −1
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ use std::path::Path;
use std::net::TcpListener;
#[cfg(feature = "npn")]
use std::thread;
use std::fs::File;

use crypto::hash::Type::{SHA256};
use ssl;
@@ -16,7 +17,8 @@ use ssl::SSL_VERIFY_PEER;
use x509::X509StoreContext;
#[cfg(feature = "npn")]
use x509::X509FileType;
use x509::{X509StoreContext};
use x509::X509;
use crypto::pkey::PKey;

#[test]
fn test_new_ctx() {
@@ -183,6 +185,27 @@ fn test_verify_callback_data() {
    }
}

#[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 mut ctx = SslContext::new(Sslv23).unwrap();
    ctx.set_private_key(&key);
    ctx.set_certificate(&cert);

    assert!(ctx.check_private_key().is_none());
}

#[test]
fn test_get_ctx_options() {
    let mut ctx = SslContext::new(Sslv23).unwrap();
+4 −0
Original line number Diff line number Diff line
@@ -393,6 +393,10 @@ impl<'ctx> X509<'ctx> {
        }
    }

    pub fn get_handle(&self) -> *mut ffi::X509 {
        self.handle
    }

    pub fn subject_name<'a>(&'a self) -> X509Name<'a> {
        let name = unsafe { ffi::X509_get_subject_name(self.handle) };
        X509Name { x509: self, name: name }