summaryrefslogtreecommitdiffstats
path: root/vendor/openssl/src/pkey.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/openssl/src/pkey.rs')
-rw-r--r--vendor/openssl/src/pkey.rs1173
1 files changed, 1173 insertions, 0 deletions
diff --git a/vendor/openssl/src/pkey.rs b/vendor/openssl/src/pkey.rs
new file mode 100644
index 0000000..453aeed
--- /dev/null
+++ b/vendor/openssl/src/pkey.rs
@@ -0,0 +1,1173 @@
+//! Public/private key processing.
+//!
+//! Asymmetric public key algorithms solve the problem of establishing and sharing
+//! secret keys to securely send and receive messages.
+//! This system uses a pair of keys: a public key, which can be freely
+//! distributed, and a private key, which is kept to oneself. An entity may
+//! encrypt information using a user's public key. The encrypted information can
+//! only be deciphered using that user's private key.
+//!
+//! This module offers support for five popular algorithms:
+//!
+//! * RSA
+//!
+//! * DSA
+//!
+//! * Diffie-Hellman
+//!
+//! * Elliptic Curves
+//!
+//! * HMAC
+//!
+//! These algorithms rely on hard mathematical problems - namely integer factorization,
+//! discrete logarithms, and elliptic curve relationships - that currently do not
+//! yield efficient solutions. This property ensures the security of these
+//! cryptographic algorithms.
+//!
+//! # Example
+//!
+//! Generate a 2048-bit RSA public/private key pair and print the public key.
+//!
+//! ```rust
+//! use openssl::rsa::Rsa;
+//! use openssl::pkey::PKey;
+//! use std::str;
+//!
+//! let rsa = Rsa::generate(2048).unwrap();
+//! let pkey = PKey::from_rsa(rsa).unwrap();
+//!
+//! let pub_key: Vec<u8> = pkey.public_key_to_pem().unwrap();
+//! println!("{:?}", str::from_utf8(pub_key.as_slice()).unwrap());
+//! ```
+#![allow(clippy::missing_safety_doc)]
+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(any(ossl110, boringssl, libressl370))]
+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 openssl_macros::corresponds;
+use std::convert::{TryFrom, TryInto};
+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 {}
+
+/// A tag type indicating that a key only has public components.
+pub enum Public {}
+
+/// A tag type indicating that a key has private components.
+pub enum Private {}
+
+/// An identifier of a kind of key.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct Id(c_int);
+
+impl Id {
+ pub const RSA: Id = Id(ffi::EVP_PKEY_RSA);
+ #[cfg(not(boringssl))]
+ pub const HMAC: Id = Id(ffi::EVP_PKEY_HMAC);
+ #[cfg(not(boringssl))]
+ 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);
+ #[cfg(ossl111)]
+ pub const SM2: Id = Id(ffi::EVP_PKEY_SM2);
+
+ #[cfg(any(ossl110, boringssl))]
+ pub const HKDF: Id = Id(ffi::EVP_PKEY_HKDF);
+
+ #[cfg(any(ossl111, boringssl, libressl370))]
+ pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519);
+ #[cfg(ossl111)]
+ pub const ED448: Id = Id(ffi::EVP_PKEY_ED448);
+ #[cfg(any(ossl111, boringssl, libressl370))]
+ pub const X25519: Id = Id(ffi::EVP_PKEY_X25519);
+ #[cfg(ossl111)]
+ pub const X448: Id = Id(ffi::EVP_PKEY_X448);
+ #[cfg(ossl111)]
+ pub const POLY1305: Id = Id(ffi::EVP_PKEY_POLY1305);
+
+ /// Creates a `Id` from an integer representation.
+ pub fn from_raw(value: c_int) -> Id {
+ Id(value)
+ }
+
+ /// Returns the integer representation of the `Id`.
+ #[allow(clippy::trivially_copy_pass_by_ref)]
+ pub fn as_raw(&self) -> c_int {
+ self.0
+ }
+}
+
+/// A trait indicating that a key has parameters.
+pub unsafe trait HasParams {}
+
+unsafe impl HasParams for Params {}
+
+unsafe impl<T> HasParams for T where T: HasPublic {}
+
+/// A trait indicating that a key has public components.
+pub unsafe trait HasPublic {}
+
+unsafe impl HasPublic for Public {}
+
+unsafe impl<T> HasPublic for T where T: HasPrivate {}
+
+/// A trait indicating that a key has private components.
+pub unsafe trait HasPrivate {}
+
+unsafe impl HasPrivate for Private {}
+
+generic_foreign_type_and_impl_send_sync! {
+ type CType = ffi::EVP_PKEY;
+ fn drop = ffi::EVP_PKEY_free;
+
+ /// A public or private key.
+ pub struct PKey<T>;
+ /// Reference to `PKey`.
+ pub struct PKeyRef<T>;
+}
+
+impl<T> ToOwned for PKeyRef<T> {
+ type Owned = PKey<T>;
+
+ fn to_owned(&self) -> PKey<T> {
+ unsafe {
+ EVP_PKEY_up_ref(self.as_ptr());
+ PKey::from_ptr(self.as_ptr())
+ }
+ }
+}
+
+impl<T> PKeyRef<T> {
+ /// Returns a copy of the internal RSA key.
+ #[corresponds(EVP_PKEY_get1_RSA)]
+ pub fn rsa(&self) -> Result<Rsa<T>, ErrorStack> {
+ unsafe {
+ let rsa = cvt_p(ffi::EVP_PKEY_get1_RSA(self.as_ptr()))?;
+ Ok(Rsa::from_ptr(rsa))
+ }
+ }
+
+ /// Returns a copy of the internal DSA key.
+ #[corresponds(EVP_PKEY_get1_DSA)]
+ pub fn dsa(&self) -> Result<Dsa<T>, ErrorStack> {
+ unsafe {
+ let dsa = cvt_p(ffi::EVP_PKEY_get1_DSA(self.as_ptr()))?;
+ Ok(Dsa::from_ptr(dsa))
+ }
+ }
+
+ /// Returns a copy of the internal DH key.
+ #[corresponds(EVP_PKEY_get1_DH)]
+ pub fn dh(&self) -> Result<Dh<T>, ErrorStack> {
+ unsafe {
+ let dh = cvt_p(ffi::EVP_PKEY_get1_DH(self.as_ptr()))?;
+ Ok(Dh::from_ptr(dh))
+ }
+ }
+
+ /// Returns a copy of the internal elliptic curve key.
+ #[corresponds(EVP_PKEY_get1_EC_KEY)]
+ pub fn ec_key(&self) -> Result<EcKey<T>, ErrorStack> {
+ unsafe {
+ let ec_key = cvt_p(ffi::EVP_PKEY_get1_EC_KEY(self.as_ptr()))?;
+ Ok(EcKey::from_ptr(ec_key))
+ }
+ }
+
+ /// Returns the `Id` that represents the type of this key.
+ #[corresponds(EVP_PKEY_id)]
+ pub fn id(&self) -> Id {
+ unsafe { Id::from_raw(ffi::EVP_PKEY_id(self.as_ptr())) }
+ }
+
+ /// Returns the maximum size of a signature in bytes.
+ #[corresponds(EVP_PKEY_size)]
+ pub fn size(&self) -> usize {
+ unsafe { ffi::EVP_PKEY_size(self.as_ptr()) as usize }
+ }
+}
+
+impl<T> PKeyRef<T>
+where
+ T: HasPublic,
+{
+ to_pem! {
+ /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure.
+ ///
+ /// The output will have a header of `-----BEGIN PUBLIC KEY-----`.
+ #[corresponds(PEM_write_bio_PUBKEY)]
+ public_key_to_pem,
+ ffi::PEM_write_bio_PUBKEY
+ }
+
+ to_der! {
+ /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure.
+ #[corresponds(i2d_PUBKEY)]
+ public_key_to_der,
+ ffi::i2d_PUBKEY
+ }
+
+ /// Returns the size of the key.
+ ///
+ /// This corresponds to the bit length of the modulus of an RSA key, and the bit length of the
+ /// group order for an elliptic curve key, for example.
+ #[corresponds(EVP_PKEY_bits)]
+ pub fn bits(&self) -> u32 {
+ unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as u32 }
+ }
+
+ ///Returns the number of security bits.
+ ///
+ ///Bits of security is defined in NIST SP800-57.
+ #[corresponds(EVP_PKEY_security_bits)]
+ #[cfg(any(ossl110, libressl360))]
+ pub fn security_bits(&self) -> u32 {
+ unsafe { ffi::EVP_PKEY_security_bits(self.as_ptr()) as u32 }
+ }
+
+ /// Compares the public component of this key with another.
+ #[corresponds(EVP_PKEY_cmp)]
+ pub fn public_eq<U>(&self, other: &PKeyRef<U>) -> bool
+ where
+ U: HasPublic,
+ {
+ let res = unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 };
+ // Clear the stack. OpenSSL will put an error on the stack when the
+ // keys are different types in some situations.
+ let _ = ErrorStack::get();
+ res
+ }
+
+ /// Raw byte representation of a public key.
+ ///
+ /// This function only works for algorithms that support raw public keys.
+ /// Currently this is: [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`].
+ #[corresponds(EVP_PKEY_get_raw_public_key)]
+ #[cfg(any(ossl111, boringssl, libressl370))]
+ pub fn raw_public_key(&self) -> Result<Vec<u8>, ErrorStack> {
+ unsafe {
+ let mut len = 0;
+ cvt(ffi::EVP_PKEY_get_raw_public_key(
+ self.as_ptr(),
+ ptr::null_mut(),
+ &mut len,
+ ))?;
+ let mut buf = vec![0u8; len];
+ cvt(ffi::EVP_PKEY_get_raw_public_key(
+ self.as_ptr(),
+ buf.as_mut_ptr(),
+ &mut len,
+ ))?;
+ buf.truncate(len);
+ Ok(buf)
+ }
+ }
+}
+
+impl<T> PKeyRef<T>
+where
+ T: HasPrivate,
+{
+ private_key_to_pem! {
+ /// Serializes the private key to a PEM-encoded PKCS#8 PrivateKeyInfo structure.
+ ///
+ /// The output will have a header of `-----BEGIN PRIVATE KEY-----`.
+ #[corresponds(PEM_write_bio_PKCS8PrivateKey)]
+ private_key_to_pem_pkcs8,
+ /// Serializes the private key to a PEM-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
+ ///
+ /// The output will have a header of `-----BEGIN ENCRYPTED PRIVATE KEY-----`.
+ #[corresponds(PEM_write_bio_PKCS8PrivateKey)]
+ private_key_to_pem_pkcs8_passphrase,
+ ffi::PEM_write_bio_PKCS8PrivateKey
+ }
+
+ to_der! {
+ /// Serializes the private key to a DER-encoded key type specific format.
+ #[corresponds(i2d_PrivateKey)]
+ private_key_to_der,
+ ffi::i2d_PrivateKey
+ }
+
+ /// Raw byte representation of a private key.
+ ///
+ /// This function only works for algorithms that support raw private keys.
+ /// Currently this is: [`Id::HMAC`], [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`].
+ #[corresponds(EVP_PKEY_get_raw_private_key)]
+ #[cfg(any(ossl111, boringssl, libressl370))]
+ pub fn raw_private_key(&self) -> Result<Vec<u8>, ErrorStack> {
+ unsafe {
+ let mut len = 0;
+ cvt(ffi::EVP_PKEY_get_raw_private_key(
+ self.as_ptr(),
+ ptr::null_mut(),
+ &mut len,
+ ))?;
+ let mut buf = vec![0u8; len];
+ cvt(ffi::EVP_PKEY_get_raw_private_key(
+ self.as_ptr(),
+ buf.as_mut_ptr(),
+ &mut len,
+ ))?;
+ buf.truncate(len);
+ Ok(buf)
+ }
+ }
+
+ /// Serializes a private key into an unencrypted DER-formatted PKCS#8
+ #[corresponds(i2d_PKCS8PrivateKey_bio)]
+ pub fn private_key_to_pkcs8(&self) -> Result<Vec<u8>, ErrorStack> {
+ unsafe {
+ let bio = MemBio::new()?;
+ cvt(ffi::i2d_PKCS8PrivateKey_bio(
+ bio.as_ptr(),
+ self.as_ptr(),
+ ptr::null(),
+ ptr::null_mut(),
+ 0,
+ None,
+ ptr::null_mut(),
+ ))?;
+
+ Ok(bio.get_buf().to_owned())
+ }
+ }
+
+ /// Serializes a private key into a DER-formatted PKCS#8, using the supplied password to
+ /// encrypt the key.
+ #[corresponds(i2d_PKCS8PrivateKey_bio)]
+ pub fn private_key_to_pkcs8_passphrase(
+ &self,
+ cipher: Cipher,
+ passphrase: &[u8],
+ ) -> Result<Vec<u8>, ErrorStack> {
+ unsafe {
+ let bio = MemBio::new()?;
+ cvt(ffi::i2d_PKCS8PrivateKey_bio(
+ bio.as_ptr(),
+ self.as_ptr(),
+ cipher.as_ptr(),
+ passphrase.as_ptr() as *const _ as *mut _,
+ passphrase.len().try_into().unwrap(),
+ None,
+ ptr::null_mut(),
+ ))?;
+
+ Ok(bio.get_buf().to_owned())
+ }
+ }
+}
+
+impl<T> fmt::Debug for PKey<T> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let alg = match self.id() {
+ Id::RSA => "RSA",
+ #[cfg(not(boringssl))]
+ Id::HMAC => "HMAC",
+ Id::DSA => "DSA",
+ Id::DH => "DH",
+ Id::EC => "EC",
+ #[cfg(ossl111)]
+ Id::ED25519 => "Ed25519",
+ #[cfg(ossl111)]
+ Id::ED448 => "Ed448",
+ _ => "unknown",
+ };
+ fmt.debug_struct("PKey").field("algorithm", &alg).finish()
+ // TODO: Print details for each specific type of key
+ }
+}
+
+impl<T> Clone for PKey<T> {
+ fn clone(&self) -> PKey<T> {
+ PKeyRef::to_owned(self)
+ }
+}
+
+impl<T> PKey<T> {
+ /// Creates a new `PKey` containing an RSA key.
+ #[corresponds(EVP_PKEY_assign_RSA)]
+ pub fn from_rsa(rsa: Rsa<T>) -> Result<PKey<T>, ErrorStack> {
+ unsafe {
+ let evp = cvt_p(ffi::EVP_PKEY_new())?;
+ let pkey = PKey::from_ptr(evp);
+ cvt(ffi::EVP_PKEY_assign_RSA(pkey.0, rsa.as_ptr()))?;
+ mem::forget(rsa);
+ Ok(pkey)
+ }
+ }
+
+ /// Creates a new `PKey` containing a DSA key.
+ #[corresponds(EVP_PKEY_assign_DSA)]
+ pub fn from_dsa(dsa: Dsa<T>) -> Result<PKey<T>, ErrorStack> {
+ unsafe {
+ let evp = cvt_p(ffi::EVP_PKEY_new())?;
+ let pkey = PKey::from_ptr(evp);
+ cvt(ffi::EVP_PKEY_assign_DSA(pkey.0, dsa.as_ptr()))?;
+ mem::forget(dsa);
+ Ok(pkey)
+ }
+ }
+
+ /// Creates a new `PKey` containing a Diffie-Hellman key.
+ #[corresponds(EVP_PKEY_assign_DH)]
+ #[cfg(not(boringssl))]
+ pub fn from_dh(dh: Dh<T>) -> Result<PKey<T>, ErrorStack> {
+ unsafe {
+ let evp = cvt_p(ffi::EVP_PKEY_new())?;
+ let pkey = PKey::from_ptr(evp);
+ cvt(ffi::EVP_PKEY_assign_DH(pkey.0, dh.as_ptr()))?;
+ mem::forget(dh);
+ Ok(pkey)
+ }
+ }
+
+ /// Creates a new `PKey` containing an elliptic curve key.
+ #[corresponds(EVP_PKEY_assign_EC_KEY)]
+ pub fn from_ec_key(ec_key: EcKey<T>) -> Result<PKey<T>, ErrorStack> {
+ unsafe {
+ let evp = cvt_p(ffi::EVP_PKEY_new())?;
+ let pkey = PKey::from_ptr(evp);
+ cvt(ffi::EVP_PKEY_assign_EC_KEY(pkey.0, ec_key.as_ptr()))?;
+ mem::forget(ec_key);
+ Ok(pkey)
+ }
+ }
+}
+
+impl PKey<Private> {
+ /// Creates a new `PKey` containing an HMAC key.
+ ///
+ /// # Note
+ ///
+ /// To compute HMAC values, use the `sign` module.
+ #[corresponds(EVP_PKEY_new_mac_key)]
+ #[cfg(not(boringssl))]
+ pub fn hmac(key: &[u8]) -> Result<PKey<Private>, ErrorStack> {
+ unsafe {
+ assert!(key.len() <= c_int::max_value() as usize);
+ let key = cvt_p(ffi::EVP_PKEY_new_mac_key(
+ ffi::EVP_PKEY_HMAC,
+ ptr::null_mut(),
+ key.as_ptr() as *const _,
+ key.len() as c_int,
+ ))?;
+ Ok(PKey::from_ptr(key))
+ }
+ }
+
+ /// Creates a new `PKey` containing a CMAC key.
+ ///
+ /// Requires OpenSSL 1.1.0 or newer.
+ ///
+ /// # Note
+ ///
+ /// To compute CMAC values, use the `sign` module.
+ #[cfg(all(not(boringssl), ossl110))]
+ #[allow(clippy::trivially_copy_pass_by_ref)]
+ pub fn cmac(cipher: &Cipher, key: &[u8]) -> Result<PKey<Private>, ErrorStack> {
+ 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(any(ossl111, boringssl, libressl370))]
+ fn generate_eddsa(id: Id) -> Result<PKey<Private>, ErrorStack> {
+ let mut ctx = PkeyCtx::new_id(id)?;
+ ctx.keygen_init()?;
+ ctx.keygen()
+ }
+
+ /// Generates a new private X25519 key.
+ ///
+ /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+ /// use openssl::pkey::{PKey, Id};
+ /// use openssl::derive::Deriver;
+ ///
+ /// let public = // ...
+ /// # &PKey::generate_x25519()?.raw_public_key()?;
+ /// let public_key = PKey::public_key_from_raw_bytes(public, Id::X25519)?;
+ ///
+ /// let key = PKey::generate_x25519()?;
+ /// let mut deriver = Deriver::new(&key)?;
+ /// deriver.set_peer(&public_key)?;
+ ///
+ /// let secret = deriver.derive_to_vec()?;
+ /// assert_eq!(secret.len(), 32);
+ /// # Ok(()) }
+ /// ```
+ #[cfg(any(ossl111, boringssl, libressl370))]
+ pub fn generate_x25519() -> Result<PKey<Private>, ErrorStack> {
+ PKey::generate_eddsa(Id::X25519)
+ }
+
+ /// Generates a new private X448 key.
+ ///
+ /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+ /// use openssl::pkey::{PKey, Id};
+ /// use openssl::derive::Deriver;
+ ///
+ /// let public = // ...
+ /// # &PKey::generate_x448()?.raw_public_key()?;
+ /// let public_key = PKey::public_key_from_raw_bytes(public, Id::X448)?;
+ ///
+ /// let key = PKey::generate_x448()?;
+ /// let mut deriver = Deriver::new(&key)?;
+ /// deriver.set_peer(&public_key)?;
+ ///
+ /// let secret = deriver.derive_to_vec()?;
+ /// assert_eq!(secret.len(), 56);
+ /// # Ok(()) }
+ /// ```
+ #[cfg(ossl111)]
+ pub fn generate_x448() -> Result<PKey<Private>, ErrorStack> {
+ PKey::generate_eddsa(Id::X448)
+ }
+
+ /// Generates a new private Ed25519 key.
+ ///
+ /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+ /// use openssl::pkey::{PKey, Id};
+ /// use openssl::sign::Signer;
+ ///
+ /// let key = PKey::generate_ed25519()?;
+ /// let public_key = key.raw_public_key()?;
+ ///
+ /// let mut signer = Signer::new_without_digest(&key)?;
+ /// let digest = // ...
+ /// # &vec![0; 32];
+ /// let signature = signer.sign_oneshot_to_vec(digest)?;
+ /// assert_eq!(signature.len(), 64);
+ /// # Ok(()) }
+ /// ```
+ #[cfg(any(ossl111, boringssl, libressl370))]
+ pub fn generate_ed25519() -> Result<PKey<Private>, ErrorStack> {
+ PKey::generate_eddsa(Id::ED25519)
+ }
+
+ /// Generates a new private Ed448 key.
+ ///
+ /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+ /// use openssl::pkey::{PKey, Id};
+ /// use openssl::sign::Signer;
+ ///
+ /// let key = PKey::generate_ed448()?;
+ /// let public_key = key.raw_public_key()?;
+ ///
+ /// let mut signer = Signer::new_without_digest(&key)?;
+ /// let digest = // ...
+ /// # &vec![0; 32];
+ /// let signature = signer.sign_oneshot_to_vec(digest)?;
+ /// assert_eq!(signature.len(), 114);
+ /// # Ok(()) }
+ /// ```
+ #[cfg(ossl111)]
+ pub fn generate_ed448() -> Result<PKey<Private>, ErrorStack> {
+ PKey::generate_eddsa(Id::ED448)
+ }
+
+ /// Generates a new EC key using the provided curve.
+ ///
+ /// Requires OpenSSL 3.0.0 or newer.
+ #[corresponds(EVP_EC_gen)]
+ #[cfg(ossl300)]
+ pub fn ec_gen(curve: &str) -> Result<PKey<Private>, ErrorStack> {
+ ffi::init();
+
+ let curve = CString::new(curve).unwrap();
+ unsafe {
+ let ptr = cvt_p(ffi::EVP_EC_gen(curve.as_ptr()))?;
+ Ok(PKey::from_ptr(ptr))
+ }
+ }
+
+ private_key_from_pem! {
+ /// Deserializes a private key from a PEM-encoded key type specific format.
+ #[corresponds(PEM_read_bio_PrivateKey)]
+ private_key_from_pem,
+
+ /// Deserializes a private key from a PEM-encoded encrypted key type specific format.
+ #[corresponds(PEM_read_bio_PrivateKey)]
+ private_key_from_pem_passphrase,
+
+ /// Deserializes a private key from a PEM-encoded encrypted key type specific format.
+ ///
+ /// The callback should fill the password into the provided buffer and return its length.
+ #[corresponds(PEM_read_bio_PrivateKey)]
+ private_key_from_pem_callback,
+ PKey<Private>,
+ ffi::PEM_read_bio_PrivateKey
+ }
+
+ from_der! {
+ /// Decodes a DER-encoded private key.
+ ///
+ /// This function will attempt to automatically detect the underlying key format, and
+ /// supports the unencrypted PKCS#8 PrivateKeyInfo structures as well as key type specific
+ /// formats.
+ #[corresponds(d2i_AutoPrivateKey)]
+ private_key_from_der,
+ PKey<Private>,
+ ffi::d2i_AutoPrivateKey
+ }
+
+ /// Deserializes a DER-formatted PKCS#8 unencrypted private key.
+ ///
+ /// This method is mainly for interoperability reasons. Encrypted keyfiles should be preferred.
+ pub fn private_key_from_pkcs8(der: &[u8]) -> Result<PKey<Private>, ErrorStack> {
+ unsafe {
+ ffi::init();
+ let len = der.len().min(c_long::max_value() as usize) as c_long;
+ let p8inf = cvt_p(ffi::d2i_PKCS8_PRIV_KEY_INFO(
+ ptr::null_mut(),
+ &mut der.as_ptr(),
+ len,
+ ))?;
+ let res = cvt_p(ffi::EVP_PKCS82PKEY(p8inf)).map(|p| PKey::from_ptr(p));
+ ffi::PKCS8_PRIV_KEY_INFO_free(p8inf);
+ res
+ }
+ }
+
+ /// Deserializes a DER-formatted PKCS#8 private key, using a callback to retrieve the password
+ /// if the key is encrypted.
+ ///
+ /// The callback should copy the password into the provided buffer and return the number of
+ /// bytes written.
+ #[corresponds(d2i_PKCS8PrivateKey_bio)]
+ pub fn private_key_from_pkcs8_callback<F>(
+ der: &[u8],
+ callback: F,
+ ) -> Result<PKey<Private>, ErrorStack>
+ where
+ F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>,
+ {
+ unsafe {
+ ffi::init();
+ let mut cb = CallbackState::new(callback);
+ let bio = MemBioSlice::new(der)?;
+ cvt_p(ffi::d2i_PKCS8PrivateKey_bio(
+ bio.as_ptr(),
+ ptr::null_mut(),
+ Some(invoke_passwd_cb::<F>),
+ &mut cb as *mut _ as *mut _,
+ ))
+ .map(|p| PKey::from_ptr(p))
+ }
+ }
+
+ /// Deserializes a DER-formatted PKCS#8 private key, using the supplied password if the key is
+ /// encrypted.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `passphrase` contains an embedded null.
+ #[corresponds(d2i_PKCS8PrivateKey_bio)]
+ pub fn private_key_from_pkcs8_passphrase(
+ der: &[u8],
+ passphrase: &[u8],
+ ) -> Result<PKey<Private>, ErrorStack> {
+ unsafe {
+ ffi::init();
+ let bio = MemBioSlice::new(der)?;
+ let passphrase = CString::new(passphrase).unwrap();
+ cvt_p(ffi::d2i_PKCS8PrivateKey_bio(
+ bio.as_ptr(),
+ ptr::null_mut(),
+ None,
+ passphrase.as_ptr() as *const _ as *mut _,
+ ))
+ .map(|p| PKey::from_ptr(p))
+ }
+ }
+
+ /// Creates a private key from its raw byte representation
+ ///
+ /// Algorithm types that support raw private keys are HMAC, X25519, ED25519, X448 or ED448
+ #[corresponds(EVP_PKEY_new_raw_private_key)]
+ #[cfg(any(ossl111, boringssl, libressl370))]
+ pub fn private_key_from_raw_bytes(
+ bytes: &[u8],
+ key_type: Id,
+ ) -> Result<PKey<Private>, ErrorStack> {
+ unsafe {
+ ffi::init();
+ cvt_p(ffi::EVP_PKEY_new_raw_private_key(
+ key_type.as_raw(),
+ ptr::null_mut(),
+ bytes.as_ptr(),
+ bytes.len(),
+ ))
+ .map(|p| PKey::from_ptr(p))
+ }
+ }
+}
+
+impl PKey<Public> {
+ from_pem! {
+ /// Decodes a PEM-encoded SubjectPublicKeyInfo structure.
+ ///
+ /// The input should have a header of `-----BEGIN PUBLIC KEY-----`.
+ #[corresponds(PEM_read_bio_PUBKEY)]
+ public_key_from_pem,
+ PKey<Public>,
+ ffi::PEM_read_bio_PUBKEY
+ }
+
+ from_der! {
+ /// Decodes a DER-encoded SubjectPublicKeyInfo structure.
+ #[corresponds(d2i_PUBKEY)]
+ public_key_from_der,
+ PKey<Public>,
+ ffi::d2i_PUBKEY
+ }
+
+ /// Creates a public key from its raw byte representation
+ ///
+ /// Algorithm types that support raw public keys are X25519, ED25519, X448 or ED448
+ #[corresponds(EVP_PKEY_new_raw_public_key)]
+ #[cfg(any(ossl111, boringssl, libressl370))]
+ pub fn public_key_from_raw_bytes(
+ bytes: &[u8],
+ key_type: Id,
+ ) -> Result<PKey<Public>, ErrorStack> {
+ unsafe {
+ ffi::init();
+ cvt_p(ffi::EVP_PKEY_new_raw_public_key(
+ key_type.as_raw(),
+ ptr::null_mut(),
+ bytes.as_ptr(),
+ bytes.len(),
+ ))
+ .map(|p| PKey::from_ptr(p))
+ }
+ }
+}
+
+cfg_if! {
+ if #[cfg(any(boringssl, ossl110, libressl270))] {
+ use ffi::EVP_PKEY_up_ref;
+ } else {
+ #[allow(bad_style)]
+ unsafe extern "C" fn EVP_PKEY_up_ref(pkey: *mut ffi::EVP_PKEY) {
+ ffi::CRYPTO_add_lock(
+ &mut (*pkey).references,
+ 1,
+ ffi::CRYPTO_LOCK_EVP_PKEY,
+ "pkey.rs\0".as_ptr() as *const _,
+ line!() as c_int,
+ );
+ }
+ }
+}
+
+impl<T> TryFrom<EcKey<T>> for PKey<T> {
+ type Error = ErrorStack;
+
+ fn try_from(ec_key: EcKey<T>) -> Result<PKey<T>, ErrorStack> {
+ PKey::from_ec_key(ec_key)
+ }
+}
+
+impl<T> TryFrom<PKey<T>> for EcKey<T> {
+ type Error = ErrorStack;
+
+ fn try_from(pkey: PKey<T>) -> Result<EcKey<T>, ErrorStack> {
+ pkey.ec_key()
+ }
+}
+
+impl<T> TryFrom<Rsa<T>> for PKey<T> {
+ type Error = ErrorStack;
+
+ fn try_from(rsa: Rsa<T>) -> Result<PKey<T>, ErrorStack> {
+ PKey::from_rsa(rsa)
+ }
+}
+
+impl<T> TryFrom<PKey<T>> for Rsa<T> {
+ type Error = ErrorStack;
+
+ fn try_from(pkey: PKey<T>) -> Result<Rsa<T>, ErrorStack> {
+ pkey.rsa()
+ }
+}
+
+impl<T> TryFrom<Dsa<T>> for PKey<T> {
+ type Error = ErrorStack;
+
+ fn try_from(dsa: Dsa<T>) -> Result<PKey<T>, ErrorStack> {
+ PKey::from_dsa(dsa)
+ }
+}
+
+impl<T> TryFrom<PKey<T>> for Dsa<T> {
+ type Error = ErrorStack;
+
+ fn try_from(pkey: PKey<T>) -> Result<Dsa<T>, ErrorStack> {
+ pkey.dsa()
+ }
+}
+
+#[cfg(not(boringssl))]
+impl<T> TryFrom<Dh<T>> for PKey<T> {
+ type Error = ErrorStack;
+
+ fn try_from(dh: Dh<T>) -> Result<PKey<T>, ErrorStack> {
+ PKey::from_dh(dh)
+ }
+}
+
+impl<T> TryFrom<PKey<T>> for Dh<T> {
+ type Error = ErrorStack;
+
+ fn try_from(pkey: PKey<T>) -> Result<Dh<T>, ErrorStack> {
+ pkey.dh()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use std::convert::TryInto;
+
+ #[cfg(not(boringssl))]
+ use crate::dh::Dh;
+ use crate::dsa::Dsa;
+ use crate::ec::EcKey;
+ use crate::error::Error;
+ use crate::nid::Nid;
+ use crate::rsa::Rsa;
+ use crate::symm::Cipher;
+
+ use super::*;
+
+ #[cfg(ossl111)]
+ use crate::rand::rand_bytes;
+
+ #[test]
+ fn test_to_password() {
+ let rsa = Rsa::generate(2048).unwrap();
+ let pkey = PKey::from_rsa(rsa).unwrap();
+ let pem = pkey
+ .private_key_to_pem_pkcs8_passphrase(Cipher::aes_128_cbc(), b"foobar")
+ .unwrap();
+ PKey::private_key_from_pem_passphrase(&pem, b"foobar").unwrap();
+ assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err());
+ }
+
+ #[test]
+ fn test_unencrypted_pkcs8() {
+ let key = include_bytes!("../test/pkcs8-nocrypt.der");
+ let pkey = PKey::private_key_from_pkcs8(key).unwrap();
+ let serialized = pkey.private_key_to_pkcs8().unwrap();
+ let pkey2 = PKey::private_key_from_pkcs8(&serialized).unwrap();
+
+ assert_eq!(
+ pkey2.private_key_to_der().unwrap(),
+ pkey.private_key_to_der().unwrap()
+ );
+ }
+
+ #[test]
+ fn test_encrypted_pkcs8_passphrase() {
+ let key = include_bytes!("../test/pkcs8.der");
+ PKey::private_key_from_pkcs8_passphrase(key, b"mypass").unwrap();
+
+ let rsa = Rsa::generate(2048).unwrap();
+ let pkey = PKey::from_rsa(rsa).unwrap();
+ let der = pkey
+ .private_key_to_pkcs8_passphrase(Cipher::aes_128_cbc(), b"mypass")
+ .unwrap();
+ let pkey2 = PKey::private_key_from_pkcs8_passphrase(&der, b"mypass").unwrap();
+ assert_eq!(
+ pkey.private_key_to_der().unwrap(),
+ pkey2.private_key_to_der().unwrap()
+ );
+ }
+
+ #[test]
+ fn test_encrypted_pkcs8_callback() {
+ let mut password_queried = false;
+ let key = include_bytes!("../test/pkcs8.der");
+ PKey::private_key_from_pkcs8_callback(key, |password| {
+ password_queried = true;
+ password[..6].copy_from_slice(b"mypass");
+ Ok(6)
+ })
+ .unwrap();
+ assert!(password_queried);
+ }
+
+ #[test]
+ fn test_private_key_from_pem() {
+ let key = include_bytes!("../test/key.pem");
+ PKey::private_key_from_pem(key).unwrap();
+ }
+
+ #[test]
+ fn test_public_key_from_pem() {
+ let key = include_bytes!("../test/key.pem.pub");
+ PKey::public_key_from_pem(key).unwrap();
+ }
+
+ #[test]
+ fn test_public_key_from_der() {
+ let key = include_bytes!("../test/key.der.pub");
+ PKey::public_key_from_der(key).unwrap();
+ }
+
+ #[test]
+ fn test_private_key_from_der() {
+ let key = include_bytes!("../test/key.der");
+ PKey::private_key_from_der(key).unwrap();
+ }
+
+ #[test]
+ fn test_pem() {
+ let key = include_bytes!("../test/key.pem");
+ let key = PKey::private_key_from_pem(key).unwrap();
+
+ let priv_key = key.private_key_to_pem_pkcs8().unwrap();
+ let pub_key = key.public_key_to_pem().unwrap();
+
+ // As a super-simple verification, just check that the buffers contain
+ // the `PRIVATE KEY` or `PUBLIC KEY` strings.
+ assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY"));
+ assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY"));
+ }
+
+ #[test]
+ fn test_rsa_accessor() {
+ let rsa = Rsa::generate(2048).unwrap();
+ let pkey = PKey::from_rsa(rsa).unwrap();
+ pkey.rsa().unwrap();
+ assert_eq!(pkey.id(), Id::RSA);
+ assert!(pkey.dsa().is_err());
+ }
+
+ #[test]
+ fn test_dsa_accessor() {
+ let dsa = Dsa::generate(2048).unwrap();
+ let pkey = PKey::from_dsa(dsa).unwrap();
+ pkey.dsa().unwrap();
+ assert_eq!(pkey.id(), Id::DSA);
+ assert!(pkey.rsa().is_err());
+ }
+
+ #[test]
+ #[cfg(not(boringssl))]
+ fn test_dh_accessor() {
+ let dh = include_bytes!("../test/dhparams.pem");
+ let dh = Dh::params_from_pem(dh).unwrap();
+ let pkey = PKey::from_dh(dh).unwrap();
+ pkey.dh().unwrap();
+ assert_eq!(pkey.id(), Id::DH);
+ assert!(pkey.rsa().is_err());
+ }
+
+ #[test]
+ fn test_ec_key_accessor() {
+ let ec_key = EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
+ let pkey = PKey::from_ec_key(ec_key).unwrap();
+ pkey.ec_key().unwrap();
+ assert_eq!(pkey.id(), Id::EC);
+ assert!(pkey.rsa().is_err());
+ }
+
+ #[test]
+ fn test_rsa_conversion() {
+ let rsa = Rsa::generate(2048).unwrap();
+ let pkey: PKey<Private> = rsa.clone().try_into().unwrap();
+ let rsa_: Rsa<Private> = pkey.try_into().unwrap();
+ // Eq is missing
+ assert_eq!(rsa.p(), rsa_.p());
+ assert_eq!(rsa.q(), rsa_.q());
+ }
+
+ #[test]
+ fn test_dsa_conversion() {
+ let dsa = Dsa::generate(2048).unwrap();
+ let pkey: PKey<Private> = dsa.clone().try_into().unwrap();
+ let dsa_: Dsa<Private> = pkey.try_into().unwrap();
+ // Eq is missing
+ assert_eq!(dsa.priv_key(), dsa_.priv_key());
+ }
+
+ #[test]
+ fn test_ec_key_conversion() {
+ let group = crate::ec::EcGroup::from_curve_name(crate::nid::Nid::X9_62_PRIME256V1).unwrap();
+ let ec_key = EcKey::generate(&group).unwrap();
+ let pkey: PKey<Private> = ec_key.clone().try_into().unwrap();
+ let ec_key_: EcKey<Private> = pkey.try_into().unwrap();
+ // Eq is missing
+ assert_eq!(ec_key.private_key(), ec_key_.private_key());
+ }
+
+ #[test]
+ #[cfg(any(ossl110, libressl360))]
+ fn test_security_bits() {
+ let group = crate::ec::EcGroup::from_curve_name(crate::nid::Nid::SECP521R1).unwrap();
+ let ec_key = EcKey::generate(&group).unwrap();
+ let pkey: PKey<Private> = ec_key.try_into().unwrap();
+
+ assert_eq!(pkey.security_bits(), 256);
+ }
+
+ #[test]
+ #[cfg(not(boringssl))]
+ fn test_dh_conversion() {
+ let dh_params = include_bytes!("../test/dhparams.pem");
+ let dh_params = Dh::params_from_pem(dh_params).unwrap();
+ let dh = dh_params.generate_key().unwrap();
+
+ // Clone is missing for Dh, save the parameters
+ let p = dh.prime_p().to_owned().unwrap();
+ let q = dh.prime_q().map(|q| q.to_owned().unwrap());
+ let g = dh.generator().to_owned().unwrap();
+
+ let pkey: PKey<Private> = dh.try_into().unwrap();
+ let dh_: Dh<Private> = pkey.try_into().unwrap();
+
+ // Eq is missing
+ assert_eq!(&p, dh_.prime_p());
+ assert_eq!(q, dh_.prime_q().map(|q| q.to_owned().unwrap()));
+ assert_eq!(&g, dh_.generator());
+ }
+
+ #[cfg(any(ossl111, boringssl, libressl370))]
+ fn test_raw_public_key(gen: fn() -> Result<PKey<Private>, ErrorStack>, key_type: Id) {
+ // Generate a new key
+ let key = gen().unwrap();
+
+ // Get the raw bytes, and create a new key from the raw bytes
+ let raw = key.raw_public_key().unwrap();
+ let from_raw = PKey::public_key_from_raw_bytes(&raw, key_type).unwrap();
+
+ // Compare the der encoding of the original and raw / restored public key
+ assert_eq!(
+ key.public_key_to_der().unwrap(),
+ from_raw.public_key_to_der().unwrap()
+ );
+ }
+
+ #[cfg(any(ossl111, boringssl, libressl370))]
+ fn test_raw_private_key(gen: fn() -> Result<PKey<Private>, ErrorStack>, key_type: Id) {
+ // Generate a new key
+ let key = gen().unwrap();
+
+ // Get the raw bytes, and create a new key from the raw bytes
+ let raw = key.raw_private_key().unwrap();
+ let from_raw = PKey::private_key_from_raw_bytes(&raw, key_type).unwrap();
+
+ // Compare the der encoding of the original and raw / restored public key
+ assert_eq!(
+ key.private_key_to_pkcs8().unwrap(),
+ from_raw.private_key_to_pkcs8().unwrap()
+ );
+ }
+
+ #[cfg(any(ossl111, boringssl, libressl370))]
+ #[test]
+ fn test_raw_public_key_bytes() {
+ test_raw_public_key(PKey::generate_x25519, Id::X25519);
+ test_raw_public_key(PKey::generate_ed25519, Id::ED25519);
+ #[cfg(all(not(boringssl), not(libressl370)))]
+ test_raw_public_key(PKey::generate_x448, Id::X448);
+ #[cfg(all(not(boringssl), not(libressl370)))]
+ test_raw_public_key(PKey::generate_ed448, Id::ED448);
+ }
+
+ #[cfg(any(ossl111, boringssl, libressl370))]
+ #[test]
+ fn test_raw_private_key_bytes() {
+ test_raw_private_key(PKey::generate_x25519, Id::X25519);
+ test_raw_private_key(PKey::generate_ed25519, Id::ED25519);
+ #[cfg(all(not(boringssl), not(libressl370)))]
+ test_raw_private_key(PKey::generate_x448, Id::X448);
+ #[cfg(all(not(boringssl), not(libressl370)))]
+ test_raw_private_key(PKey::generate_ed448, Id::ED448);
+ }
+
+ #[cfg(ossl111)]
+ #[test]
+ fn test_raw_hmac() {
+ let mut test_bytes = vec![0u8; 32];
+ rand_bytes(&mut test_bytes).unwrap();
+
+ let hmac_key = PKey::hmac(&test_bytes).unwrap();
+ assert!(hmac_key.raw_public_key().is_err());
+
+ let key_bytes = hmac_key.raw_private_key().unwrap();
+ assert_eq!(key_bytes, test_bytes);
+ }
+
+ #[cfg(ossl111)]
+ #[test]
+ fn test_raw_key_fail() {
+ // Getting a raw byte representation will not work with Nist curves
+ let group = crate::ec::EcGroup::from_curve_name(Nid::SECP256K1).unwrap();
+ let ec_key = EcKey::generate(&group).unwrap();
+ let pkey = PKey::from_ec_key(ec_key).unwrap();
+ assert!(pkey.raw_private_key().is_err());
+ assert!(pkey.raw_public_key().is_err());
+ }
+
+ #[cfg(ossl300)]
+ #[test]
+ fn test_ec_gen() {
+ let key = PKey::ec_gen("prime256v1").unwrap();
+ assert!(key.ec_key().is_ok());
+ }
+
+ #[test]
+ fn test_public_eq() {
+ let rsa = Rsa::generate(2048).unwrap();
+ let pkey1 = PKey::from_rsa(rsa).unwrap();
+
+ let group = crate::ec::EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
+ let ec_key = EcKey::generate(&group).unwrap();
+ let pkey2 = PKey::from_ec_key(ec_key).unwrap();
+
+ assert!(!pkey1.public_eq(&pkey2));
+ assert!(Error::get().is_none());
+ }
+}