Commit 7bd90dcb authored by Steven Fackler's avatar Steven Fackler Committed by GitHub
Browse files

Merge pull request #570 from brianchin/add_evp_pkey_ctx_ctrl

Add PKey context options
parents a27bc0a3 4900d3fe
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -151,6 +151,12 @@ pub const EVP_PKEY_DSA: c_int = NID_dsa;
pub const EVP_PKEY_DH: c_int = NID_dhKeyAgreement;
pub const EVP_PKEY_EC: c_int = NID_X9_62_id_ecPublicKey;

pub const EVP_PKEY_ALG_CTRL: c_int = 0x1000;

pub const EVP_PKEY_CTRL_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 1;

pub const EVP_PKEY_CTRL_GET_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 6;

pub const EVP_CTRL_GCM_SET_IVLEN: c_int = 0x9;
pub const EVP_CTRL_GCM_GET_TAG: c_int = 0x10;
pub const EVP_CTRL_GCM_SET_TAG: c_int = 0x11;
@@ -1304,6 +1310,15 @@ pub unsafe fn BIO_set_retry_write(b: *mut BIO) {
    BIO_set_flags(b, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY)
}

// EVP_PKEY_CTX_ctrl macros
pub unsafe fn EVP_PKEY_CTX_set_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad: c_int) -> c_int {
    EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_RSA_PADDING, pad, ptr::null_mut())
}

pub unsafe fn EVP_PKEY_CTX_get_rsa_padding(ctx: *mut EVP_PKEY_CTX, ppad: *mut c_int) -> c_int {
    EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_GET_RSA_PADDING, 0, ppad as *mut c_void)
}

pub unsafe fn SSL_CTX_set_mode(ctx: *mut SSL_CTX, op: c_long) -> c_long {
    SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, op, ptr::null_mut())
}
@@ -1632,6 +1647,9 @@ extern {
                                key: *const c_uchar,
                                keylen: c_int) -> *mut EVP_PKEY;


    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;

    pub fn OCSP_BASICRESP_new() -> *mut OCSP_BASICRESP;
+24 −1
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@ use bio::MemBioSlice;
use dh::Dh;
use dsa::Dsa;
use ec::EcKey;
use rsa::Rsa;
use rsa::{Rsa, Padding};
use error::ErrorStack;
use util::{CallbackState, invoke_passwd_cb_old};
use types::{OpenSslType, OpenSslTypeRef};
@@ -151,6 +151,29 @@ impl PKey {
    }
}

pub struct PKeyCtxRef(::util::Opaque);

impl PKeyCtxRef {
    pub fn set_rsa_padding(&mut self, pad: Padding) -> Result<(), ErrorStack> {
        unsafe {
            try!(cvt(ffi::EVP_PKEY_CTX_set_rsa_padding(self.as_ptr(), pad.as_raw())));
        }
        Ok(())
    }

    pub fn rsa_padding(&self) -> Result<Padding, ErrorStack> {
        let mut pad: c_int = 0;
        unsafe {
            try!(cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.as_ptr(), &mut pad)));
        };
        Ok(Padding::from_raw(pad))
    }
}

impl ::types::OpenSslTypeRef for PKeyCtxRef {
    type CType = ffi::EVP_PKEY_CTX;
}

#[cfg(test)]
mod tests {
    use symm::Cipher;
+11 −2
Original line number Diff line number Diff line
@@ -12,9 +12,19 @@ use util::{CallbackState, invoke_passwd_cb_old};
use types::OpenSslTypeRef;

/// Type of encryption padding to use.
#[derive(Copy, Clone)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Padding(c_int);

impl Padding {
    pub fn from_raw(value: c_int) -> Padding {
        Padding(value)
    }

