Commit d2078974 authored by Steven Fackler's avatar Steven Fackler
Browse files

Parameterize keys over what they contain

Closes #790
parent 6238b4a2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1723,6 +1723,7 @@ extern "C" {
    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_up_ref(key: *mut EC_KEY) -> c_int;
    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;
+7 −4
Original line number Diff line number Diff line
@@ -7,14 +7,14 @@ use openssl::asn1::Asn1Time;
use openssl::bn::{BigNum, MsbOption};
use openssl::error::ErrorStack;
use openssl::hash::MessageDigest;
use openssl::pkey::{PKey, PKeyRef};
use openssl::pkey::{PKey, PKeyRef, Private};
use openssl::rsa::Rsa;
use openssl::x509::{X509, X509NameBuilder, X509Ref, X509Req, X509ReqBuilder, X509VerifyResult};
use openssl::x509::extension::{AuthorityKeyIdentifier, BasicConstraints, KeyUsage,
                               SubjectAlternativeName, SubjectKeyIdentifier};

/// Make a CA certificate and private key
fn mk_ca_cert() -> Result<(X509, PKey), ErrorStack> {
fn mk_ca_cert() -> Result<(X509, PKey<Private>), ErrorStack> {
    let rsa = Rsa::generate(2048)?;
    let privkey = PKey::from_rsa(rsa)?;

@@ -59,7 +59,7 @@ fn mk_ca_cert() -> Result<(X509, PKey), ErrorStack> {
}

/// Make a X509 request with the given private key
fn mk_request(privkey: &PKey) -> Result<(X509Req), ErrorStack> {
fn mk_request(privkey: &PKey<Private>) -> Result<X509Req, ErrorStack> {
    let mut req_builder = X509ReqBuilder::new()?;
    req_builder.set_pubkey(&privkey)?;

@@ -77,7 +77,10 @@ fn mk_request(privkey: &PKey) -> Result<(X509Req), ErrorStack> {
}

/// Make a certificate and private key signed by the given CA cert and private key
fn mk_ca_signed_cert(ca_cert: &X509Ref, ca_privkey: &PKeyRef) -> Result<(X509, PKey), ErrorStack> {
fn mk_ca_signed_cert(
    ca_cert: &X509Ref,
    ca_privkey: &PKeyRef<Private>,
) -> Result<(X509, PKey<Private>), ErrorStack> {
    let rsa = Rsa::generate(2048)?;
    let privkey = PKey::from_rsa(rsa)?;

+8 −12
Original line number Diff line number Diff line
@@ -8,15 +8,12 @@
use ffi;
use foreign_types::{ForeignType, ForeignTypeRef};
use std::ptr;
use error::ErrorStack;

use {cvt, cvt_p};
use bio::{MemBio, MemBioSlice};

use error::ErrorStack;
use pkey::{HasPrivate, PKeyRef};
use x509::X509;
use pkey::PKeyRef;

use cvt;
use cvt_p;

foreign_type_and_impl_send_sync! {
    type CType = ffi::CMS_ContentInfo;
@@ -44,7 +41,10 @@ impl CmsContentInfoRef {
    /// OpenSSL documentation at [`CMS_decrypt`]
    ///
    /// [`CMS_decrypt`]: https://www.openssl.org/docs/man1.1.0/crypto/CMS_decrypt.html
    pub fn decrypt(&self, pkey: &PKeyRef, cert: &X509) -> Result<Vec<u8>, ErrorStack> {
    pub fn decrypt<T>(&self, pkey: &PKeyRef<T>, cert: &X509) -> Result<Vec<u8>, ErrorStack>
    where
        T: HasPrivate,
    {
        unsafe {
            let pkey = pkey.as_ptr();
            let cert = cert.as_ptr();
@@ -63,7 +63,6 @@ impl CmsContentInfoRef {
            Ok(out.get_buf().to_owned())
        }
    }

}

impl CmsContentInfo {
@@ -76,10 +75,7 @@ impl CmsContentInfo {
        unsafe {
            let bio = MemBioSlice::new(smime)?;

            let cms = cvt_p(ffi::SMIME_read_CMS(
                bio.as_ptr(),
                ptr::null_mut(),
            ))?;
            let cms = cvt_p(ffi::SMIME_read_CMS(bio.as_ptr(), ptr::null_mut()))?;

            Ok(CmsContentInfo::from_ptr(cms))
        }

openssl/src/derive.rs

0 → 100644
+120 −0
Original line number Diff line number Diff line
//! Shared secret derivation.
use ffi;
use std::marker::PhantomData;
use std::ptr;
use foreign_types::ForeignTypeRef;

use {cvt, cvt_p};
use error::ErrorStack;
use pkey::{HasPrivate, HasPublic, PKeyRef};

/// A type used to derive a shared secret between two keys.
pub struct Deriver<'a>(*mut ffi::EVP_PKEY_CTX, PhantomData<&'a ()>);

impl<'a> Deriver<'a> {
    /// Creates a new `Deriver` using the provided private key.
    ///
    /// This corresponds to [`EVP_PKEY_derive_init`].
    ///
    /// [`EVP_PKEY_derive_init`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html
    pub fn new<T>(key: &'a PKeyRef<T>) -> Result<Deriver<'a>, ErrorStack>
    where
        T: HasPrivate,
    {
        unsafe {
            cvt_p(ffi::EVP_PKEY_CTX_new(key.as_ptr(), ptr::null_mut()))
                .map(|p| Deriver(p, PhantomData))
                .and_then(|ctx| cvt(ffi::EVP_PKEY_derive_init(ctx.0)).map(|_| ctx))
        }
    }

    /// Sets the peer key used for secret derivation.
    ///
    /// This corresponds to [`EVP_PKEY_derive_set_peer`]:
    ///
    /// [`EVP_PKEY_derive_set_peer`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html
    pub fn set_peer<T>(&mut self, key: &'a PKeyRef<T>) -> Result<(), ErrorStack>
    where
        T: HasPublic,
    {
        unsafe { cvt(ffi::EVP_PKEY_derive_set_peer(self.0, key.as_ptr())).map(|_| ()) }
    }

    /// Returns the size of the shared secret.
    ///
    /// It can be used to size the buffer passed to [`Deriver::derive`].
    ///
    /// This corresponds to [`EVP_PKEY_derive`].
    ///
    /// [`Deriver::derive`]: #method.derive
    /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html
    pub fn len(&mut self) -> Result<usize, ErrorStack> {
        unsafe {
            let mut len = 0;
            cvt(ffi::EVP_PKEY_derive(self.0, ptr::null_mut(), &mut len)).map(|_| len)
        }
    }

    /// Derives a shared secret between the two keys, writing it into the buffer.
    ///
    /// Returns the number of bytes written.
    ///
    /// This corresponds to [`EVP_PKEY_derive`].
    ///
    /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html
    pub fn derive(&mut self, buf: &mut [u8]) -> Result<usize, ErrorStack> {
        let mut len = buf.len();
        unsafe {
            cvt(ffi::EVP_PKEY_derive(
                self.0,
                buf.as_mut_ptr() as *mut _,
                &mut len,
            )).map(|_| len)
        }
    }

    /// A convenience function which derives a shared secret and returns it in a new buffer.
    ///
    /// This simply wraps [`Deriver::len`] and [`Deriver::derive`].
    ///
    /// [`Deriver::len`]: #method.len
    /// [`Deriver::derive`]: #method.derive
    pub fn derive_to_vec(&mut self) -> Result<Vec<u8>, ErrorStack> {
        let len = self.len()?;
        let mut buf = vec![0; len];
        let len = self.derive(&mut buf)?;
        buf.truncate(len);
        Ok(buf)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    use ec::{EcGroup, EcKey};
    use nid::Nid;
    use pkey::PKey;

    #[test]
    fn derive_without_peer() {
        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
        let ec_key = EcKey::generate(&group).unwrap();
        let pkey = PKey::from_ec_key(ec_key).unwrap();
        let mut deriver = Deriver::new(&pkey).unwrap();
        deriver.derive_to_vec().unwrap_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 deriver = Deriver::new(&pkey).unwrap();
        deriver.set_peer(&pkey2).unwrap();
        let shared = deriver.derive_to_vec().unwrap();
        assert!(!shared.is_empty());
    }
}
+20 −16
Original line number Diff line number Diff line
use error::ErrorStack;
use ffi;
use foreign_types::ForeignTypeRef;
use foreign_types::{ForeignType, ForeignTypeRef};
use std::mem;
use std::ptr;

use {cvt, cvt_p};
use bn::BigNum;
use pkey::{HasParams, Params};

foreign_type_and_impl_send_sync! {
generic_foreign_type_and_impl_send_sync! {
    type CType = ffi::DH;
    fn drop = ffi::DH_free;

    pub struct Dh;
    pub struct Dh<T>;

    pub struct DhRef;
    pub struct DhRef<T>;
}

impl DhRef {
impl<T> DhRef<T>
where
    T: HasParams,
{
    to_pem!(ffi::PEM_write_bio_DHparams);
    to_der!(ffi::i2d_DHparams);
}

impl Dh {
    pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result<Dh, ErrorStack> {
impl Dh<Params> {
    pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result<Dh<Params>, ErrorStack> {
        unsafe {
            let dh = Dh(cvt_p(ffi::DH_new())?);
            let dh = Dh::from_ptr(cvt_p(ffi::DH_new())?);
            cvt(compat::DH_set0_pqg(
                dh.0,
                p.as_ptr(),
@@ -36,33 +40,33 @@ impl Dh {
        }
    }

    from_pem!(Dh, ffi::PEM_read_bio_DHparams);
    from_der!(Dh, ffi::d2i_DHparams);
    from_pem!(Dh<Params>, ffi::PEM_read_bio_DHparams);
    from_der!(Dh<Params>, ffi::d2i_DHparams);

    /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
    #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
    pub fn get_1024_160() -> Result<Dh, ErrorStack> {
    pub fn get_1024_160() -> Result<Dh<Params>, ErrorStack> {
        unsafe {
            ffi::init();
            cvt_p(ffi::DH_get_1024_160()).map(Dh)
            cvt_p(ffi::DH_get_1024_160()).map(|p| Dh::from_ptr(p))
        }
    }

    /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
    #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
    pub fn get_2048_224() -> Result<Dh, ErrorStack> {
    pub fn get_2048_224() -> Result<Dh<Params>, ErrorStack> {
        unsafe {
            ffi::init();
            cvt_p(ffi::DH_get_2048_224()).map(Dh)
            cvt_p(ffi::DH_get_2048_224()).map(|p| Dh::from_ptr(p))
        }
    }

    /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
    #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
    pub fn get_2048_256() -> Result<Dh, ErrorStack> {
    pub fn get_2048_256() -> Result<Dh<Params>, ErrorStack> {
        unsafe {
            ffi::init();
            cvt_p(ffi::DH_get_2048_256()).map(Dh)
            cvt_p(ffi::DH_get_2048_256()).map(|p| Dh::from_ptr(p))
        }
    }
}
Loading