Merge pull request #613 from aosmond/add_evp_pkey_derive

Add new EC/PKEY methods to permit deriving shared secrets.
This commit is contained in:
Steven Fackler 2017-04-11 10:04:57 -07:00 committed by GitHub
commit 3439ec6f41
3 changed files with 75 additions and 7 deletions

View File

@ -1510,6 +1510,7 @@ extern {
pub fn EC_KEY_new() -> *mut EC_KEY;
pub fn EC_KEY_new_by_curve_name(nid: c_int) -> *mut EC_KEY;
pub fn EC_KEY_dup(key: *const EC_KEY) -> *mut EC_KEY;
pub fn EC_KEY_set_group(key: *mut EC_KEY, group: *const EC_GROUP) -> c_int;
pub fn EC_KEY_get0_group(key: *const EC_KEY) -> *const EC_GROUP;
pub fn EC_KEY_set_public_key(key: *mut EC_KEY, key: *const EC_POINT) -> c_int;
@ -1650,8 +1651,13 @@ extern {
e: *mut ENGINE,
key: *const c_uchar,
keylen: c_int) -> *mut EVP_PKEY;
pub fn EVP_PKEY_derive_init(ctx: *mut EVP_PKEY_CTX) -> c_int;
pub fn EVP_PKEY_derive_set_peer(ctx: *mut EVP_PKEY_CTX, peer: *mut EVP_PKEY) -> c_int;
pub fn EVP_PKEY_derive(ctx: *mut EVP_PKEY_CTX, key: *mut c_uchar, size: *mut size_t) -> c_int;
pub fn d2i_PKCS8PrivateKey_bio(bp: *mut BIO, x: *mut *mut EVP_PKEY, cb: Option<PasswordCallback>, u: *mut c_void) -> *mut EVP_PKEY;
pub fn EVP_PKEY_CTX_new(k: *mut EVP_PKEY, e: *mut ENGINE) -> *mut EVP_PKEY_CTX;
pub fn EVP_PKEY_CTX_free(ctx: *mut EVP_PKEY_CTX);
pub fn EVP_PKEY_CTX_ctrl(ctx: *mut EVP_PKEY_CTX, keytype: c_int, optype: c_int, cmd: c_int, p1: c_int, p2: *mut c_void) -> c_int;
pub fn HMAC_CTX_copy(dst: *mut HMAC_CTX, src: *mut HMAC_CTX) -> c_int;

View File

@ -314,6 +314,10 @@ impl EcKeyRef {
pub fn check_key(&self) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) }
}
pub fn to_owned(&self) -> Result<EcKey, ErrorStack> {
unsafe { cvt_p(ffi::EC_KEY_dup(self.as_ptr())).map(EcKey) }
}
}
impl EcKey {
@ -440,6 +444,13 @@ mod test {
key.private_key().unwrap();
}
#[test]
fn dup() {
let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap();
let key = EcKey::generate(&group).unwrap();
key.to_owned().unwrap();
}
#[test]
fn point_new() {
let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap();

View File

@ -1,9 +1,9 @@
use libc::{c_void, c_char, c_int};
use libc::{c_void, c_char, c_int, size_t};
use std::ptr;
use std::mem;
use std::ffi::CString;
use ffi;
use foreign_types::{Opaque, ForeignType, ForeignTypeRef};
use foreign_types::{ForeignType, ForeignTypeRef};
use {cvt, cvt_p};
use bio::MemBioSlice;
@ -199,7 +199,25 @@ impl PKey {
}
}
pub struct PKeyCtxRef(Opaque);
foreign_type! {
type CType = ffi::EVP_PKEY_CTX;
fn drop = ffi::EVP_PKEY_CTX_free;
pub struct PKeyCtx;
pub struct PKeyCtxRef;
}
unsafe impl Send for PKeyCtx {}
unsafe impl Sync for PKeyCtx {}
impl PKeyCtx {
pub fn from_pkey(pkey: &PKeyRef) -> Result<PKeyCtx, ErrorStack> {
unsafe {
let evp = try!(cvt_p(ffi::EVP_PKEY_CTX_new(pkey.as_ptr(), ptr::null_mut())));
Ok(PKeyCtx(evp))
}
}
}
impl PKeyCtxRef {
pub fn set_rsa_padding(&mut self, pad: Padding) -> Result<(), ErrorStack> {
@ -216,10 +234,29 @@ impl PKeyCtxRef {
};
Ok(Padding::from_raw(pad))
}
}
impl ForeignTypeRef for PKeyCtxRef {
type CType = ffi::EVP_PKEY_CTX;
pub fn derive_init(&mut self) -> Result<(), ErrorStack> {
unsafe {
try!(cvt(ffi::EVP_PKEY_derive_init(self.as_ptr())));
}
Ok(())
}
pub fn derive_set_peer(&mut self, peer: &PKeyRef) -> Result<(), ErrorStack> {
unsafe {
try!(cvt(ffi::EVP_PKEY_derive_set_peer(self.as_ptr(), peer.as_ptr())));
}
Ok(())
}
pub fn derive(&mut self) -> Result<Vec<u8>, ErrorStack> {
let mut len: size_t = 0;
unsafe { try!(cvt(ffi::EVP_PKEY_derive(self.as_ptr(), ptr::null_mut(), &mut len))); }
let mut key = vec![0u8; len];
unsafe { try!(cvt(ffi::EVP_PKEY_derive(self.as_ptr(), key.as_mut_ptr(), &mut len))); }
Ok(key)
}
}
#[cfg(test)]
@ -227,7 +264,7 @@ mod tests {
use symm::Cipher;
use dh::Dh;
use dsa::Dsa;
use ec::EcKey;
use ec::{EcGroup, EcKey};
use rsa::Rsa;
use nid;
@ -319,4 +356,18 @@ mod tests {
pkey.ec_key().unwrap();
assert!(pkey.rsa().is_err());
}
#[test]
fn test_ec_key_derive() {
let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap();
let ec_key = EcKey::generate(&group).unwrap();
let ec_key2 = EcKey::generate(&group).unwrap();
let pkey = PKey::from_ec_key(ec_key).unwrap();
let pkey2 = PKey::from_ec_key(ec_key2).unwrap();
let mut pkey_ctx = PKeyCtx::from_pkey(&pkey).unwrap();
pkey_ctx.derive_init().unwrap();
pkey_ctx.derive_set_peer(&pkey2).unwrap();
let shared = pkey_ctx.derive().unwrap();
assert!(!shared.is_empty());
}
}