Skip to main content

boring/
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 boring::rsa::Rsa;
33//! use boring::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
43use foreign_types::{ForeignType, ForeignTypeRef};
44use libc::{c_int, c_long};
45use openssl_macros::corresponds;
46use std::ffi::CString;
47use std::fmt;
48use std::mem;
49use std::ptr;
50
51use crate::bio::MemBioSlice;
52use crate::dh::Dh;
53use crate::dsa::Dsa;
54use crate::ec::EcKey;
55use crate::error::ErrorStack;
56use crate::ffi;
57use crate::rsa::Rsa;
58use crate::try_int;
59use crate::util::{invoke_passwd_cb, CallbackState};
60use crate::{cvt, cvt_0i, cvt_p};
61
62/// A tag type indicating that a key only has parameters.
63pub enum Params {}
64
65/// A tag type indicating that a key only has public components.
66pub enum Public {}
67
68/// A tag type indicating that a key has private components.
69pub enum Private {}
70
71/// An identifier of a kind of key.
72#[derive(Debug, Copy, Clone, PartialEq, Eq)]
73pub struct Id(c_int);
74
75impl Id {
76    pub const RSA: Id = Id(ffi::EVP_PKEY_RSA);
77    pub const RSAPSS: Id = Id(ffi::EVP_PKEY_RSA_PSS);
78    pub const DSA: Id = Id(ffi::EVP_PKEY_DSA);
79    pub const DH: Id = Id(ffi::EVP_PKEY_DH);
80    pub const EC: Id = Id(ffi::EVP_PKEY_EC);
81    pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519);
82    pub const ED448: Id = Id(ffi::EVP_PKEY_ED448);
83    pub const X25519: Id = Id(ffi::EVP_PKEY_X25519);
84    pub const X448: Id = Id(ffi::EVP_PKEY_X448);
85
86    /// Creates a `Id` from an integer representation.
87    #[must_use]
88    pub fn from_raw(value: c_int) -> Id {
89        Id(value)
90    }
91
92    /// Returns the integer representation of the `Id`.
93    #[allow(clippy::trivially_copy_pass_by_ref)]
94    #[must_use]
95    pub fn as_raw(&self) -> c_int {
96        self.0
97    }
98}
99
100/// A trait indicating that a key has parameters.
101#[allow(clippy::missing_safety_doc)]
102pub unsafe trait HasParams {}
103
104unsafe impl HasParams for Params {}
105
106unsafe impl<T> HasParams for T where T: HasPublic {}
107
108/// A trait indicating that a key has public components.
109#[allow(clippy::missing_safety_doc)]
110pub unsafe trait HasPublic {}
111
112unsafe impl HasPublic for Public {}
113
114unsafe impl<T> HasPublic for T where T: HasPrivate {}
115
116/// A trait indicating that a key has private components.
117#[allow(clippy::missing_safety_doc)]
118pub unsafe trait HasPrivate {}
119
120unsafe impl HasPrivate for Private {}
121
122generic_foreign_type_and_impl_send_sync! {
123    type CType = ffi::EVP_PKEY;
124    fn drop = ffi::EVP_PKEY_free;
125
126    /// A public or private key.
127    pub struct PKey<T>;
128    /// Reference to [`PKey`].
129    pub struct PKeyRef<T>;
130}
131
132impl<T> ToOwned for PKeyRef<T> {
133    type Owned = PKey<T>;
134
135    fn to_owned(&self) -> PKey<T> {
136        unsafe {
137            EVP_PKEY_up_ref(self.as_ptr());
138            PKey::from_ptr(self.as_ptr())
139        }
140    }
141}
142
143impl<T> PKeyRef<T> {
144    /// Returns a copy of the internal RSA key.
145    #[corresponds(EVP_PKEY_get1_RSA)]
146    pub fn rsa(&self) -> Result<Rsa<T>, ErrorStack> {
147        unsafe {
148            let rsa = cvt_p(ffi::EVP_PKEY_get1_RSA(self.as_ptr()))?;
149            Ok(Rsa::from_ptr(rsa))
150        }
151    }
152
153    /// Returns a copy of the internal DSA key.
154    #[corresponds(EVP_PKEY_get1_DSA)]
155    pub fn dsa(&self) -> Result<Dsa<T>, ErrorStack> {
156        unsafe {
157            let dsa = cvt_p(ffi::EVP_PKEY_get1_DSA(self.as_ptr()))?;
158            Ok(Dsa::from_ptr(dsa))
159        }
160    }
161
162    /// Returns a copy of the internal DH key.
163    #[corresponds(EVP_PKEY_get1_DH)]
164    pub fn dh(&self) -> Result<Dh<T>, ErrorStack> {
165        unsafe {
166            let dh = cvt_p(ffi::EVP_PKEY_get1_DH(self.as_ptr()))?;
167            Ok(Dh::from_ptr(dh))
168        }
169    }
170
171    /// Returns a copy of the internal elliptic curve key.
172    #[corresponds(EVP_PKEY_get1_EC_KEY)]
173    pub fn ec_key(&self) -> Result<EcKey<T>, ErrorStack> {
174        unsafe {
175            let ec_key = cvt_p(ffi::EVP_PKEY_get1_EC_KEY(self.as_ptr()))?;
176            Ok(EcKey::from_ptr(ec_key))
177        }
178    }
179
180    /// Returns the `Id` that represents the type of this key.
181    #[corresponds(EVP_PKEY_id)]
182    #[must_use]
183    pub fn id(&self) -> Id {
184        unsafe { Id::from_raw(ffi::EVP_PKEY_id(self.as_ptr())) }
185    }
186
187    /// Returns the maximum size of a signature in bytes.
188    #[corresponds(EVP_PKEY_size)]
189    #[must_use]
190    pub fn size(&self) -> usize {
191        unsafe { ffi::EVP_PKEY_size(self.as_ptr()) as usize }
192    }
193}
194
195impl<T> PKeyRef<T>
196where
197    T: HasPublic,
198{
199    to_pem! {
200        /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure.
201        ///
202        /// The output will have a header of `-----BEGIN PUBLIC KEY-----`.
203        #[corresponds(PEM_write_bio_PUBKEY)]
204        public_key_to_pem,
205        ffi::PEM_write_bio_PUBKEY
206    }
207
208    to_der! {
209        /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure.
210        #[corresponds(i2d_PUBKEY)]
211        public_key_to_der,
212        ffi::i2d_PUBKEY
213    }
214
215    /// Returns the size of the key.
216    ///
217    /// This corresponds to the bit length of the modulus of an RSA key, and the bit length of the
218    /// group order for an elliptic curve key, for example.
219    #[must_use]
220    pub fn bits(&self) -> u32 {
221        unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as u32 }
222    }
223
224    /// Compares the public component of this key with another.
225    #[must_use]
226    pub fn public_eq<U>(&self, other: &PKeyRef<U>) -> bool
227    where
228        U: HasPublic,
229    {
230        unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 }
231    }
232
233    /// Returns the length of the "raw" form of the public key. Only supported for certain key types.
234    #[corresponds(EVP_PKEY_get_raw_public_key)]
235    pub fn raw_public_key_len(&self) -> Result<usize, ErrorStack> {
236        unsafe {
237            let mut size = 0;
238            _ = cvt_0i(ffi::EVP_PKEY_get_raw_public_key(
239                self.as_ptr(),
240                std::ptr::null_mut(),
241                &mut size,
242            ))?;
243            Ok(size)
244        }
245    }
246
247    /// Outputs a copy of the "raw" form of the public key. Only supported for certain key types.
248    ///
249    /// Returns the used portion of `out`.
250    #[corresponds(EVP_PKEY_get_raw_public_key)]
251    pub fn raw_public_key<'a>(&self, out: &'a mut [u8]) -> Result<&'a [u8], ErrorStack> {
252        unsafe {
253            let mut size = out.len();
254            _ = cvt_0i(ffi::EVP_PKEY_get_raw_public_key(
255                self.as_ptr(),
256                out.as_mut_ptr(),
257                &mut size,
258            ))?;
259            Ok(&out[..size])
260        }
261    }
262}
263
264impl<T> PKeyRef<T>
265where
266    T: HasPrivate,
267{
268    private_key_to_pem! {
269        /// Serializes the private key to a PEM-encoded PKCS#8 PrivateKeyInfo structure.
270        ///
271        /// The output will have a header of `-----BEGIN PRIVATE KEY-----`.
272        #[corresponds(PEM_write_bio_PKCS8PrivateKey)]
273        private_key_to_pem_pkcs8,
274        /// Serializes the private key to a PEM-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
275        ///
276        /// The output will have a header of `-----BEGIN ENCRYPTED PRIVATE KEY-----`.
277        #[corresponds(PEM_write_bio_PKCS8PrivateKey)]
278        private_key_to_pem_pkcs8_passphrase,
279        ffi::PEM_write_bio_PKCS8PrivateKey
280    }
281
282    to_der! {
283        /// Serializes the private key to a DER-encoded key type specific format.
284        #[corresponds(i2d_PrivateKey)]
285        private_key_to_der,
286        ffi::i2d_PrivateKey
287    }
288
289    // This isn't actually PEM output, but `i2d_PKCS8PrivateKey_bio` is documented to be
290    // "identical to the corresponding PEM function", and it's declared in pem.h.
291    private_key_to_pem! {
292        /// Serializes the private key to a DER-encoded PKCS#8 PrivateKeyInfo structure.
293        #[corresponds(i2d_PKCS8PrivateKey_bio)]
294        private_key_to_der_pkcs8,
295        /// Serializes the private key to a DER-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
296        #[corresponds(i2d_PKCS8PrivateKey_bio)]
297        private_key_to_der_pkcs8_passphrase,
298        ffi::i2d_PKCS8PrivateKey_bio
299    }
300
301    /// Returns the length of the "raw" form of the private key. Only supported for certain key types.
302    #[corresponds(EVP_PKEY_get_raw_private_key)]
303    pub fn raw_private_key_len(&self) -> Result<usize, ErrorStack> {
304        unsafe {
305            let mut size = 0;
306            _ = cvt_0i(ffi::EVP_PKEY_get_raw_private_key(
307                self.as_ptr(),
308                std::ptr::null_mut(),
309                &mut size,
310            ))?;
311            Ok(size)
312        }
313    }
314
315    /// Outputs a copy of the "raw" form of the private key. Only supported for certain key types.
316    ///
317    /// Returns the used portion of `out`.
318    #[corresponds(EVP_PKEY_get_raw_private_key)]
319    pub fn raw_private_key<'a>(&self, out: &'a mut [u8]) -> Result<&'a [u8], ErrorStack> {
320        unsafe {
321            let mut size = out.len();
322            _ = cvt_0i(ffi::EVP_PKEY_get_raw_private_key(
323                self.as_ptr(),
324                out.as_mut_ptr(),
325                &mut size,
326            ))?;
327            Ok(&out[..size])
328        }
329    }
330}
331
332impl<T> fmt::Debug for PKey<T> {
333    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
334        let alg = match self.id() {
335            Id::RSA => "RSA",
336            Id::RSAPSS => "RSAPSS",
337            Id::DSA => "DSA",
338            Id::DH => "DH",
339            Id::EC => "EC",
340            Id::ED25519 => "Ed25519",
341            Id::ED448 => "Ed448",
342            _ => "unknown",
343        };
344        fmt.debug_struct("PKey").field("algorithm", &alg).finish()
345        // TODO: Print details for each specific type of key
346    }
347}
348
349impl<T> Clone for PKey<T> {
350    fn clone(&self) -> PKey<T> {
351        PKeyRef::to_owned(self)
352    }
353}
354
355impl<T> PKey<T> {
356    /// Creates a new `PKey` containing an RSA key.
357    #[corresponds(EVP_PKEY_assign_RSA)]
358    pub fn from_rsa(rsa: Rsa<T>) -> Result<PKey<T>, ErrorStack> {
359        unsafe {
360            let evp = cvt_p(ffi::EVP_PKEY_new())?;
361            let pkey = PKey::from_ptr(evp);
362            cvt(ffi::EVP_PKEY_assign(
363                pkey.0,
364                ffi::EVP_PKEY_RSA,
365                rsa.as_ptr().cast(),
366            ))?;
367            mem::forget(rsa);
368            Ok(pkey)
369        }
370    }
371
372    /// Creates a new `PKey` containing an elliptic curve key.
373    #[corresponds(EVP_PKEY_assign_EC_KEY)]
374    pub fn from_ec_key(ec_key: EcKey<T>) -> Result<PKey<T>, ErrorStack> {
375        unsafe {
376            let evp = cvt_p(ffi::EVP_PKEY_new())?;
377            let pkey = PKey::from_ptr(evp);
378            cvt(ffi::EVP_PKEY_assign(
379                pkey.0,
380                ffi::EVP_PKEY_EC,
381                ec_key.as_ptr().cast(),
382            ))?;
383            mem::forget(ec_key);
384            Ok(pkey)
385        }
386    }
387}
388
389impl PKey<Private> {
390    /// Generates a private key for key types that support parameterless
391    /// `EVP_PKEY_keygen`.
392    ///
393    /// This is primarily useful for modern "raw" key types such as X25519,
394    /// Ed25519, Ed448, and X448.
395    ///
396    /// Algorithms that require explicit generation parameters (for example RSA
397    /// key size or an EC group) should use their dedicated APIs instead, such
398    /// as [`Rsa::generate`] and [`EcKey::generate`].
399    #[corresponds(EVP_PKEY_keygen)]
400    pub fn generate(id: Id) -> Result<PKey<Private>, ErrorStack> {
401        unsafe {
402            ffi::init();
403
404            let ctx = cvt_p(ffi::EVP_PKEY_CTX_new_id(id.as_raw(), ptr::null_mut()))?;
405
406            let result = (|| {
407                cvt(ffi::EVP_PKEY_keygen_init(ctx))?;
408
409                let mut pkey = ptr::null_mut();
410                cvt(ffi::EVP_PKEY_keygen(ctx, &mut pkey))?;
411
412                Ok(PKey::from_ptr(pkey))
413            })();
414
415            ffi::EVP_PKEY_CTX_free(ctx);
416            result
417        }
418    }
419
420    private_key_from_pem! {
421        /// Deserializes a private key from a PEM-encoded key type specific format.
422        #[corresponds(PEM_read_bio_PrivateKey)]
423        private_key_from_pem,
424
425        /// Deserializes a private key from a PEM-encoded encrypted key type specific format.
426        #[corresponds(PEM_read_bio_PrivateKey)]
427        private_key_from_pem_passphrase,
428
429        /// Deserializes a private key from a PEM-encoded encrypted key type specific format.
430        ///
431        /// The callback should fill the password into the provided buffer and return its length.
432        #[corresponds(PEM_read_bio_PrivateKey)]
433        private_key_from_pem_callback,
434        PKey<Private>,
435        ffi::PEM_read_bio_PrivateKey
436    }
437
438    from_der! {
439        /// Decodes a DER-encoded private key.
440        ///
441        /// This function will automatically attempt to detect the underlying key format, and
442        /// supports the unencrypted PKCS#8 PrivateKeyInfo structures as well as key type specific
443        /// formats.
444        #[corresponds(d2i_AutoPrivateKey)]
445        private_key_from_der,
446        PKey<Private>,
447        ffi::d2i_AutoPrivateKey,
448        ::libc::c_long
449    }
450
451    /// Deserializes a DER-formatted PKCS#8 unencrypted private key.
452    ///
453    /// This method is mainly for interoperability reasons. Encrypted keyfiles should be preferred.
454    pub fn private_key_from_pkcs8(der: &[u8]) -> Result<PKey<Private>, ErrorStack> {
455        unsafe {
456            ffi::init();
457            let len = der.len().min(c_long::MAX as usize) as c_long;
458            let p8inf = cvt_p(ffi::d2i_PKCS8_PRIV_KEY_INFO(
459                ptr::null_mut(),
460                &mut der.as_ptr(),
461                len,
462            ))?;
463            let res = cvt_p(ffi::EVP_PKCS82PKEY(p8inf)).map(|p| PKey::from_ptr(p));
464            ffi::PKCS8_PRIV_KEY_INFO_free(p8inf);
465            res
466        }
467    }
468
469    /// Deserializes a DER-formatted PKCS#8 private key, using a callback to retrieve the password
470    /// if the key is encrypted.
471    ///
472    /// The callback should copy the password into the provided buffer and return the number of
473    /// bytes written.
474    pub fn private_key_from_pkcs8_callback<F>(
475        der: &[u8],
476        callback: F,
477    ) -> Result<PKey<Private>, ErrorStack>
478    where
479        F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>,
480    {
481        unsafe {
482            ffi::init();
483            let mut cb = CallbackState::new(callback);
484            let bio = MemBioSlice::new(der)?;
485            cvt_p(ffi::d2i_PKCS8PrivateKey_bio(
486                bio.as_ptr(),
487                ptr::null_mut(),
488                Some(invoke_passwd_cb::<F>),
489                std::ptr::addr_of_mut!(cb).cast(),
490            ))
491            .map(|p| PKey::from_ptr(p))
492        }
493    }
494
495    /// Deserializes a DER-formatted PKCS#8 private key, using the supplied password if the key is
496    /// encrypted.
497    ///
498    /// # Panics
499    ///
500    /// Panics if `passphrase` contains an embedded null.
501    pub fn private_key_from_pkcs8_passphrase(
502        der: &[u8],
503        passphrase: &[u8],
504    ) -> Result<PKey<Private>, ErrorStack> {
505        unsafe {
506            ffi::init();
507            let bio = MemBioSlice::new(der)?;
508            let passphrase = CString::new(passphrase).map_err(ErrorStack::internal_error)?;
509            cvt_p(ffi::d2i_PKCS8PrivateKey_bio(
510                bio.as_ptr(),
511                ptr::null_mut(),
512                None,
513                passphrase.as_ptr().cast_mut().cast(),
514            ))
515            .map(|p| PKey::from_ptr(p))
516        }
517    }
518}
519
520impl PKey<Public> {
521    from_pem! {
522        /// Decodes a PEM-encoded SubjectPublicKeyInfo structure.
523        ///
524        /// The input should have a header of `-----BEGIN PUBLIC KEY-----`.
525        #[corresponds(PEM_read_bio_PUBKEY)]
526        public_key_from_pem,
527        PKey<Public>,
528        ffi::PEM_read_bio_PUBKEY
529    }
530
531    from_der! {
532        /// Decodes a DER-encoded SubjectPublicKeyInfo structure.
533        #[corresponds(d2i_PUBKEY)]
534        public_key_from_der,
535        PKey<Public>,
536        ffi::d2i_PUBKEY,
537        ::libc::c_long
538    }
539}
540
541use crate::ffi::EVP_PKEY_up_ref;
542
543#[cfg(test)]
544mod tests {
545    use hex::FromHex as _;
546
547    use crate::derive::Deriver;
548    use crate::ec::EcKey;
549    use crate::nid::Nid;
550    use crate::rsa::Rsa;
551    use crate::symm::Cipher;
552
553    use super::*;
554
555    #[test]
556    fn test_to_password() {
557        let rsa = Rsa::generate(2048).unwrap();
558        let pkey = PKey::from_rsa(rsa).unwrap();
559        let pem = pkey
560            .private_key_to_pem_pkcs8_passphrase(Cipher::aes_128_cbc(), b"foobar")
561            .unwrap();
562        PKey::private_key_from_pem_passphrase(&pem, b"foobar").unwrap();
563        assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err());
564    }
565
566    #[test]
567    fn test_unencrypted_pkcs8() {
568        let key = include_bytes!("../test/pkcs8-nocrypt.der");
569        PKey::private_key_from_pkcs8(key).unwrap();
570    }
571
572    #[test]
573    fn test_encrypted_pkcs8_passphrase() {
574        let key = include_bytes!("../test/pkcs8.der");
575        PKey::private_key_from_pkcs8_passphrase(key, b"mypass").unwrap();
576    }
577
578    #[test]
579    fn test_encrypted_pkcs8_callback() {
580        let mut password_queried = false;
581        let key = include_bytes!("../test/pkcs8.der");
582        PKey::private_key_from_pkcs8_callback(key, |password| {
583            password_queried = true;
584            password[..6].copy_from_slice(b"mypass");
585            Ok(6)
586        })
587        .unwrap();
588        assert!(password_queried);
589    }
590
591    #[test]
592    fn test_private_key_from_pem() {
593        let key = include_bytes!("../test/key.pem");
594        PKey::private_key_from_pem(key).unwrap();
595    }
596
597    #[test]
598    fn test_public_key_from_pem() {
599        let key = include_bytes!("../test/key.pem.pub");
600        PKey::public_key_from_pem(key).unwrap();
601    }
602
603    #[test]
604    fn test_public_key_from_der() {
605        let key = include_bytes!("../test/key.der.pub");
606        PKey::public_key_from_der(key).unwrap();
607    }
608
609    #[test]
610    fn test_private_key_from_der() {
611        let key = include_bytes!("../test/key.der");
612        PKey::private_key_from_der(key).unwrap();
613    }
614
615    #[test]
616    fn test_pem() {
617        let key = include_bytes!("../test/key.pem");
618        let key = PKey::private_key_from_pem(key).unwrap();
619
620        let priv_key = key.private_key_to_pem_pkcs8().unwrap();
621        let pub_key = key.public_key_to_pem().unwrap();
622
623        // As a super-simple verification, just check that the buffers contain
624        // the `PRIVATE KEY` or `PUBLIC KEY` strings.
625        assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY"));
626        assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY"));
627    }
628
629    #[test]
630    fn test_der_pkcs8() {
631        let key = include_bytes!("../test/key.der");
632        let key = PKey::private_key_from_der(key).unwrap();
633
634        let priv_key = key.private_key_to_der_pkcs8().unwrap();
635
636        // Check that this has the correct PKCS#8 version number and algorithm.
637        assert_eq!(hex::encode(&priv_key[4..=6]), "020100"); // Version 0
638        assert_eq!(hex::encode(&priv_key[9..=19]), "06092a864886f70d010101"); // Algorithm RSA/PKCS#1
639    }
640
641    #[test]
642    fn test_rsa_accessor() {
643        let rsa = Rsa::generate(2048).unwrap();
644        let pkey = PKey::from_rsa(rsa).unwrap();
645        pkey.rsa().unwrap();
646        assert_eq!(pkey.id(), Id::RSA);
647        assert!(pkey.dsa().is_err());
648    }
649
650    #[test]
651    fn test_ec_key_accessor() {
652        let ec_key = EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
653        let pkey = PKey::from_ec_key(ec_key).unwrap();
654        pkey.ec_key().unwrap();
655        assert_eq!(pkey.id(), Id::EC);
656        assert!(pkey.rsa().is_err());
657    }
658
659    #[test]
660    fn test_raw_accessors() {
661        const ED25519_PRIVATE_KEY_DER: &str = concat!(
662            "302e020100300506032b6570042204207c8c6497f9960d5595d7815f550569e5",
663            "f77764ac97e63e339aaa68cc1512b683"
664        );
665        let pkey =
666            PKey::private_key_from_der(&Vec::from_hex(ED25519_PRIVATE_KEY_DER).unwrap()).unwrap();
667        assert_eq!(pkey.id(), Id::ED25519);
668
669        let priv_len = pkey.raw_private_key_len().unwrap();
670        assert_eq!(priv_len, 32);
671        let mut raw_private_key_buf = [0; 40];
672        let raw_private_key = pkey.raw_private_key(&mut raw_private_key_buf).unwrap();
673        assert_eq!(raw_private_key.len(), 32);
674        assert_ne!(raw_private_key, [0; 32]);
675        pkey.raw_private_key(&mut [0; 5])
676            .expect_err("buffer too small");
677
678        let pub_len = pkey.raw_public_key_len().unwrap();
679        assert_eq!(pub_len, 32);
680        let mut raw_public_key_buf = [0; 40];
681        let raw_public_key = pkey.raw_public_key(&mut raw_public_key_buf).unwrap();
682        assert_eq!(raw_public_key.len(), 32);
683        assert_ne!(raw_public_key, [0; 32]);
684        assert_ne!(raw_public_key, raw_private_key);
685        pkey.raw_public_key(&mut [0; 5])
686            .expect_err("buffer too small");
687    }
688
689    #[test]
690    fn test_generate_x25519() {
691        let key = PKey::generate(Id::X25519).unwrap();
692        assert_eq!(key.id(), Id::X25519);
693
694        let mut pubkey = [0u8; 32];
695        assert_eq!(key.raw_public_key(&mut pubkey).unwrap().len(), 32);
696    }
697
698    #[test]
699    fn test_generate_x25519_derivation() {
700        let alice = PKey::generate(Id::X25519).unwrap();
701        let bob = PKey::generate(Id::X25519).unwrap();
702
703        let mut alice_deriver = Deriver::new(&alice).unwrap();
704        alice_deriver.set_peer(&bob).unwrap();
705        let shared_alice = alice_deriver.derive_to_vec().unwrap();
706
707        let mut bob_deriver = Deriver::new(&bob).unwrap();
708        bob_deriver.set_peer(&alice).unwrap();
709        let shared_bob = bob_deriver.derive_to_vec().unwrap();
710
711        assert!(!shared_alice.is_empty());
712        assert_eq!(shared_alice, shared_bob);
713    }
714
715    #[test]
716    fn test_generate_invalid_id() {
717        assert!(PKey::generate(Id::from_raw(0)).is_err());
718    }
719}