Skip to main content

variant_ssl/
pkey.rs

1//! Public/private key processing.
2//!
3//! Asymmetric public key algorithms solve the problem of establishing and sharing
4//! secret keys to securely send and receive messages.
5//! This system uses a pair of keys: a public key, which can be freely
6//! distributed, and a private key, which is kept to oneself. An entity may
7//! encrypt information using a user's public key. The encrypted information can
8//! only be deciphered using that user's private key.
9//!
10//! This module offers support for five popular algorithms:
11//!
12//! * RSA
13//!
14//! * DSA
15//!
16//! * Diffie-Hellman
17//!
18//! * Elliptic Curves
19//!
20//! * HMAC
21//!
22//! These algorithms rely on hard mathematical problems - namely integer factorization,
23//! discrete logarithms, and elliptic curve relationships - that currently do not
24//! yield efficient solutions. This property ensures the security of these
25//! cryptographic algorithms.
26//!
27//! # Example
28//!
29//! Generate a 2048-bit RSA public/private key pair and print the public key.
30//!
31//! ```rust
32//! use openssl::rsa::Rsa;
33//! use openssl::pkey::PKey;
34//! use std::str;
35//!
36//! let rsa = Rsa::generate(2048).unwrap();
37//! let pkey = PKey::from_rsa(rsa).unwrap();
38//!
39//! let pub_key: Vec<u8> = pkey.public_key_to_pem().unwrap();
40//! println!("{:?}", str::from_utf8(pub_key.as_slice()).unwrap());
41//! ```
42#![allow(clippy::missing_safety_doc)]
43use crate::bio::{MemBio, MemBioSlice};
44#[cfg(ossl110)]
45use crate::cipher::CipherRef;
46use crate::dh::Dh;
47use crate::dsa::Dsa;
48use crate::ec::EcKey;
49use crate::error::ErrorStack;
50#[cfg(ossl300)]
51use crate::lib_ctx::LibCtxRef;
52#[cfg(any(ossl110, boringssl, libressl370, awslc))]
53use crate::pkey_ctx::PkeyCtx;
54use crate::rsa::Rsa;
55use crate::symm::Cipher;
56use crate::util::{invoke_passwd_cb, CallbackState};
57use crate::{cvt, cvt_p};
58use foreign_types::{ForeignType, ForeignTypeRef};
59use libc::{c_int, c_long};
60use openssl_macros::corresponds;
61use std::convert::{TryFrom, TryInto};
62use std::ffi::{CStr, CString};
63use std::fmt;
64#[cfg(all(not(any(boringssl, awslc)), ossl110))]
65use std::mem;
66use std::ptr;
67
68/// A tag type indicating that a key only has parameters.
69pub enum Params {}
70
71/// A tag type indicating that a key only has public components.
72pub enum Public {}
73
74/// A tag type indicating that a key has private components.
75pub enum Private {}
76
77/// An identifier of a kind of key.
78#[derive(Debug, Copy, Clone, PartialEq, Eq)]
79pub struct Id(c_int);
80
81impl Id {
82    pub const RSA: Id = Id(ffi::EVP_PKEY_RSA);
83    #[cfg(any(ossl111, libressl, boringssl, awslc))]
84    pub const RSA_PSS: Id = Id(ffi::EVP_PKEY_RSA_PSS);
85    #[cfg(not(boringssl))]
86    pub const HMAC: Id = Id(ffi::EVP_PKEY_HMAC);
87    #[cfg(not(any(boringssl, awslc)))]
88    pub const CMAC: Id = Id(ffi::EVP_PKEY_CMAC);
89    pub const DSA: Id = Id(ffi::EVP_PKEY_DSA);
90    pub const DH: Id = Id(ffi::EVP_PKEY_DH);
91    #[cfg(ossl110)]
92    pub const DHX: Id = Id(ffi::EVP_PKEY_DHX);
93    pub const EC: Id = Id(ffi::EVP_PKEY_EC);
94    #[cfg(ossl111)]
95    pub const SM2: Id = Id(ffi::EVP_PKEY_SM2);
96
97    #[cfg(any(ossl110, boringssl, libressl360, awslc))]
98    pub const HKDF: Id = Id(ffi::EVP_PKEY_HKDF);
99
100    #[cfg(any(ossl111, boringssl, libressl370, awslc))]
101    pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519);
102    #[cfg(ossl111)]
103    pub const ED448: Id = Id(ffi::EVP_PKEY_ED448);
104    #[cfg(any(ossl111, boringssl, libressl370, awslc))]
105    pub const X25519: Id = Id(ffi::EVP_PKEY_X25519);
106    #[cfg(ossl111)]
107    pub const X448: Id = Id(ffi::EVP_PKEY_X448);
108    #[cfg(ossl111)]
109    pub const POLY1305: Id = Id(ffi::EVP_PKEY_POLY1305);
110
111    /// Creates a `Id` from an integer representation.
112    pub const fn from_raw(value: c_int) -> Id {
113        Id(value)
114    }
115
116    /// Returns the integer representation of the `Id`.
117    #[allow(clippy::trivially_copy_pass_by_ref)]
118    pub fn as_raw(&self) -> c_int {
119        self.0
120    }
121}
122
123/// The name of a key algorithm, used with [`PKeyRef::is_a`].
124///
125/// In OpenSSL 3.0+, provider-supplied keys do not have a meaningful numeric
126/// id (`EVP_PKEY_id` returns `-1`), so identifying them requires a name-based
127/// check via `EVP_PKEY_is_a`. `KeyType` wraps the algorithm name as a static
128/// C string and exposes constants for common algorithms.
129#[derive(Debug, Copy, Clone, PartialEq, Eq)]
130pub struct KeyType(&'static CStr);
131
132impl KeyType {
133    pub const RSA: KeyType = KeyType(c"RSA");
134    pub const RSA_PSS: KeyType = KeyType(c"RSA-PSS");
135    pub const DSA: KeyType = KeyType(c"DSA");
136    pub const DH: KeyType = KeyType(c"DH");
137    pub const EC: KeyType = KeyType(c"EC");
138    pub const ED25519: KeyType = KeyType(c"ED25519");
139    pub const ED448: KeyType = KeyType(c"ED448");
140    pub const X25519: KeyType = KeyType(c"X25519");
141    pub const X448: KeyType = KeyType(c"X448");
142    pub const HMAC: KeyType = KeyType(c"HMAC");
143    pub const CMAC: KeyType = KeyType(c"CMAC");
144    pub const ML_DSA_44: KeyType = KeyType(c"ML-DSA-44");
145    pub const ML_DSA_65: KeyType = KeyType(c"ML-DSA-65");
146    pub const ML_DSA_87: KeyType = KeyType(c"ML-DSA-87");
147    pub const ML_KEM_512: KeyType = KeyType(c"ML-KEM-512");
148    pub const ML_KEM_768: KeyType = KeyType(c"ML-KEM-768");
149    pub const ML_KEM_1024: KeyType = KeyType(c"ML-KEM-1024");
150
151    /// Returns the algorithm name as a C string.
152    #[cfg(ossl300)]
153    pub(crate) fn as_cstr(&self) -> &'static CStr {
154        self.0
155    }
156}
157
158/// A trait indicating that a key has parameters.
159pub unsafe trait HasParams {}
160
161unsafe impl HasParams for Params {}
162
163unsafe impl<T> HasParams for T where T: HasPublic {}
164
165/// A trait indicating that a key has public components.
166pub unsafe trait HasPublic {}
167
168unsafe impl HasPublic for Public {}
169
170unsafe impl<T> HasPublic for T where T: HasPrivate {}
171
172/// A trait indicating that a key has private components.
173pub unsafe trait HasPrivate {}
174
175unsafe impl HasPrivate for Private {}
176
177generic_foreign_type_and_impl_send_sync! {
178    type CType = ffi::EVP_PKEY;
179    fn drop = ffi::EVP_PKEY_free;
180
181    /// A public or private key.
182    pub struct PKey<T>;
183    /// Reference to `PKey`.
184    pub struct PKeyRef<T>;
185}
186
187impl<T> ToOwned for PKeyRef<T> {
188    type Owned = PKey<T>;
189
190    fn to_owned(&self) -> PKey<T> {
191        unsafe {
192            let r = EVP_PKEY_up_ref(self.as_ptr());
193            assert!(r == 1);
194            PKey::from_ptr(self.as_ptr())
195        }
196    }
197}
198
199impl<T> PKeyRef<T> {
200    /// Returns a copy of the internal RSA key.
201    #[corresponds(EVP_PKEY_get1_RSA)]
202    pub fn rsa(&self) -> Result<Rsa<T>, ErrorStack> {
203        unsafe {
204            let rsa = cvt_p(ffi::EVP_PKEY_get1_RSA(self.as_ptr()))?;
205            Ok(Rsa::from_ptr(rsa))
206        }
207    }
208
209    /// Returns a copy of the internal DSA key.
210    #[corresponds(EVP_PKEY_get1_DSA)]
211    pub fn dsa(&self) -> Result<Dsa<T>, ErrorStack> {
212        unsafe {
213            let dsa = cvt_p(ffi::EVP_PKEY_get1_DSA(self.as_ptr()))?;
214            Ok(Dsa::from_ptr(dsa))
215        }
216    }
217
218    /// Returns a copy of the internal DH key.
219    #[corresponds(EVP_PKEY_get1_DH)]
220    pub fn dh(&self) -> Result<Dh<T>, ErrorStack> {
221        unsafe {
222            let dh = cvt_p(ffi::EVP_PKEY_get1_DH(self.as_ptr()))?;
223            Ok(Dh::from_ptr(dh))
224        }
225    }
226
227    /// Returns a copy of the internal elliptic curve key.
228    #[corresponds(EVP_PKEY_get1_EC_KEY)]
229    pub fn ec_key(&self) -> Result<EcKey<T>, ErrorStack> {
230        unsafe {
231            let ec_key = cvt_p(ffi::EVP_PKEY_get1_EC_KEY(self.as_ptr()))?;
232            Ok(EcKey::from_ptr(ec_key))
233        }
234    }
235
236    /// Returns the `Id` that represents the type of this key.
237    ///
238    /// In OpenSSL 3.0+, provider-supplied keys (such as ML-DSA or any key
239    /// from a third-party provider) return `-1` from `EVP_PKEY_id`. Use
240    /// [`PKeyRef::is_a`] for a name-based check that works for those keys.
241    #[corresponds(EVP_PKEY_id)]
242    pub fn id(&self) -> Id {
243        unsafe { Id::from_raw(ffi::EVP_PKEY_id(self.as_ptr())) }
244    }
245
246    /// Returns `true` if this key is an instance of the algorithm named
247    /// by `key_type`.
248    ///
249    /// This is the OpenSSL 3.0+ name-based equivalent of [`PKeyRef::id`].
250    /// It is the only reliable way to identify provider-supplied keys,
251    /// which return `-1` from `EVP_PKEY_id`.
252    #[corresponds(EVP_PKEY_is_a)]
253    #[cfg(ossl300)]
254    pub fn is_a(&self, key_type: KeyType) -> bool {
255        unsafe { ffi::EVP_PKEY_is_a(self.as_ptr(), key_type.as_cstr().as_ptr()) == 1 }
256    }
257
258    /// Returns the maximum size of a signature in bytes.
259    #[corresponds(EVP_PKEY_size)]
260    pub fn size(&self) -> usize {
261        unsafe { ffi::EVP_PKEY_size(self.as_ptr()) as usize }
262    }
263}
264
265impl<T> PKeyRef<T>
266where
267    T: HasPublic,
268{
269    to_pem! {
270        /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure.
271        ///
272        /// The output will have a header of `-----BEGIN PUBLIC KEY-----`.
273        #[corresponds(PEM_write_bio_PUBKEY)]
274        public_key_to_pem,
275        ffi::PEM_write_bio_PUBKEY
276    }
277
278    to_der! {
279        /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure.
280        #[corresponds(i2d_PUBKEY)]
281        public_key_to_der,
282        ffi::i2d_PUBKEY
283    }
284
285    /// Returns the size of the key.
286    ///
287    /// This corresponds to the bit length of the modulus of an RSA key, and the bit length of the
288    /// group order for an elliptic curve key, for example.
289    #[corresponds(EVP_PKEY_bits)]
290    pub fn bits(&self) -> u32 {
291        unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as u32 }
292    }
293
294    ///Returns the number of security bits.
295    ///
296    ///Bits of security is defined in NIST SP800-57.
297    #[corresponds(EVP_PKEY_security_bits)]
298    #[cfg(any(ossl110, libressl360))]
299    pub fn security_bits(&self) -> u32 {
300        unsafe { ffi::EVP_PKEY_security_bits(self.as_ptr()) as u32 }
301    }
302
303    /// Compares the public component of this key with another.
304    #[corresponds(EVP_PKEY_cmp)]
305    pub fn public_eq<U>(&self, other: &PKeyRef<U>) -> bool
306    where
307        U: HasPublic,
308    {
309        let res = unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 };
310        // Clear the stack. OpenSSL will put an error on the stack when the
311        // keys are different types in some situations.
312        let _ = ErrorStack::get();
313        res
314    }
315
316    /// Raw byte representation of a public key.
317    ///
318    /// This function only works for algorithms that support raw public keys.
319    /// Currently this is: [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`].
320    #[corresponds(EVP_PKEY_get_raw_public_key)]
321    #[cfg(any(ossl111, boringssl, libressl370, awslc))]
322    pub fn raw_public_key(&self) -> Result<Vec<u8>, ErrorStack> {
323        unsafe {
324            let mut len = 0;
325            cvt(ffi::EVP_PKEY_get_raw_public_key(
326                self.as_ptr(),
327                ptr::null_mut(),
328                &mut len,
329            ))?;
330            let mut buf = vec![0u8; len];
331            cvt(ffi::EVP_PKEY_get_raw_public_key(
332                self.as_ptr(),
333                buf.as_mut_ptr(),
334                &mut len,
335            ))?;
336            buf.truncate(len);
337            Ok(buf)
338        }
339    }
340}
341
342impl<T> PKeyRef<T>
343where
344    T: HasPrivate,
345{
346    private_key_to_pem! {
347        /// Serializes the private key to a PEM-encoded PKCS#8 PrivateKeyInfo structure.
348        ///
349        /// The output will have a header of `-----BEGIN PRIVATE KEY-----`.
350        #[corresponds(PEM_write_bio_PKCS8PrivateKey)]
351        private_key_to_pem_pkcs8,
352        /// Serializes the private key to a PEM-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
353        ///
354        /// The output will have a header of `-----BEGIN ENCRYPTED PRIVATE KEY-----`.
355        #[corresponds(PEM_write_bio_PKCS8PrivateKey)]
356        private_key_to_pem_pkcs8_passphrase,
357        ffi::PEM_write_bio_PKCS8PrivateKey
358    }
359
360    to_der! {
361        /// Serializes the private key to a DER-encoded key type specific format.
362        #[corresponds(i2d_PrivateKey)]
363        private_key_to_der,
364        ffi::i2d_PrivateKey
365    }
366
367    /// Raw byte representation of a private key.
368    ///
369    /// This function only works for algorithms that support raw private keys.
370    /// Currently this is: [`Id::HMAC`], [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`].
371    #[corresponds(EVP_PKEY_get_raw_private_key)]
372    #[cfg(any(ossl111, boringssl, libressl370, awslc))]
373    pub fn raw_private_key(&self) -> Result<Vec<u8>, ErrorStack> {
374        unsafe {
375            let mut len = 0;
376            cvt(ffi::EVP_PKEY_get_raw_private_key(
377                self.as_ptr(),
378                ptr::null_mut(),
379                &mut len,
380            ))?;
381            let mut buf = vec![0u8; len];
382            cvt(ffi::EVP_PKEY_get_raw_private_key(
383                self.as_ptr(),
384                buf.as_mut_ptr(),
385                &mut len,
386            ))?;
387            buf.truncate(len);
388            Ok(buf)
389        }
390    }
391
392    /// Writes the algorithm-defined seed for an ML-DSA or ML-KEM private key
393    /// into `buf`, returning the number of bytes written.
394    ///
395    /// `buf` must be at least 32 bytes long for ML-DSA and 64 bytes long for
396    /// ML-KEM. The inverse of [`PKey::private_key_from_seed`].
397    ///
398    /// Errors when called on a key whose algorithm has no `"seed"`
399    /// `OSSL_PARAM` (e.g. RSA, EC, Ed25519), when `buf` is too small for
400    /// the algorithm's seed, or when the underlying key was imported from
401    /// an encoded form that retains only the expanded private key with no
402    /// seed.
403    #[corresponds(EVP_PKEY_get_params)]
404    #[cfg(ossl350)]
405    pub fn seed_into(&self, buf: &mut [u8]) -> Result<usize, ErrorStack> {
406        unsafe {
407            let mut params = [
408                ffi::OSSL_PARAM_construct_octet_string(
409                    c"seed".as_ptr(),
410                    buf.as_mut_ptr() as *mut libc::c_void,
411                    buf.len(),
412                ),
413                ffi::OSSL_PARAM_construct_end(),
414            ];
415            cvt(ffi::EVP_PKEY_get_params(self.as_ptr(), params.as_mut_ptr()))?;
416            // OpenSSL silently ignores OSSL_PARAMs the keymgmt doesn't
417            // recognise and returns success. Detect that case via
418            // OSSL_PARAM_modified before trusting return_size.
419            if ffi::OSSL_PARAM_modified(&params[0]) == 0 {
420                return Err(ErrorStack::get());
421            }
422            Ok(params[0].return_size)
423        }
424    }
425
426    /// Serializes a private key into an unencrypted DER-formatted PKCS#8
427    #[corresponds(i2d_PKCS8PrivateKey_bio)]
428    pub fn private_key_to_pkcs8(&self) -> Result<Vec<u8>, ErrorStack> {
429        unsafe {
430            let bio = MemBio::new()?;
431            cvt(ffi::i2d_PKCS8PrivateKey_bio(
432                bio.as_ptr(),
433                self.as_ptr(),
434                ptr::null(),
435                ptr::null_mut(),
436                0,
437                None,
438                ptr::null_mut(),
439            ))?;
440
441            Ok(bio.get_buf().to_owned())
442        }
443    }
444
445    /// Serializes a private key into a DER-formatted PKCS#8, using the supplied password to
446    /// encrypt the key.
447    #[corresponds(i2d_PKCS8PrivateKey_bio)]
448    pub fn private_key_to_pkcs8_passphrase(
449        &self,
450        cipher: Cipher,
451        passphrase: &[u8],
452    ) -> Result<Vec<u8>, ErrorStack> {
453        unsafe {
454            let bio = MemBio::new()?;
455            cvt(ffi::i2d_PKCS8PrivateKey_bio(
456                bio.as_ptr(),
457                self.as_ptr(),
458                cipher.as_ptr(),
459                passphrase.as_ptr() as *const _ as *mut _,
460                passphrase.len().try_into().unwrap(),
461                None,
462                ptr::null_mut(),
463            ))?;
464
465            Ok(bio.get_buf().to_owned())
466        }
467    }
468}
469
470impl<T> fmt::Debug for PKey<T> {
471    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
472        let alg = match self.id() {
473            Id::RSA => "RSA",
474            #[cfg(any(ossl111, libressl, boringssl, awslc))]
475            Id::RSA_PSS => "RSA-PSS",
476            #[cfg(not(boringssl))]
477            Id::HMAC => "HMAC",
478            #[cfg(not(any(boringssl, awslc)))]
479            Id::CMAC => "CMAC",
480            Id::DSA => "DSA",
481            Id::DH => "DH",
482            #[cfg(ossl110)]
483            Id::DHX => "DHX",
484            Id::EC => "EC",
485            #[cfg(ossl111)]
486            Id::SM2 => "SM2",
487            #[cfg(any(ossl110, boringssl, libressl360, awslc))]
488            Id::HKDF => "HKDF",
489            #[cfg(any(ossl111, boringssl, libressl370, awslc))]
490            Id::ED25519 => "Ed25519",
491            #[cfg(ossl111)]
492            Id::ED448 => "Ed448",
493            #[cfg(any(ossl111, boringssl, libressl370, awslc))]
494            Id::X25519 => "X25519",
495            #[cfg(ossl111)]
496            Id::X448 => "X448",
497            #[cfg(ossl111)]
498            Id::POLY1305 => "POLY1305",
499            _ => "unknown",
500        };
501        fmt.debug_struct("PKey").field("algorithm", &alg).finish()
502        // TODO: Print details for each specific type of key
503    }
504}
505
506impl<T> Clone for PKey<T> {
507    fn clone(&self) -> PKey<T> {
508        PKeyRef::to_owned(self)
509    }
510}
511
512impl<T> PKey<T> {
513    /// Creates a new `PKey` containing an RSA key.
514    #[corresponds(EVP_PKEY_set1_RSA)]
515    pub fn from_rsa(rsa: Rsa<T>) -> Result<PKey<T>, ErrorStack> {
516        // TODO: Next time we make backwards incompatible changes, this could
517        // become an `&RsaRef<T>`. Same for all the other `from_*` methods.
518        unsafe {
519            let evp = cvt_p(ffi::EVP_PKEY_new())?;
520            let pkey = PKey::from_ptr(evp);
521            cvt(ffi::EVP_PKEY_set1_RSA(pkey.0, rsa.as_ptr()))?;
522            Ok(pkey)
523        }
524    }
525
526    /// Creates a new `PKey` containing a DSA key.
527    #[corresponds(EVP_PKEY_set1_DSA)]
528    pub fn from_dsa(dsa: Dsa<T>) -> Result<PKey<T>, ErrorStack> {
529        unsafe {
530            let evp = cvt_p(ffi::EVP_PKEY_new())?;
531            let pkey = PKey::from_ptr(evp);
532            cvt(ffi::EVP_PKEY_set1_DSA(pkey.0, dsa.as_ptr()))?;
533            Ok(pkey)
534        }
535    }
536
537    /// Creates a new `PKey` containing a Diffie-Hellman key.
538    #[corresponds(EVP_PKEY_set1_DH)]
539    #[cfg(not(boringssl))]
540    pub fn from_dh(dh: Dh<T>) -> Result<PKey<T>, ErrorStack> {
541        unsafe {
542            let evp = cvt_p(ffi::EVP_PKEY_new())?;
543            let pkey = PKey::from_ptr(evp);
544            cvt(ffi::EVP_PKEY_set1_DH(pkey.0, dh.as_ptr()))?;
545            Ok(pkey)
546        }
547    }
548
549    /// Creates a new `PKey` containing a Diffie-Hellman key with type DHX.
550    #[cfg(all(not(any(boringssl, awslc)), ossl110))]
551    pub fn from_dhx(dh: Dh<T>) -> Result<PKey<T>, ErrorStack> {
552        unsafe {
553            let evp = cvt_p(ffi::EVP_PKEY_new())?;
554            let pkey = PKey::from_ptr(evp);
555            cvt(ffi::EVP_PKEY_assign(
556                pkey.0,
557                ffi::EVP_PKEY_DHX,
558                dh.as_ptr().cast(),
559            ))?;
560            mem::forget(dh);
561            Ok(pkey)
562        }
563    }
564
565    /// Creates a new `PKey` containing an elliptic curve key.
566    #[corresponds(EVP_PKEY_set1_EC_KEY)]
567    pub fn from_ec_key(ec_key: EcKey<T>) -> Result<PKey<T>, ErrorStack> {
568        unsafe {
569            let evp = cvt_p(ffi::EVP_PKEY_new())?;
570            let pkey = PKey::from_ptr(evp);
571            cvt(ffi::EVP_PKEY_set1_EC_KEY(pkey.0, ec_key.as_ptr()))?;
572            Ok(pkey)
573        }
574    }
575}
576
577impl PKey<Private> {
578    /// Creates a new `PKey` containing an HMAC key.
579    ///
580    /// # Note
581    ///
582    /// To compute HMAC values, use the `sign` module.
583    #[corresponds(EVP_PKEY_new_mac_key)]
584    #[cfg(not(boringssl))]
585    pub fn hmac(key: &[u8]) -> Result<PKey<Private>, ErrorStack> {
586        #[cfg(awslc)]
587        let key_len = key.len();
588        #[cfg(not(awslc))]
589        let key_len = key.len() as c_int;
590        unsafe {
591            assert!(key.len() <= c_int::MAX as usize);
592            let key = cvt_p(ffi::EVP_PKEY_new_mac_key(
593                ffi::EVP_PKEY_HMAC,
594                ptr::null_mut(),
595                key.as_ptr() as *const _,
596                key_len,
597            ))?;
598            Ok(PKey::from_ptr(key))
599        }
600    }
601
602    /// Creates a new `PKey` containing a CMAC key.
603    ///
604    /// Requires OpenSSL 1.1.0 or newer.
605    ///
606    /// # Note
607    ///
608    /// To compute CMAC values, use the `sign` module.
609    #[cfg(all(not(any(boringssl, awslc)), ossl110))]
610    #[allow(clippy::trivially_copy_pass_by_ref)]
611    pub fn cmac(cipher: &Cipher, key: &[u8]) -> Result<PKey<Private>, ErrorStack> {
612        let mut ctx = PkeyCtx::new_id(Id::CMAC)?;
613        ctx.keygen_init()?;
614        ctx.set_keygen_cipher(unsafe { CipherRef::from_ptr(cipher.as_ptr() as *mut _) })?;
615        ctx.set_keygen_mac_key(key)?;
616        ctx.keygen()
617    }
618
619    #[cfg(any(ossl111, boringssl, libressl370, awslc))]
620    fn generate_eddsa(id: Id) -> Result<PKey<Private>, ErrorStack> {
621        let mut ctx = PkeyCtx::new_id(id)?;
622        ctx.keygen_init()?;
623        ctx.keygen()
624    }
625
626    /// Generates a new private X25519 key.
627    ///
628    /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`].
629    ///
630    /// # Examples
631    ///
632    /// ```
633    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
634    /// use openssl::pkey::{PKey, Id};
635    /// use openssl::derive::Deriver;
636    ///
637    /// let public = // ...
638    /// # &PKey::generate_x25519()?.raw_public_key()?;
639    /// let public_key = PKey::public_key_from_raw_bytes(public, Id::X25519)?;
640    ///
641    /// let key = PKey::generate_x25519()?;
642    /// let mut deriver = Deriver::new(&key)?;
643    /// deriver.set_peer(&public_key)?;
644    ///
645    /// let secret = deriver.derive_to_vec()?;
646    /// assert_eq!(secret.len(), 32);
647    /// # Ok(()) }
648    /// ```
649    #[cfg(any(ossl111, boringssl, libressl370, awslc))]
650    pub fn generate_x25519() -> Result<PKey<Private>, ErrorStack> {
651        PKey::generate_eddsa(Id::X25519)
652    }
653
654    /// Generates a new private X448 key.
655    ///
656    /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`].
657    ///
658    /// # Examples
659    ///
660    /// ```
661    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
662    /// use openssl::pkey::{PKey, Id};
663    /// use openssl::derive::Deriver;
664    ///
665    /// let public = // ...
666    /// # &PKey::generate_x448()?.raw_public_key()?;
667    /// let public_key = PKey::public_key_from_raw_bytes(public, Id::X448)?;
668    ///
669    /// let key = PKey::generate_x448()?;
670    /// let mut deriver = Deriver::new(&key)?;
671    /// deriver.set_peer(&public_key)?;
672    ///
673    /// let secret = deriver.derive_to_vec()?;
674    /// assert_eq!(secret.len(), 56);
675    /// # Ok(()) }
676    /// ```
677    #[cfg(ossl111)]
678    pub fn generate_x448() -> Result<PKey<Private>, ErrorStack> {
679        PKey::generate_eddsa(Id::X448)
680    }
681
682    /// Generates a new private Ed25519 key.
683    ///
684    /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`].
685    ///
686    /// # Examples
687    ///
688    /// ```
689    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
690    /// use openssl::pkey::{PKey, Id};
691    /// use openssl::sign::Signer;
692    ///
693    /// let key = PKey::generate_ed25519()?;
694    /// let public_key = key.raw_public_key()?;
695    ///
696    /// let mut signer = Signer::new_without_digest(&key)?;
697    /// let digest = // ...
698    /// # &vec![0; 32];
699    /// let signature = signer.sign_oneshot_to_vec(digest)?;
700    /// assert_eq!(signature.len(), 64);
701    /// # Ok(()) }
702    /// ```
703    #[cfg(any(ossl111, boringssl, libressl370, awslc))]
704    pub fn generate_ed25519() -> Result<PKey<Private>, ErrorStack> {
705        PKey::generate_eddsa(Id::ED25519)
706    }
707
708    /// Generates a new private Ed448 key.
709    ///
710    /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`].
711    ///
712    /// # Examples
713    ///
714    /// ```
715    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
716    /// use openssl::pkey::{PKey, Id};
717    /// use openssl::sign::Signer;
718    ///
719    /// let key = PKey::generate_ed448()?;
720    /// let public_key = key.raw_public_key()?;
721    ///
722    /// let mut signer = Signer::new_without_digest(&key)?;
723    /// let digest = // ...
724    /// # &vec![0; 32];
725    /// let signature = signer.sign_oneshot_to_vec(digest)?;
726    /// assert_eq!(signature.len(), 114);
727    /// # Ok(()) }
728    /// ```
729    #[cfg(ossl111)]
730    pub fn generate_ed448() -> Result<PKey<Private>, ErrorStack> {
731        PKey::generate_eddsa(Id::ED448)
732    }
733
734    /// Generates a new EC key using the provided curve.
735    ///
736    /// Requires OpenSSL 3.0.0 or newer.
737    #[corresponds(EVP_EC_gen)]
738    #[cfg(ossl300)]
739    pub fn ec_gen(curve: &str) -> Result<PKey<Private>, ErrorStack> {
740        ffi::init();
741
742        let curve = CString::new(curve).unwrap();
743        unsafe {
744            let ptr = cvt_p(ffi::EVP_EC_gen(curve.as_ptr()))?;
745            Ok(PKey::from_ptr(ptr))
746        }
747    }
748
749    private_key_from_pem! {
750        /// Deserializes a private key from a PEM-encoded key type specific format.
751        #[corresponds(PEM_read_bio_PrivateKey)]
752        private_key_from_pem,
753
754        /// Deserializes a private key from a PEM-encoded encrypted key type specific format.
755        #[corresponds(PEM_read_bio_PrivateKey)]
756        private_key_from_pem_passphrase,
757
758        /// Deserializes a private key from a PEM-encoded encrypted key type specific format.
759        ///
760        /// The callback should fill the password into the provided buffer and return its length.
761        #[corresponds(PEM_read_bio_PrivateKey)]
762        private_key_from_pem_callback,
763        PKey<Private>,
764        ffi::PEM_read_bio_PrivateKey
765    }
766
767    from_der! {
768        /// Decodes a DER-encoded private key.
769        ///
770        /// This function will attempt to automatically detect the underlying key format, and
771        /// supports the unencrypted PKCS#8 PrivateKeyInfo structures as well as key type specific
772        /// formats.
773        #[corresponds(d2i_AutoPrivateKey)]
774        private_key_from_der,
775        PKey<Private>,
776        ffi::d2i_AutoPrivateKey
777    }
778
779    /// Deserializes a DER-formatted PKCS#8 unencrypted private key.
780    ///
781    /// This method is mainly for interoperability reasons. Encrypted keyfiles should be preferred.
782    pub fn private_key_from_pkcs8(der: &[u8]) -> Result<PKey<Private>, ErrorStack> {
783        unsafe {
784            ffi::init();
785            let len = der.len().min(c_long::MAX as usize) as c_long;
786            let p8inf = cvt_p(ffi::d2i_PKCS8_PRIV_KEY_INFO(
787                ptr::null_mut(),
788                &mut der.as_ptr(),
789                len,
790            ))?;
791            let res = cvt_p(ffi::EVP_PKCS82PKEY(p8inf)).map(|p| PKey::from_ptr(p));
792            ffi::PKCS8_PRIV_KEY_INFO_free(p8inf);
793            res
794        }
795    }
796
797    /// Deserializes a DER-formatted PKCS#8 private key, using a callback to retrieve the password
798    /// if the key is encrypted.
799    ///
800    /// The callback should copy the password into the provided buffer and return the number of
801    /// bytes written.
802    #[corresponds(d2i_PKCS8PrivateKey_bio)]
803    pub fn private_key_from_pkcs8_callback<F>(
804        der: &[u8],
805        callback: F,
806    ) -> Result<PKey<Private>, ErrorStack>
807    where
808        F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>,
809    {
810        unsafe {
811            ffi::init();
812            let mut cb = CallbackState::new(callback);
813            let bio = MemBioSlice::new(der)?;
814            cvt_p(ffi::d2i_PKCS8PrivateKey_bio(
815                bio.as_ptr(),
816                ptr::null_mut(),
817                Some(invoke_passwd_cb::<F>),
818                &mut cb as *mut _ as *mut _,
819            ))
820            .map(|p| PKey::from_ptr(p))
821        }
822    }
823
824    /// Deserializes a DER-formatted PKCS#8 private key, using the supplied password if the key is
825    /// encrypted.
826    ///
827    /// # Panics
828    ///
829    /// Panics if `passphrase` contains an embedded null.
830    #[corresponds(d2i_PKCS8PrivateKey_bio)]
831    pub fn private_key_from_pkcs8_passphrase(
832        der: &[u8],
833        passphrase: &[u8],
834    ) -> Result<PKey<Private>, ErrorStack> {
835        unsafe {
836            ffi::init();
837            let bio = MemBioSlice::new(der)?;
838            let passphrase = CString::new(passphrase).unwrap();
839            cvt_p(ffi::d2i_PKCS8PrivateKey_bio(
840                bio.as_ptr(),
841                ptr::null_mut(),
842                None,
843                passphrase.as_ptr() as *const _ as *mut _,
844            ))
845            .map(|p| PKey::from_ptr(p))
846        }
847    }
848
849    /// Creates a private key from its raw byte representation
850    ///
851    /// Algorithm types that support raw private keys are HMAC, X25519, ED25519, X448 or ED448
852    #[corresponds(EVP_PKEY_new_raw_private_key)]
853    #[cfg(any(ossl111, boringssl, libressl370, awslc))]
854    pub fn private_key_from_raw_bytes(
855        bytes: &[u8],
856        key_type: Id,
857    ) -> Result<PKey<Private>, ErrorStack> {
858        unsafe {
859            ffi::init();
860            cvt_p(ffi::EVP_PKEY_new_raw_private_key(
861                key_type.as_raw(),
862                ptr::null_mut(),
863                bytes.as_ptr(),
864                bytes.len(),
865            ))
866            .map(|p| PKey::from_ptr(p))
867        }
868    }
869
870    /// Creates a private key from its raw byte representation, identifying
871    /// the algorithm by name and optionally taking a library context and
872    /// property query string.
873    ///
874    /// This is required for algorithms that are only available via OpenSSL
875    /// 3.0+ providers and have no associated `Id`, such as ML-DSA.
876    #[corresponds(EVP_PKEY_new_raw_private_key_ex)]
877    #[cfg(ossl300)]
878    pub fn private_key_from_raw_bytes_ex(
879        ctx: Option<&LibCtxRef>,
880        key_type: KeyType,
881        properties: Option<&CStr>,
882        bytes: &[u8],
883    ) -> Result<PKey<Private>, ErrorStack> {
884        unsafe {
885            ffi::init();
886            cvt_p(ffi::EVP_PKEY_new_raw_private_key_ex(
887                ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr),
888                key_type.as_cstr().as_ptr(),
889                properties.map_or(ptr::null(), |s| s.as_ptr()),
890                bytes.as_ptr(),
891                bytes.len(),
892            ))
893            .map(|p| PKey::from_ptr(p))
894        }
895    }
896
897    /// Constructs a private keypair from an algorithm-defined `seed`.
898    ///
899    /// Only ML-DSA (32-byte seed) and ML-KEM (64-byte seed) are supported at
900    /// this time, and require OpenSSL 3.5 or newer at runtime. The seed
901    /// length is algorithm-defined and a wrong-sized seed is rejected by the
902    /// provider.
903    ///
904    /// Internally this calls `EVP_PKEY_CTX_new_from_name` followed by
905    /// `EVP_PKEY_fromdata` with a single `seed` octet-string `OSSL_PARAM` and
906    /// `EVP_PKEY_KEYPAIR` selection.
907    #[corresponds(EVP_PKEY_fromdata)]
908    #[cfg(ossl350)]
909    pub fn private_key_from_seed(
910        ctx: Option<&LibCtxRef>,
911        key_type: KeyType,
912        properties: Option<&CStr>,
913        seed: &[u8],
914    ) -> Result<PKey<Private>, ErrorStack> {
915        let mut builder = crate::ossl_param::OsslParamBuilder::new()?;
916        builder.add_octet_string(c"seed", seed)?;
917        let params = builder.to_param()?;
918        unsafe {
919            ffi::init();
920            let pkey_ctx = cvt_p(ffi::EVP_PKEY_CTX_new_from_name(
921                ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr),
922                key_type.as_cstr().as_ptr(),
923                properties.map_or(ptr::null(), |s| s.as_ptr()),
924            ))?;
925            // Take ownership immediately so the context is freed on early return.
926            let pkey_ctx = PkeyCtx::<Private>::from_ptr(pkey_ctx);
927            cvt(ffi::EVP_PKEY_fromdata_init(pkey_ctx.as_ptr()))?;
928            let mut pkey: *mut ffi::EVP_PKEY = ptr::null_mut();
929            cvt(ffi::EVP_PKEY_fromdata(
930                pkey_ctx.as_ptr(),
931                &mut pkey,
932                ffi::EVP_PKEY_KEYPAIR,
933                params.as_ptr(),
934            ))?;
935            Ok(PKey::from_ptr(pkey))
936        }
937    }
938}
939
940impl PKey<Public> {
941    private_key_from_pem! {
942        /// Decodes a PEM-encoded SubjectPublicKeyInfo structure.
943        ///
944        /// The input should have a header of `-----BEGIN PUBLIC KEY-----`.
945        #[corresponds(PEM_read_bio_PUBKEY)]
946        public_key_from_pem,
947
948        /// Decodes a PEM-encoded SubjectPublicKeyInfo structure.
949        #[corresponds(PEM_read_bio_PUBKEY)]
950        public_key_from_pem_passphrase,
951
952        /// Decodes a PEM-encoded SubjectPublicKeyInfo structure.
953        ///
954        /// The callback should fill the password into the provided buffer and return its length.
955        #[corresponds(PEM_read_bio_PrivateKey)]
956        public_key_from_pem_callback,
957        PKey<Public>,
958        ffi::PEM_read_bio_PUBKEY
959    }
960
961    from_der! {
962        /// Decodes a DER-encoded SubjectPublicKeyInfo structure.
963        #[corresponds(d2i_PUBKEY)]
964        public_key_from_der,
965        PKey<Public>,
966        ffi::d2i_PUBKEY
967    }
968
969    /// Creates a public key from its raw byte representation
970    ///
971    /// Algorithm types that support raw public keys are X25519, ED25519, X448 or ED448
972    #[corresponds(EVP_PKEY_new_raw_public_key)]
973    #[cfg(any(ossl111, boringssl, libressl370, awslc))]
974    pub fn public_key_from_raw_bytes(
975        bytes: &[u8],
976        key_type: Id,
977    ) -> Result<PKey<Public>, ErrorStack> {
978        unsafe {
979            ffi::init();
980            cvt_p(ffi::EVP_PKEY_new_raw_public_key(
981                key_type.as_raw(),
982                ptr::null_mut(),
983                bytes.as_ptr(),
984                bytes.len(),
985            ))
986            .map(|p| PKey::from_ptr(p))
987        }
988    }
989
990    /// Creates a public key from its raw byte representation, identifying
991    /// the algorithm by name and optionally taking a library context and
992    /// property query string.
993    ///
994    /// This is required for algorithms that are only available via OpenSSL
995    /// 3.0+ providers and have no associated `Id`, such as ML-DSA.
996    #[corresponds(EVP_PKEY_new_raw_public_key_ex)]
997    #[cfg(ossl300)]
998    pub fn public_key_from_raw_bytes_ex(
999        ctx: Option<&LibCtxRef>,
1000        key_type: KeyType,
1001        properties: Option<&CStr>,
1002        bytes: &[u8],
1003    ) -> Result<PKey<Public>, ErrorStack> {
1004        unsafe {
1005            ffi::init();
1006            cvt_p(ffi::EVP_PKEY_new_raw_public_key_ex(
1007                ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr),
1008                key_type.as_cstr().as_ptr(),
1009                properties.map_or(ptr::null(), |s| s.as_ptr()),
1010                bytes.as_ptr(),
1011                bytes.len(),
1012            ))
1013            .map(|p| PKey::from_ptr(p))
1014        }
1015    }
1016}
1017
1018use ffi::EVP_PKEY_up_ref;
1019
1020impl<T> TryFrom<EcKey<T>> for PKey<T> {
1021    type Error = ErrorStack;
1022
1023    fn try_from(ec_key: EcKey<T>) -> Result<PKey<T>, ErrorStack> {
1024        PKey::from_ec_key(ec_key)
1025    }
1026}
1027
1028impl<T> TryFrom<PKey<T>> for EcKey<T> {
1029    type Error = ErrorStack;
1030
1031    fn try_from(pkey: PKey<T>) -> Result<EcKey<T>, ErrorStack> {
1032        pkey.ec_key()
1033    }
1034}
1035
1036impl<T> TryFrom<Rsa<T>> for PKey<T> {
1037    type Error = ErrorStack;
1038
1039    fn try_from(rsa: Rsa<T>) -> Result<PKey<T>, ErrorStack> {
1040        PKey::from_rsa(rsa)
1041    }
1042}
1043
1044impl<T> TryFrom<PKey<T>> for Rsa<T> {
1045    type Error = ErrorStack;
1046
1047    fn try_from(pkey: PKey<T>) -> Result<Rsa<T>, ErrorStack> {
1048        pkey.rsa()
1049    }
1050}
1051
1052impl<T> TryFrom<Dsa<T>> for PKey<T> {
1053    type Error = ErrorStack;
1054
1055    fn try_from(dsa: Dsa<T>) -> Result<PKey<T>, ErrorStack> {
1056        PKey::from_dsa(dsa)
1057    }
1058}
1059
1060impl<T> TryFrom<PKey<T>> for Dsa<T> {
1061    type Error = ErrorStack;
1062
1063    fn try_from(pkey: PKey<T>) -> Result<Dsa<T>, ErrorStack> {
1064        pkey.dsa()
1065    }
1066}
1067
1068#[cfg(not(boringssl))]
1069impl<T> TryFrom<Dh<T>> for PKey<T> {
1070    type Error = ErrorStack;
1071
1072    fn try_from(dh: Dh<T>) -> Result<PKey<T>, ErrorStack> {
1073        PKey::from_dh(dh)
1074    }
1075}
1076
1077impl<T> TryFrom<PKey<T>> for Dh<T> {
1078    type Error = ErrorStack;
1079
1080    fn try_from(pkey: PKey<T>) -> Result<Dh<T>, ErrorStack> {
1081        pkey.dh()
1082    }
1083}
1084
1085#[cfg(test)]
1086mod tests {
1087    use std::convert::TryInto;
1088
1089    #[cfg(not(boringssl))]
1090    use crate::dh::Dh;
1091    use crate::dsa::Dsa;
1092    use crate::ec::EcKey;
1093    use crate::error::Error;
1094    use crate::nid::Nid;
1095    use crate::rsa::Rsa;
1096    use crate::symm::Cipher;
1097
1098    use super::*;
1099
1100    #[cfg(any(ossl111, awslc))]
1101    use crate::rand::rand_bytes;
1102
1103    #[test]
1104    fn test_to_password() {
1105        let rsa = Rsa::generate(2048).unwrap();
1106        let pkey = PKey::from_rsa(rsa).unwrap();
1107        let pem = pkey
1108            .private_key_to_pem_pkcs8_passphrase(Cipher::aes_128_cbc(), b"foobar")
1109            .unwrap();
1110        PKey::private_key_from_pem_passphrase(&pem, b"foobar").unwrap();
1111        assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err());
1112    }
1113
1114    #[test]
1115    fn test_unencrypted_pkcs8() {
1116        let key = include_bytes!("../test/pkcs8-nocrypt.der");
1117        let pkey = PKey::private_key_from_pkcs8(key).unwrap();
1118        let serialized = pkey.private_key_to_pkcs8().unwrap();
1119        let pkey2 = PKey::private_key_from_pkcs8(&serialized).unwrap();
1120
1121        assert_eq!(
1122            pkey2.private_key_to_der().unwrap(),
1123            pkey.private_key_to_der().unwrap()
1124        );
1125    }
1126
1127    #[test]
1128    fn test_encrypted_pkcs8_passphrase() {
1129        let key = include_bytes!("../test/pkcs8.der");
1130        PKey::private_key_from_pkcs8_passphrase(key, b"mypass").unwrap();
1131
1132        let rsa = Rsa::generate(2048).unwrap();
1133        let pkey = PKey::from_rsa(rsa).unwrap();
1134        let der = pkey
1135            .private_key_to_pkcs8_passphrase(Cipher::aes_128_cbc(), b"mypass")
1136            .unwrap();
1137        let pkey2 = PKey::private_key_from_pkcs8_passphrase(&der, b"mypass").unwrap();
1138        assert_eq!(
1139            pkey.private_key_to_der().unwrap(),
1140            pkey2.private_key_to_der().unwrap()
1141        );
1142    }
1143
1144    #[test]
1145    fn test_encrypted_pkcs8_callback() {
1146        let mut password_queried = false;
1147        let key = include_bytes!("../test/pkcs8.der");
1148        PKey::private_key_from_pkcs8_callback(key, |password| {
1149            password_queried = true;
1150            password[..6].copy_from_slice(b"mypass");
1151            Ok(6)
1152        })
1153        .unwrap();
1154        assert!(password_queried);
1155    }
1156
1157    #[test]
1158    fn test_private_key_from_pem() {
1159        let key = include_bytes!("../test/key.pem");
1160        PKey::private_key_from_pem(key).unwrap();
1161    }
1162
1163    #[test]
1164    fn test_public_key_from_pem() {
1165        let key = include_bytes!("../test/key.pem.pub");
1166        PKey::public_key_from_pem(key).unwrap();
1167    }
1168
1169    #[test]
1170    fn test_public_key_from_der() {
1171        let key = include_bytes!("../test/key.der.pub");
1172        PKey::public_key_from_der(key).unwrap();
1173    }
1174
1175    #[test]
1176    fn test_private_key_from_der() {
1177        let key = include_bytes!("../test/key.der");
1178        PKey::private_key_from_der(key).unwrap();
1179    }
1180
1181    #[test]
1182    fn test_pem() {
1183        let key = include_bytes!("../test/key.pem");
1184        let key = PKey::private_key_from_pem(key).unwrap();
1185
1186        let priv_key = key.private_key_to_pem_pkcs8().unwrap();
1187        let pub_key = key.public_key_to_pem().unwrap();
1188
1189        // As a super-simple verification, just check that the buffers contain
1190        // the `PRIVATE KEY` or `PUBLIC KEY` strings.
1191        assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY"));
1192        assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY"));
1193    }
1194
1195    #[test]
1196    fn test_rsa_accessor() {
1197        let rsa = Rsa::generate(2048).unwrap();
1198        let pkey = PKey::from_rsa(rsa).unwrap();
1199        pkey.rsa().unwrap();
1200        assert_eq!(pkey.id(), Id::RSA);
1201        assert!(pkey.dsa().is_err());
1202    }
1203
1204    #[test]
1205    fn test_dsa_accessor() {
1206        let dsa = Dsa::generate(2048).unwrap();
1207        let pkey = PKey::from_dsa(dsa).unwrap();
1208        pkey.dsa().unwrap();
1209        assert_eq!(pkey.id(), Id::DSA);
1210        assert!(pkey.rsa().is_err());
1211    }
1212
1213    #[test]
1214    #[cfg(not(boringssl))]
1215    fn test_dh_accessor() {
1216        let dh = include_bytes!("../test/dhparams.pem");
1217        let dh = Dh::params_from_pem(dh).unwrap();
1218        let pkey = PKey::from_dh(dh).unwrap();
1219        pkey.dh().unwrap();
1220        assert_eq!(pkey.id(), Id::DH);
1221        assert!(pkey.rsa().is_err());
1222    }
1223
1224    #[test]
1225    fn test_ec_key_accessor() {
1226        let ec_key = EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1227        let pkey = PKey::from_ec_key(ec_key).unwrap();
1228        pkey.ec_key().unwrap();
1229        assert_eq!(pkey.id(), Id::EC);
1230        assert!(pkey.rsa().is_err());
1231    }
1232
1233    #[test]
1234    fn test_rsa_conversion() {
1235        let rsa = Rsa::generate(2048).unwrap();
1236        let pkey: PKey<Private> = rsa.clone().try_into().unwrap();
1237        let rsa_: Rsa<Private> = pkey.try_into().unwrap();
1238        // Eq is missing
1239        assert_eq!(rsa.p(), rsa_.p());
1240        assert_eq!(rsa.q(), rsa_.q());
1241    }
1242
1243    #[test]
1244    fn test_dsa_conversion() {
1245        let dsa = Dsa::generate(2048).unwrap();
1246        let pkey: PKey<Private> = dsa.clone().try_into().unwrap();
1247        let dsa_: Dsa<Private> = pkey.try_into().unwrap();
1248        // Eq is missing
1249        assert_eq!(dsa.priv_key(), dsa_.priv_key());
1250    }
1251
1252    #[test]
1253    fn test_ec_key_conversion() {
1254        let group = crate::ec::EcGroup::from_curve_name(crate::nid::Nid::X9_62_PRIME256V1).unwrap();
1255        let ec_key = EcKey::generate(&group).unwrap();
1256        let pkey: PKey<Private> = ec_key.clone().try_into().unwrap();
1257        let ec_key_: EcKey<Private> = pkey.try_into().unwrap();
1258        // Eq is missing
1259        assert_eq!(ec_key.private_key(), ec_key_.private_key());
1260    }
1261
1262    #[test]
1263    #[cfg(any(ossl110, libressl360))]
1264    fn test_security_bits() {
1265        let group = crate::ec::EcGroup::from_curve_name(crate::nid::Nid::SECP521R1).unwrap();
1266        let ec_key = EcKey::generate(&group).unwrap();
1267        let pkey: PKey<Private> = ec_key.try_into().unwrap();
1268
1269        assert_eq!(pkey.security_bits(), 256);
1270    }
1271
1272    #[test]
1273    #[cfg(not(boringssl))]
1274    fn test_dh_conversion() {
1275        let dh_params = include_bytes!("../test/dhparams.pem");
1276        let dh_params = Dh::params_from_pem(dh_params).unwrap();
1277        let dh = dh_params.generate_key().unwrap();
1278
1279        // Clone is missing for Dh, save the parameters
1280        let p = dh.prime_p().to_owned().unwrap();
1281        let q = dh.prime_q().map(|q| q.to_owned().unwrap());
1282        let g = dh.generator().to_owned().unwrap();
1283
1284        let pkey: PKey<Private> = dh.try_into().unwrap();
1285        let dh_: Dh<Private> = pkey.try_into().unwrap();
1286
1287        // Eq is missing
1288        assert_eq!(&p, dh_.prime_p());
1289        assert_eq!(q, dh_.prime_q().map(|q| q.to_owned().unwrap()));
1290        assert_eq!(&g, dh_.generator());
1291    }
1292
1293    #[cfg(any(ossl111, boringssl, libressl370, awslc))]
1294    fn test_raw_public_key(gen: fn() -> Result<PKey<Private>, ErrorStack>, key_type: Id) {
1295        // Generate a new key
1296        let key = gen().unwrap();
1297
1298        // Get the raw bytes, and create a new key from the raw bytes
1299        let raw = key.raw_public_key().unwrap();
1300        let from_raw = PKey::public_key_from_raw_bytes(&raw, key_type).unwrap();
1301
1302        // Compare the der encoding of the original and raw / restored public key
1303        assert_eq!(
1304            key.public_key_to_der().unwrap(),
1305            from_raw.public_key_to_der().unwrap()
1306        );
1307    }
1308
1309    #[cfg(any(ossl111, boringssl, libressl370, awslc))]
1310    fn test_raw_private_key(gen: fn() -> Result<PKey<Private>, ErrorStack>, key_type: Id) {
1311        // Generate a new key
1312        let key = gen().unwrap();
1313
1314        // Get the raw bytes, and create a new key from the raw bytes
1315        let raw = key.raw_private_key().unwrap();
1316        let from_raw = PKey::private_key_from_raw_bytes(&raw, key_type).unwrap();
1317
1318        // Compare the der encoding of the original and raw / restored public key
1319        assert_eq!(
1320            key.private_key_to_pkcs8().unwrap(),
1321            from_raw.private_key_to_pkcs8().unwrap()
1322        );
1323    }
1324
1325    #[cfg(any(ossl111, boringssl, libressl370, awslc))]
1326    #[test]
1327    fn test_raw_public_key_bytes() {
1328        test_raw_public_key(PKey::generate_x25519, Id::X25519);
1329        test_raw_public_key(PKey::generate_ed25519, Id::ED25519);
1330        #[cfg(not(any(libressl, boringssl, awslc)))]
1331        test_raw_public_key(PKey::generate_x448, Id::X448);
1332        #[cfg(not(any(libressl, boringssl, awslc)))]
1333        test_raw_public_key(PKey::generate_ed448, Id::ED448);
1334    }
1335
1336    #[cfg(any(ossl111, boringssl, libressl370, awslc))]
1337    #[test]
1338    fn test_raw_private_key_bytes() {
1339        test_raw_private_key(PKey::generate_x25519, Id::X25519);
1340        test_raw_private_key(PKey::generate_ed25519, Id::ED25519);
1341        #[cfg(not(any(libressl, boringssl, awslc)))]
1342        test_raw_private_key(PKey::generate_x448, Id::X448);
1343        #[cfg(not(any(libressl, boringssl, awslc)))]
1344        test_raw_private_key(PKey::generate_ed448, Id::ED448);
1345    }
1346
1347    #[cfg(any(ossl111, awslc))]
1348    #[test]
1349    fn test_raw_hmac() {
1350        let mut test_bytes = vec![0u8; 32];
1351        rand_bytes(&mut test_bytes).unwrap();
1352
1353        let hmac_key = PKey::hmac(&test_bytes).unwrap();
1354        assert!(hmac_key.raw_public_key().is_err());
1355
1356        let key_bytes = hmac_key.raw_private_key().unwrap();
1357        assert_eq!(key_bytes, test_bytes);
1358    }
1359
1360    #[cfg(any(ossl111, awslc))]
1361    #[test]
1362    fn test_raw_key_fail() {
1363        // Getting a raw byte representation will not work with Nist curves
1364        let group = crate::ec::EcGroup::from_curve_name(Nid::SECP256K1).unwrap();
1365        let ec_key = EcKey::generate(&group).unwrap();
1366        let pkey = PKey::from_ec_key(ec_key).unwrap();
1367        assert!(pkey.raw_private_key().is_err());
1368        assert!(pkey.raw_public_key().is_err());
1369    }
1370
1371    #[cfg(ossl300)]
1372    #[test]
1373    fn test_is_a() {
1374        let rsa = Rsa::generate(2048).unwrap();
1375        let pkey = PKey::from_rsa(rsa).unwrap();
1376        assert!(pkey.is_a(KeyType::RSA));
1377        assert!(!pkey.is_a(KeyType::EC));
1378        assert!(!pkey.is_a(KeyType::ML_DSA_65));
1379
1380        let ed = PKey::generate_ed25519().unwrap();
1381        assert!(ed.is_a(KeyType::ED25519));
1382        assert!(!ed.is_a(KeyType::X25519));
1383    }
1384
1385    #[cfg(ossl300)]
1386    #[test]
1387    fn test_raw_public_key_from_bytes_ex() {
1388        let key = PKey::generate_ed25519().unwrap();
1389        let raw = key.raw_public_key().unwrap();
1390        let from_raw =
1391            PKey::public_key_from_raw_bytes_ex(None, KeyType::ED25519, None, &raw).unwrap();
1392        assert_eq!(
1393            key.public_key_to_der().unwrap(),
1394            from_raw.public_key_to_der().unwrap()
1395        );
1396        assert!(from_raw.is_a(KeyType::ED25519));
1397
1398        // Wrong key length should fail.
1399        assert!(PKey::public_key_from_raw_bytes_ex(None, KeyType::ED25519, None, &[]).is_err());
1400    }
1401
1402    #[cfg(ossl300)]
1403    #[test]
1404    fn test_raw_private_key_from_bytes_ex() {
1405        let key = PKey::generate_ed25519().unwrap();
1406        let raw = key.raw_private_key().unwrap();
1407        let from_raw =
1408            PKey::private_key_from_raw_bytes_ex(None, KeyType::ED25519, None, &raw).unwrap();
1409        assert_eq!(
1410            key.private_key_to_pkcs8().unwrap(),
1411            from_raw.private_key_to_pkcs8().unwrap()
1412        );
1413    }
1414
1415    #[cfg(ossl300)]
1416    #[test]
1417    fn test_ec_gen() {
1418        let key = PKey::ec_gen("prime256v1").unwrap();
1419        assert!(key.ec_key().is_ok());
1420    }
1421
1422    #[cfg(ossl350)]
1423    #[test]
1424    fn test_private_key_from_seed_mldsa() {
1425        // ML-DSA-65 KAT vector 0 from
1426        // https://github.com/post-quantum-cryptography/KAT/blob/main/MLDSA/kat_MLDSA_65_det_pure.rsp
1427        // (xi is the 32-byte ML-DSA key generation seed per FIPS 204).
1428        let xi = hex::decode("f696484048ec21f96cf50a56d0759c448f3779752f0383d37449690694cf7a68")
1429            .unwrap();
1430        let key = PKey::private_key_from_seed(None, KeyType::ML_DSA_65, None, &xi).unwrap();
1431        assert!(key.is_a(KeyType::ML_DSA_65));
1432        let expected_pk = "e50d03fff3b3a70961abbb92a390008dec1283f603f50cdbaaa3d00bd659bc767c3f24ec864ceb07b865aa148647698df8e63f244c4de08affc0210f1560f64822961972463e403bbe97ce7a539fc013527558ad824202a90b1e9a045d89a51c3a31d0330f2099d0f5e0b9e8de8d1e340c91d6a0f61cb8a6548e2614a1b6a2ad80f4e567f0f134700b1563ccaab71f28e7bf509858d85218166dd9a0e1dfad4bee180b4cdaf6e37623558f64fd124d3d7543aade0b28fb8f193159cea7dfb172174b6c25375c9c1903636bfaa41791b1f2f16158020806a1d95979f678a46a209a8780345d2d092c52b576b5e263e870570cc1084058676fbddb2c93bc87fd81a90f7081c04fb299415f761966614aedeea40386f0dbe97512956c3f16c3e210a364de926e37374637d95d0420de7f2f72365392a6d4392018762cd6aa4d6ec629f6d0605ab86862a34c3f1fb55695ae35e736404044aad617d192e8ff07a16f5c6291c2edb0bf1d601a6b08f1c9b444e31570113124cd20eeb299d30a4546243a9f20ed36fa963edab2f494cd92f766633b97237ccc3485387f4344839f4656fbf1eb7f4f24712f432f3b74df325747405bc9ee39f42f87653322f1d23c92c981953fc107570053ce46b6741410a99cdb1888d33943e191c0a395085b9d14a3fbdc58a3ea16706c937ea44aebc9764df142010eab022c40b28e63da853ae03843bfe02eed35331571ec89895c1ea2256cb7591e63c7a5870455663ef9804b84d524470a08cda9bbbfd07ba6537473163cf030849c5f31679c610d56d5e31c0e73f23098d3a19dd39afe507e25d053e7d5b0d9b18c53b153c2d5b162558939a6e24e7ba02d1d736b6a4c93a4f3bc50d4ab16ef350b411e6f4a734be03242fd67ee47eb4ec3d453d1a9254c4e02f68a366702ef2875932b72125ee81da1c10a336b4a4990a5e36f0b59b00e3471c56314d6e92bcb7bacd6219fd99c1ca50c3342ce62cd98be9458a17cf243c60c09b106e86fab345a997f7b46d4ac1c790c37dbdb93d29c532a5cb097a30f92d47c460ec8345b17ba5db77c1a6533a9448a353663f187517a399583b2f98cb0a8dc3f64d049716a5c8aee6ede0bb6958fc70f2fce706f20622d35e9ff2a1c30dd5e71bebe4a33fd74ab768cd34a2d9ec59845a8f38b5dd6c0008b678876e493c9afc2396a16721142803f1f38c579036858a25a1a1abfae94c7dc1ecb26c1d3b4d96209be238360fc8554e33f5fba2b92abf207b677d433b58275366b836be7081d7b50f9d29652c836ffb11596317cb3aaaf4ed41441298fb386fbd9237227bb7529bf5eeb7711bc6936cd4fba98b8404dd1e8650a3a1bf29869835797b9537db1afc0f4339ad3b296401100520dd43d2cd453534f1df776c0aa184f2e5cb658fee5b54bb44d9ee13b3486c37b1fea4284327ce15400ecd93a0c01852d045c3c7af348d4786845984fde0d086c115d4fcbcfee73688ef61601ce3560d6db6f0a6be4dc05640c575a2d24a6a5b5d697ecc3a6844bf7405f68c5450b1d67b5dfcfcc8f878d787f7f57d3875fdf345f1730f9e7493e9a4acacb7b8832b0141a1bdb082a95d8be8f5280035f42f05f9ecf663fa5d03b056c43bc39ba1a6f7375961c4e94830c51e276cc4bc826518f84f51e8ea6f59a3d12ad9d5ef2ca6db70155cabd655713641a885551ab65a358d2e7baf68a39567ba2278d9493562aa4e903ad6f304d2752064d8dbc8a2bf53e24d2f77e47da1d0519212148daf2cb99453b44c7337db46390a6d67d0bbdfa980bfca35d68df1e904168f64fd6b22710eac8bab8757a9e3bb43c5f907949cddecf0321d728a2bbb74e6cc4959c1516c9b2981150f054ec05bd3844e99a7788d5d018c2dc4642969059601a6928963500f085c84cda6454dfc4be63ba82182104499d778e0e998e1cf9086d7990ed03704753f10cb4df6076341f1d556aae9a15ade459e74817fa1d9cb8d0a816afc5947c81368bda9c3a587565b3c39199bf3e24254c601c43002c37b83e43116f25ebfb206d081d81c34618e53aba8ef65af1c5dff402839d71c0319cb7696922088cb9ab3f2eee8ea79228ae12dc9aa1db9acd1309d7171b47a7043fe73cfb4e6b11a3da910f5e5e734c26b41a93452848e735d1679963a413d69a0d275ba10693fb922d8f8c32310dee718125b29d1366201399eb253ba5a1fed099f9df91e3c59c16dfe8f7074045760527327e1e5852537ae96962553b69d85da962a5a6789d19fe585e257012132a7c91feaf4c58a4fa7c126fe68406f34ebf1f371adb4b30514b18dd6e7e659df07776238e48cb7fabd08b5f6a9fc05a7ffbf019a2632c257bf79636994c807fa2f513f60940800e290c2e684d9162858bca138a8634e23b1bb4b49f77af7eb717a79b2f293f814849a8d7e0aae2a734259395c4bf6a3a8deb37a0638121a9dcf83dfecd0c6c58a8eb05c4706e395a869c3ce01d42e31466fba05a45e4181dddb177fa20fef50a770d9da14cffb55ac3e829bd932eff759eeaeebd37d3ecb38f2046528affc969b008d2f9fad5acb4682f119011cbb4ffb11dae5d91dfe9ec7ba5142086e5c09eb398e3685413a394b385a5e377c4996848d862ed7f70b3bb75cff88cf89db9146ea82b5611569a8bb67dc95ab4135c2a427f12ba1c9b50cf86d1a238ba0c99c3d82dbc90dd0f7b281494df1a25848ecadfe915a95a43247bc5a55e1e2d90ed05f70be8b2e5fc9d5b";
1433        assert_eq!(hex::encode(key.raw_public_key().unwrap()), expected_pk);
1434
1435        // Wrong seed length is rejected by the provider.
1436        assert!(PKey::private_key_from_seed(None, KeyType::ML_DSA_65, None, &[]).is_err());
1437    }
1438
1439    #[cfg(ossl350)]
1440    #[test]
1441    fn test_private_key_from_seed_mlkem() {
1442        // ML-KEM-768 KAT vector 0 from
1443        // https://github.com/post-quantum-cryptography/KAT/blob/main/MLKEM/kat_MLKEM_768.rsp
1444        // (per FIPS 203 the OpenSSL "seed" param is d || z, 64 bytes total).
1445        let d = hex::decode("6dbbc4375136df3b07f7c70e639e223e177e7fd53b161b3f4d57791794f12624")
1446            .unwrap();
1447        let z = hex::decode("f696484048ec21f96cf50a56d0759c448f3779752f0383d37449690694cf7a68")
1448            .unwrap();
1449        let mut seed = d;
1450        seed.extend_from_slice(&z);
1451        let key = PKey::private_key_from_seed(None, KeyType::ML_KEM_768, None, &seed).unwrap();
1452        assert!(key.is_a(KeyType::ML_KEM_768));
1453        let expected_pk = "01f60af1dc8e6360ae78b59d4a5042eb9145a269046d6236b8304f305c2d9dcb189fe5a62df89b2f5a7bce3bbc753c1e78f730a99869f809aba856b676b707b26601d1d909bab32451494eb7d0a2153a6350b79789a9b115f83ea12037256562f06a1d5aba378da77039d3bdecaca8e6a22a49050a76300a0267cdb38b7ac77903c50ca53b99283cac6b95fba651b11a4d1a692e4072965060587669f253b1bb182e661446168ac60221894660020e9bb5f5b7124a0303e2543ea3ea6ce97a2482b255ca346fb27a847b33b93f3ab2d33064c6e6632d1a23f1144e907b246b479f4a5c928929a1e24150f5241258a5b67766a66f6a33846495907828ebe44ecc5b73124071ba479073910410a16d5d5696b48b194752979795772a91c348f502b37aa650983ebb89bf3c081ff273544129c9137a6e1834c8f2e7ce14c7870c53c05b9b94ecd38e6645911b0912336863ec168831f811881075cf38a59de4b5c738aa6ef03d779b295588cfb62491cc7b3e08b48473354f9ac8061c152a9e205997499b970b69bce66fe42bca2924ccdf0103d0a4c39193c2df25118d72b17aab26b0c60d4cd2c306ca4696c185de05035f4a09cf970aecc8cc93436f83b1aeaf452c41929a2eabc151938f74c93b858546df2264eeeab602e04a85c522f8fb1a5214afd8d4cae57a47b6f381a23126bd9917173128af917f1d483691c450d1151cfe9a1492d473ed862e27da92500c86a20019e9f975e4f54ad319ba2c5630c4014219d7ba235456fe530140193d662445e6a941d1e238567ba8d4d95ab1c7447d690821876d017270cfb169f2d792f03c800720697b410ab41c66f2b24585125655eb10aa1087ffcb7750cb887ad4467377500a6a7d3a82976b415a54469577b4138d919b03f4c9a4d3390bdcb6f1717a5fa4ab25a34f4ba5039bb22c7f3c234ea4427347aa7251464e631904d7cac4784f78b49d5f4a104a301809a779f6466131f9c62bb67147f4cd4973a6aa1c29ae6a8647b6268be089fe048ce990cd638743d285c889a707f581b63af41731f0246b054bc4b47aab01b6842a2709d02e8158ab90f48b69d136082b34cb0673b74aa3f54508ed029fb8f5045ee0639e150ee3b3c85f68a310ec0441980100b42abf2bad10d4a9e0c7b2bc5bbcaf73cbcdc49dc2c949111936779b178974a0392947745a47189bc3fa8a679c80af964a9f9b1b56577274a2a669d2da6704aa496af407fa1aa964cc3dc3140f5f959a7ea974bdb1b83e48a99c0a3e2d75b0669b5c1278962540609166266da18886fc237af30cefd569dbe399e6652e45f06a5dfc9a758a4987088ff8e38a3cf36b9d988f0e070b68d0b88f7bcc41306080d889780c7e238895ccaa4f3577225cca4c8a9330ce613e717798c9670924b271ac402b51538b8b5967ac490dcab5300e6c54d6a3632f3b973e4186ee1a7e2e85649185b26370c387235c4df28a9937a49d4078bf883f4e6346cb3251d9e13f1bda087b285afaa80e262641c5527b0a184b8bc84a62e577314658e2029d850064f7a7b81f253e7cc124a9c5b039dc9b179a80c2f6aee6ea0815172537331a57b505baa76ff5b4c1f0da754b6194f4b39a9b18730d3cdab925d691ed77a8db9927ea233ac2a12744fdc27e5d221b9369adb325d8";
1454        assert_eq!(hex::encode(key.raw_public_key().unwrap()), expected_pk);
1455
1456        // Wrong seed length is rejected by the provider.
1457        assert!(PKey::private_key_from_seed(None, KeyType::ML_KEM_768, None, &[]).is_err());
1458    }
1459
1460    #[cfg(ossl350)]
1461    #[test]
1462    fn test_private_key_from_seed_invalid_algorithm() {
1463        let seed = [0u8; 64];
1464        assert!(
1465            PKey::private_key_from_seed(None, KeyType::RSA, None, &seed).is_err(),
1466            "Unexpectedly accepted a seed-only fromdata import",
1467        );
1468    }
1469
1470    #[cfg(ossl350)]
1471    #[test]
1472    fn test_seed_into_mldsa_roundtrip() {
1473        let xi = hex::decode("f696484048ec21f96cf50a56d0759c448f3779752f0383d37449690694cf7a68")
1474            .unwrap();
1475        let key = PKey::private_key_from_seed(None, KeyType::ML_DSA_65, None, &xi).unwrap();
1476
1477        // Exact-sized buffer succeeds.
1478        let mut exact = [0u8; 32];
1479        let n = key.seed_into(&mut exact).unwrap();
1480        assert_eq!(n, 32);
1481        assert_eq!(&exact[..], &xi[..]);
1482
1483        // Buffer too small is rejected by OpenSSL.
1484        let mut small = [0u8; 16];
1485        assert!(key.seed_into(&mut small).is_err());
1486
1487        // Buffer larger than required succeeds; the trailing bytes are
1488        // left untouched.
1489        let mut large = [0xaau8; 64];
1490        let n = key.seed_into(&mut large).unwrap();
1491        assert_eq!(n, 32);
1492        assert_eq!(&large[..32], &xi[..]);
1493        assert!(large[32..].iter().all(|&b| b == 0xaa));
1494    }
1495
1496    #[cfg(ossl350)]
1497    #[test]
1498    fn test_seed_into_mlkem_roundtrip() {
1499        let d = hex::decode("6dbbc4375136df3b07f7c70e639e223e177e7fd53b161b3f4d57791794f12624")
1500            .unwrap();
1501        let z = hex::decode("f696484048ec21f96cf50a56d0759c448f3779752f0383d37449690694cf7a68")
1502            .unwrap();
1503        let mut seed = d;
1504        seed.extend_from_slice(&z);
1505        let key = PKey::private_key_from_seed(None, KeyType::ML_KEM_768, None, &seed).unwrap();
1506        let mut buf = [0u8; 64];
1507        let n = key.seed_into(&mut buf).unwrap();
1508        assert_eq!(n, 64);
1509        assert_eq!(&buf[..], &seed[..]);
1510    }
1511
1512    /// `seed_into()` must error on key types that don't have a "seed" OSSL_PARAM.
1513    #[cfg(ossl350)]
1514    #[test]
1515    fn test_seed_into_rejects_non_pq_algorithms() {
1516        let mut buf = [0u8; 64];
1517        let rsa = PKey::from_rsa(Rsa::generate(2048).unwrap()).unwrap();
1518        assert!(rsa.seed_into(&mut buf).is_err());
1519
1520        let ed = PKey::generate_ed25519().unwrap();
1521        assert!(ed.seed_into(&mut buf).is_err());
1522    }
1523
1524    #[test]
1525    fn test_public_eq() {
1526        let rsa = Rsa::generate(2048).unwrap();
1527        let pkey1 = PKey::from_rsa(rsa).unwrap();
1528
1529        let group = crate::ec::EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1530        let ec_key = EcKey::generate(&group).unwrap();
1531        let pkey2 = PKey::from_ec_key(ec_key).unwrap();
1532
1533        assert!(!pkey1.public_eq(&pkey2));
1534        assert!(Error::get().is_none());
1535    }
1536}