summaryrefslogtreecommitdiffstats
path: root/vendor/openssl/src/pkey_ctx.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/openssl/src/pkey_ctx.rs')
-rw-r--r--vendor/openssl/src/pkey_ctx.rs1002
1 files changed, 1002 insertions, 0 deletions
diff --git a/vendor/openssl/src/pkey_ctx.rs b/vendor/openssl/src/pkey_ctx.rs
new file mode 100644
index 0000000..4ac32a8
--- /dev/null
+++ b/vendor/openssl/src/pkey_ctx.rs
@@ -0,0 +1,1002 @@
+//! 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();
+//! ```
+
+#![cfg_attr(
+ not(boringssl),
+ doc = r#"\
+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().unwrap();
+ctx.set_keygen_cipher(Cipher::aes_128_cbc()).unwrap();
+ctx.set_keygen_mac_key(b"0123456789abcdef").unwrap();
+let cmac_key = ctx.keygen().unwrap();
+```"#
+)]
+
+//!
+//! Sign and verify data with RSA
+//!
+//! ```
+//! use openssl::pkey_ctx::PkeyCtx;
+//! use openssl::pkey::PKey;
+//! use openssl::rsa::Rsa;
+//!
+//! // Generate a random RSA key.
+//! let key = Rsa::generate(4096).unwrap();
+//! let key = PKey::from_rsa(key).unwrap();
+//!
+//! let text = b"Some Crypto Text";
+//!
+//! // Create the signature.
+//! let mut ctx = PkeyCtx::new(&key).unwrap();
+//! ctx.sign_init().unwrap();
+//! let mut signature = vec![];
+//! ctx.sign_to_vec(text, &mut signature).unwrap();
+//!
+//! // Verify the signature.
+//! let mut ctx = PkeyCtx::new(&key).unwrap();
+//! ctx.verify_init().unwrap();
+//! let valid = ctx.verify(text, &signature).unwrap();
+//! assert!(valid);
+//! ```
+#[cfg(not(boringssl))]
+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::sign::RsaPssSaltlen;
+use crate::{cvt, cvt_p};
+use foreign_types::{ForeignType, ForeignTypeRef};
+#[cfg(not(boringssl))]
+use libc::c_int;
+use openssl_macros::corresponds;
+use std::convert::TryFrom;
+use std::ptr;
+
+/// HKDF modes of operation.
+#[cfg(ossl111)]
+pub struct HkdfMode(c_int);
+
+#[cfg(ossl111)]
+impl HkdfMode {
+ /// This is the default mode. Calling [`derive`][PkeyCtxRef::derive] on a [`PkeyCtxRef`] set up
+ /// for HKDF will perform an extract followed by an expand operation in one go. The derived key
+ /// returned will be the result after the expand operation. The intermediate fixed-length
+ /// pseudorandom key K is not returned.
+ pub const EXTRACT_THEN_EXPAND: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND);
+
+ /// In this mode calling [`derive`][PkeyCtxRef::derive] will just perform the extract operation.
+ /// The value returned will be the intermediate fixed-length pseudorandom key K.
+ ///
+ /// The digest, key and salt values must be set before a key is derived or an error occurs.
+ pub const EXTRACT_ONLY: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY);
+
+ /// In this mode calling [`derive`][PkeyCtxRef::derive] will just perform the expand operation.
+ /// The input key should be set to the intermediate fixed-length pseudorandom key K returned
+ /// from a previous extract operation.
+ ///
+ /// The digest, key and info values must be set before a key is derived or an error occurs.
+ pub const EXPAND_ONLY: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXPAND_ONLY);
+}
+
+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<T>;
+ /// A reference to a [`PkeyCtx`].
+ pub struct PkeyCtxRef<T>;
+}
+
+impl<T> PkeyCtx<T> {
+ /// Creates a new pkey context using the provided key.
+ #[corresponds(EVP_PKEY_CTX_new)]
+ #[inline]
+ pub fn new(pkey: &PKeyRef<T>) -> Result<Self, ErrorStack> {
+ 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.
+ #[corresponds(EVP_PKEY_new_id)]
+ #[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,
+{
+ /// Prepares the context for encryption using the public key.
+ #[corresponds(EVP_PKEY_encrypt_init)]
+ #[inline]
+ pub fn encrypt_init(&mut self) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::EVP_PKEY_encrypt_init(self.as_ptr()))?;
+ }
+
+ Ok(())
+ }
+
+ /// Prepares the context for signature verification using the public key.
+ #[corresponds(EVP_PKEY_verify_init)]
+ #[inline]
+ pub fn verify_init(&mut self) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::EVP_PKEY_verify_init(self.as_ptr()))?;
+ }
+
+ Ok(())
+ }
+
+ /// Prepares the context for signature recovery using the public key.
+ #[corresponds(EVP_PKEY_verify_recover_init)]
+ #[inline]
+ pub fn verify_recover_init(&mut self) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::EVP_PKEY_verify_recover_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.
+ #[corresponds(EVP_PKEY_encrypt)]
+ #[inline]
+ pub fn encrypt(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result<usize, ErrorStack> {
+ 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<u8>) -> Result<usize, ErrorStack> {
+ 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)
+ }
+
+ /// Verifies the signature of data using the public key.
+ ///
+ /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if the signature is invalid, and `Err` if an error
+ /// occurred.
+ ///
+ /// # Note
+ ///
+ /// This verifies the signature of the *raw* data. It is more common to compute and verify the signature of the
+ /// cryptographic hash of an arbitrary amount of data. The [`MdCtx`](crate::md_ctx::MdCtx) type can be used to do
+ /// that.
+ #[corresponds(EVP_PKEY_verify)]
+ #[inline]
+ pub fn verify(&mut self, data: &[u8], sig: &[u8]) -> Result<bool, ErrorStack> {
+ unsafe {
+ let r = ffi::EVP_PKEY_verify(
+ self.as_ptr(),
+ sig.as_ptr(),
+ sig.len(),
+ data.as_ptr(),
+ data.len(),
+ );
+ // `EVP_PKEY_verify` is not terribly consistent about how it,
+ // reports errors. It does not clearly distinguish between 0 and
+ // -1, and may put errors on the stack in both cases. If there's
+ // errors on the stack, we return `Err()`, else we return
+ // `Ok(false)`.
+ if r <= 0 {
+ let errors = ErrorStack::get();
+ if !errors.errors().is_empty() {
+ return Err(errors);
+ }
+ }
+
+ Ok(r == 1)
+ }
+ }
+
+ /// Recovers the original data signed by the private key. You almost
+ /// always want `verify` instead.
+ ///
+ /// Returns the number of bytes written to `to`, or the number of bytes
+ /// that would be written, if `to` is `None.
+ #[corresponds(EVP_PKEY_verify_recover)]
+ #[inline]
+ pub fn verify_recover(
+ &mut self,
+ sig: &[u8],
+ to: Option<&mut [u8]>,
+ ) -> Result<usize, ErrorStack> {
+ let mut written = to.as_ref().map_or(0, |b| b.len());
+ unsafe {
+ cvt(ffi::EVP_PKEY_verify_recover(
+ self.as_ptr(),
+ to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
+ &mut written,
+ sig.as_ptr(),
+ sig.len(),
+ ))?;
+ }
+
+ Ok(written)
+ }
+}
+
+impl<T> PkeyCtxRef<T>
+where
+ T: HasPrivate,
+{
+ /// Prepares the context for decryption using the private key.
+ #[corresponds(EVP_PKEY_decrypt_init)]
+ #[inline]
+ pub fn decrypt_init(&mut self) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::EVP_PKEY_decrypt_init(self.as_ptr()))?;
+ }
+
+ Ok(())
+ }
+
+ /// Prepares the context for signing using the private key.
+ #[corresponds(EVP_PKEY_sign_init)]
+ #[inline]
+ pub fn sign_init(&mut self) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::EVP_PKEY_sign_init(self.as_ptr()))?;
+ }
+
+ Ok(())
+ }
+
+ /// Sets the peer key used for secret derivation.
+ #[corresponds(EVP_PKEY_derive_set_peer)]
+ pub fn derive_set_peer<U>(&mut self, key: &PKeyRef<U>) -> 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.
+ #[corresponds(EVP_PKEY_decrypt)]
+ #[inline]
+ pub fn decrypt(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result<usize, ErrorStack> {
+ 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<u8>) -> Result<usize, ErrorStack> {
+ 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)
+ }
+
+ /// Signs the contents of `data`.
+ ///
+ /// If `sig` is set to `None`, an upper bound on the number of bytes required for the output buffer will be
+ /// returned.
+ ///
+ /// # Note
+ ///
+ /// This computes the signature of the *raw* bytes of `data`. It is more common to sign the cryptographic hash of
+ /// an arbitrary amount of data. The [`MdCtx`](crate::md_ctx::MdCtx) type can be used to do that.
+ #[corresponds(EVP_PKEY_sign)]
+ #[inline]
+ pub fn sign(&mut self, data: &[u8], sig: Option<&mut [u8]>) -> Result<usize, ErrorStack> {
+ let mut written = sig.as_ref().map_or(0, |b| b.len());
+ unsafe {
+ cvt(ffi::EVP_PKEY_sign(
+ self.as_ptr(),
+ sig.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
+ &mut written,
+ data.as_ptr(),
+ data.len(),
+ ))?;
+ }
+
+ Ok(written)
+ }
+
+ /// Like [`Self::sign`] but appends the signature to a [`Vec`].
+ pub fn sign_to_vec(&mut self, data: &[u8], sig: &mut Vec<u8>) -> Result<usize, ErrorStack> {
+ let base = sig.len();
+ let len = self.sign(data, None)?;
+ sig.resize(base + len, 0);
+ let len = self.sign(data, Some(&mut sig[base..]))?;
+ sig.truncate(base + len);
+ Ok(len)
+ }
+}
+
+impl<T> PkeyCtxRef<T> {
+ /// Prepares the context for shared secret derivation.
+ #[corresponds(EVP_PKEY_derive_init)]
+ #[inline]
+ pub fn derive_init(&mut self) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::EVP_PKEY_derive_init(self.as_ptr()))?;
+ }
+
+ Ok(())
+ }
+
+ /// Prepares the context for key generation.
+ #[corresponds(EVP_PKEY_keygen_init)]
+ #[inline]
+ pub fn keygen_init(&mut self) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::EVP_PKEY_keygen_init(self.as_ptr()))?;
+ }
+
+ Ok(())
+ }
+
+ /// Sets which algorithm was used to compute the digest used in a
+ /// signature. With RSA signatures this causes the signature to be wrapped
+ /// in a `DigestInfo` structure. This is almost always what you want with
+ /// RSA signatures.
+ #[corresponds(EVP_PKEY_CTX_set_signature_md)]
+ #[inline]
+ pub fn set_signature_md(&self, md: &MdRef) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::EVP_PKEY_CTX_set_signature_md(
+ self.as_ptr(),
+ md.as_ptr(),
+ ))?;
+ }
+ Ok(())
+ }
+
+ /// Returns the RSA padding mode in use.
+ ///
+ /// This is only useful for RSA keys.
+ #[corresponds(EVP_PKEY_CTX_get_rsa_padding)]
+ #[inline]
+ pub fn rsa_padding(&self) -> Result<Padding, ErrorStack> {
+ 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.
+ #[corresponds(EVP_PKEY_CTX_set_rsa_padding)]
+ #[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 PSS salt length.
+ ///
+ /// This is only useful for RSA keys.
+ #[corresponds(EVP_PKEY_CTX_set_rsa_pss_saltlen)]
+ #[inline]
+ pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen(
+ self.as_ptr(),
+ len.as_raw(),
+ ))
+ .map(|_| ())
+ }
+ }
+
+ /// Sets the RSA MGF1 algorithm.
+ ///
+ /// This is only useful for RSA keys.
+ #[corresponds(EVP_PKEY_CTX_set_rsa_mgf1_md)]
+ #[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.
+ #[corresponds(EVP_PKEY_CTX_set_rsa_oaep_md)]
+ #[cfg(any(ossl102, libressl310, boringssl))]
+ #[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.
+ #[corresponds(EVP_PKEY_CTX_set0_rsa_oaep_label)]
+ #[cfg(any(ossl102, libressl310, boringssl))]
+ pub fn set_rsa_oaep_label(&mut self, label: &[u8]) -> Result<(), ErrorStack> {
+ use crate::LenType;
+ let len = LenType::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 as *mut _,
+ len,
+ ));
+ if r.is_err() {
+ ffi::OPENSSL_free(p);
+ }
+ r?;
+ }
+
+ Ok(())
+ }
+
+ /// Sets the cipher used during key generation.
+ #[cfg(not(boringssl))]
+ #[corresponds(EVP_PKEY_CTX_ctrl)]
+ #[inline]
+ 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.
+ #[cfg(not(boringssl))]
+ #[corresponds(EVP_PKEY_CTX_ctrl)]
+ #[inline]
+ 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(())
+ }
+
+ /// Sets the digest used for HKDF derivation.
+ ///
+ /// Requires OpenSSL 1.1.0 or newer.
+ #[corresponds(EVP_PKEY_CTX_set_hkdf_md)]
+ #[cfg(any(ossl110, boringssl))]
+ #[inline]
+ pub fn set_hkdf_md(&mut self, digest: &MdRef) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::EVP_PKEY_CTX_set_hkdf_md(
+ self.as_ptr(),
+ digest.as_ptr(),
+ ))?;
+ }
+
+ Ok(())
+ }
+
+ /// Sets the HKDF mode of operation.
+ ///
+ /// Defaults to [`HkdfMode::EXTRACT_THEN_EXPAND`].
+ ///
+ /// WARNING: Although this API calls it a "mode", HKDF-Extract and HKDF-Expand are distinct
+ /// operations with distinct inputs and distinct kinds of keys. Callers should not pass input
+ /// secrets for one operation into the other.
+ ///
+ /// Requires OpenSSL 1.1.1 or newer.
+ #[corresponds(EVP_PKEY_CTX_set_hkdf_mode)]
+ #[cfg(ossl111)]
+ #[inline]
+ pub fn set_hkdf_mode(&mut self, mode: HkdfMode) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::EVP_PKEY_CTX_set_hkdf_mode(self.as_ptr(), mode.0))?;
+ }
+
+ Ok(())
+ }
+
+ /// Sets the input material for HKDF generation as the "key".
+ ///
+ /// Which input is the key depends on the "mode" (see [`set_hkdf_mode`][Self::set_hkdf_mode]).
+ /// If [`HkdfMode::EXTRACT_THEN_EXPAND`] or [`HkdfMode::EXTRACT_ONLY`], this function specifies
+ /// the input keying material (IKM) for HKDF-Extract. If [`HkdfMode::EXPAND_ONLY`], it instead
+ /// specifies the pseudorandom key (PRK) for HKDF-Expand.
+ ///
+ /// Requires OpenSSL 1.1.0 or newer.
+ #[corresponds(EVP_PKEY_CTX_set1_hkdf_key)]
+ #[cfg(any(ossl110, boringssl))]
+ #[inline]
+ pub fn set_hkdf_key(&mut self, key: &[u8]) -> Result<(), ErrorStack> {
+ #[cfg(not(boringssl))]
+ let len = c_int::try_from(key.len()).unwrap();
+ #[cfg(boringssl)]
+ let len = key.len();
+
+ unsafe {
+ cvt(ffi::EVP_PKEY_CTX_set1_hkdf_key(
+ self.as_ptr(),
+ key.as_ptr(),
+ len,
+ ))?;
+ }
+
+ Ok(())
+ }
+
+ /// Sets the salt value for HKDF generation.
+ ///
+ /// If performing HKDF-Expand only, this parameter is ignored.
+ ///
+ /// Requires OpenSSL 1.1.0 or newer.
+ #[corresponds(EVP_PKEY_CTX_set1_hkdf_salt)]
+ #[cfg(any(ossl110, boringssl))]
+ #[inline]
+ pub fn set_hkdf_salt(&mut self, salt: &[u8]) -> Result<(), ErrorStack> {
+ #[cfg(not(boringssl))]
+ let len = c_int::try_from(salt.len()).unwrap();
+ #[cfg(boringssl)]
+ let len = salt.len();
+
+ unsafe {
+ cvt(ffi::EVP_PKEY_CTX_set1_hkdf_salt(
+ self.as_ptr(),
+ salt.as_ptr(),
+ len,
+ ))?;
+ }
+
+ Ok(())
+ }
+
+ /// Appends info bytes for HKDF generation.
+ ///
+ /// If performing HKDF-Extract only, this parameter is ignored.
+ ///
+ /// Requires OpenSSL 1.1.0 or newer.
+ #[corresponds(EVP_PKEY_CTX_add1_hkdf_info)]
+ #[cfg(any(ossl110, boringssl))]
+ #[inline]
+ pub fn add_hkdf_info(&mut self, info: &[u8]) -> Result<(), ErrorStack> {
+ #[cfg(not(boringssl))]
+ let len = c_int::try_from(info.len()).unwrap();
+ #[cfg(boringssl)]
+ let len = info.len();
+
+ unsafe {
+ cvt(ffi::EVP_PKEY_CTX_add1_hkdf_info(
+ self.as_ptr(),
+ info.as_ptr(),
+ len,
+ ))?;
+ }
+
+ Ok(())
+ }
+
+ /// Derives a shared secret between two keys.
+ ///
+ /// If `buf` is set to `None`, an upper bound on the number of bytes required for the buffer will be returned.
+ #[corresponds(EVP_PKEY_derive)]
+ pub fn derive(&mut self, buf: Option<&mut [u8]>) -> Result<usize, ErrorStack> {
+ 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<u8>) -> Result<usize, ErrorStack> {
+ 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)
+ }
+
+ /// Generates a new public/private keypair.
+ #[corresponds(EVP_PKEY_keygen)]
+ #[inline]
+ 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::*;
+ #[cfg(not(boringssl))]
+ use crate::cipher::Cipher;
+ use crate::ec::{EcGroup, EcKey};
+ use crate::hash::{hash, MessageDigest};
+ use crate::md::Md;
+ use crate::nid::Nid;
+ use crate::pkey::PKey;
+ use crate::rsa::Rsa;
+ use crate::sign::Verifier;
+
+ #[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, boringssl))]
+ 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 rsa_sign() {
+ 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.sign_init().unwrap();
+ ctx.set_rsa_padding(Padding::PKCS1).unwrap();
+ ctx.set_signature_md(Md::sha384()).unwrap();
+
+ let msg = b"hello world";
+ let digest = hash(MessageDigest::sha384(), msg).unwrap();
+ let mut signature = vec![];
+ ctx.sign_to_vec(&digest, &mut signature).unwrap();
+
+ let mut verifier = Verifier::new(MessageDigest::sha384(), &pkey).unwrap();
+ verifier.update(msg).unwrap();
+ assert!(matches!(verifier.verify(&signature), Ok(true)));
+ }
+
+ #[test]
+ fn rsa_sign_pss() {
+ 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.sign_init().unwrap();
+ ctx.set_rsa_padding(Padding::PKCS1_PSS).unwrap();
+ ctx.set_signature_md(Md::sha384()).unwrap();
+ ctx.set_rsa_pss_saltlen(RsaPssSaltlen::custom(14)).unwrap();
+
+ let msg = b"hello world";
+ let digest = hash(MessageDigest::sha384(), msg).unwrap();
+ let mut signature = vec![];
+ ctx.sign_to_vec(&digest, &mut signature).unwrap();
+
+ let mut verifier = Verifier::new(MessageDigest::sha384(), &pkey).unwrap();
+ verifier.set_rsa_padding(Padding::PKCS1_PSS).unwrap();
+ verifier
+ .set_rsa_pss_saltlen(RsaPssSaltlen::custom(14))
+ .unwrap();
+ verifier.update(msg).unwrap();
+ assert!(matches!(verifier.verify(&signature), Ok(true)));
+ }
+
+ #[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]
+ #[cfg(not(boringssl))]
+ 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();
+ }
+
+ #[test]
+ #[cfg(any(ossl110, boringssl))]
+ fn hkdf() {
+ let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap();
+ ctx.derive_init().unwrap();
+ ctx.set_hkdf_md(Md::sha256()).unwrap();
+ ctx.set_hkdf_key(&hex::decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap())
+ .unwrap();
+ ctx.set_hkdf_salt(&hex::decode("000102030405060708090a0b0c").unwrap())
+ .unwrap();
+ ctx.add_hkdf_info(&hex::decode("f0f1f2f3f4f5f6f7f8f9").unwrap())
+ .unwrap();
+ let mut out = [0; 42];
+ ctx.derive(Some(&mut out)).unwrap();
+
+ assert_eq!(
+ &out[..],
+ hex::decode("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865")
+ .unwrap()
+ );
+ }
+
+ #[test]
+ #[cfg(ossl111)]
+ fn hkdf_expand() {
+ let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap();
+ ctx.derive_init().unwrap();
+ ctx.set_hkdf_mode(HkdfMode::EXPAND_ONLY).unwrap();
+ ctx.set_hkdf_md(Md::sha256()).unwrap();
+ ctx.set_hkdf_key(
+ &hex::decode("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5")
+ .unwrap(),
+ )
+ .unwrap();
+ ctx.add_hkdf_info(&hex::decode("f0f1f2f3f4f5f6f7f8f9").unwrap())
+ .unwrap();
+ let mut out = [0; 42];
+ ctx.derive(Some(&mut out)).unwrap();
+
+ assert_eq!(
+ &out[..],
+ hex::decode("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865")
+ .unwrap()
+ );
+ }
+
+ #[test]
+ #[cfg(ossl111)]
+ fn hkdf_extract() {
+ let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap();
+ ctx.derive_init().unwrap();
+ ctx.set_hkdf_mode(HkdfMode::EXTRACT_ONLY).unwrap();
+ ctx.set_hkdf_md(Md::sha256()).unwrap();
+ ctx.set_hkdf_key(&hex::decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap())
+ .unwrap();
+ ctx.set_hkdf_salt(&hex::decode("000102030405060708090a0b0c").unwrap())
+ .unwrap();
+ let mut out = vec![];
+ ctx.derive_to_vec(&mut out).unwrap();
+
+ assert_eq!(
+ &out[..],
+ hex::decode("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5")
+ .unwrap()
+ );
+ }
+
+ #[test]
+ fn verify_fail() {
+ let key1 = Rsa::generate(4096).unwrap();
+ let key1 = PKey::from_rsa(key1).unwrap();
+
+ let data = b"Some Crypto Text";
+
+ let mut ctx = PkeyCtx::new(&key1).unwrap();
+ ctx.sign_init().unwrap();
+ let mut signature = vec![];
+ ctx.sign_to_vec(data, &mut signature).unwrap();
+
+ let bad_data = b"Some Crypto text";
+
+ ctx.verify_init().unwrap();
+ let valid = ctx.verify(bad_data, &signature);
+ assert!(matches!(valid, Ok(false) | Err(_)));
+ assert!(ErrorStack::get().errors().is_empty());
+ }
+
+ #[test]
+ fn verify_fail_ec() {
+ let key1 =
+ EcKey::generate(&EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap()).unwrap();
+ let key1 = PKey::from_ec_key(key1).unwrap();
+
+ let data = b"Some Crypto Text";
+ let mut ctx = PkeyCtx::new(&key1).unwrap();
+ ctx.verify_init().unwrap();
+ assert!(matches!(ctx.verify(data, &[0; 64]), Ok(false) | Err(_)));
+ assert!(ErrorStack::get().errors().is_empty());
+ }
+
+ #[test]
+ fn test_verify_recover() {
+ let key = Rsa::generate(2048).unwrap();
+ let key = PKey::from_rsa(key).unwrap();
+
+ let digest = [
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ ];
+
+ let mut ctx = PkeyCtx::new(&key).unwrap();
+ ctx.sign_init().unwrap();
+ ctx.set_rsa_padding(Padding::PKCS1).unwrap();
+ ctx.set_signature_md(Md::sha256()).unwrap();
+ let mut signature = vec![];
+ ctx.sign_to_vec(&digest, &mut signature).unwrap();
+
+ // Attempt recovery of just the digest.
+ let mut ctx = PkeyCtx::new(&key).unwrap();
+ ctx.verify_recover_init().unwrap();
+ ctx.set_rsa_padding(Padding::PKCS1).unwrap();
+ ctx.set_signature_md(Md::sha256()).unwrap();
+ let length = ctx.verify_recover(&signature, None).unwrap();
+ let mut result_buf = vec![0; length];
+ let length = ctx
+ .verify_recover(&signature, Some(&mut result_buf))
+ .unwrap();
+ assert_eq!(length, digest.len());
+ // result_buf contains the digest
+ assert_eq!(result_buf[..length], digest);
+
+ // Attempt recovery of teh entire DigestInfo
+ let mut ctx = PkeyCtx::new(&key).unwrap();
+ ctx.verify_recover_init().unwrap();
+ ctx.set_rsa_padding(Padding::PKCS1).unwrap();
+ let length = ctx.verify_recover(&signature, None).unwrap();
+ let mut result_buf = vec![0; length];
+ let length = ctx
+ .verify_recover(&signature, Some(&mut result_buf))
+ .unwrap();
+ // 32-bytes of SHA256 digest + the ASN.1 DigestInfo structure == 51 bytes
+ assert_eq!(length, 51);
+ // The digest is the end of the DigestInfo structure.
+ assert_eq!(result_buf[length - digest.len()..length], digest);
+ }
+}