Unverified Commit 58fbb56e authored by Steven Fackler's avatar Steven Fackler
Browse files

PkeyCtx keygen

parent 73cd5e9c
Loading
Loading
Loading
Loading
+16 −61
Original line number Diff line number Diff line
@@ -39,25 +39,25 @@
//! let pub_key: Vec<u8> = pkey.public_key_to_pem().unwrap();
//! println!("{:?}", str::from_utf8(pub_key.as_slice()).unwrap());
//! ```

use cfg_if::cfg_if;
use foreign_types::{ForeignType, ForeignTypeRef};
use libc::{c_int, c_long};
use std::convert::TryFrom;
use std::ffi::CString;
use std::fmt;
use std::mem;
use std::ptr;

use crate::bio::{MemBio, MemBioSlice};
use crate::cipher::CipherRef;
use crate::dh::Dh;
use crate::dsa::Dsa;
use crate::ec::EcKey;
use crate::error::ErrorStack;
use crate::pkey_ctx::PkeyCtx;
use crate::rsa::Rsa;
use crate::symm::Cipher;
use crate::util::{invoke_passwd_cb, CallbackState};
use crate::{cvt, cvt_p};
use cfg_if::cfg_if;
use foreign_types::{ForeignType, ForeignTypeRef};
use libc::{c_int, c_long};
use std::convert::TryFrom;
use std::ffi::CString;
use std::fmt;
use std::mem;
use std::ptr;

