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 
43 use cfg_if::cfg_if;
44 use foreign_types::{ForeignType, ForeignTypeRef};
45 use libc::{c_int, c_long};
46 use std::convert::TryFrom;
47 use std::ffi::CString;
48 use std::fmt;
49 use std::mem;
50 use std::ptr;
51 
52 use crate::bio::MemBioSlice;
53 use crate::dh::Dh;
54 use crate::dsa::Dsa;
55 use crate::ec::EcKey;
56 use crate::error::ErrorStack;
57 use crate::rsa::Rsa;
58 #[cfg(ossl110)]
59 use crate::symm::Cipher;
60 use crate::util::{invoke_passwd_cb, CallbackState};
61 use crate::{cvt, cvt_p};
62 
63 /// A tag type indicating that a key only has parameters.
64 pub enum Params {}
65 
66 /// A tag type indicating that a key only has public components.
67 pub enum Public {}
68 
69 /// A tag type indicating that a key has private components.
70 pub enum Private {}
71 
72 /// An identifier of a kind of key.
73 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
74 pub struct Id(c_int);
75 
76 impl Id {
77     pub const RSA: Id = Id(ffi::EVP_PKEY_RSA);
78     pub const HMAC: Id = Id(ffi::EVP_PKEY_HMAC);
79     pub const DSA: Id = Id(ffi::EVP_PKEY_DSA);
80     pub const DH: Id = Id(ffi::EVP_PKEY_DH);
81     pub const EC: Id = Id(ffi::EVP_PKEY_EC);
82 
83     #[cfg(ossl111)]
84     pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519);
85     #[cfg(ossl111)]
86     pub const ED448: Id = Id(ffi::EVP_PKEY_ED448);
87     #[cfg(ossl111)]
88     pub const X25519: Id = Id(ffi::EVP_PKEY_X25519);
89     #[cfg(ossl111)]
90     pub const X448: Id = Id(ffi::EVP_PKEY_X448);
91 
92     /// Creates a `Id` from an integer representation.
from_raw(value: c_int) -> Id93     pub fn from_raw(value: c_int) -> Id {
94         Id(value)
95     }
96 
97     /// Returns the integer representation of the `Id`.
98     #[allow(clippy::trivially_copy_pass_by_ref)]
as_raw(&self) -> c_int99     pub fn as_raw(&self) -> c_int {
100         self.0
101     }
102 }
103 
104 /// A trait indicating that a key has parameters.
105 pub unsafe trait HasParams {}
106 
107 unsafe impl HasParams for Params {}
108 
109 unsafe impl<T> HasParams for T where T: HasPublic {}
110 
111 /// A trait indicating that a key has public components.
112 pub unsafe trait HasPublic {}
113 
114 unsafe impl HasPublic for Public {}
115 
116 unsafe impl<T> HasPublic for T where T: HasPrivate {}
117 
118 /// A trait indicating that a key has private components.
119 pub unsafe trait HasPrivate {}
120 
121 unsafe impl HasPrivate for Private {}
122 
123 generic_foreign_type_and_impl_send_sync! {
124     type CType = ffi::EVP_PKEY;
125     fn drop = ffi::EVP_PKEY_free;
126 
127     /// A public or private key.
128     pub struct PKey<T>;
129     /// Reference to `PKey`.
130     pub struct PKeyRef<T>;
131 }
132 
133 impl<T> ToOwned for PKeyRef<T> {
134     type Owned = PKey<T>;
135 
to_owned(&self) -> PKey<T>136     fn to_owned(&self) -> PKey<T> {
137         unsafe {
138             EVP_PKEY_up_ref(self.as_ptr());
139             PKey::from_ptr(self.as_ptr())
140         }
141     }
142 }
143 
144 impl<T> PKeyRef<T> {
145     /// Returns a copy of the internal RSA key.
146     ///
147     /// This corresponds to [`EVP_PKEY_get1_RSA`].
148     ///
149     /// [`EVP_PKEY_get1_RSA`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_RSA.html
rsa(&self) -> Result<Rsa<T>, ErrorStack>150     pub fn rsa(&self) -> Result<Rsa<T>, ErrorStack> {
151         unsafe {
152             let rsa = cvt_p(ffi::EVP_PKEY_get1_RSA(self.as_ptr()))?;
153             Ok(Rsa::from_ptr(rsa))
154         }
155     }
156 
157     /// Returns a copy of the internal DSA key.
158     ///
159     /// This corresponds to [`EVP_PKEY_get1_DSA`].
160     ///
161     /// [`EVP_PKEY_get1_DSA`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_DSA.html
dsa(&self) -> Result<Dsa<T>, ErrorStack>162     pub fn dsa(&self) -> Result<Dsa<T>, ErrorStack> {
163         unsafe {
164             let dsa = cvt_p(ffi::EVP_PKEY_get1_DSA(self.as_ptr()))?;
165             Ok(Dsa::from_ptr(dsa))
166         }
167     }
168 
169     /// Returns a copy of the internal DH key.
170     ///
171     /// This corresponds to [`EVP_PKEY_get1_DH`].
172     ///
173     /// [`EVP_PKEY_get1_DH`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_DH.html
dh(&self) -> Result<Dh<T>, ErrorStack>174     pub fn dh(&self) -> Result<Dh<T>, ErrorStack> {
175         unsafe {
176             let dh = cvt_p(ffi::EVP_PKEY_get1_DH(self.as_ptr()))?;
177             Ok(Dh::from_ptr(dh))
178         }
179     }
180 
181     /// Returns a copy of the internal elliptic curve key.
182     ///
183     /// This corresponds to [`EVP_PKEY_get1_EC_KEY`].
184     ///
185     /// [`EVP_PKEY_get1_EC_KEY`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_EC_KEY.html
ec_key(&self) -> Result<EcKey<T>, ErrorStack>186     pub fn ec_key(&self) -> Result<EcKey<T>, ErrorStack> {
187         unsafe {
188             let ec_key = cvt_p(ffi::EVP_PKEY_get1_EC_KEY(self.as_ptr()))?;
189             Ok(EcKey::from_ptr(ec_key))
190         }
191     }
192 
193     /// Returns the `Id` that represents the type of this key.
194     ///
195     /// This corresponds to [`EVP_PKEY_id`].
196     ///
197     /// [`EVP_PKEY_id`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_id.html
id(&self) -> Id198     pub fn id(&self) -> Id {
199         unsafe { Id::from_raw(ffi::EVP_PKEY_id(self.as_ptr())) }
200     }
201 
202     /// Returns the maximum size of a signature in bytes.
203     ///
204     /// This corresponds to [`EVP_PKEY_size`].
205     ///
206     /// [`EVP_PKEY_size`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_size.html
size(&self) -> usize207     pub fn size(&self) -> usize {
208         unsafe { ffi::EVP_PKEY_size(self.as_ptr()) as usize }
209     }
210 }
211 
212 impl<T> PKeyRef<T>
213 where
214     T: HasPublic,
215 {
216     to_pem! {
217         /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure.
218         ///
219         /// The output will have a header of `-----BEGIN PUBLIC KEY-----`.
220         ///
221         /// This corresponds to [`PEM_write_bio_PUBKEY`].
222         ///
223         /// [`PEM_write_bio_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_PUBKEY.html
224         public_key_to_pem,
225         ffi::PEM_write_bio_PUBKEY
226     }
227 
228     to_der! {
229         /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure.
230         ///
231         /// This corresponds to [`i2d_PUBKEY`].
232         ///
233         /// [`i2d_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_PUBKEY.html
234         public_key_to_der,
235         ffi::i2d_PUBKEY
236     }
237 
238     /// Returns the size of the key.
239     ///
240     /// This corresponds to the bit length of the modulus of an RSA key, and the bit length of the
241     /// group order for an elliptic curve key, for example.
bits(&self) -> u32242     pub fn bits(&self) -> u32 {
243         unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as u32 }
244     }
245 
246     /// Compares the public component of this key with another.
public_eq<U>(&self, other: &PKeyRef<U>) -> bool where U: HasPublic,247     pub fn public_eq<U>(&self, other: &PKeyRef<U>) -> bool
248     where
249         U: HasPublic,
250     {
251         unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 }
252     }
253 }
254 
255 impl<T> PKeyRef<T>
256 where
257     T: HasPrivate,
258 {
259     private_key_to_pem! {
260         /// Serializes the private key to a PEM-encoded PKCS#8 PrivateKeyInfo structure.
261         ///
262         /// The output will have a header of `-----BEGIN PRIVATE KEY-----`.
263         ///
264         /// This corresponds to [`PEM_write_bio_PKCS8PrivateKey`].
265         ///
266         /// [`PEM_write_bio_PKCS8PrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_PKCS8PrivateKey.html
267         private_key_to_pem_pkcs8,
268         /// Serializes the private key to a PEM-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
269         ///
270         /// The output will have a header of `-----BEGIN ENCRYPTED PRIVATE KEY-----`.
271         ///
272         /// This corresponds to [`PEM_write_bio_PKCS8PrivateKey`].
273         ///
274         /// [`PEM_write_bio_PKCS8PrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_PKCS8PrivateKey.html
275         private_key_to_pem_pkcs8_passphrase,
276         ffi::PEM_write_bio_PKCS8PrivateKey
277     }
278 
279     to_der! {
280         /// Serializes the private key to a DER-encoded key type specific format.
281         ///
282         /// This corresponds to [`i2d_PrivateKey`].
283         ///
284         /// [`i2d_PrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_PrivateKey.html
285         private_key_to_der,
286         ffi::i2d_PrivateKey
287     }
288 }
289 
290 impl<T> fmt::Debug for PKey<T> {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result291     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
292         let alg = match self.id() {
293             Id::RSA => "RSA",
294             Id::HMAC => "HMAC",
295             Id::DSA => "DSA",
296             Id::DH => "DH",
297             Id::EC => "EC",
298             #[cfg(ossl111)]
299             Id::ED25519 => "Ed25519",
300             #[cfg(ossl111)]
301             Id::ED448 => "Ed448",
302             _ => "unknown",
303         };
304         fmt.debug_struct("PKey").field("algorithm", &alg).finish()
305         // TODO: Print details for each specific type of key
306     }
307 }
308 
309 impl<T> Clone for PKey<T> {
clone(&self) -> PKey<T>310     fn clone(&self) -> PKey<T> {
311         PKeyRef::to_owned(self)
312     }
313 }
314 
315 impl<T> PKey<T> {
316     /// Creates a new `PKey` containing an RSA key.
317     ///
318     /// This corresponds to [`EVP_PKEY_assign_RSA`].
319     ///
320     /// [`EVP_PKEY_assign_RSA`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_assign_RSA.html
from_rsa(rsa: Rsa<T>) -> Result<PKey<T>, ErrorStack>321     pub fn from_rsa(rsa: Rsa<T>) -> Result<PKey<T>, ErrorStack> {
322         unsafe {
323             let evp = cvt_p(ffi::EVP_PKEY_new())?;
324             let pkey = PKey::from_ptr(evp);
325             cvt(ffi::EVP_PKEY_assign(
326                 pkey.0,
327                 ffi::EVP_PKEY_RSA,
328                 rsa.as_ptr() as *mut _,
329             ))?;
330             mem::forget(rsa);
331             Ok(pkey)
332         }
333     }
334 
335     /// Creates a new `PKey` containing a DSA key.
336     ///
337     /// This corresponds to [`EVP_PKEY_assign_DSA`].
338     ///
339     /// [`EVP_PKEY_assign_DSA`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_assign_DSA.html
from_dsa(dsa: Dsa<T>) -> Result<PKey<T>, ErrorStack>340     pub fn from_dsa(dsa: Dsa<T>) -> Result<PKey<T>, ErrorStack> {
341         unsafe {
342             let evp = cvt_p(ffi::EVP_PKEY_new())?;
343             let pkey = PKey::from_ptr(evp);
344             cvt(ffi::EVP_PKEY_assign(
345                 pkey.0,
346                 ffi::EVP_PKEY_DSA,
347                 dsa.as_ptr() as *mut _,
348             ))?;
349             mem::forget(dsa);
350             Ok(pkey)
351         }
352     }
353 
354     /// Creates a new `PKey` containing a Diffie-Hellman key.
355     ///
356     /// This corresponds to [`EVP_PKEY_assign_DH`].
357     ///
358     /// [`EVP_PKEY_assign_DH`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_assign_DH.html
from_dh(dh: Dh<T>) -> Result<PKey<T>, ErrorStack>359     pub fn from_dh(dh: Dh<T>) -> Result<PKey<T>, ErrorStack> {
360         unsafe {
361             let evp = cvt_p(ffi::EVP_PKEY_new())?;
362             let pkey = PKey::from_ptr(evp);
363             cvt(ffi::EVP_PKEY_assign(
364                 pkey.0,
365                 ffi::EVP_PKEY_DH,
366                 dh.as_ptr() as *mut _,
367             ))?;
368             mem::forget(dh);
369             Ok(pkey)
370         }
371     }
372 
373     /// Creates a new `PKey` containing an elliptic curve key.
374     ///
375     /// This corresponds to [`EVP_PKEY_assign_EC_KEY`].
376     ///
377     /// [`EVP_PKEY_assign_EC_KEY`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_assign_EC_KEY.html
from_ec_key(ec_key: EcKey<T>) -> Result<PKey<T>, ErrorStack>378     pub fn from_ec_key(ec_key: EcKey<T>) -> Result<PKey<T>, ErrorStack> {
379         unsafe {
380             let evp = cvt_p(ffi::EVP_PKEY_new())?;
381             let pkey = PKey::from_ptr(evp);
382             cvt(ffi::EVP_PKEY_assign(
383                 pkey.0,
384                 ffi::EVP_PKEY_EC,
385                 ec_key.as_ptr() as *mut _,
386             ))?;
387             mem::forget(ec_key);
388             Ok(pkey)
389         }
390     }
391 }
392 
393 impl PKey<Private> {
394     /// Creates a new `PKey` containing an HMAC key.
395     ///
396     /// # Note
397     ///
398     /// To compute HMAC values, use the `sign` module.
hmac(key: &[u8]) -> Result<PKey<Private>, ErrorStack>399     pub fn hmac(key: &[u8]) -> Result<PKey<Private>, ErrorStack> {
400         unsafe {
401             assert!(key.len() <= c_int::max_value() as usize);
402             let key = cvt_p(ffi::EVP_PKEY_new_mac_key(
403                 ffi::EVP_PKEY_HMAC,
404                 ptr::null_mut(),
405                 key.as_ptr() as *const _,
406                 key.len() as c_int,
407             ))?;
408             Ok(PKey::from_ptr(key))
409         }
410     }
411 
412     /// Creates a new `PKey` containing a CMAC key.
413     ///
414     /// Requires OpenSSL 1.1.0 or newer.
415     ///
416     /// # Note
417     ///
418     /// To compute CMAC values, use the `sign` module.
419     #[cfg(ossl110)]
420     #[allow(clippy::trivially_copy_pass_by_ref)]
cmac(cipher: &Cipher, key: &[u8]) -> Result<PKey<Private>, ErrorStack>421     pub fn cmac(cipher: &Cipher, key: &[u8]) -> Result<PKey<Private>, ErrorStack> {
422         unsafe {
423             assert!(key.len() <= c_int::max_value() as usize);
424             let kctx = cvt_p(ffi::EVP_PKEY_CTX_new_id(
425                 ffi::EVP_PKEY_CMAC,
426                 ptr::null_mut(),
427             ))?;
428 
429             let ret = (|| {
430                 cvt(ffi::EVP_PKEY_keygen_init(kctx))?;
431 
432                 // Set cipher for cmac
433                 cvt(ffi::EVP_PKEY_CTX_ctrl(
434                     kctx,
435                     -1,
436                     ffi::EVP_PKEY_OP_KEYGEN,
437                     ffi::EVP_PKEY_CTRL_CIPHER,
438                     0,
439                     cipher.as_ptr() as *mut _,
440                 ))?;
441 
442                 // Set the key data
443                 cvt(ffi::EVP_PKEY_CTX_ctrl(
444                     kctx,
445                     -1,
446                     ffi::EVP_PKEY_OP_KEYGEN,
447                     ffi::EVP_PKEY_CTRL_SET_MAC_KEY,
448                     key.len() as c_int,
449                     key.as_ptr() as *mut _,
450                 ))?;
451                 Ok(())
452             })();
453 
454             if let Err(e) = ret {
455                 // Free memory
456                 ffi::EVP_PKEY_CTX_free(kctx);
457                 return Err(e);
458             }
459 
460             // Generate key
461             let mut key = ptr::null_mut();
462             let ret = cvt(ffi::EVP_PKEY_keygen(kctx, &mut key));
463 
464             // Free memory
465             ffi::EVP_PKEY_CTX_free(kctx);
466 
467             if let Err(e) = ret {
468                 return Err(e);
469             }
470 
471             Ok(PKey::from_ptr(key))
472         }
473     }
474 
475     #[cfg(ossl111)]
generate_eddsa(nid: c_int) -> Result<PKey<Private>, ErrorStack>476     fn generate_eddsa(nid: c_int) -> Result<PKey<Private>, ErrorStack> {
477         unsafe {
478             let kctx = cvt_p(ffi::EVP_PKEY_CTX_new_id(nid, ptr::null_mut()))?;
479             let ret = cvt(ffi::EVP_PKEY_keygen_init(kctx));
480             if let Err(e) = ret {
481                 ffi::EVP_PKEY_CTX_free(kctx);
482                 return Err(e);
483             }
484             let mut key = ptr::null_mut();
485             let ret = cvt(ffi::EVP_PKEY_keygen(kctx, &mut key));
486 
487             ffi::EVP_PKEY_CTX_free(kctx);
488 
489             if let Err(e) = ret {
490                 return Err(e);
491             }
492 
493             Ok(PKey::from_ptr(key))
494         }
495     }
496 
497     /// Generates a new private Ed25519 key
498     #[cfg(ossl111)]
generate_x25519() -> Result<PKey<Private>, ErrorStack>499     pub fn generate_x25519() -> Result<PKey<Private>, ErrorStack> {
500         PKey::generate_eddsa(ffi::EVP_PKEY_X25519)
501     }
502 
503     /// Generates a new private Ed448 key
504     #[cfg(ossl111)]
generate_x448() -> Result<PKey<Private>, ErrorStack>505     pub fn generate_x448() -> Result<PKey<Private>, ErrorStack> {
506         PKey::generate_eddsa(ffi::EVP_PKEY_X448)
507     }
508 
509     /// Generates a new private Ed25519 key
510     #[cfg(ossl111)]
generate_ed25519() -> Result<PKey<Private>, ErrorStack>511     pub fn generate_ed25519() -> Result<PKey<Private>, ErrorStack> {
512         PKey::generate_eddsa(ffi::EVP_PKEY_ED25519)
513     }
514 
515     /// Generates a new private Ed448 key
516     #[cfg(ossl111)]
generate_ed448() -> Result<PKey<Private>, ErrorStack>517     pub fn generate_ed448() -> Result<PKey<Private>, ErrorStack> {
518         PKey::generate_eddsa(ffi::EVP_PKEY_ED448)
519     }
520 
521     private_key_from_pem! {
522         /// Deserializes a private key from a PEM-encoded key type specific format.
523         ///
524         /// This corresponds to [`PEM_read_bio_PrivateKey`].
525         ///
526         /// [`PEM_read_bio_PrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_PrivateKey.html
527         private_key_from_pem,
528 
529         /// Deserializes a private key from a PEM-encoded encrypted key type specific format.
530         ///
531         /// This corresponds to [`PEM_read_bio_PrivateKey`].
532         ///
533         /// [`PEM_read_bio_PrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_PrivateKey.html
534         private_key_from_pem_passphrase,
535 
536         /// Deserializes a private key from a PEM-encoded encrypted key type specific format.
537         ///
538         /// The callback should fill the password into the provided buffer and return its length.
539         ///
540         /// This corresponds to [`PEM_read_bio_PrivateKey`].
541         ///
542         /// [`PEM_read_bio_PrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_PrivateKey.html
543         private_key_from_pem_callback,
544         PKey<Private>,
545         ffi::PEM_read_bio_PrivateKey
546     }
547 
548     from_der! {
549         /// Decodes a DER-encoded private key.
550         ///
551         /// This function will automatically attempt to detect the underlying key format, and
552         /// supports the unencrypted PKCS#8 PrivateKeyInfo structures as well as key type specific
553         /// formats.
554         ///
555         /// This corresponds to [`d2i_AutoPrivateKey`].
556         ///
557         /// [`d2i_AutoPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_AutoPrivateKey.html
558         private_key_from_der,
559         PKey<Private>,
560         ffi::d2i_AutoPrivateKey
561     }
562 
563     /// Deserializes a DER-formatted PKCS#8 unencrypted private key.
564     ///
565     /// This method is mainly for interoperability reasons. Encrypted keyfiles should be preferred.
private_key_from_pkcs8(der: &[u8]) -> Result<PKey<Private>, ErrorStack>566     pub fn private_key_from_pkcs8(der: &[u8]) -> Result<PKey<Private>, ErrorStack> {
567         unsafe {
568             ffi::init();
569             let len = der.len().min(c_long::max_value() as usize) as c_long;
570             let p8inf = cvt_p(ffi::d2i_PKCS8_PRIV_KEY_INFO(
571                 ptr::null_mut(),
572                 &mut der.as_ptr(),
573                 len,
574             ))?;
575             let res = cvt_p(ffi::EVP_PKCS82PKEY(p8inf)).map(|p| PKey::from_ptr(p));
576             ffi::PKCS8_PRIV_KEY_INFO_free(p8inf);
577             res
578         }
579     }
580 
581     /// Deserializes a DER-formatted PKCS#8 private key, using a callback to retrieve the password
582     /// if the key is encrpyted.
583     ///
584     /// The callback should copy the password into the provided buffer and return the number of
585     /// bytes written.
private_key_from_pkcs8_callback<F>( der: &[u8], callback: F, ) -> Result<PKey<Private>, ErrorStack> where F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>,586     pub fn private_key_from_pkcs8_callback<F>(
587         der: &[u8],
588         callback: F,
589     ) -> Result<PKey<Private>, ErrorStack>
590     where
591         F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>,
592     {
593         unsafe {
594             ffi::init();
595             let mut cb = CallbackState::new(callback);
596             let bio = MemBioSlice::new(der)?;
597             cvt_p(ffi::d2i_PKCS8PrivateKey_bio(
598                 bio.as_ptr(),
599                 ptr::null_mut(),
600                 Some(invoke_passwd_cb::<F>),
601                 &mut cb as *mut _ as *mut _,
602             ))
603             .map(|p| PKey::from_ptr(p))
604         }
605     }
606 
607     /// Deserializes a DER-formatted PKCS#8 private key, using the supplied password if the key is
608     /// encrypted.
609     ///
610     /// # Panics
611     ///
612     /// Panics if `passphrase` contains an embedded null.
private_key_from_pkcs8_passphrase( der: &[u8], passphrase: &[u8], ) -> Result<PKey<Private>, ErrorStack>613     pub fn private_key_from_pkcs8_passphrase(
614         der: &[u8],
615         passphrase: &[u8],
616     ) -> Result<PKey<Private>, ErrorStack> {
617         unsafe {
618             ffi::init();
619             let bio = MemBioSlice::new(der)?;
620             let passphrase = CString::new(passphrase).unwrap();
621             cvt_p(ffi::d2i_PKCS8PrivateKey_bio(
622                 bio.as_ptr(),
623                 ptr::null_mut(),
624                 None,
625                 passphrase.as_ptr() as *const _ as *mut _,
626             ))
627             .map(|p| PKey::from_ptr(p))
628         }
629     }
630 }
631 
632 impl PKey<Public> {
633     from_pem! {
634         /// Decodes a PEM-encoded SubjectPublicKeyInfo structure.
635         ///
636         /// The input should have a header of `-----BEGIN PUBLIC KEY-----`.
637         ///
638         /// This corresponds to [`PEM_read_bio_PUBKEY`].
639         ///
640         /// [`PEM_read_bio_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_PUBKEY.html
641         public_key_from_pem,
642         PKey<Public>,
643         ffi::PEM_read_bio_PUBKEY
644     }
645 
646     from_der! {
647         /// Decodes a DER-encoded SubjectPublicKeyInfo structure.
648         ///
649         /// This corresponds to [`d2i_PUBKEY`].
650         ///
651         /// [`d2i_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_PUBKEY.html
652         public_key_from_der,
653         PKey<Public>,
654         ffi::d2i_PUBKEY
655     }
656 }
657 
658 cfg_if! {
659     if #[cfg(any(ossl110, libressl270))] {
660         use ffi::EVP_PKEY_up_ref;
661     } else {
662         #[allow(bad_style)]
663         unsafe extern "C" fn EVP_PKEY_up_ref(pkey: *mut ffi::EVP_PKEY) {
664             ffi::CRYPTO_add_lock(
665                 &mut (*pkey).references,
666                 1,
667                 ffi::CRYPTO_LOCK_EVP_PKEY,
668                 "pkey.rs\0".as_ptr() as *const _,
669                 line!() as c_int,
670             );
671         }
672     }
673 }
674 
675 impl<T> TryFrom<EcKey<T>> for PKey<T> {
676     type Error = ErrorStack;
677 
try_from(ec_key: EcKey<T>) -> Result<PKey<T>, ErrorStack>678     fn try_from(ec_key: EcKey<T>) -> Result<PKey<T>, ErrorStack> {
679         PKey::from_ec_key(ec_key)
680     }
681 }
682 
683 impl<T> TryFrom<PKey<T>> for EcKey<T> {
684     type Error = ErrorStack;
685 
try_from(pkey: PKey<T>) -> Result<EcKey<T>, ErrorStack>686     fn try_from(pkey: PKey<T>) -> Result<EcKey<T>, ErrorStack> {
687         pkey.ec_key()
688     }
689 }
690 
691 impl<T> TryFrom<Rsa<T>> for PKey<T> {
692     type Error = ErrorStack;
693 
try_from(rsa: Rsa<T>) -> Result<PKey<T>, ErrorStack>694     fn try_from(rsa: Rsa<T>) -> Result<PKey<T>, ErrorStack> {
695         PKey::from_rsa(rsa)
696     }
697 }
698 
699 impl<T> TryFrom<PKey<T>> for Rsa<T> {
700     type Error = ErrorStack;
701 
try_from(pkey: PKey<T>) -> Result<Rsa<T>, ErrorStack>702     fn try_from(pkey: PKey<T>) -> Result<Rsa<T>, ErrorStack> {
703         pkey.rsa()
704     }
705 }
706 
707 impl<T> TryFrom<Dsa<T>> for PKey<T> {
708     type Error = ErrorStack;
709 
try_from(dsa: Dsa<T>) -> Result<PKey<T>, ErrorStack>710     fn try_from(dsa: Dsa<T>) -> Result<PKey<T>, ErrorStack> {
711         PKey::from_dsa(dsa)
712     }
713 }
714 
715 impl<T> TryFrom<PKey<T>> for Dsa<T> {
716     type Error = ErrorStack;
717 
try_from(pkey: PKey<T>) -> Result<Dsa<T>, ErrorStack>718     fn try_from(pkey: PKey<T>) -> Result<Dsa<T>, ErrorStack> {
719         pkey.dsa()
720     }
721 }
722 
723 impl<T> TryFrom<Dh<T>> for PKey<T> {
724     type Error = ErrorStack;
725 
try_from(dh: Dh<T>) -> Result<PKey<T>, ErrorStack>726     fn try_from(dh: Dh<T>) -> Result<PKey<T>, ErrorStack> {
727         PKey::from_dh(dh)
728     }
729 }
730 
731 impl<T> TryFrom<PKey<T>> for Dh<T> {
732     type Error = ErrorStack;
733 
try_from(pkey: PKey<T>) -> Result<Dh<T>, ErrorStack>734     fn try_from(pkey: PKey<T>) -> Result<Dh<T>, ErrorStack> {
735         pkey.dh()
736     }
737 }
738 
739 #[cfg(test)]
740 mod tests {
741     use std::convert::TryInto;
742 
743     use crate::dh::Dh;
744     use crate::dsa::Dsa;
745     use crate::ec::EcKey;
746     use crate::nid::Nid;
747     use crate::rsa::Rsa;
748     use crate::symm::Cipher;
749 
750     use super::*;
751 
752     #[test]
test_to_password()753     fn test_to_password() {
754         let rsa = Rsa::generate(2048).unwrap();
755         let pkey = PKey::from_rsa(rsa).unwrap();
756         let pem = pkey
757             .private_key_to_pem_pkcs8_passphrase(Cipher::aes_128_cbc(), b"foobar")
758             .unwrap();
759         PKey::private_key_from_pem_passphrase(&pem, b"foobar").unwrap();
760         assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err());
761     }
762 
763     #[test]
test_unencrypted_pkcs8()764     fn test_unencrypted_pkcs8() {
765         let key = include_bytes!("../test/pkcs8-nocrypt.der");
766         PKey::private_key_from_pkcs8(key).unwrap();
767     }
768 
769     #[test]
test_encrypted_pkcs8_passphrase()770     fn test_encrypted_pkcs8_passphrase() {
771         let key = include_bytes!("../test/pkcs8.der");
772         PKey::private_key_from_pkcs8_passphrase(key, b"mypass").unwrap();
773     }
774 
775     #[test]
test_encrypted_pkcs8_callback()776     fn test_encrypted_pkcs8_callback() {
777         let mut password_queried = false;
778         let key = include_bytes!("../test/pkcs8.der");
779         PKey::private_key_from_pkcs8_callback(key, |password| {
780             password_queried = true;
781             password[..6].copy_from_slice(b"mypass");
782             Ok(6)
783         })
784         .unwrap();
785         assert!(password_queried);
786     }
787 
788     #[test]
test_private_key_from_pem()789     fn test_private_key_from_pem() {
790         let key = include_bytes!("../test/key.pem");
791         PKey::private_key_from_pem(key).unwrap();
792     }
793 
794     #[test]
test_public_key_from_pem()795     fn test_public_key_from_pem() {
796         let key = include_bytes!("../test/key.pem.pub");
797         PKey::public_key_from_pem(key).unwrap();
798     }
799 
800     #[test]
test_public_key_from_der()801     fn test_public_key_from_der() {
802         let key = include_bytes!("../test/key.der.pub");
803         PKey::public_key_from_der(key).unwrap();
804     }
805 
806     #[test]
test_private_key_from_der()807     fn test_private_key_from_der() {
808         let key = include_bytes!("../test/key.der");
809         PKey::private_key_from_der(key).unwrap();
810     }
811 
812     #[test]
test_pem()813     fn test_pem() {
814         let key = include_bytes!("../test/key.pem");
815         let key = PKey::private_key_from_pem(key).unwrap();
816 
817         let priv_key = key.private_key_to_pem_pkcs8().unwrap();
818         let pub_key = key.public_key_to_pem().unwrap();
819 
820         // As a super-simple verification, just check that the buffers contain
821         // the `PRIVATE KEY` or `PUBLIC KEY` strings.
822         assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY"));
823         assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY"));
824     }
825 
826     #[test]
test_rsa_accessor()827     fn test_rsa_accessor() {
828         let rsa = Rsa::generate(2048).unwrap();
829         let pkey = PKey::from_rsa(rsa).unwrap();
830         pkey.rsa().unwrap();
831         assert_eq!(pkey.id(), Id::RSA);
832         assert!(pkey.dsa().is_err());
833     }
834 
835     #[test]
test_dsa_accessor()836     fn test_dsa_accessor() {
837         let dsa = Dsa::generate(2048).unwrap();
838         let pkey = PKey::from_dsa(dsa).unwrap();
839         pkey.dsa().unwrap();
840         assert_eq!(pkey.id(), Id::DSA);
841         assert!(pkey.rsa().is_err());
842     }
843 
844     #[test]
test_dh_accessor()845     fn test_dh_accessor() {
846         let dh = include_bytes!("../test/dhparams.pem");
847         let dh = Dh::params_from_pem(dh).unwrap();
848         let pkey = PKey::from_dh(dh).unwrap();
849         pkey.dh().unwrap();
850         assert_eq!(pkey.id(), Id::DH);
851         assert!(pkey.rsa().is_err());
852     }
853 
854     #[test]
test_ec_key_accessor()855     fn test_ec_key_accessor() {
856         let ec_key = EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
857         let pkey = PKey::from_ec_key(ec_key).unwrap();
858         pkey.ec_key().unwrap();
859         assert_eq!(pkey.id(), Id::EC);
860         assert!(pkey.rsa().is_err());
861     }
862 
863     #[test]
test_rsa_conversion()864     fn test_rsa_conversion() {
865         let rsa = Rsa::generate(2048).unwrap();
866         let pkey: PKey<Private> = rsa.clone().try_into().unwrap();
867         let rsa_: Rsa<Private> = pkey.try_into().unwrap();
868         // Eq is missing
869         assert_eq!(rsa.p(), rsa_.p());
870         assert_eq!(rsa.q(), rsa_.q());
871     }
872 
873     #[test]
test_dsa_conversion()874     fn test_dsa_conversion() {
875         let dsa = Dsa::generate(2048).unwrap();
876         let pkey: PKey<Private> = dsa.clone().try_into().unwrap();
877         let dsa_: Dsa<Private> = pkey.try_into().unwrap();
878         // Eq is missing
879         assert_eq!(dsa.priv_key(), dsa_.priv_key());
880     }
881 
882     #[test]
test_ec_key_conversion()883     fn test_ec_key_conversion() {
884         let group = crate::ec::EcGroup::from_curve_name(crate::nid::Nid::X9_62_PRIME256V1).unwrap();
885         let ec_key = EcKey::generate(&group).unwrap();
886         let pkey: PKey<Private> = ec_key.clone().try_into().unwrap();
887         let ec_key_: EcKey<Private> = pkey.try_into().unwrap();
888         // Eq is missing
889         assert_eq!(ec_key.private_key(), ec_key_.private_key());
890     }
891 
892     #[test]
test_dh_conversion()893     fn test_dh_conversion() {
894         let dh_params = include_bytes!("../test/dhparams.pem");
895         let dh_params = Dh::params_from_pem(dh_params).unwrap();
896         let dh = dh_params.generate_key().unwrap();
897 
898         // Clone is missing for Dh, save the parameters
899         let p = dh.prime_p().to_owned().unwrap();
900         let q = dh.prime_q().map(|q| q.to_owned().unwrap());
901         let g = dh.generator().to_owned().unwrap();
902 
903         let pkey: PKey<Private> = dh.try_into().unwrap();
904         let dh_: Dh<Private> = pkey.try_into().unwrap();
905 
906         // Eq is missing
907         assert_eq!(&p, dh_.prime_p());
908         assert_eq!(q, dh_.prime_q().map(|q| q.to_owned().unwrap()));
909         assert_eq!(&g, dh_.generator());
910     }
911 }
912