diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 2dbb6022ae8030a9109aa4e898cf7b3f0c61915d..f8b679aa36473687cbf048a98fd46873594e2b37 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -39,25 +39,25 @@ //! let pub_key: Vec = 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 { #[cfg(ossl110)] #[allow(clippy::trivially_copy_pass_by_ref)] pub fn cmac(cipher: &Cipher, key: &[u8]) -> Result, 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)] diff --git a/openssl/src/pkey_ctx.rs b/openssl/src/pkey_ctx.rs index 76861458f011e6712de2a6753063221ea42b0a42..4a8b4eb0d44c916ab0ee94afed1367050514fb10 100644 --- a/openssl/src/pkey_ctx.rs +++ b/openssl/src/pkey_ctx.rs @@ -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 PkeyCtx { + /// 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) -> Result { unsafe { @@ -53,6 +72,21 @@ impl PkeyCtx { } } +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 { + unsafe { + let ptr = cvt_p(ffi::EVP_PKEY_CTX_new_id(id.as_raw(), ptr::null_mut()))?; + Ok(PkeyCtx::from_ptr(ptr)) + } + } +} + impl PkeyCtxRef where T: HasPublic, @@ -220,6 +254,19 @@ where } impl PkeyCtxRef { + /// 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 PkeyCtxRef { 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, 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(); + } }