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 //!
33 //! extern crate openssl;
34 //!
35 //! use openssl::rsa::Rsa;
36 //! use openssl::pkey::PKey;
37 //! use std::str;
38 //!
39 //! fn main() {
40 //!     let rsa = Rsa::generate(2048).unwrap();
41 //!     let pkey = PKey::from_rsa(rsa).unwrap();
42 //!
43 //!     let pub_key: Vec<u8> = pkey.public_key_to_pem().unwrap();
44 //!     println!("{:?}", str::from_utf8(pub_key.as_slice()).unwrap());
45 //! }
46 //! ```
47 
48 use ffi;
49 use foreign_types::{ForeignType, ForeignTypeRef};
50 use libc::c_int;
51 use std::ffi::CString;
52 use std::mem;
53 use std::ptr;
54 
55 use bio::MemBioSlice;
56 use dh::Dh;
57 use dsa::Dsa;
58 use ec::EcKey;
59 use error::ErrorStack;
60 use rsa::Rsa;
61 use util::{invoke_passwd_cb, CallbackState};
62 use {cvt, cvt_p};
63 
64 /// A tag type indicating that a key only has parameters.
65 pub enum Params {}
66 
67 /// A tag type indicating that a key only has public components.
68 pub enum Public {}
69 
70 /// A tag type indicating that a key has private components.
71 pub enum Private {}
72 
73 /// An identifier of a kind of key.
74 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
75 pub struct Id(c_int);
76 
77 impl Id {
78     /// Creates a `Id` from an integer representation.
from_raw(value: c_int) -> Id79     pub fn from_raw(value: c_int) -> Id {
80         Id(value)
81     }
82 
83     /// Returns the integer representation of the `Id`.
as_raw(&self) -> c_int84     pub fn as_raw(&self) -> c_int {
85         self.0
86     }
87 
88     pub const RSA: Id = Id(ffi::EVP_PKEY_RSA);
89     pub const HMAC: Id = Id(ffi::EVP_PKEY_HMAC);
90     pub const DSA: Id = Id(ffi::EVP_PKEY_DSA);
91     pub const DH: Id = Id(ffi::EVP_PKEY_DH);
92     pub const EC: Id = Id(ffi::EVP_PKEY_EC);
93 
94     #[cfg(ossl111)]
95     pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519);
96     #[cfg(ossl111)]
97     pub const ED448: Id = Id(ffi::EVP_PKEY_ED448);
98 }
99 
100 /// A trait indicating that a key has parameters.
101 pub unsafe trait HasParams {}
102 
103 unsafe impl HasParams for Params {}
104 
105 unsafe impl<T> HasParams for T where T: HasPublic {}
106 
107 /// A trait indicating that a key has public components.
108 pub unsafe trait HasPublic {}
109 
110 unsafe impl HasPublic for Public {}
111 
112 unsafe impl<T> HasPublic for T where T: HasPrivate {}
113 
114 /// A trait indicating that a key has private components.
115 pub unsafe trait HasPrivate {}
116 
117 unsafe impl HasPrivate for Private {}
118 
119 generic_foreign_type_and_impl_send_sync! {
120     type CType = ffi::EVP_PKEY;
121     fn drop = ffi::EVP_PKEY_free;
122 
123     /// A public or private key.
124     pub struct PKey<T>;
125     /// Reference to `PKey`.
126     pub struct PKeyRef<T>;
127 }
128 
129 impl<T> ToOwned for PKeyRef<T> {
130     type Owned = PKey<T>;
131 
to_owned(&self) -> PKey<T>132     fn to_owned(&self) -> PKey<T> {
133         unsafe {
134             EVP_PKEY_up_ref(self.as_ptr());
135             PKey::from_ptr(self.as_ptr())
136         }
137     }
138 }
139 
140 impl<T> PKeyRef<T> {
141     /// Returns a copy of the internal RSA key.
142     ///
143     /// This corresponds to [`EVP_PKEY_get1_RSA`].
144     ///
145     /// [`EVP_PKEY_get1_RSA`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_RSA.html
rsa(&self) -> Result<Rsa<T>, ErrorStack>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     ///
155     /// This corresponds to [`EVP_PKEY_get1_DSA`].
156     ///
157     /// [`EVP_PKEY_get1_DSA`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_DSA.html
dsa(&self) -> Result<Dsa<T>, ErrorStack>158     pub fn dsa(&self) -> Result<Dsa<T>, ErrorStack> {
159         unsafe {
160             let dsa = cvt_p(ffi::EVP_PKEY_get1_DSA(self.as_ptr()))?;
161             Ok(Dsa::from_ptr(dsa))
162         }
163     }
164 
165     /// Returns a copy of the internal DH key.
166     ///
167     /// This corresponds to [`EVP_PKEY_get1_DH`].
168     ///
169     /// [`EVP_PKEY_get1_DH`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_DH.html
dh(&self) -> Result<Dh<T>, ErrorStack>170     pub fn dh(&self) -> Result<Dh<T>, ErrorStack> {
171         unsafe {
172             let dh = cvt_p(ffi::EVP_PKEY_get1_DH(self.as_ptr()))?;
173             Ok(Dh::from_ptr(dh))
174         }
175     }
176 
177     /// Returns a copy of the internal elliptic curve key.
178     ///
179     /// This corresponds to [`EVP_PKEY_get1_EC_KEY`].
180     ///
181     /// [`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>182     pub fn ec_key(&self) -> Result<EcKey<T>, ErrorStack> {
183         unsafe {
184             let ec_key = cvt_p(ffi::EVP_PKEY_get1_EC_KEY(self.as_ptr()))?;
185             Ok(EcKey::from_ptr(ec_key))
186         }
187     }
188 
189     /// Returns the `Id` that represents the type of this key.
190     ///
191     /// This corresponds to [`EVP_PKEY_id`].
192     ///
193     /// [`EVP_PKEY_id`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_id.html
id(&self) -> Id194     pub fn id(&self) -> Id {
195         unsafe { Id::from_raw(ffi::EVP_PKEY_id(self.as_ptr())) }
196     }
197 
198     /// Returns the maximum size of a signature in bytes.
199     ///
200     /// This corresponds to [`EVP_PKEY_size`].
201     ///
202     /// [`EVP_PKEY_size`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_size.html
size(&self) -> usize203     pub fn size(&self) -> usize {
204         unsafe { ffi::EVP_PKEY_size(self.as_ptr()) as usize }
205     }
206 }
207 
208 impl<T> PKeyRef<T>
209 where
210     T: HasPublic,
211 {
212     to_pem! {
213         /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure.
214         ///
215         /// The output will have a header of `-----BEGIN PUBLIC KEY-----`.
216         ///
217         /// This corresponds to [`PEM_write_bio_PUBKEY`].
218         ///
219         /// [`PEM_write_bio_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_PUBKEY.html
220         public_key_to_pem,
221         ffi::PEM_write_bio_PUBKEY
222     }
223 
224     to_der! {
225         /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure.
226         ///
227         /// This corresponds to [`i2d_PUBKEY`].
228         ///
229         /// [`i2d_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_PUBKEY.html
230         public_key_to_der,
231         ffi::i2d_PUBKEY
232     }
233 
234     /// Returns the size of the key.
235     ///
236     /// This corresponds to the bit length of the modulus of an RSA key, and the bit length of the
237     /// group order for an elliptic curve key, for example.
bits(&self) -> u32238     pub fn bits(&self) -> u32 {
239         unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as u32 }
240     }
241 
242     /// Compares the public component of this key with another.
public_eq<U>(&self, other: &PKeyRef<U>) -> bool where U: HasPublic,243     pub fn public_eq<U>(&self, other: &PKeyRef<U>) -> bool
244     where
245         U: HasPublic,
246     {
247         unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 }
248     }
249 }
250 
251 impl<T> PKeyRef<T>
252 where
253     T: HasPrivate,
254 {
255     private_key_to_pem! {
256         /// Serializes the private key to a PEM-encoded PKCS#8 PrivateKeyInfo structure.
257         ///
258         /// The output will have a header of `-----BEGIN PRIVATE KEY-----`.
259         ///
260         /// This corresponds to [`PEM_write_bio_PKCS8PrivateKey`].
261         ///
262         /// [`PEM_write_bio_PKCS8PrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_PKCS8PrivateKey.html
263         private_key_to_pem_pkcs8,
264         /// Serializes the private key to a PEM-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
265         ///
266         /// The output will have a header of `-----BEGIN ENCRYPTED PRIVATE KEY-----`.
267         ///
268         /// This corresponds to [`PEM_write_bio_PKCS8PrivateKey`].
269         ///
270         /// [`PEM_write_bio_PKCS8PrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_PKCS8PrivateKey.html
271         private_key_to_pem_pkcs8_passphrase,
272         ffi::PEM_write_bio_PKCS8PrivateKey
273     }
274 
275     to_der! {
276         /// Serializes the private key to a DER-encoded key type specific format.
277         ///
278         /// This corresponds to [`i2d_PrivateKey`].
279         ///
280         /// [`i2d_PrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_PrivateKey.html
281         private_key_to_der,
282         ffi::i2d_PrivateKey
283     }
284 }
285 
286 impl<T> Clone for PKey<T> {
clone(&self) -> PKey<T>287     fn clone(&self) -> PKey<T> {
288         PKeyRef::to_owned(self)
289     }
290 }
291 
292 impl<T> PKey<T> {
293     /// Creates a new `PKey` containing an RSA key.
294     ///
295     /// This corresponds to [`EVP_PKEY_assign_RSA`].
296     ///
297     /// [`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>298     pub fn from_rsa(rsa: Rsa<T>) -> Result<PKey<T>, ErrorStack> {
299         unsafe {
300             let evp = cvt_p(ffi::EVP_PKEY_new())?;
301             let pkey = PKey::from_ptr(evp);
302             cvt(ffi::EVP_PKEY_assign(
303                 pkey.0,
304                 ffi::EVP_PKEY_RSA,
305                 rsa.as_ptr() as *mut _,
306             ))?;
307             mem::forget(rsa);
308             Ok(pkey)
309         }
310     }
311 
312     /// Creates a new `PKey` containing a DSA key.
313     ///
314     /// This corresponds to [`EVP_PKEY_assign_DSA`].
315     ///
316     /// [`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>317     pub fn from_dsa(dsa: Dsa<T>) -> Result<PKey<T>, ErrorStack> {
318         unsafe {
319             let evp = cvt_p(ffi::EVP_PKEY_new())?;
320             let pkey = PKey::from_ptr(evp);
321             cvt(ffi::EVP_PKEY_assign(
322                 pkey.0,
323                 ffi::EVP_PKEY_DSA,
324                 dsa.as_ptr() as *mut _,
325             ))?;
326             mem::forget(dsa);
327             Ok(pkey)
328         }
329     }
330 
331     /// Creates a new `PKey` containing a Diffie-Hellman key.
332     ///
333     /// This corresponds to [`EVP_PKEY_assign_DH`].
334     ///
335     /// [`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>336     pub fn from_dh(dh: Dh<T>) -> Result<PKey<T>, ErrorStack> {
337         unsafe {
338             let evp = cvt_p(ffi::EVP_PKEY_new())?;
339             let pkey = PKey::from_ptr(evp);
340             cvt(ffi::EVP_PKEY_assign(
341                 pkey.0,
342                 ffi::EVP_PKEY_DH,
343                 dh.as_ptr() as *mut _,
344             ))?;
345             mem::forget(dh);
346             Ok(pkey)
347         }
348     }
349 
350     /// Creates a new `PKey` containing an elliptic curve key.
351     ///
352     /// This corresponds to [`EVP_PKEY_assign_EC_KEY`].
353     ///
354     /// [`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>355     pub fn from_ec_key(ec_key: EcKey<T>) -> Result<PKey<T>, ErrorStack> {
356         unsafe {
357             let evp = cvt_p(ffi::EVP_PKEY_new())?;
358             let pkey = PKey::from_ptr(evp);
359             cvt(ffi::EVP_PKEY_assign(
360                 pkey.0,
361                 ffi::EVP_PKEY_EC,
362                 ec_key.as_ptr() as *mut _,
363             ))?;
364             mem::forget(ec_key);
365             Ok(pkey)
366         }
367     }
368 }
369 
370 impl PKey<Private> {
371     /// Creates a new `PKey` containing an HMAC key.
372     ///
373     /// # Note
374     ///
375     /// To compute HMAC values, use the `sign` module.
hmac(key: &[u8]) -> Result<PKey<Private>, ErrorStack>376     pub fn hmac(key: &[u8]) -> Result<PKey<Private>, ErrorStack> {
377         unsafe {
378             assert!(key.len() <= c_int::max_value() as usize);
379             let key = cvt_p(ffi::EVP_PKEY_new_mac_key(
380                 ffi::EVP_PKEY_HMAC,
381                 ptr::null_mut(),
382                 key.as_ptr() as *const _,
383                 key.len() as c_int,
384             ))?;
385             Ok(PKey::from_ptr(key))
386         }
387     }
388 
389     /// Creates a new `PKey` containing a CMAC key.
390     ///
391     /// Requires OpenSSL 1.1.0 or newer.
392     ///
393     /// # Note
394     ///
395     /// To compute CMAC values, use the `sign` module.
396     #[cfg(ossl110)]
cmac(cipher: &::symm::Cipher, key: &[u8]) -> Result<PKey<Private>, ErrorStack>397     pub fn cmac(cipher: &::symm::Cipher, key: &[u8]) -> Result<PKey<Private>, ErrorStack> {
398         unsafe {
399             assert!(key.len() <= c_int::max_value() as usize);
400             let kctx = cvt_p(ffi::EVP_PKEY_CTX_new_id(
401                 ffi::EVP_PKEY_CMAC,
402                 ptr::null_mut(),
403             ))?;
404 
405             let ret = (|| {
406                 cvt(ffi::EVP_PKEY_keygen_init(kctx))?;
407 
408                 // Set cipher for cmac
409                 cvt(ffi::EVP_PKEY_CTX_ctrl(
410                     kctx,
411                     -1,
412                     ffi::EVP_PKEY_OP_KEYGEN,
413                     ffi::EVP_PKEY_CTRL_CIPHER,
414                     0,
415                     cipher.as_ptr() as *mut _,
416                 ))?;
417 
418                 // Set the key data
419                 cvt(ffi::EVP_PKEY_CTX_ctrl(
420                     kctx,
421                     -1,
422                     ffi::EVP_PKEY_OP_KEYGEN,
423                     ffi::EVP_PKEY_CTRL_SET_MAC_KEY,
424                     key.len() as c_int,
425                     key.as_ptr() as *mut _,
426                 ))?;
427                 Ok(())
428             })();
429 
430             if let Err(e) = ret {
431                 // Free memory
432                 ffi::EVP_PKEY_CTX_free(kctx);
433                 return Err(e);
434             }
435 
436             // Generate key
437             let mut key = ptr::null_mut();
438             let ret = cvt(ffi::EVP_PKEY_keygen(kctx, &mut key));
439 
440             // Free memory
441             ffi::EVP_PKEY_CTX_free(kctx);
442 
443             if let Err(e) = ret {
444                 return Err(e);
445             }
446 
447             Ok(PKey::from_ptr(key))
448         }
449     }
450 
451     #[cfg(ossl110)]
generate_eddsa(nid: c_int) -> Result<PKey<Private>, ErrorStack>452     fn generate_eddsa(nid: c_int) -> Result<PKey<Private>, ErrorStack> {
453         unsafe {
454             let kctx = cvt_p(ffi::EVP_PKEY_CTX_new_id(nid, ptr::null_mut()))?;
455             let ret = cvt(ffi::EVP_PKEY_keygen_init(kctx));
456             if let Err(e) = ret {
457                 ffi::EVP_PKEY_CTX_free(kctx);
458                 return Err(e);
459             }
460             let mut key = ptr::null_mut();
461             let ret = cvt(ffi::EVP_PKEY_keygen(kctx, &mut key));
462 
463             ffi::EVP_PKEY_CTX_free(kctx);
464 
465             if let Err(e) = ret {
466                 return Err(e);
467             }
468 
469             Ok(PKey::from_ptr(key))
470         }
471     }
472 
473     /// Generates a new private Ed25519 key
474     #[cfg(ossl111)]
generate_ed25519() -> Result<PKey<Private>, ErrorStack>475     pub fn generate_ed25519() -> Result<PKey<Private>, ErrorStack> {
476         PKey::generate_eddsa(ffi::EVP_PKEY_ED25519)
477     }
478 
479     /// Generates a new private Ed448 key
480     #[cfg(ossl111)]
generate_ed448() -> Result<PKey<Private>, ErrorStack>481     pub fn generate_ed448() -> Result<PKey<Private>, ErrorStack> {
482         PKey::generate_eddsa(ffi::EVP_PKEY_ED448)
483     }
484 
485     private_key_from_pem! {
486         /// Deserializes a private key from a PEM-encoded key type specific format.
487         ///
488         /// This corresponds to [`PEM_read_bio_PrivateKey`].
489         ///
490         /// [`PEM_read_bio_PrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_PrivateKey.html
491         private_key_from_pem,
492 
493         /// Deserializes a private key from a PEM-encoded encrypted key type specific format.
494         ///
495         /// This corresponds to [`PEM_read_bio_PrivateKey`].
496         ///
497         /// [`PEM_read_bio_PrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_PrivateKey.html
498         private_key_from_pem_passphrase,
499 
500         /// Deserializes a private key from a PEM-encoded encrypted key type specific format.
501         ///
502         /// The callback should fill the password into the provided buffer and return its length.
503         ///
504         /// This corresponds to [`PEM_read_bio_PrivateKey`].
505         ///
506         /// [`PEM_read_bio_PrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_PrivateKey.html
507         private_key_from_pem_callback,
508         PKey<Private>,
509         ffi::PEM_read_bio_PrivateKey
510     }
511 
512     from_der! {
513         /// Decodes a DER-encoded private key.
514         ///
515         /// This function will automatically attempt to detect the underlying key format, and
516         /// supports the unencrypted PKCS#8 PrivateKeyInfo structures as well as key type specific
517         /// formats.
518         ///
519         /// This corresponds to [`d2i_AutoPrivateKey`].
520         ///
521         /// [`d2i_AutoPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_AutoPrivateKey.html
522         private_key_from_der,
523         PKey<Private>,
524         ffi::d2i_AutoPrivateKey
525     }
526 
527     /// Deserializes a DER-formatted PKCS#8 private key, using a callback to retrieve the password
528     /// if the key is encrpyted.
529     ///
530     /// The callback should copy the password into the provided buffer and return the number of
531     /// bytes written.
private_key_from_pkcs8_callback<F>( der: &[u8], callback: F, ) -> Result<PKey<Private>, ErrorStack> where F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>,532     pub fn private_key_from_pkcs8_callback<F>(
533         der: &[u8],
534         callback: F,
535     ) -> Result<PKey<Private>, ErrorStack>
536     where
537         F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>,
538     {
539         unsafe {
540             ffi::init();
541             let mut cb = CallbackState::new(callback);
542             let bio = MemBioSlice::new(der)?;
543             cvt_p(ffi::d2i_PKCS8PrivateKey_bio(
544                 bio.as_ptr(),
545                 ptr::null_mut(),
546                 Some(invoke_passwd_cb::<F>),
547                 &mut cb as *mut _ as *mut _,
548             ))
549             .map(|p| PKey::from_ptr(p))
550         }
551     }
552 
553     /// Deserializes a DER-formatted PKCS#8 private key, using the supplied password if the key is
554     /// encrypted.
555     ///
556     /// # Panics
557     ///
558     /// Panics if `passphrase` contains an embedded null.
private_key_from_pkcs8_passphrase( der: &[u8], passphrase: &[u8], ) -> Result<PKey<Private>, ErrorStack>559     pub fn private_key_from_pkcs8_passphrase(
560         der: &[u8],
561         passphrase: &[u8],
562     ) -> Result<PKey<Private>, ErrorStack> {
563         unsafe {
564             ffi::init();
565             let bio = MemBioSlice::new(der)?;
566             let passphrase = CString::new(passphrase).unwrap();
567             cvt_p(ffi::d2i_PKCS8PrivateKey_bio(
568                 bio.as_ptr(),
569                 ptr::null_mut(),
570                 None,
571                 passphrase.as_ptr() as *const _ as *mut _,
572             ))
573             .map(|p| PKey::from_ptr(p))
574         }
575     }
576 }
577 
578 impl PKey<Public> {
579     from_pem! {
580         /// Decodes a PEM-encoded SubjectPublicKeyInfo structure.
581         ///
582         /// The input should have a header of `-----BEGIN PUBLIC KEY-----`.
583         ///
584         /// This corresponds to [`PEM_read_bio_PUBKEY`].
585         ///
586         /// [`PEM_read_bio_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_PUBKEY.html
587         public_key_from_pem,
588         PKey<Public>,
589         ffi::PEM_read_bio_PUBKEY
590     }
591 
592     from_der! {
593         /// Decodes a DER-encoded SubjectPublicKeyInfo structure.
594         ///
595         /// This corresponds to [`d2i_PUBKEY`].
596         ///
597         /// [`d2i_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_PUBKEY.html
598         public_key_from_der,
599         PKey<Public>,
600         ffi::d2i_PUBKEY
601     }
602 }
603 
604 cfg_if! {
605     if #[cfg(any(ossl110, libressl270))] {
606         use ffi::EVP_PKEY_up_ref;
607     } else {
608         unsafe extern "C" fn EVP_PKEY_up_ref(pkey: *mut ffi::EVP_PKEY) {
609             ffi::CRYPTO_add_lock(
610                 &mut (*pkey).references,
611                 1,
612                 ffi::CRYPTO_LOCK_EVP_PKEY,
613                 "pkey.rs\0".as_ptr() as *const _,
614                 line!() as c_int,
615             );
616         }
617     }
618 }
619 
620 #[cfg(test)]
621 mod tests {
622     use dh::Dh;
623     use dsa::Dsa;
624     use ec::EcKey;
625     use nid::Nid;
626     use rsa::Rsa;
627     use symm::Cipher;
628 
629     use super::*;
630 
631     #[test]
test_to_password()632     fn test_to_password() {
633         let rsa = Rsa::generate(2048).unwrap();
634         let pkey = PKey::from_rsa(rsa).unwrap();
635         let pem = pkey
636             .private_key_to_pem_pkcs8_passphrase(Cipher::aes_128_cbc(), b"foobar")
637             .unwrap();
638         PKey::private_key_from_pem_passphrase(&pem, b"foobar").unwrap();
639         assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err());
640     }
641 
642     #[test]
test_encrypted_pkcs8_passphrase()643     fn test_encrypted_pkcs8_passphrase() {
644         let key = include_bytes!("../test/pkcs8.der");
645         PKey::private_key_from_pkcs8_passphrase(key, b"mypass").unwrap();
646     }
647 
648     #[test]
test_encrypted_pkcs8_callback()649     fn test_encrypted_pkcs8_callback() {
650         let mut password_queried = false;
651         let key = include_bytes!("../test/pkcs8.der");
652         PKey::private_key_from_pkcs8_callback(key, |password| {
653             password_queried = true;
654             password[..6].copy_from_slice(b"mypass");
655             Ok(6)
656         })
657         .unwrap();
658         assert!(password_queried);
659     }
660 
661     #[test]
test_private_key_from_pem()662     fn test_private_key_from_pem() {
663         let key = include_bytes!("../test/key.pem");
664         PKey::private_key_from_pem(key).unwrap();
665     }
666 
667     #[test]
test_public_key_from_pem()668     fn test_public_key_from_pem() {
669         let key = include_bytes!("../test/key.pem.pub");
670         PKey::public_key_from_pem(key).unwrap();
671     }
672 
673     #[test]
test_public_key_from_der()674     fn test_public_key_from_der() {
675         let key = include_bytes!("../test/key.der.pub");
676         PKey::public_key_from_der(key).unwrap();
677     }
678 
679     #[test]
test_private_key_from_der()680     fn test_private_key_from_der() {
681         let key = include_bytes!("../test/key.der");
682         PKey::private_key_from_der(key).unwrap();
683     }
684 
685     #[test]
test_pem()686     fn test_pem() {
687         let key = include_bytes!("../test/key.pem");
688         let key = PKey::private_key_from_pem(key).unwrap();
689 
690         let priv_key = key.private_key_to_pem_pkcs8().unwrap();
691         let pub_key = key.public_key_to_pem().unwrap();
692 
693         // As a super-simple verification, just check that the buffers contain
694         // the `PRIVATE KEY` or `PUBLIC KEY` strings.
695         assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY"));
696         assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY"));
697     }
698 
699     #[test]
test_rsa_accessor()700     fn test_rsa_accessor() {
701         let rsa = Rsa::generate(2048).unwrap();
702         let pkey = PKey::from_rsa(rsa).unwrap();
703         pkey.rsa().unwrap();
704         assert_eq!(pkey.id(), Id::RSA);
705         assert!(pkey.dsa().is_err());
706     }
707 
708     #[test]
test_dsa_accessor()709     fn test_dsa_accessor() {
710         let dsa = Dsa::generate(2048).unwrap();
711         let pkey = PKey::from_dsa(dsa).unwrap();
712         pkey.dsa().unwrap();
713         assert_eq!(pkey.id(), Id::DSA);
714         assert!(pkey.rsa().is_err());
715     }
716 
717     #[test]
test_dh_accessor()718     fn test_dh_accessor() {
719         let dh = include_bytes!("../test/dhparams.pem");
720         let dh = Dh::params_from_pem(dh).unwrap();
721         let pkey = PKey::from_dh(dh).unwrap();
722         pkey.dh().unwrap();
723         assert_eq!(pkey.id(), Id::DH);
724         assert!(pkey.rsa().is_err());
725     }
726 
727     #[test]
test_ec_key_accessor()728     fn test_ec_key_accessor() {
729         let ec_key = EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
730         let pkey = PKey::from_ec_key(ec_key).unwrap();
731         pkey.ec_key().unwrap();
732         assert_eq!(pkey.id(), Id::EC);
733         assert!(pkey.rsa().is_err());
734     }
735 }
736