/// A tag type indicating that a key only has parameters.
pub enum Params {}
@@ -75,6 +75,7 @@ pub struct Id(c_int);
impl Id {
    pub const RSA: Id = Id(ffi::EVP_PKEY_RSA);
    pub const HMAC: Id = Id(ffi::EVP_PKEY_HMAC);
    pub const CMAC: Id = Id(ffi::EVP_PKEY_CMAC);
    pub const DSA: Id = Id(ffi::EVP_PKEY_DSA);
    pub const DH: Id = Id(ffi::EVP_PKEY_DH);
    pub const EC: Id = Id(ffi::EVP_PKEY_EC);
@@ -503,57 +504,11 @@ impl PKey<Private> {
    #[cfg(ossl110)]
    #[allow(clippy::trivially_copy_pass_by_ref)]
    pub fn cmac(cipher: &Cipher, key: &[u8]) -> Result<PKey<Private>, ErrorStack> {
        unsafe {
            assert!(key.len() <= c_int::max_value() as usize);
            let kctx = cvt_p(ffi::EVP_PKEY_CTX_new_id(
                ffi::EVP_PKEY_CMAC,
                ptr::null_mut(),
            ))?;

            let ret = (|| {
                cvt(ffi::EVP_PKEY_keygen_init(kctx))?;

                // Set cipher for cmac
                cvt(ffi::EVP_PKEY_CTX_ctrl(
                    kctx,
                    -1,
                    ffi::EVP_PKEY_OP_KEYGEN,
                    ffi::EVP_PKEY_CTRL_CIPHER,
                    0,
                    cipher.as_ptr() as *mut _,
                ))?;

                // Set the key data
                cvt(ffi::EVP_PKEY_CTX_ctrl(
                    kctx,
                    -1,
                    ffi::EVP_PKEY_OP_KEYGEN,
                    ffi::EVP_PKEY_CTRL_SET_MAC_KEY,
                    key.len() as c_int,
                    key.as_ptr() as *mut _,
                ))?;
                Ok(())
            })();

            if let Err(e) = ret {
                // Free memory
                ffi::EVP_PKEY_CTX_free(kctx);
                return Err(e);
            }

            // Generate key
            let mut key = ptr::null_mut();
            let ret = cvt(ffi::EVP_PKEY_keygen(kctx, &mut key));

            // Free memory
            ffi::EVP_PKEY_CTX_free(kctx);

            if let Err(e) = ret {
                return Err(e);
            }

            Ok(PKey::from_ptr(key))
        }
        let mut ctx = PkeyCtx::new_id(Id::CMAC)?;
        ctx.keygen_init()?;
        ctx.set_keygen_cipher(unsafe { CipherRef::from_ptr(cipher.as_ptr() as *mut _) })?;
        ctx.set_keygen_mac_key(key)?;
        ctx.keygen()
    }

    #[cfg(ossl111)]
+115 −2
Original line number Diff line number Diff line
@@ -19,9 +19,24 @@
//! let mut ciphertext = vec![];
//! ctx.encrypt_to_vec(data, &mut ciphertext).unwrap();
//! ```
//!
//! Generate a CMAC key
//!
//! ```
//! use openssl::pkey_ctx::PkeyCtx;
//! use openssl::pkey::Id;
//! use openssl::cipher::Cipher;
//!
//! let mut ctx = PkeyCtx::new_id(Id::CMAC).unwrap();
//! ctx.keygen_init();
//! ctx.set_keygen_cipher(Cipher::aes_128_cbc()).unwrap();
//! ctx.set_keygen_mac_key(b"0123456789abcdef").unwrap();
//! let cmac_key = ctx.keygen().unwrap();
//! ```
use crate::cipher::CipherRef;
use crate::error::ErrorStack;
use crate::md::MdRef;
use crate::pkey::{HasPrivate, HasPublic, PKeyRef};
use crate::pkey::{HasPrivate, HasPublic, Id, PKey, PKeyRef, Private};
use crate::rsa::Padding;
#[cfg(any(ossl102, libressl310))]
use crate::util;
@@ -29,7 +44,6 @@ use crate::{cvt, cvt_p};
use foreign_types::{ForeignType, ForeignTypeRef};
#[cfg(any(ossl102, libressl310))]
use libc::c_int;
#[cfg(any(ossl102, libressl310))]
use std::convert::TryFrom;
use std::ptr;

@@ -44,6 +58,11 @@ generic_foreign_type_and_impl_send_sync! {
}

impl<T> PkeyCtx<T> {
    /// Creates a new pkey context using the provided key.
    ///
    /// This corresponds to [`EVP_PKEY_CTX_new`].
    ///
    /// [`EVP_PKEY_CTX_new`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_new.html
    #[inline]
    pub fn new(pkey: &PKeyRef<T>) -> Result<Self, ErrorStack> {
        unsafe {
@@ -53,6 +72,21 @@ impl<T> PkeyCtx<T> {
    }
}

impl PkeyCtx<()> {
    /// Creates a new pkey context for the specified algorithm ID.
    ///
    /// This corresponds to [`EVP_PKEY_new_id`].
    ///
    /// [`EVP_PKEY_new_id`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_new_id.html
    #[inline]
    pub fn new_id(id: Id) -> Result<Self, ErrorStack> {
        unsafe {
            let ptr = cvt_p(ffi::EVP_PKEY_CTX_new_id(id.as_raw(), ptr::null_mut()))?;
            Ok(PkeyCtx::from_ptr(ptr))
        }
    }
}

impl<T> PkeyCtxRef<T>
where
    T: HasPublic,
@@ -220,6 +254,19 @@ where
}

impl<T> PkeyCtxRef<T> {
    /// Prepares the context for key generation.
    ///
    /// This corresponds to [`EVP_PKEY_keygen_init`].
    ///
    /// [`EVP_PKEY_keygen_init`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_keygen_init.html
    pub fn keygen_init(&mut self) -> Result<(), ErrorStack> {
        unsafe {
            cvt(ffi::EVP_PKEY_keygen_init(self.as_ptr()))?;
        }

        Ok(())
    }

    /// Returns the RSA padding mode in use.
    ///
    /// This is only useful for RSA keys.
@@ -319,11 +366,67 @@ impl<T> PkeyCtxRef<T> {

        Ok(())
    }

    /// Sets the cipher used during key generation.
    ///
    /// This corresponds to [`EVP_PKEY_CTX_ctrl`] with `EVP_PKEY_CTRL_CIPHER`.
    ///
    /// [`EVP_PKEY_CTX_ctrl`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_ctrl.html
    pub fn set_keygen_cipher(&mut self, cipher: &CipherRef) -> Result<(), ErrorStack> {
        unsafe {
            cvt(ffi::EVP_PKEY_CTX_ctrl(
                self.as_ptr(),
                -1,
                ffi::EVP_PKEY_OP_KEYGEN,
                ffi::EVP_PKEY_CTRL_CIPHER,
                0,
                cipher.as_ptr() as *mut _,
            ))?;
        }

        Ok(())
    }

    /// Sets the key MAC key used during key generation.
    ///
    /// This corresponds to [`EVP_PKEY_CTX_ctrl`] with `EVP_PKEY_CTRL_SET_MAC_KEY`.
    ///
    /// [`EVP_PKEY_CTX_ctrl`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_ctrl.html
    pub fn set_keygen_mac_key(&mut self, key: &[u8]) -> Result<(), ErrorStack> {
        let len = c_int::try_from(key.len()).unwrap();

        unsafe {
            cvt(ffi::EVP_PKEY_CTX_ctrl(
                self.as_ptr(),
                -1,
                ffi::EVP_PKEY_OP_KEYGEN,
                ffi::EVP_PKEY_CTRL_SET_MAC_KEY,
                len,
                key.as_ptr() as *mut _,
            ))?;
        }

        Ok(())
    }

    /// Generates a new public/private keypair.
    ///
    /// This corresponds to [`EVP_PKEY_keygen`].
    ///
    /// [`EVP_PKEY_keygen`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_ctrl.html
    pub fn keygen(&mut self) -> Result<PKey<Private>, ErrorStack> {
        unsafe {
            let mut key = ptr::null_mut();
            cvt(ffi::EVP_PKEY_keygen(self.as_ptr(), &mut key))?;
            Ok(PKey::from_ptr(key))
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::cipher::Cipher;
    use crate::ec::{EcGroup, EcKey};
    use crate::md::Md;
    use crate::nid::Nid;
@@ -396,4 +499,14 @@ mod test {
        let mut buf = vec![];
        ctx.derive_to_vec(&mut buf).unwrap();
    }

    #[test]
    fn cmac_keygen() {
        let mut ctx = PkeyCtx::new_id(Id::CMAC).unwrap();
        ctx.keygen_init().unwrap();
        ctx.set_keygen_cipher(Cipher::aes_128_cbc()).unwrap();
        ctx.set_keygen_mac_key(&hex::decode("9294727a3638bb1c13f48ef8158bfc9d").unwrap())
            .unwrap();
        ctx.keygen().unwrap();
    }
}