Merge pull request #1196 from oberien/private-key-from-pkcs8

Support for PKCS#8 unencrypted private key deserialization
This commit is contained in:
Steven Fackler 2019-12-03 21:37:21 -05:00 committed by GitHub
commit 9ccddf7abc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 51 additions and 1 deletions

View File

@ -405,6 +405,18 @@ extern "C" {
pub fn EVP_PKEY_keygen(ctx: *mut EVP_PKEY_CTX, key: *mut *mut EVP_PKEY) -> c_int; pub fn EVP_PKEY_keygen(ctx: *mut EVP_PKEY_CTX, key: *mut *mut EVP_PKEY) -> c_int;
} }
cfg_if! {
if #[cfg(any(ossl110, libressl280))] {
extern "C" {
pub fn EVP_PKCS82PKEY(p8: *const PKCS8_PRIV_KEY_INFO) -> *mut EVP_PKEY;
}
} else {
extern "C" {
pub fn EVP_PKCS82PKEY(p8: *mut PKCS8_PRIV_KEY_INFO) -> *mut EVP_PKEY;
}
}
}
extern "C" { extern "C" {
pub fn EVP_EncodeBlock(dst: *mut c_uchar, src: *const c_uchar, src_len: c_int) -> c_int; pub fn EVP_EncodeBlock(dst: *mut c_uchar, src: *const c_uchar, src_len: c_int) -> c_int;
pub fn EVP_DecodeBlock(dst: *mut c_uchar, src: *const c_uchar, src_len: c_int) -> c_int; pub fn EVP_DecodeBlock(dst: *mut c_uchar, src: *const c_uchar, src_len: c_int) -> c_int;

View File

@ -123,6 +123,8 @@ cfg_if! {
} }
} }
pub enum PKCS8_PRIV_KEY_INFO {}
pub enum EVP_PKEY_ASN1_METHOD {} pub enum EVP_PKEY_ASN1_METHOD {}
pub enum EVP_PKEY_CTX {} pub enum EVP_PKEY_CTX {}

View File

@ -137,6 +137,14 @@ extern "C" {
cb: pem_password_cb, cb: pem_password_cb,
u: *mut c_void, u: *mut c_void,
) -> *mut EVP_PKEY; ) -> *mut EVP_PKEY;
pub fn d2i_PKCS8_PRIV_KEY_INFO(
k: *mut *mut PKCS8_PRIV_KEY_INFO,
buf: *mut *const u8,
length: c_long,
) -> *mut PKCS8_PRIV_KEY_INFO;
pub fn PKCS8_PRIV_KEY_INFO_free(
p8inf: *mut PKCS8_PRIV_KEY_INFO,
);
pub fn PEM_read_bio_PKCS7( pub fn PEM_read_bio_PKCS7(
bio: *mut BIO, bio: *mut BIO,

View File

@ -47,7 +47,7 @@
use ffi; use ffi;
use foreign_types::{ForeignType, ForeignTypeRef}; use foreign_types::{ForeignType, ForeignTypeRef};
use libc::c_int; use libc::{c_int, c_long};
use std::ffi::CString; use std::ffi::CString;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
@ -524,6 +524,28 @@ impl PKey<Private> {
ffi::d2i_AutoPrivateKey ffi::d2i_AutoPrivateKey
} }
/// Deserializes a DER-formatted PKCS#8 unencrypted private key.
///
/// This method is mainly for interoperability reasons. Encrypted keyfiles should be preferred.
pub fn private_key_from_pkcs8(
der: &[u8],
) -> Result<PKey<Private>, ErrorStack>
{
unsafe {
ffi::init();
let len = der.len().min(c_long::max_value() as usize) as c_long;
let p8inf = cvt_p(ffi::d2i_PKCS8_PRIV_KEY_INFO(
ptr::null_mut(),
&mut der.as_ptr(),
len,
))?;
let res = cvt_p(ffi::EVP_PKCS82PKEY(p8inf))
.map(|p| PKey::from_ptr(p));
ffi::PKCS8_PRIV_KEY_INFO_free(p8inf);
res
}
}
/// Deserializes a DER-formatted PKCS#8 private key, using a callback to retrieve the password /// Deserializes a DER-formatted PKCS#8 private key, using a callback to retrieve the password
/// if the key is encrpyted. /// if the key is encrpyted.
/// ///
@ -639,6 +661,12 @@ mod tests {
assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err()); assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err());
} }
#[test]
fn test_unencrypted_pkcs8() {
let key = include_bytes!("../test/pkcs8-nocrypt.der");
PKey::private_key_from_pkcs8(key).unwrap();
}
#[test] #[test]
fn test_encrypted_pkcs8_passphrase() { fn test_encrypted_pkcs8_passphrase() {
let key = include_bytes!("../test/pkcs8.der"); let key = include_bytes!("../test/pkcs8.der");

Binary file not shown.