Commit 6b12a0cd authored by Steven Fackler's avatar Steven Fackler
Browse files

PKCS #12 support

parent ad4a8cc1
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -1086,6 +1086,10 @@ extern "C" {
                        -> c_int;
    pub fn PKCS12_free(p12: *mut PKCS12);

    pub fn sk_free(st: *mut _STACK);
    pub fn sk_pop_free(st: *mut _STACK, free: Option<unsafe extern "C" fn (*mut c_void)>);
    pub fn sk_pop(st: *mut _STACK) -> *mut c_char;

    pub fn SSLeay() -> c_long;
    pub fn SSLeay_version(key: c_int) -> *const c_char;
}
+53 −2
Original line number Diff line number Diff line
@@ -4,8 +4,11 @@ use ffi;
use libc::{c_long, c_uchar};
use std::cmp;
use std::ptr;
use std::ffi::CString;

use crypto::pkey::PKey;
use error::ErrorStack;
use x509::X509;

/// A PKCS #12 archive.
pub struct Pkcs12(*mut ffi::PKCS12);
@@ -19,21 +22,69 @@ impl Drop for Pkcs12 {
impl Pkcs12 {
    pub fn from_der(der: &[u8]) -> Result<Pkcs12, ErrorStack> {
        unsafe {
            ffi::init();
            let mut ptr = der.as_ptr() as *const c_uchar;
            let length = cmp::min(der.len(), c_long::max_value() as usize) as c_long;
            let p12 = try_ssl_null!(ffi::d2i_PKCS12(ptr::null_mut(), &mut ptr, length));
            Ok(Pkcs12(p12))
        }
    }

    pub fn parse(&self, pass: &str) -> Result<ParsedPkcs12, ErrorStack> {
        unsafe {
            let pass = CString::new(pass).unwrap();

            let mut pkey = ptr::null_mut();
            let mut cert = ptr::null_mut();
            let mut chain = ptr::null_mut();

            try_ssl!(ffi::PKCS12_parse(self.0, pass.as_ptr(), &mut pkey, &mut cert, &mut chain));

            let pkey = PKey::from_ptr(pkey);
            let cert = X509::from_ptr(cert);

            let mut chain_out = vec![];
            for i in 0..(*chain).stack.num {
                let x509 = *(*chain).stack.data.offset(i as isize) as *mut _;
                chain_out.push(X509::from_ptr(x509));
            }
            ffi::sk_free(&mut (*chain).stack);

            Ok(ParsedPkcs12 {
                pkey: pkey,
                cert: cert,
                chain: chain_out,
                _p: (),
            })
        }
    }
}

pub struct ParsedPkcs12 {
    pub pkey: PKey,
    pub cert: X509,
    pub chain: Vec<X509>,
    _p: (),
}

#[cfg(test)]
mod test {
    use crypto::hash::Type::SHA1;
    use serialize::hex::ToHex;

    use super::*;

    #[test]
    fn from_der() {
    fn parse() {
        let der = include_bytes!("../../test/identity.p12");
        Pkcs12::from_der(der).unwrap();
        let pkcs12 = Pkcs12::from_der(der).unwrap();
        let parsed = pkcs12.parse("mypass").unwrap();

        assert_eq!(parsed.cert.fingerprint(SHA1).unwrap().to_hex(),
                   "59172d9313e84459bcff27f967e79e6e9217e584");

        assert_eq!(parsed.chain.len(), 1);
        assert_eq!(parsed.chain[0].fingerprint(SHA1).unwrap().to_hex(),
                   "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875");
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -933,7 +933,7 @@ impl<'a> SslRef<'a> {
            if ptr.is_null() {
                None
            } else {
                Some(X509::new(ptr))
                Some(X509::from_ptr(ptr))
            }
        }
    }
+18 −6
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@ impl X509StoreContext {
            if ptr.is_null() {
                None
            } else {
                Some(X509Ref::new(ptr))
                Some(X509Ref::from_ptr(ptr))
            }
        }
    }
@@ -298,7 +298,7 @@ impl X509Generator {

        unsafe {
            let x509 = try_ssl_null!(ffi::X509_new());
            let x509 = X509::new(x509);
            let x509 = X509::from_ptr(x509);

            try_ssl!(ffi::X509_set_version(x509.as_ptr(), 2));
            try_ssl!(ffi::ASN1_INTEGER_set(ffi::X509_get_serialNumber(x509.as_ptr()),
@@ -377,8 +377,14 @@ pub struct X509Ref<'a>(*mut ffi::X509, PhantomData<&'a ()>);

impl<'a> X509Ref<'a> {
    /// Creates a new `X509Ref` wrapping the provided handle.
    pub unsafe fn new(handle: *mut ffi::X509) -> X509Ref<'a> {
        X509Ref(handle, PhantomData)
    pub unsafe fn from_ptr(x509: *mut ffi::X509) -> X509Ref<'a> {
        X509Ref(x509, PhantomData)
    }

    ///
    #[deprecated(note = "renamed to `X509::from_ptr`", since = "0.8.1")]
    pub unsafe fn new(x509: *mut ffi::X509) -> X509Ref<'a> {
        X509Ref::from_ptr(x509)
    }

    pub fn as_ptr(&self) -> *mut ffi::X509 {
@@ -451,8 +457,14 @@ pub struct X509(X509Ref<'static>);

impl X509 {
    /// Returns a new `X509`, taking ownership of the handle.
    pub unsafe fn from_ptr(x509: *mut ffi::X509) -> X509 {
        X509(X509Ref::from_ptr(x509))
    }

    ///
    #[deprecated(note = "renamed to `X509::from_ptr`", since = "0.8.1")]
    pub unsafe fn new(x509: *mut ffi::X509) -> X509 {
        X509(X509Ref::new(x509))
        X509::from_ptr(x509)
    }

    /// Reads a certificate from PEM.
@@ -463,7 +475,7 @@ impl X509 {
                                                              ptr::null_mut(),
                                                              None,
                                                              ptr::null_mut()));
            Ok(X509::new(handle))
            Ok(X509::from_ptr(handle))
        }
    }
}