diff --git a/openssl-sys/src/crypto.rs b/openssl-sys/src/crypto.rs index b5b6f351edb1211fdf89b542db6b269b16630a0e..6d0ffb305b5d4f5cb85966489624ce38849d7a12 100644 --- a/openssl-sys/src/crypto.rs +++ b/openssl-sys/src/crypto.rs @@ -1,7 +1,45 @@ use libc::*; - use *; +#[cfg(ossl110)] +#[inline] +#[track_caller] +pub unsafe fn OPENSSL_malloc(num: usize) -> *mut c_void { + CRYPTO_malloc( + num, + concat!(file!(), "\0").as_ptr() as *const _, + line!() as _, + ) +} + +#[cfg(not(ossl110))] +#[inline] +#[track_caller] +pub unsafe fn OPENSSL_malloc(num: c_int) -> *mut c_void { + CRYPTO_malloc( + num, + concat!(file!(), "\0").as_ptr() as *const _, + line!() as _, + ) +} + +#[cfg(ossl110)] +#[inline] +#[track_caller] +pub unsafe fn OPENSSL_free(addr: *mut c_void) { + CRYPTO_free( + addr, + concat!(file!(), "\0").as_ptr() as *const _, + line!() as _, + ) +} + +#[cfg(not(ossl110))] +#[inline] +pub unsafe fn OPENSSL_free(addr: *mut c_void) { + CRYPTO_free(addr) +} + #[cfg(not(ossl110))] pub const CRYPTO_LOCK_X509: c_int = 3; #[cfg(not(ossl110))] diff --git a/openssl-sys/src/evp.rs b/openssl-sys/src/evp.rs index 3872ed9225c39aacb36e2434ab0f6447a94234b0..a319646dd8ad85dc4b137b2039f959175a518892 100644 --- a/openssl-sys/src/evp.rs +++ b/openssl-sys/src/evp.rs @@ -149,6 +149,16 @@ extern "C" { #[cfg(ossl111)] pub fn EVP_DigestFinalXOF(ctx: *mut EVP_MD_CTX, res: *mut u8, len: usize) -> c_int; + #[cfg(ossl300)] + pub fn EVP_MD_fetch( + ctx: *mut OSSL_LIB_CTX, + algorithm: *const c_char, + properties: *const c_char, + ) -> *mut EVP_MD; + + #[cfg(ossl300)] + pub fn EVP_MD_free(md: *mut EVP_MD); + pub fn EVP_BytesToKey( typ: *const EVP_CIPHER, md: *const EVP_MD, diff --git a/openssl/src/encrypt.rs b/openssl/src/encrypt.rs index 4f8914c81decdeab11d62990e043dda2ebe18843..e2acd3f78598a3330adde1db47351bf5fee07dee 100644 --- a/openssl/src/encrypt.rs +++ b/openssl/src/encrypt.rs @@ -169,11 +169,7 @@ impl<'a> Encrypter<'a> { #[cfg(any(ossl102, libressl310))] pub fn set_rsa_oaep_label(&mut self, label: &[u8]) -> Result<(), ErrorStack> { unsafe { - let p = cvt_p(ffi::CRYPTO_malloc( - label.len() as _, - concat!(file!(), "\0").as_ptr() as *const _, - line!() as c_int, - ))?; + let p = cvt_p(ffi::OPENSSL_malloc(label.len() as _))?; ptr::copy_nonoverlapping(label.as_ptr(), p as *mut u8, label.len()); cvt(ffi::EVP_PKEY_CTX_set0_rsa_oaep_label( @@ -183,14 +179,7 @@ impl<'a> Encrypter<'a> { )) .map(|_| ()) .map_err(|e| { - #[cfg(not(ossl110))] - ::ffi::CRYPTO_free(p as *mut c_void); - #[cfg(ossl110)] - ::ffi::CRYPTO_free( - p as *mut c_void, - concat!(file!(), "\0").as_ptr() as *const _, - line!() as c_int, - ); + ffi::OPENSSL_free(p); e }) } diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index 016d0cd828da1d4e15e7e76fa651f6324d296e69..1b4b58f93d03aa71553992091ad781ef62ecf8a5 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -153,6 +153,7 @@ pub mod fips; pub mod hash; #[cfg(ossl300)] pub mod lib_ctx; +pub mod md; pub mod memcmp; pub mod nid; #[cfg(not(osslconf = "OPENSSL_NO_OCSP"))] @@ -161,6 +162,7 @@ pub mod pkcs12; pub mod pkcs5; pub mod pkcs7; pub mod pkey; +pub mod pkey_ctx; pub mod rand; pub mod rsa; pub mod sha; @@ -173,6 +175,7 @@ pub mod symm; pub mod version; pub mod x509; +#[inline] fn cvt_p(r: *mut T) -> Result<*mut T, ErrorStack> { if r.is_null() { Err(ErrorStack::get()) @@ -181,6 +184,7 @@ fn cvt_p(r: *mut T) -> Result<*mut T, ErrorStack> { } } +#[inline] fn cvt(r: c_int) -> Result { if r <= 0 { Err(ErrorStack::get()) @@ -189,6 +193,7 @@ fn cvt(r: c_int) -> Result { } } +#[inline] fn cvt_n(r: c_int) -> Result { if r < 0 { Err(ErrorStack::get()) diff --git a/openssl/src/md.rs b/openssl/src/md.rs new file mode 100644 index 0000000000000000000000000000000000000000..87356d2bd9f183ab1f7242e49e686dd67c2d42d6 --- /dev/null +++ b/openssl/src/md.rs @@ -0,0 +1,234 @@ +#[cfg(ossl300)] +use crate::cvt_p; +#[cfg(ossl300)] +use crate::error::ErrorStack; +#[cfg(ossl300)] +use crate::lib_ctx::LibCtxRef; +use crate::nid::Nid; +use cfg_if::cfg_if; +use foreign_types::{ForeignTypeRef, Opaque}; +#[cfg(ossl300)] +use std::ffi::CString; +#[cfg(ossl300)] +use std::ptr; + +cfg_if! { + if #[cfg(ossl300)] { + use foreign_types::ForeignType; + use std::ops::{Deref, DerefMut}; + + type Inner = *mut ffi::EVP_MD; + + impl Drop for Md { + #[inline] + fn drop(&mut self) { + unsafe { + ffi::EVP_MD_free(self.as_ptr()); + } + } + } + + impl ForeignType for Md { + type CType = ffi::EVP_MD; + type Ref = MdRef; + + #[inline] + unsafe fn from_ptr(ptr: *mut Self::CType) -> Self { + Md(ptr) + } + + #[inline] + fn as_ptr(&self) -> *mut Self::CType { + self.0 + } + } + + impl Deref for Md { + type Target = MdRef; + + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { + MdRef::from_ptr(self.as_ptr()) + } + } + } + + impl DerefMut for Md { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + MdRef::from_ptr_mut(self.as_ptr()) + } + } + } + } else { + enum Inner {} + } +} + +/// A message digest algorithm. +pub struct Md(Inner); + +unsafe impl Sync for Md {} +unsafe impl Send for Md {} + +impl Md { + /// Returns the `Md` corresponding to an [`Nid`]. + /// + /// This corresponds to [`EVP_get_digestbynid`]. + /// + /// [`EVP_get_digestbynid`]: https://www.openssl.org/docs/manmaster/crypto/EVP_DigestInit.html + pub fn from_nid(type_: Nid) -> Option<&'static MdRef> { + unsafe { + let ptr = ffi::EVP_get_digestbynid(type_.as_raw()); + if ptr.is_null() { + None + } else { + Some(MdRef::from_ptr(ptr as *mut _)) + } + } + } + + /// Fetches an `Md` object corresponding to the specified algorithm name and properties. + /// + /// This corresponds to [`EVP_MD_fetch`]. + /// + /// Requires OpenSSL 3.0.0 or newer. + /// + /// [`EVP_MD_fetch`]: https://www.openssl.org/docs/manmaster/man3/EVP_MD_fetch.html + #[cfg(ossl300)] + pub fn fetch( + ctx: Option<&LibCtxRef>, + algorithm: &str, + properties: Option<&str>, + ) -> Result { + let algorithm = CString::new(algorithm).unwrap(); + let properties = properties.map(|s| CString::new(s).unwrap()); + + unsafe { + let ptr = cvt_p(ffi::EVP_MD_fetch( + ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr), + algorithm.as_ptr(), + properties.map_or(ptr::null_mut(), |s| s.as_ptr()), + ))?; + + Ok(Md::from_ptr(ptr)) + } + } + + #[inline] + pub fn null() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_md_null() as *mut _) } + } + + #[inline] + pub fn md5() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_md5() as *mut _) } + } + + #[inline] + pub fn sha1() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha1() as *mut _) } + } + + #[inline] + pub fn sha224() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha224() as *mut _) } + } + + #[inline] + pub fn sha256() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha256() as *mut _) } + } + + #[inline] + pub fn sha384() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha384() as *mut _) } + } + + #[inline] + pub fn sha512() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha512() as *mut _) } + } + + #[cfg(ossl111)] + #[inline] + pub fn sha3_224() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha3_224() as *mut _) } + } + + #[cfg(ossl111)] + #[inline] + pub fn sha3_256() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha3_256() as *mut _) } + } + + #[cfg(ossl111)] + #[inline] + pub fn sha3_384() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha3_384() as *mut _) } + } + + #[cfg(ossl111)] + #[inline] + pub fn sha3_512() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sha3_512() as *mut _) } + } + + #[cfg(ossl111)] + #[inline] + pub fn shake128() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_shake128() as *mut _) } + } + + #[cfg(ossl111)] + #[inline] + pub fn shake256() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_shake256() as *mut _) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_RMD160"))] + #[inline] + pub fn ripemd160() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_ripemd160() as *mut _) } + } + + #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))] + #[inline] + pub fn sm3() -> &'static MdRef { + unsafe { MdRef::from_ptr(ffi::EVP_sm3() as *mut _) } + } +} + +/// A reference to an [`Md`]. +pub struct MdRef(Opaque); + +impl ForeignTypeRef for MdRef { + type CType = ffi::EVP_MD; +} + +unsafe impl Sync for MdRef {} +unsafe impl Send for MdRef {} + +impl MdRef { + /// Returns the size of the digest in bytes. + /// + /// This corresponds to [`EVP_MD_size`]. + /// + /// [`EVP_MD_size`]: https://www.openssl.org/docs/manmaster/man3/EVP_MD_size.html + #[inline] + pub fn size(&self) -> usize { + unsafe { ffi::EVP_MD_size(self.as_ptr()) as usize } + } + + /// Returns the [`Nid`] of the digest. + /// + /// This corresponds to [`EVP_MD_type`]. + /// + /// [`EVP_MD_type`]: https://www.openssl.org/docs/manmaster/man3/EVP_MD_type.html + #[inline] + pub fn type_(&self) -> Nid { + unsafe { Nid::from_raw(ffi::EVP_MD_type(self.as_ptr())) } + } +} diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 2dbb6022ae8030a9109aa4e898cf7b3f0c61915d..1db6f6050bd0509233e093fe4d2a9ef60dc3dad9 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -39,25 +39,27 @@ //! 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}; +#[cfg(ossl110)] +use crate::cipher::CipherRef; use crate::dh::Dh; use crate::dsa::Dsa; use crate::ec::EcKey; use crate::error::ErrorStack; +#[cfg(ossl110)] +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 +77,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,103 +506,42 @@ 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)] - fn generate_eddsa(nid: c_int) -> Result, ErrorStack> { - unsafe { - let kctx = cvt_p(ffi::EVP_PKEY_CTX_new_id(nid, ptr::null_mut()))?; - let ret = cvt(ffi::EVP_PKEY_keygen_init(kctx)); - if let Err(e) = ret { - ffi::EVP_PKEY_CTX_free(kctx); - return Err(e); - } - let mut key = ptr::null_mut(); - let ret = cvt(ffi::EVP_PKEY_keygen(kctx, &mut key)); - - ffi::EVP_PKEY_CTX_free(kctx); - - if let Err(e) = ret { - return Err(e); - } - - Ok(PKey::from_ptr(key)) - } + fn generate_eddsa(id: Id) -> Result, ErrorStack> { + let mut ctx = PkeyCtx::new_id(id)?; + ctx.keygen_init()?; + ctx.keygen() } /// Generates a new private Ed25519 key #[cfg(ossl111)] pub fn generate_x25519() -> Result, ErrorStack> { - PKey::generate_eddsa(ffi::EVP_PKEY_X25519) + PKey::generate_eddsa(Id::X25519) } /// Generates a new private Ed448 key #[cfg(ossl111)] pub fn generate_x448() -> Result, ErrorStack> { - PKey::generate_eddsa(ffi::EVP_PKEY_X448) + PKey::generate_eddsa(Id::X448) } /// Generates a new private Ed25519 key #[cfg(ossl111)] pub fn generate_ed25519() -> Result, ErrorStack> { - PKey::generate_eddsa(ffi::EVP_PKEY_ED25519) + PKey::generate_eddsa(Id::ED25519) } /// Generates a new private Ed448 key #[cfg(ossl111)] pub fn generate_ed448() -> Result, ErrorStack> { - PKey::generate_eddsa(ffi::EVP_PKEY_ED448) + PKey::generate_eddsa(Id::ED448) } /// Generates a new EC key using the provided curve. diff --git a/openssl/src/pkey_ctx.rs b/openssl/src/pkey_ctx.rs new file mode 100644 index 0000000000000000000000000000000000000000..8c22a46227915a8f5724600d586fddb46cbb6a2c --- /dev/null +++ b/openssl/src/pkey_ctx.rs @@ -0,0 +1,510 @@ +//! The asymmetric encryption context. +//! +//! # Examples +//! +//! Encrypt data with RSA +//! +//! ``` +//! use openssl::rsa::Rsa; +//! use openssl::pkey::PKey; +//! use openssl::pkey_ctx::PkeyCtx; +//! +//! let key = Rsa::generate(4096).unwrap(); +//! let key = PKey::from_rsa(key).unwrap(); +//! +//! let mut ctx = PkeyCtx::new(&key).unwrap(); +//! ctx.encrypt_init().unwrap(); +//! +//! let data = b"Some Crypto Text"; +//! 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, Id, PKey, PKeyRef, Private}; +use crate::rsa::Padding; +use crate::{cvt, cvt_p}; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::c_int; +use std::convert::TryFrom; +use std::ptr; + +generic_foreign_type_and_impl_send_sync! { + type CType = ffi::EVP_PKEY_CTX; + fn drop = ffi::EVP_PKEY_CTX_free; + + /// A context object which can perform asymmetric cryptography operations. + pub struct PkeyCtx; + /// A reference to a [`PkeyCtx`]. + pub struct PkeyCtxRef; +} + +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 { + let ptr = cvt_p(ffi::EVP_PKEY_CTX_new(pkey.as_ptr(), ptr::null_mut()))?; + Ok(PkeyCtx::from_ptr(ptr)) + } + } +} + +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, +{ + /// Prepares the context for encryption using the public key. + /// + /// This corresponds to [`EVP_PKEY_encrypt_init`]. + /// + /// [`EVP_PKEY_encrypt_init`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_encrypt_init.html + #[inline] + pub fn encrypt_init(&mut self) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_encrypt_init(self.as_ptr()))?; + } + + Ok(()) + } + + /// Encrypts data using the public key. + /// + /// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be + /// returned. + /// + /// This corresponds to [`EVP_PKEY_encrypt`]. + /// + /// [`EVP_PKEY_encrypt`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_encrypt.html + #[inline] + pub fn encrypt(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result { + let mut written = to.as_ref().map_or(0, |b| b.len()); + unsafe { + cvt(ffi::EVP_PKEY_encrypt( + self.as_ptr(), + to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), + &mut written, + from.as_ptr(), + from.len(), + ))?; + } + + Ok(written) + } + + /// Like [`Self::encrypt`] but appends ciphertext to a [`Vec`]. + pub fn encrypt_to_vec(&mut self, from: &[u8], out: &mut Vec) -> Result { + let base = out.len(); + let len = self.encrypt(from, None)?; + out.resize(base + len, 0); + let len = self.encrypt(from, Some(&mut out[base..]))?; + out.truncate(base + len); + Ok(len) + } +} + +impl PkeyCtxRef +where + T: HasPrivate, +{ + /// Prepares the context for encryption using the private key. + /// + /// This corresponds to [`EVP_PKEY_decrypt_init`]. + /// + /// [`EVP_PKEY_decrypt_init`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_decrypt_init.html + #[inline] + pub fn decrypt_init(&mut self) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_decrypt_init(self.as_ptr()))?; + } + + Ok(()) + } + + /// Prepares the context for shared secret derivation. + /// + /// This corresponds to [`EVP_PKEY_derive_init`]. + /// + /// [`EVP_PKEY_derive_init`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_derive_init.html + #[inline] + pub fn derive_init(&mut self) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_derive_init(self.as_ptr()))?; + } + + Ok(()) + } + + /// 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/manmaster/man3/EVP_PKEY_derive_set_peer.html + pub fn derive_set_peer(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> + where + U: HasPublic, + { + unsafe { + cvt(ffi::EVP_PKEY_derive_set_peer(self.as_ptr(), key.as_ptr()))?; + } + + Ok(()) + } + + /// Decrypts data using the private key. + /// + /// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be + /// returned. + /// + /// This corresponds to [`EVP_PKEY_decrypt`]. + /// + /// [`EVP_PKEY_decrypt`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_encrypt.html + #[inline] + pub fn decrypt(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result { + let mut written = to.as_ref().map_or(0, |b| b.len()); + unsafe { + cvt(ffi::EVP_PKEY_decrypt( + self.as_ptr(), + to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), + &mut written, + from.as_ptr(), + from.len(), + ))?; + } + + Ok(written) + } + + /// Like [`Self::decrypt`] but appends plaintext to a [`Vec`]. + pub fn decrypt_to_vec(&mut self, from: &[u8], out: &mut Vec) -> Result { + let base = out.len(); + let len = self.decrypt(from, None)?; + out.resize(base + len, 0); + let len = self.decrypt(from, Some(&mut out[base..]))?; + out.truncate(base + len); + Ok(len) + } + + /// Derives a shared secrete between two keys. + /// + /// If `buf` is set to `None`, an upper bound on the number of bytes required for the buffer will be returned. + /// + /// This corresponds to [`EVP_PKEY_derive`]. + /// + /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_derive_init.html + pub fn derive(&mut self, buf: Option<&mut [u8]>) -> Result { + let mut len = buf.as_ref().map_or(0, |b| b.len()); + unsafe { + cvt(ffi::EVP_PKEY_derive( + self.as_ptr(), + buf.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), + &mut len, + ))?; + } + + Ok(len) + } + + /// Like [`Self::derive`] but appends the secret to a [`Vec`]. + pub fn derive_to_vec(&mut self, buf: &mut Vec) -> Result { + let base = buf.len(); + let len = self.derive(None)?; + buf.resize(base + len, 0); + let len = self.derive(Some(&mut buf[base..]))?; + buf.truncate(base + len); + Ok(len) + } +} + +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. + /// + /// This corresponds to [`EVP_PKEY_CTX_get_rsa_padding`]. + /// + /// [`EVP_PKEY_CTX_get_rsa_padding`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_get_rsa_padding.html + #[inline] + pub fn rsa_padding(&self) -> Result { + let mut pad = 0; + unsafe { + cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.as_ptr(), &mut pad))?; + } + + Ok(Padding::from_raw(pad)) + } + + /// Sets the RSA padding mode. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_padding`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_CTX_set_rsa_padding.html + #[inline] + pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( + self.as_ptr(), + padding.as_raw(), + ))?; + } + + Ok(()) + } + + /// Sets the RSA MGF1 algorithm. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_mgf1_md`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_mgf1_md`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_rsa_mgf1_md.html + #[inline] + pub fn set_rsa_mgf1_md(&mut self, md: &MdRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( + self.as_ptr(), + md.as_ptr(), + ))?; + } + + Ok(()) + } + + /// Sets the RSA OAEP algorithm. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_oaep_md`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_oaep_md`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_rsa_oaep_md.html + #[cfg(any(ossl102, libressl310))] + #[inline] + pub fn set_rsa_oaep_md(&mut self, md: &MdRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md( + self.as_ptr(), + md.as_ptr() as *mut _, + ))?; + } + + Ok(()) + } + + /// Sets the RSA OAEP label. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set0_rsa_oaep_label`]. + /// + /// [`EVP_PKEY_CTX_set0_rsa_oaep_label`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set0_rsa_oaep_label.html + #[cfg(any(ossl102, libressl310))] + pub fn set_rsa_oaep_label(&mut self, label: &[u8]) -> Result<(), ErrorStack> { + let len = c_int::try_from(label.len()).unwrap(); + + unsafe { + let p = ffi::OPENSSL_malloc(label.len() as _); + ptr::copy_nonoverlapping(label.as_ptr(), p as *mut _, label.len()); + + let r = cvt(ffi::EVP_PKEY_CTX_set0_rsa_oaep_label(self.as_ptr(), p, len)); + if r.is_err() { + ffi::OPENSSL_free(p); + } + r?; + } + + 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}; + #[cfg(any(ossl102, libressl310))] + use crate::md::Md; + use crate::nid::Nid; + use crate::pkey::PKey; + use crate::rsa::Rsa; + + #[test] + fn rsa() { + let key = include_bytes!("../test/rsa.pem"); + let rsa = Rsa::private_key_from_pem(key).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + + let mut ctx = PkeyCtx::new(&pkey).unwrap(); + ctx.encrypt_init().unwrap(); + ctx.set_rsa_padding(Padding::PKCS1).unwrap(); + + let pt = "hello world".as_bytes(); + let mut ct = vec![]; + ctx.encrypt_to_vec(pt, &mut ct).unwrap(); + + ctx.decrypt_init().unwrap(); + ctx.set_rsa_padding(Padding::PKCS1).unwrap(); + + let mut out = vec![]; + ctx.decrypt_to_vec(&ct, &mut out).unwrap(); + + assert_eq!(pt, out); + } + + #[test] + #[cfg(any(ossl102, libressl310))] + fn rsa_oaep() { + let key = include_bytes!("../test/rsa.pem"); + let rsa = Rsa::private_key_from_pem(key).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + + let mut ctx = PkeyCtx::new(&pkey).unwrap(); + ctx.encrypt_init().unwrap(); + ctx.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); + ctx.set_rsa_oaep_md(Md::sha256()).unwrap(); + ctx.set_rsa_mgf1_md(Md::sha256()).unwrap(); + + let pt = "hello world".as_bytes(); + let mut ct = vec![]; + ctx.encrypt_to_vec(pt, &mut ct).unwrap(); + + ctx.decrypt_init().unwrap(); + ctx.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); + ctx.set_rsa_oaep_md(Md::sha256()).unwrap(); + ctx.set_rsa_mgf1_md(Md::sha256()).unwrap(); + + let mut out = vec![]; + ctx.decrypt_to_vec(&ct, &mut out).unwrap(); + + assert_eq!(pt, out); + } + + #[test] + fn derive() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let key1 = EcKey::generate(&group).unwrap(); + let key1 = PKey::from_ec_key(key1).unwrap(); + let key2 = EcKey::generate(&group).unwrap(); + let key2 = PKey::from_ec_key(key2).unwrap(); + + let mut ctx = PkeyCtx::new(&key1).unwrap(); + ctx.derive_init().unwrap(); + ctx.derive_set_peer(&key2).unwrap(); + + 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(); + } +} diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 8289c9882b58a443503aa6c20d900569c8b0c69e..68ee52b83574aa8343b006a01f0fda1df6b702d1 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -3155,11 +3155,7 @@ impl SslRef { pub fn set_ocsp_status(&mut self, response: &[u8]) -> Result<(), ErrorStack> { unsafe { assert!(response.len() <= c_int::max_value() as usize); - let p = cvt_p(ffi::CRYPTO_malloc( - response.len() as _, - concat!(file!(), "\0").as_ptr() as *const _, - line!() as c_int, - ))?; + let p = cvt_p(ffi::OPENSSL_malloc(response.len() as _))?; ptr::copy_nonoverlapping(response.as_ptr(), p as *mut u8, response.len()); cvt(ffi::SSL_set_tlsext_status_ocsp_resp( self.as_ptr(), diff --git a/openssl/src/string.rs b/openssl/src/string.rs index bca53a1b643671d0f18081dfdaf0d53e899ad145..df151b23ea267a39d891dbd59aa05348b9f1684b 100644 --- a/openssl/src/string.rs +++ b/openssl/src/string.rs @@ -79,16 +79,7 @@ impl fmt::Debug for OpensslStringRef { } } -#[cfg(not(ossl110))] +#[inline] unsafe fn free(buf: *mut c_char) { - ::ffi::CRYPTO_free(buf as *mut c_void); -} - -#[cfg(ossl110)] -unsafe fn free(buf: *mut c_char) { - ffi::CRYPTO_free( - buf as *mut c_void, - concat!(file!(), "\0").as_ptr() as *const c_char, - line!() as ::libc::c_int, - ); + ffi::OPENSSL_free(buf as *mut c_void); } diff --git a/openssl/src/util.rs b/openssl/src/util.rs index e390ea05e18fb1fe7f01a73bcfddf2c42f85069a..d852a4b9d8d83b8a26d29713b4002f89abfaa502 100644 --- a/openssl/src/util.rs +++ b/openssl/src/util.rs @@ -1,11 +1,10 @@ +use crate::error::ErrorStack; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_char, c_int, c_void}; use std::any::Any; use std::panic::{self, AssertUnwindSafe}; use std::slice; -use crate::error::ErrorStack; - /// Wraps a user-supplied callback and a slot for panics thrown inside the callback (while FFI /// frames are on the stack). ///