    pub fn as_raw(&self) -> c_int {
        self.0
    }
}

pub const NO_PADDING: Padding = Padding(ffi::RSA_NO_PADDING);
pub const PKCS1_PADDING: Padding = Padding(ffi::RSA_PKCS1_PADDING);
pub const PKCS1_OAEP_PADDING: Padding = Padding(ffi::RSA_PKCS1_OAEP_PADDING);
@@ -343,7 +353,6 @@ mod compat {
    }
}


#[cfg(test)]
mod test {
    use symm::Cipher;
+59 −15
Original line number Diff line number Diff line
@@ -68,7 +68,7 @@ use std::ptr;

use {cvt, cvt_p};
use hash::MessageDigest;
use pkey::PKeyRef;
use pkey::{PKeyRef, PKeyCtxRef};
use error::ErrorStack;
use types::OpenSslTypeRef;

@@ -77,12 +77,17 @@ use ffi::{EVP_MD_CTX_new, EVP_MD_CTX_free};
#[cfg(any(ossl101, ossl102))]
use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free};

pub struct Signer<'a>(*mut ffi::EVP_MD_CTX, PhantomData<&'a PKeyRef>);
pub struct Signer<'a> {
    md_ctx: *mut ffi::EVP_MD_CTX,
    pkey_ctx: *mut ffi::EVP_PKEY_CTX,
    pkey_pd: PhantomData<&'a PKeyRef>,
}

impl<'a> Drop for Signer<'a> {
    fn drop(&mut self) {
        // pkey_ctx is owned by the md_ctx, so no need to explicitly free it.
        unsafe {
            EVP_MD_CTX_free(self.0);
            EVP_MD_CTX_free(self.md_ctx);
        }
    }
}
@@ -93,8 +98,9 @@ impl<'a> Signer<'a> {
            ffi::init();

            let ctx = try!(cvt_p(EVP_MD_CTX_new()));
            let mut pctx: *mut ffi::EVP_PKEY_CTX = ptr::null_mut();
            let r = ffi::EVP_DigestSignInit(ctx,
                                            ptr::null_mut(),
                                            &mut pctx,
                                            type_.as_ptr(),
                                            ptr::null_mut(),
                                            pkey.as_ptr());
@@ -102,22 +108,37 @@ impl<'a> Signer<'a> {
                EVP_MD_CTX_free(ctx);
                return Err(ErrorStack::get());
            }
            Ok(Signer(ctx, PhantomData))

            assert!(!pctx.is_null());

            Ok(Signer {
                md_ctx: ctx,
                pkey_ctx: pctx,
                pkey_pd: PhantomData,
            })
        }
    }

    pub fn pkey_ctx(&self) -> &PKeyCtxRef {
        unsafe { ::types::OpenSslTypeRef::from_ptr(self.pkey_ctx) }
    }

    pub fn pkey_ctx_mut(&mut self) -> &mut PKeyCtxRef {
        unsafe { ::types::OpenSslTypeRef::from_ptr_mut(self.pkey_ctx) }
    }

    pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> {
        unsafe {
            cvt(ffi::EVP_DigestUpdate(self.0, buf.as_ptr() as *const _, buf.len())).map(|_| ())
            cvt(ffi::EVP_DigestUpdate(self.md_ctx, buf.as_ptr() as *const _, buf.len())).map(|_| ())
        }
    }

    pub fn finish(&self) -> Result<Vec<u8>, ErrorStack> {
        unsafe {
            let mut len = 0;
            try!(cvt(ffi::EVP_DigestSignFinal(self.0, ptr::null_mut(), &mut len)));
            try!(cvt(ffi::EVP_DigestSignFinal(self.md_ctx, ptr::null_mut(), &mut len)));
            let mut buf = vec![0; len];
            try!(cvt(ffi::EVP_DigestSignFinal(self.0, buf.as_mut_ptr() as *mut _, &mut len)));
            try!(cvt(ffi::EVP_DigestSignFinal(self.md_ctx, buf.as_mut_ptr() as *mut _, &mut len)));
            // The advertised length is not always equal to the real length for things like DSA
            buf.truncate(len);
            Ok(buf)
@@ -136,12 +157,17 @@ impl<'a> Write for Signer<'a> {
    }
}

pub struct Verifier<'a>(*mut ffi::EVP_MD_CTX, PhantomData<&'a PKeyRef>);
pub struct Verifier<'a> {
    md_ctx: *mut ffi::EVP_MD_CTX,
    pkey_ctx: *mut ffi::EVP_PKEY_CTX,
    pkey_pd: PhantomData<&'a PKeyRef>,
}

