Commit 3439ec6f authored by Steven Fackler's avatar Steven Fackler Committed by GitHub
Browse files

Merge pull request #613 from aosmond/add_evp_pkey_derive

Add new EC/PKEY methods to permit deriving shared secrets.
parents fc1bcecf e6a6ebb8
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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;
+11 −0
Original line number Diff line number Diff line
@@ -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();
+58 −7
Original line number Diff line number Diff line
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))
    }

    pub fn derive_init(&mut self) -> Result<(), ErrorStack> {
        unsafe {
            try!(cvt(ffi::EVP_PKEY_derive_init(self.as_ptr())));
        }
        Ok(())
    }

impl ForeignTypeRef for PKeyCtxRef {
    type CType = ffi::EVP_PKEY_CTX;
    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());
    }
}