Skip to main content

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