PKCS #12 support

This commit is contained in:
Steven Fackler 2016-08-14 11:11:26 -07:00
parent ad4a8cc140
commit 6b12a0cdde
4 changed files with 76 additions and 9 deletions

View File

@ -1086,6 +1086,10 @@ extern "C" {
-> c_int; -> c_int;
pub fn PKCS12_free(p12: *mut PKCS12); 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() -> c_long;
pub fn SSLeay_version(key: c_int) -> *const c_char; pub fn SSLeay_version(key: c_int) -> *const c_char;
} }

View File

@ -4,8 +4,11 @@ use ffi;
use libc::{c_long, c_uchar}; use libc::{c_long, c_uchar};
use std::cmp; use std::cmp;
use std::ptr; use std::ptr;
use std::ffi::CString;
use crypto::pkey::PKey;
use error::ErrorStack; use error::ErrorStack;
use x509::X509;
/// A PKCS #12 archive. /// A PKCS #12 archive.
pub struct Pkcs12(*mut ffi::PKCS12); pub struct Pkcs12(*mut ffi::PKCS12);
@ -19,21 +22,69 @@ impl Drop for Pkcs12 {
impl Pkcs12 { impl Pkcs12 {
pub fn from_der(der: &[u8]) -> Result<Pkcs12, ErrorStack> { pub fn from_der(der: &[u8]) -> Result<Pkcs12, ErrorStack> {
unsafe { unsafe {
ffi::init();
let mut ptr = der.as_ptr() as *const c_uchar; 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 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)); let p12 = try_ssl_null!(ffi::d2i_PKCS12(ptr::null_mut(), &mut ptr, length));
Ok(Pkcs12(p12)) 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)] #[cfg(test)]
mod test { mod test {
use crypto::hash::Type::SHA1;
use serialize::hex::ToHex;
use super::*; use super::*;
#[test] #[test]
fn from_der() { fn parse() {
let der = include_bytes!("../../test/identity.p12"); 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");
} }
} }

View File

@ -933,7 +933,7 @@ impl<'a> SslRef<'a> {
if ptr.is_null() { if ptr.is_null() {
None None
} else { } else {
Some(X509::new(ptr)) Some(X509::from_ptr(ptr))
} }
} }
} }

View File

@ -94,7 +94,7 @@ impl X509StoreContext {
if ptr.is_null() { if ptr.is_null() {
None None
} else { } else {
Some(X509Ref::new(ptr)) Some(X509Ref::from_ptr(ptr))
} }
} }
} }
@ -298,7 +298,7 @@ impl X509Generator {
unsafe { unsafe {
let x509 = try_ssl_null!(ffi::X509_new()); 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::X509_set_version(x509.as_ptr(), 2));
try_ssl!(ffi::ASN1_INTEGER_set(ffi::X509_get_serialNumber(x509.as_ptr()), 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> { impl<'a> X509Ref<'a> {
/// Creates a new `X509Ref` wrapping the provided handle. /// Creates a new `X509Ref` wrapping the provided handle.
pub unsafe fn new(handle: *mut ffi::X509) -> X509Ref<'a> { pub unsafe fn from_ptr(x509: *mut ffi::X509) -> X509Ref<'a> {
X509Ref(handle, PhantomData) 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 { pub fn as_ptr(&self) -> *mut ffi::X509 {
@ -451,8 +457,14 @@ pub struct X509(X509Ref<'static>);
impl X509 { impl X509 {
/// Returns a new `X509`, taking ownership of the handle. /// 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 { pub unsafe fn new(x509: *mut ffi::X509) -> X509 {
X509(X509Ref::new(x509)) X509::from_ptr(x509)
} }
/// Reads a certificate from PEM. /// Reads a certificate from PEM.
@ -463,7 +475,7 @@ impl X509 {
ptr::null_mut(), ptr::null_mut(),
None, None,
ptr::null_mut())); ptr::null_mut()));
Ok(X509::new(handle)) Ok(X509::from_ptr(handle))
} }
} }
} }