impl<'a> Drop for Verifier<'a> {
    fn drop(&mut self) {
        // pkey_ctx is owned by the md_ctx, so no need to explicitly free it.
        unsafe {
            EVP_MD_CTX_free(self.0);
            EVP_MD_CTX_free(self.md_ctx);
        }
    }
}
@@ -152,8 +178,9 @@ impl<'a> Verifier<'a> {
            ffi::init();

            let ctx = try!(cvt_p(EVP_MD_CTX_new()));
            let mut pctx: *mut ffi::EVP_PKEY_CTX = ptr::null_mut();
            let r = ffi::EVP_DigestVerifyInit(ctx,
                                              ptr::null_mut(),
                                              &mut pctx,
                                              type_.as_ptr(),
                                              ptr::null_mut(),
                                              pkey.as_ptr());
@@ -162,19 +189,33 @@ impl<'a> Verifier<'a> {
                return Err(ErrorStack::get());
            }

            Ok(Verifier(ctx, PhantomData))
            assert!(!pctx.is_null());

            Ok(Verifier {
                md_ctx: ctx,
                pkey_ctx: pctx,
                pkey_pd: PhantomData,
            })
        }
    }

    pub fn pkey_ctx(&self) -> &PKeyCtxRef {
        unsafe { ::types::OpenSslTypeRef::from_ptr(self.pkey_ctx) }
    }

    pub fn pkey_ctx_mut(&mut self) -> &mut PKeyCtxRef {
        unsafe { ::types::OpenSslTypeRef::from_ptr_mut(self.pkey_ctx) }
    }

    pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> {
        unsafe {
            cvt(ffi::EVP_DigestUpdate(self.0, buf.as_ptr() as *const _, buf.len())).map(|_| ())
            cvt(ffi::EVP_DigestUpdate(self.md_ctx, buf.as_ptr() as *const _, buf.len())).map(|_| ())
        }
    }

    pub fn finish(&self, signature: &[u8]) -> Result<bool, ErrorStack> {
        unsafe {
            let r = EVP_DigestVerifyFinal(self.0, signature.as_ptr() as *const _, signature.len());
            let r = EVP_DigestVerifyFinal(self.md_ctx, signature.as_ptr() as *const _, signature.len());
            match r {
                1 => Ok(true),
                0 => {
@@ -219,7 +260,7 @@ mod test {
    use sign::{Signer, Verifier};
    use ec::{EcGroup, EcKey};
    use nid;
    use rsa::Rsa;
    use rsa::{Rsa, PKCS1_PADDING};
    use dsa::Dsa;
    use pkey::PKey;

@@ -254,6 +295,8 @@ mod test {
        let pkey = PKey::from_rsa(private_key).unwrap();

        let mut signer = Signer::new(MessageDigest::sha256(), &pkey).unwrap();
        assert_eq!(signer.pkey_ctx_mut().rsa_padding().unwrap(), PKCS1_PADDING);
        signer.pkey_ctx_mut().set_rsa_padding(PKCS1_PADDING).unwrap();
        signer.update(INPUT).unwrap();
        let result = signer.finish().unwrap();

@@ -267,6 +310,7 @@ mod test {
        let pkey = PKey::from_rsa(private_key).unwrap();

        let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap();
        assert_eq!(verifier.pkey_ctx_mut().rsa_padding().unwrap(), PKCS1_PADDING);
        verifier.update(INPUT).unwrap();
        assert!(verifier.finish(SIGNATURE).unwrap());
    }