1 | //! Public/private key processing. |
2 | //! |
3 | //! Asymmetric public key algorithms solve the problem of establishing and sharing |
4 | //! secret keys to securely send and receive messages. |
5 | //! This system uses a pair of keys: a public key, which can be freely |
6 | //! distributed, and a private key, which is kept to oneself. An entity may |
7 | //! encrypt information using a user's public key. The encrypted information can |
8 | //! only be deciphered using that user's private key. |
9 | //! |
10 | //! This module offers support for five popular algorithms: |
11 | //! |
12 | //! * RSA |
13 | //! |
14 | //! * DSA |
15 | //! |
16 | //! * Diffie-Hellman |
17 | //! |
18 | //! * Elliptic Curves |
19 | //! |
20 | //! * HMAC |
21 | //! |
22 | //! These algorithms rely on hard mathematical problems - namely integer factorization, |
23 | //! discrete logarithms, and elliptic curve relationships - that currently do not |
24 | //! yield efficient solutions. This property ensures the security of these |
25 | //! cryptographic algorithms. |
26 | //! |
27 | //! # Example |
28 | //! |
29 | //! Generate a 2048-bit RSA public/private key pair and print the public key. |
30 | //! |
31 | //! ```rust |
32 | //! use openssl::rsa::Rsa; |
33 | //! use openssl::pkey::PKey; |
34 | //! use std::str; |
35 | //! |
36 | //! let rsa = Rsa::generate(2048).unwrap(); |
37 | //! let pkey = PKey::from_rsa(rsa).unwrap(); |
38 | //! |
39 | //! let pub_key: Vec<u8> = pkey.public_key_to_pem().unwrap(); |
40 | //! println!("{:?}" , str::from_utf8(pub_key.as_slice()).unwrap()); |
41 | //! ``` |
42 | #![allow (clippy::missing_safety_doc)] |
43 | use crate::bio::{MemBio, MemBioSlice}; |
44 | #[cfg (ossl110)] |
45 | use crate::cipher::CipherRef; |
46 | use crate::dh::Dh; |
47 | use crate::dsa::Dsa; |
48 | use crate::ec::EcKey; |
49 | use crate::error::ErrorStack; |
50 | #[cfg (any(ossl110, boringssl, libressl370))] |
51 | use crate::pkey_ctx::PkeyCtx; |
52 | use crate::rsa::Rsa; |
53 | use crate::symm::Cipher; |
54 | use crate::util::{invoke_passwd_cb, CallbackState}; |
55 | use crate::{cvt, cvt_p}; |
56 | use cfg_if::cfg_if; |
57 | use foreign_types::{ForeignType, ForeignTypeRef}; |
58 | use libc::{c_int, c_long}; |
59 | use openssl_macros::corresponds; |
60 | use std::convert::{TryFrom, TryInto}; |
61 | use std::ffi::CString; |
62 | use std::fmt; |
63 | use std::mem; |
64 | use std::ptr; |
65 | |
66 | /// A tag type indicating that a key only has parameters. |
67 | pub enum Params {} |
68 | |
69 | /// A tag type indicating that a key only has public components. |
70 | pub enum Public {} |
71 | |
72 | /// A tag type indicating that a key has private components. |
73 | pub enum Private {} |
74 | |
75 | /// An identifier of a kind of key. |
76 | #[derive (Debug, Copy, Clone, PartialEq, Eq)] |
77 | pub struct Id(c_int); |
78 | |
79 | impl Id { |
80 | pub const RSA: Id = Id(ffi::EVP_PKEY_RSA); |
81 | #[cfg (any(ossl111, libressl310, boringssl))] |
82 | pub const RSA_PSS: Id = Id(ffi::EVP_PKEY_RSA_PSS); |
83 | #[cfg (not(boringssl))] |
84 | pub const HMAC: Id = Id(ffi::EVP_PKEY_HMAC); |
85 | #[cfg (not(boringssl))] |
86 | pub const CMAC: Id = Id(ffi::EVP_PKEY_CMAC); |
87 | pub const DSA: Id = Id(ffi::EVP_PKEY_DSA); |
88 | pub const DH: Id = Id(ffi::EVP_PKEY_DH); |
89 | #[cfg (ossl110)] |
90 | pub const DHX: Id = Id(ffi::EVP_PKEY_DHX); |
91 | pub const EC: Id = Id(ffi::EVP_PKEY_EC); |
92 | #[cfg (ossl111)] |
93 | pub const SM2: Id = Id(ffi::EVP_PKEY_SM2); |
94 | |
95 | #[cfg (any(ossl110, boringssl, libressl360))] |
96 | pub const HKDF: Id = Id(ffi::EVP_PKEY_HKDF); |
97 | |
98 | #[cfg (any(ossl111, boringssl, libressl370))] |
99 | pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519); |
100 | #[cfg (ossl111)] |
101 | pub const ED448: Id = Id(ffi::EVP_PKEY_ED448); |
102 | #[cfg (any(ossl111, boringssl, libressl370))] |
103 | pub const X25519: Id = Id(ffi::EVP_PKEY_X25519); |
104 | #[cfg (ossl111)] |
105 | pub const X448: Id = Id(ffi::EVP_PKEY_X448); |
106 | #[cfg (ossl111)] |
107 | pub const POLY1305: Id = Id(ffi::EVP_PKEY_POLY1305); |
108 | |
109 | /// Creates a `Id` from an integer representation. |
110 | pub fn from_raw(value: c_int) -> Id { |
111 | Id(value) |
112 | } |
113 | |
114 | /// Returns the integer representation of the `Id`. |
115 | #[allow (clippy::trivially_copy_pass_by_ref)] |
116 | pub fn as_raw(&self) -> c_int { |
117 | self.0 |
118 | } |
119 | } |
120 | |
121 | /// A trait indicating that a key has parameters. |
122 | pub unsafe trait HasParams {} |
123 | |
124 | unsafe impl HasParams for Params {} |
125 | |
126 | unsafe impl<T> HasParams for T where T: HasPublic {} |
127 | |
128 | /// A trait indicating that a key has public components. |
129 | pub unsafe trait HasPublic {} |
130 | |
131 | unsafe impl HasPublic for Public {} |
132 | |
133 | unsafe impl<T> HasPublic for T where T: HasPrivate {} |
134 | |
135 | /// A trait indicating that a key has private components. |
136 | pub unsafe trait HasPrivate {} |
137 | |
138 | unsafe impl HasPrivate for Private {} |
139 | |
140 | generic_foreign_type_and_impl_send_sync! { |
141 | type CType = ffi::EVP_PKEY; |
142 | fn drop = ffi::EVP_PKEY_free; |
143 | |
144 | /// A public or private key. |
145 | pub struct PKey<T>; |
146 | /// Reference to `PKey`. |
147 | pub struct PKeyRef<T>; |
148 | } |
149 | |
150 | impl<T> ToOwned for PKeyRef<T> { |
151 | type Owned = PKey<T>; |
152 | |
153 | fn to_owned(&self) -> PKey<T> { |
154 | unsafe { |
155 | EVP_PKEY_up_ref(self.as_ptr()); |
156 | PKey::from_ptr(self.as_ptr()) |
157 | } |
158 | } |
159 | } |
160 | |
161 | impl<T> PKeyRef<T> { |
162 | /// Returns a copy of the internal RSA key. |
163 | #[corresponds (EVP_PKEY_get1_RSA)] |
164 | pub fn rsa(&self) -> Result<Rsa<T>, ErrorStack> { |
165 | unsafe { |
166 | let rsa = cvt_p(ffi::EVP_PKEY_get1_RSA(self.as_ptr()))?; |
167 | Ok(Rsa::from_ptr(rsa)) |
168 | } |
169 | } |
170 | |
171 | /// Returns a copy of the internal DSA key. |
172 | #[corresponds (EVP_PKEY_get1_DSA)] |
173 | pub fn dsa(&self) -> Result<Dsa<T>, ErrorStack> { |
174 | unsafe { |
175 | let dsa = cvt_p(ffi::EVP_PKEY_get1_DSA(self.as_ptr()))?; |
176 | Ok(Dsa::from_ptr(dsa)) |
177 | } |
178 | } |
179 | |
180 | /// Returns a copy of the internal DH key. |
181 | #[corresponds (EVP_PKEY_get1_DH)] |
182 | pub fn dh(&self) -> Result<Dh<T>, ErrorStack> { |
183 | unsafe { |
184 | let dh = cvt_p(ffi::EVP_PKEY_get1_DH(self.as_ptr()))?; |
185 | Ok(Dh::from_ptr(dh)) |
186 | } |
187 | } |
188 | |
189 | /// Returns a copy of the internal elliptic curve key. |
190 | #[corresponds (EVP_PKEY_get1_EC_KEY)] |
191 | pub fn ec_key(&self) -> Result<EcKey<T>, ErrorStack> { |
192 | unsafe { |
193 | let ec_key = cvt_p(ffi::EVP_PKEY_get1_EC_KEY(self.as_ptr()))?; |
194 | Ok(EcKey::from_ptr(ec_key)) |
195 | } |
196 | } |
197 | |
198 | /// Returns the `Id` that represents the type of this key. |
199 | #[corresponds (EVP_PKEY_id)] |
200 | pub fn id(&self) -> Id { |
201 | unsafe { Id::from_raw(ffi::EVP_PKEY_id(self.as_ptr())) } |
202 | } |
203 | |
204 | /// Returns the maximum size of a signature in bytes. |
205 | #[corresponds (EVP_PKEY_size)] |
206 | pub fn size(&self) -> usize { |
207 | unsafe { ffi::EVP_PKEY_size(self.as_ptr()) as usize } |
208 | } |
209 | } |
210 | |
211 | impl<T> PKeyRef<T> |
212 | where |
213 | T: HasPublic, |
214 | { |
215 | to_pem! { |
216 | /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. |
217 | /// |
218 | /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. |
219 | #[corresponds (PEM_write_bio_PUBKEY)] |
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 | #[corresponds (i2d_PUBKEY)] |
227 | public_key_to_der, |
228 | ffi::i2d_PUBKEY |
229 | } |
230 | |
231 | /// Returns the size of the key. |
232 | /// |
233 | /// This corresponds to the bit length of the modulus of an RSA key, and the bit length of the |
234 | /// group order for an elliptic curve key, for example. |
235 | #[corresponds (EVP_PKEY_bits)] |
236 | pub fn bits(&self) -> u32 { |
237 | unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as u32 } |
238 | } |
239 | |
240 | ///Returns the number of security bits. |
241 | /// |
242 | ///Bits of security is defined in NIST SP800-57. |
243 | #[corresponds (EVP_PKEY_security_bits)] |
244 | #[cfg (any(ossl110, libressl360))] |
245 | pub fn security_bits(&self) -> u32 { |
246 | unsafe { ffi::EVP_PKEY_security_bits(self.as_ptr()) as u32 } |
247 | } |
248 | |
249 | /// Compares the public component of this key with another. |
250 | #[corresponds (EVP_PKEY_cmp)] |
251 | pub fn public_eq<U>(&self, other: &PKeyRef<U>) -> bool |
252 | where |
253 | U: HasPublic, |
254 | { |
255 | let res = unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 }; |
256 | // Clear the stack. OpenSSL will put an error on the stack when the |
257 | // keys are different types in some situations. |
258 | let _ = ErrorStack::get(); |
259 | res |
260 | } |
261 | |
262 | /// Raw byte representation of a public key. |
263 | /// |
264 | /// This function only works for algorithms that support raw public keys. |
265 | /// Currently this is: [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`]. |
266 | #[corresponds (EVP_PKEY_get_raw_public_key)] |
267 | #[cfg (any(ossl111, boringssl, libressl370))] |
268 | pub fn raw_public_key(&self) -> Result<Vec<u8>, ErrorStack> { |
269 | unsafe { |
270 | let mut len = 0; |
271 | cvt(ffi::EVP_PKEY_get_raw_public_key( |
272 | self.as_ptr(), |
273 | ptr::null_mut(), |
274 | &mut len, |
275 | ))?; |
276 | let mut buf = vec![0u8; len]; |
277 | cvt(ffi::EVP_PKEY_get_raw_public_key( |
278 | self.as_ptr(), |
279 | buf.as_mut_ptr(), |
280 | &mut len, |
281 | ))?; |
282 | buf.truncate(len); |
283 | Ok(buf) |
284 | } |
285 | } |
286 | } |
287 | |
288 | impl<T> PKeyRef<T> |
289 | where |
290 | T: HasPrivate, |
291 | { |
292 | private_key_to_pem! { |
293 | /// Serializes the private key to a PEM-encoded PKCS#8 PrivateKeyInfo structure. |
294 | /// |
295 | /// The output will have a header of `-----BEGIN PRIVATE KEY-----`. |
296 | #[corresponds (PEM_write_bio_PKCS8PrivateKey)] |
297 | private_key_to_pem_pkcs8, |
298 | /// Serializes the private key to a PEM-encoded PKCS#8 EncryptedPrivateKeyInfo structure. |
299 | /// |
300 | /// The output will have a header of `-----BEGIN ENCRYPTED PRIVATE KEY-----`. |
301 | #[corresponds (PEM_write_bio_PKCS8PrivateKey)] |
302 | private_key_to_pem_pkcs8_passphrase, |
303 | ffi::PEM_write_bio_PKCS8PrivateKey |
304 | } |
305 | |
306 | to_der! { |
307 | /// Serializes the private key to a DER-encoded key type specific format. |
308 | #[corresponds (i2d_PrivateKey)] |
309 | private_key_to_der, |
310 | ffi::i2d_PrivateKey |
311 | } |
312 | |
313 | /// Raw byte representation of a private key. |
314 | /// |
315 | /// This function only works for algorithms that support raw private keys. |
316 | /// Currently this is: [`Id::HMAC`], [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`]. |
317 | #[corresponds (EVP_PKEY_get_raw_private_key)] |
318 | #[cfg (any(ossl111, boringssl, libressl370))] |
319 | pub fn raw_private_key(&self) -> Result<Vec<u8>, ErrorStack> { |
320 | unsafe { |
321 | let mut len = 0; |
322 | cvt(ffi::EVP_PKEY_get_raw_private_key( |
323 | self.as_ptr(), |
324 | ptr::null_mut(), |
325 | &mut len, |
326 | ))?; |
327 | let mut buf = vec![0u8; len]; |
328 | cvt(ffi::EVP_PKEY_get_raw_private_key( |
329 | self.as_ptr(), |
330 | buf.as_mut_ptr(), |
331 | &mut len, |
332 | ))?; |
333 | buf.truncate(len); |
334 | Ok(buf) |
335 | } |
336 | } |
337 | |
338 | /// Serializes a private key into an unencrypted DER-formatted PKCS#8 |
339 | #[corresponds (i2d_PKCS8PrivateKey_bio)] |
340 | pub fn private_key_to_pkcs8(&self) -> Result<Vec<u8>, ErrorStack> { |
341 | unsafe { |
342 | let bio = MemBio::new()?; |
343 | cvt(ffi::i2d_PKCS8PrivateKey_bio( |
344 | bio.as_ptr(), |
345 | self.as_ptr(), |
346 | ptr::null(), |
347 | ptr::null_mut(), |
348 | 0, |
349 | None, |
350 | ptr::null_mut(), |
351 | ))?; |
352 | |
353 | Ok(bio.get_buf().to_owned()) |
354 | } |
355 | } |
356 | |
357 | /// Serializes a private key into a DER-formatted PKCS#8, using the supplied password to |
358 | /// encrypt the key. |
359 | #[corresponds (i2d_PKCS8PrivateKey_bio)] |
360 | pub fn private_key_to_pkcs8_passphrase( |
361 | &self, |
362 | cipher: Cipher, |
363 | passphrase: &[u8], |
364 | ) -> Result<Vec<u8>, ErrorStack> { |
365 | unsafe { |
366 | let bio = MemBio::new()?; |
367 | cvt(ffi::i2d_PKCS8PrivateKey_bio( |
368 | bio.as_ptr(), |
369 | self.as_ptr(), |
370 | cipher.as_ptr(), |
371 | passphrase.as_ptr() as *const _ as *mut _, |
372 | passphrase.len().try_into().unwrap(), |
373 | None, |
374 | ptr::null_mut(), |
375 | ))?; |
376 | |
377 | Ok(bio.get_buf().to_owned()) |
378 | } |
379 | } |
380 | } |
381 | |
382 | impl<T> fmt::Debug for PKey<T> { |
383 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
384 | let alg: &str = match self.id() { |
385 | Id::RSA => "RSA" , |
386 | #[cfg (not(boringssl))] |
387 | Id::HMAC => "HMAC" , |
388 | Id::DSA => "DSA" , |
389 | Id::DH => "DH" , |
390 | Id::EC => "EC" , |
391 | #[cfg (ossl111)] |
392 | Id::ED25519 => "Ed25519" , |
393 | #[cfg (ossl111)] |
394 | Id::ED448 => "Ed448" , |
395 | _ => "unknown" , |
396 | }; |
397 | fmt.debug_struct("PKey" ).field(name:"algorithm" , &alg).finish() |
398 | // TODO: Print details for each specific type of key |
399 | } |
400 | } |
401 | |
402 | impl<T> Clone for PKey<T> { |
403 | fn clone(&self) -> PKey<T> { |
404 | PKeyRef::to_owned(self) |
405 | } |
406 | } |
407 | |
408 | impl<T> PKey<T> { |
409 | /// Creates a new `PKey` containing an RSA key. |
410 | #[corresponds (EVP_PKEY_assign_RSA)] |
411 | pub fn from_rsa(rsa: Rsa<T>) -> Result<PKey<T>, ErrorStack> { |
412 | unsafe { |
413 | let evp = cvt_p(ffi::EVP_PKEY_new())?; |
414 | let pkey = PKey::from_ptr(evp); |
415 | cvt(ffi::EVP_PKEY_assign_RSA(pkey.0, rsa.as_ptr()))?; |
416 | mem::forget(rsa); |
417 | Ok(pkey) |
418 | } |
419 | } |
420 | |
421 | /// Creates a new `PKey` containing a DSA key. |
422 | #[corresponds (EVP_PKEY_assign_DSA)] |
423 | pub fn from_dsa(dsa: Dsa<T>) -> Result<PKey<T>, ErrorStack> { |
424 | unsafe { |
425 | let evp = cvt_p(ffi::EVP_PKEY_new())?; |
426 | let pkey = PKey::from_ptr(evp); |
427 | cvt(ffi::EVP_PKEY_assign_DSA(pkey.0, dsa.as_ptr()))?; |
428 | mem::forget(dsa); |
429 | Ok(pkey) |
430 | } |
431 | } |
432 | |
433 | /// Creates a new `PKey` containing a Diffie-Hellman key. |
434 | #[corresponds (EVP_PKEY_assign_DH)] |
435 | #[cfg (not(boringssl))] |
436 | pub fn from_dh(dh: Dh<T>) -> Result<PKey<T>, ErrorStack> { |
437 | unsafe { |
438 | let evp = cvt_p(ffi::EVP_PKEY_new())?; |
439 | let pkey = PKey::from_ptr(evp); |
440 | cvt(ffi::EVP_PKEY_assign_DH(pkey.0, dh.as_ptr()))?; |
441 | mem::forget(dh); |
442 | Ok(pkey) |
443 | } |
444 | } |
445 | |
446 | /// Creates a new `PKey` containing a Diffie-Hellman key with type DHX. |
447 | #[cfg (all(not(boringssl), ossl110))] |
448 | pub fn from_dhx(dh: Dh<T>) -> Result<PKey<T>, ErrorStack> { |
449 | unsafe { |
450 | let evp = cvt_p(ffi::EVP_PKEY_new())?; |
451 | let pkey = PKey::from_ptr(evp); |
452 | cvt(ffi::EVP_PKEY_assign( |
453 | pkey.0, |
454 | ffi::EVP_PKEY_DHX, |
455 | dh.as_ptr().cast(), |
456 | ))?; |
457 | mem::forget(dh); |
458 | Ok(pkey) |
459 | } |
460 | } |
461 | |
462 | /// Creates a new `PKey` containing an elliptic curve key. |
463 | #[corresponds (EVP_PKEY_assign_EC_KEY)] |
464 | pub fn from_ec_key(ec_key: EcKey<T>) -> Result<PKey<T>, ErrorStack> { |
465 | unsafe { |
466 | let evp = cvt_p(ffi::EVP_PKEY_new())?; |
467 | let pkey = PKey::from_ptr(evp); |
468 | cvt(ffi::EVP_PKEY_assign_EC_KEY(pkey.0, ec_key.as_ptr()))?; |
469 | mem::forget(ec_key); |
470 | Ok(pkey) |
471 | } |
472 | } |
473 | } |
474 | |
475 | impl PKey<Private> { |
476 | /// Creates a new `PKey` containing an HMAC key. |
477 | /// |
478 | /// # Note |
479 | /// |
480 | /// To compute HMAC values, use the `sign` module. |
481 | #[corresponds (EVP_PKEY_new_mac_key)] |
482 | #[cfg (not(boringssl))] |
483 | pub fn hmac(key: &[u8]) -> Result<PKey<Private>, ErrorStack> { |
484 | unsafe { |
485 | assert!(key.len() <= c_int::max_value() as usize); |
486 | let key = cvt_p(ffi::EVP_PKEY_new_mac_key( |
487 | ffi::EVP_PKEY_HMAC, |
488 | ptr::null_mut(), |
489 | key.as_ptr() as *const _, |
490 | key.len() as c_int, |
491 | ))?; |
492 | Ok(PKey::from_ptr(key)) |
493 | } |
494 | } |
495 | |
496 | /// Creates a new `PKey` containing a CMAC key. |
497 | /// |
498 | /// Requires OpenSSL 1.1.0 or newer. |
499 | /// |
500 | /// # Note |
501 | /// |
502 | /// To compute CMAC values, use the `sign` module. |
503 | #[cfg (all(not(boringssl), ossl110))] |
504 | #[allow (clippy::trivially_copy_pass_by_ref)] |
505 | pub fn cmac(cipher: &Cipher, key: &[u8]) -> Result<PKey<Private>, ErrorStack> { |
506 | let mut ctx = PkeyCtx::new_id(Id::CMAC)?; |
507 | ctx.keygen_init()?; |
508 | ctx.set_keygen_cipher(unsafe { CipherRef::from_ptr(cipher.as_ptr() as *mut _) })?; |
509 | ctx.set_keygen_mac_key(key)?; |
510 | ctx.keygen() |
511 | } |
512 | |
513 | #[cfg (any(ossl111, boringssl, libressl370))] |
514 | fn generate_eddsa(id: Id) -> Result<PKey<Private>, ErrorStack> { |
515 | let mut ctx = PkeyCtx::new_id(id)?; |
516 | ctx.keygen_init()?; |
517 | ctx.keygen() |
518 | } |
519 | |
520 | /// Generates a new private X25519 key. |
521 | /// |
522 | /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`]. |
523 | /// |
524 | /// # Examples |
525 | /// |
526 | /// ``` |
527 | /// # fn main() -> Result<(), Box<dyn std::error::Error>> { |
528 | /// use openssl::pkey::{PKey, Id}; |
529 | /// use openssl::derive::Deriver; |
530 | /// |
531 | /// let public = // ... |
532 | /// # &PKey::generate_x25519()?.raw_public_key()?; |
533 | /// let public_key = PKey::public_key_from_raw_bytes(public, Id::X25519)?; |
534 | /// |
535 | /// let key = PKey::generate_x25519()?; |
536 | /// let mut deriver = Deriver::new(&key)?; |
537 | /// deriver.set_peer(&public_key)?; |
538 | /// |
539 | /// let secret = deriver.derive_to_vec()?; |
540 | /// assert_eq!(secret.len(), 32); |
541 | /// # Ok(()) } |
542 | /// ``` |
543 | #[cfg (any(ossl111, boringssl, libressl370))] |
544 | pub fn generate_x25519() -> Result<PKey<Private>, ErrorStack> { |
545 | PKey::generate_eddsa(Id::X25519) |
546 | } |
547 | |
548 | /// Generates a new private X448 key. |
549 | /// |
550 | /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`]. |
551 | /// |
552 | /// # Examples |
553 | /// |
554 | /// ``` |
555 | /// # fn main() -> Result<(), Box<dyn std::error::Error>> { |
556 | /// use openssl::pkey::{PKey, Id}; |
557 | /// use openssl::derive::Deriver; |
558 | /// |
559 | /// let public = // ... |
560 | /// # &PKey::generate_x448()?.raw_public_key()?; |
561 | /// let public_key = PKey::public_key_from_raw_bytes(public, Id::X448)?; |
562 | /// |
563 | /// let key = PKey::generate_x448()?; |
564 | /// let mut deriver = Deriver::new(&key)?; |
565 | /// deriver.set_peer(&public_key)?; |
566 | /// |
567 | /// let secret = deriver.derive_to_vec()?; |
568 | /// assert_eq!(secret.len(), 56); |
569 | /// # Ok(()) } |
570 | /// ``` |
571 | #[cfg (ossl111)] |
572 | pub fn generate_x448() -> Result<PKey<Private>, ErrorStack> { |
573 | PKey::generate_eddsa(Id::X448) |
574 | } |
575 | |
576 | /// Generates a new private Ed25519 key. |
577 | /// |
578 | /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`]. |
579 | /// |
580 | /// # Examples |
581 | /// |
582 | /// ``` |
583 | /// # fn main() -> Result<(), Box<dyn std::error::Error>> { |
584 | /// use openssl::pkey::{PKey, Id}; |
585 | /// use openssl::sign::Signer; |
586 | /// |
587 | /// let key = PKey::generate_ed25519()?; |
588 | /// let public_key = key.raw_public_key()?; |
589 | /// |
590 | /// let mut signer = Signer::new_without_digest(&key)?; |
591 | /// let digest = // ... |
592 | /// # &vec![0; 32]; |
593 | /// let signature = signer.sign_oneshot_to_vec(digest)?; |
594 | /// assert_eq!(signature.len(), 64); |
595 | /// # Ok(()) } |
596 | /// ``` |
597 | #[cfg (any(ossl111, boringssl, libressl370))] |
598 | pub fn generate_ed25519() -> Result<PKey<Private>, ErrorStack> { |
599 | PKey::generate_eddsa(Id::ED25519) |
600 | } |
601 | |
602 | /// Generates a new private Ed448 key. |
603 | /// |
604 | /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`]. |
605 | /// |
606 | /// # Examples |
607 | /// |
608 | /// ``` |
609 | /// # fn main() -> Result<(), Box<dyn std::error::Error>> { |
610 | /// use openssl::pkey::{PKey, Id}; |
611 | /// use openssl::sign::Signer; |
612 | /// |
613 | /// let key = PKey::generate_ed448()?; |
614 | /// let public_key = key.raw_public_key()?; |
615 | /// |
616 | /// let mut signer = Signer::new_without_digest(&key)?; |
617 | /// let digest = // ... |
618 | /// # &vec![0; 32]; |
619 | /// let signature = signer.sign_oneshot_to_vec(digest)?; |
620 | /// assert_eq!(signature.len(), 114); |
621 | /// # Ok(()) } |
622 | /// ``` |
623 | #[cfg (ossl111)] |
624 | pub fn generate_ed448() -> Result<PKey<Private>, ErrorStack> { |
625 | PKey::generate_eddsa(Id::ED448) |
626 | } |
627 | |
628 | /// Generates a new EC key using the provided curve. |
629 | /// |
630 | /// Requires OpenSSL 3.0.0 or newer. |
631 | #[corresponds (EVP_EC_gen)] |
632 | #[cfg (ossl300)] |
633 | pub fn ec_gen(curve: &str) -> Result<PKey<Private>, ErrorStack> { |
634 | ffi::init(); |
635 | |
636 | let curve = CString::new(curve).unwrap(); |
637 | unsafe { |
638 | let ptr = cvt_p(ffi::EVP_EC_gen(curve.as_ptr()))?; |
639 | Ok(PKey::from_ptr(ptr)) |
640 | } |
641 | } |
642 | |
643 | private_key_from_pem! { |
644 | /// Deserializes a private key from a PEM-encoded key type specific format. |
645 | #[corresponds (PEM_read_bio_PrivateKey)] |
646 | private_key_from_pem, |
647 | |
648 | /// Deserializes a private key from a PEM-encoded encrypted key type specific format. |
649 | #[corresponds (PEM_read_bio_PrivateKey)] |
650 | private_key_from_pem_passphrase, |
651 | |
652 | /// Deserializes a private key from a PEM-encoded encrypted key type specific format. |
653 | /// |
654 | /// The callback should fill the password into the provided buffer and return its length. |
655 | #[corresponds (PEM_read_bio_PrivateKey)] |
656 | private_key_from_pem_callback, |
657 | PKey<Private>, |
658 | ffi::PEM_read_bio_PrivateKey |
659 | } |
660 | |
661 | from_der! { |
662 | /// Decodes a DER-encoded private key. |
663 | /// |
664 | /// This function will attempt to automatically detect the underlying key format, and |
665 | /// supports the unencrypted PKCS#8 PrivateKeyInfo structures as well as key type specific |
666 | /// formats. |
667 | #[corresponds (d2i_AutoPrivateKey)] |
668 | private_key_from_der, |
669 | PKey<Private>, |
670 | ffi::d2i_AutoPrivateKey |
671 | } |
672 | |
673 | /// Deserializes a DER-formatted PKCS#8 unencrypted private key. |
674 | /// |
675 | /// This method is mainly for interoperability reasons. Encrypted keyfiles should be preferred. |
676 | pub fn private_key_from_pkcs8(der: &[u8]) -> Result<PKey<Private>, ErrorStack> { |
677 | unsafe { |
678 | ffi::init(); |
679 | let len = der.len().min(c_long::max_value() as usize) as c_long; |
680 | let p8inf = cvt_p(ffi::d2i_PKCS8_PRIV_KEY_INFO( |
681 | ptr::null_mut(), |
682 | &mut der.as_ptr(), |
683 | len, |
684 | ))?; |
685 | let res = cvt_p(ffi::EVP_PKCS82PKEY(p8inf)).map(|p| PKey::from_ptr(p)); |
686 | ffi::PKCS8_PRIV_KEY_INFO_free(p8inf); |
687 | res |
688 | } |
689 | } |
690 | |
691 | /// Deserializes a DER-formatted PKCS#8 private key, using a callback to retrieve the password |
692 | /// if the key is encrypted. |
693 | /// |
694 | /// The callback should copy the password into the provided buffer and return the number of |
695 | /// bytes written. |
696 | #[corresponds (d2i_PKCS8PrivateKey_bio)] |
697 | pub fn private_key_from_pkcs8_callback<F>( |
698 | der: &[u8], |
699 | callback: F, |
700 | ) -> Result<PKey<Private>, ErrorStack> |
701 | where |
702 | F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>, |
703 | { |
704 | unsafe { |
705 | ffi::init(); |
706 | let mut cb = CallbackState::new(callback); |
707 | let bio = MemBioSlice::new(der)?; |
708 | cvt_p(ffi::d2i_PKCS8PrivateKey_bio( |
709 | bio.as_ptr(), |
710 | ptr::null_mut(), |
711 | Some(invoke_passwd_cb::<F>), |
712 | &mut cb as *mut _ as *mut _, |
713 | )) |
714 | .map(|p| PKey::from_ptr(p)) |
715 | } |
716 | } |
717 | |
718 | /// Deserializes a DER-formatted PKCS#8 private key, using the supplied password if the key is |
719 | /// encrypted. |
720 | /// |
721 | /// # Panics |
722 | /// |
723 | /// Panics if `passphrase` contains an embedded null. |
724 | #[corresponds (d2i_PKCS8PrivateKey_bio)] |
725 | pub fn private_key_from_pkcs8_passphrase( |
726 | der: &[u8], |
727 | passphrase: &[u8], |
728 | ) -> Result<PKey<Private>, ErrorStack> { |
729 | unsafe { |
730 | ffi::init(); |
731 | let bio = MemBioSlice::new(der)?; |
732 | let passphrase = CString::new(passphrase).unwrap(); |
733 | cvt_p(ffi::d2i_PKCS8PrivateKey_bio( |
734 | bio.as_ptr(), |
735 | ptr::null_mut(), |
736 | None, |
737 | passphrase.as_ptr() as *const _ as *mut _, |
738 | )) |
739 | .map(|p| PKey::from_ptr(p)) |
740 | } |
741 | } |
742 | |
743 | /// Creates a private key from its raw byte representation |
744 | /// |
745 | /// Algorithm types that support raw private keys are HMAC, X25519, ED25519, X448 or ED448 |
746 | #[corresponds (EVP_PKEY_new_raw_private_key)] |
747 | #[cfg (any(ossl111, boringssl, libressl370))] |
748 | pub fn private_key_from_raw_bytes( |
749 | bytes: &[u8], |
750 | key_type: Id, |
751 | ) -> Result<PKey<Private>, ErrorStack> { |
752 | unsafe { |
753 | ffi::init(); |
754 | cvt_p(ffi::EVP_PKEY_new_raw_private_key( |
755 | key_type.as_raw(), |
756 | ptr::null_mut(), |
757 | bytes.as_ptr(), |
758 | bytes.len(), |
759 | )) |
760 | .map(|p| PKey::from_ptr(p)) |
761 | } |
762 | } |
763 | } |
764 | |
765 | impl PKey<Public> { |
766 | private_key_from_pem! { |
767 | /// Decodes a PEM-encoded SubjectPublicKeyInfo structure. |
768 | /// |
769 | /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. |
770 | #[corresponds (PEM_read_bio_PUBKEY)] |
771 | public_key_from_pem, |
772 | |
773 | /// Decodes a PEM-encoded SubjectPublicKeyInfo structure. |
774 | #[corresponds (PEM_read_bio_PUBKEY)] |
775 | public_key_from_pem_passphrase, |
776 | |
777 | /// Decodes a PEM-encoded SubjectPublicKeyInfo structure. |
778 | /// |
779 | /// The callback should fill the password into the provided buffer and return its length. |
780 | #[corresponds (PEM_read_bio_PrivateKey)] |
781 | public_key_from_pem_callback, |
782 | PKey<Public>, |
783 | ffi::PEM_read_bio_PUBKEY |
784 | } |
785 | |
786 | from_der! { |
787 | /// Decodes a DER-encoded SubjectPublicKeyInfo structure. |
788 | #[corresponds (d2i_PUBKEY)] |
789 | public_key_from_der, |
790 | PKey<Public>, |
791 | ffi::d2i_PUBKEY |
792 | } |
793 | |
794 | /// Creates a public key from its raw byte representation |
795 | /// |
796 | /// Algorithm types that support raw public keys are X25519, ED25519, X448 or ED448 |
797 | #[corresponds (EVP_PKEY_new_raw_public_key)] |
798 | #[cfg (any(ossl111, boringssl, libressl370))] |
799 | pub fn public_key_from_raw_bytes( |
800 | bytes: &[u8], |
801 | key_type: Id, |
802 | ) -> Result<PKey<Public>, ErrorStack> { |
803 | unsafe { |
804 | ffi::init(); |
805 | cvt_p(ffi::EVP_PKEY_new_raw_public_key( |
806 | key_type.as_raw(), |
807 | ptr::null_mut(), |
808 | bytes.as_ptr(), |
809 | bytes.len(), |
810 | )) |
811 | .map(|p| PKey::from_ptr(p)) |
812 | } |
813 | } |
814 | } |
815 | |
816 | cfg_if! { |
817 | if #[cfg(any(boringssl, ossl110, libressl270))] { |
818 | use ffi::EVP_PKEY_up_ref; |
819 | } else { |
820 | #[allow (bad_style)] |
821 | unsafe extern "C" fn EVP_PKEY_up_ref(pkey: *mut ffi::EVP_PKEY) { |
822 | ffi::CRYPTO_add_lock( |
823 | &mut (*pkey).references, |
824 | 1, |
825 | ffi::CRYPTO_LOCK_EVP_PKEY, |
826 | "pkey.rs \0" .as_ptr() as *const _, |
827 | line!() as c_int, |
828 | ); |
829 | } |
830 | } |
831 | } |
832 | |
833 | impl<T> TryFrom<EcKey<T>> for PKey<T> { |
834 | type Error = ErrorStack; |
835 | |
836 | fn try_from(ec_key: EcKey<T>) -> Result<PKey<T>, ErrorStack> { |
837 | PKey::from_ec_key(ec_key) |
838 | } |
839 | } |
840 | |
841 | impl<T> TryFrom<PKey<T>> for EcKey<T> { |
842 | type Error = ErrorStack; |
843 | |
844 | fn try_from(pkey: PKey<T>) -> Result<EcKey<T>, ErrorStack> { |
845 | pkey.ec_key() |
846 | } |
847 | } |
848 | |
849 | impl<T> TryFrom<Rsa<T>> for PKey<T> { |
850 | type Error = ErrorStack; |
851 | |
852 | fn try_from(rsa: Rsa<T>) -> Result<PKey<T>, ErrorStack> { |
853 | PKey::from_rsa(rsa) |
854 | } |
855 | } |
856 | |
857 | impl<T> TryFrom<PKey<T>> for Rsa<T> { |
858 | type Error = ErrorStack; |
859 | |
860 | fn try_from(pkey: PKey<T>) -> Result<Rsa<T>, ErrorStack> { |
861 | pkey.rsa() |
862 | } |
863 | } |
864 | |
865 | impl<T> TryFrom<Dsa<T>> for PKey<T> { |
866 | type Error = ErrorStack; |
867 | |
868 | fn try_from(dsa: Dsa<T>) -> Result<PKey<T>, ErrorStack> { |
869 | PKey::from_dsa(dsa) |
870 | } |
871 | } |
872 | |
873 | impl<T> TryFrom<PKey<T>> for Dsa<T> { |
874 | type Error = ErrorStack; |
875 | |
876 | fn try_from(pkey: PKey<T>) -> Result<Dsa<T>, ErrorStack> { |
877 | pkey.dsa() |
878 | } |
879 | } |
880 | |
881 | #[cfg (not(boringssl))] |
882 | impl<T> TryFrom<Dh<T>> for PKey<T> { |
883 | type Error = ErrorStack; |
884 | |
885 | fn try_from(dh: Dh<T>) -> Result<PKey<T>, ErrorStack> { |
886 | PKey::from_dh(dh) |
887 | } |
888 | } |
889 | |
890 | impl<T> TryFrom<PKey<T>> for Dh<T> { |
891 | type Error = ErrorStack; |
892 | |
893 | fn try_from(pkey: PKey<T>) -> Result<Dh<T>, ErrorStack> { |
894 | pkey.dh() |
895 | } |
896 | } |
897 | |
898 | #[cfg (test)] |
899 | mod tests { |
900 | use std::convert::TryInto; |
901 | |
902 | #[cfg (not(boringssl))] |
903 | use crate::dh::Dh; |
904 | use crate::dsa::Dsa; |
905 | use crate::ec::EcKey; |
906 | use crate::error::Error; |
907 | use crate::nid::Nid; |
908 | use crate::rsa::Rsa; |
909 | use crate::symm::Cipher; |
910 | |
911 | use super::*; |
912 | |
913 | #[cfg (ossl111)] |
914 | use crate::rand::rand_bytes; |
915 | |
916 | #[test ] |
917 | fn test_to_password() { |
918 | let rsa = Rsa::generate(2048).unwrap(); |
919 | let pkey = PKey::from_rsa(rsa).unwrap(); |
920 | let pem = pkey |
921 | .private_key_to_pem_pkcs8_passphrase(Cipher::aes_128_cbc(), b"foobar" ) |
922 | .unwrap(); |
923 | PKey::private_key_from_pem_passphrase(&pem, b"foobar" ).unwrap(); |
924 | assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz" ).is_err()); |
925 | } |
926 | |
927 | #[test ] |
928 | fn test_unencrypted_pkcs8() { |
929 | let key = include_bytes!("../test/pkcs8-nocrypt.der" ); |
930 | let pkey = PKey::private_key_from_pkcs8(key).unwrap(); |
931 | let serialized = pkey.private_key_to_pkcs8().unwrap(); |
932 | let pkey2 = PKey::private_key_from_pkcs8(&serialized).unwrap(); |
933 | |
934 | assert_eq!( |
935 | pkey2.private_key_to_der().unwrap(), |
936 | pkey.private_key_to_der().unwrap() |
937 | ); |
938 | } |
939 | |
940 | #[test ] |
941 | fn test_encrypted_pkcs8_passphrase() { |
942 | let key = include_bytes!("../test/pkcs8.der" ); |
943 | PKey::private_key_from_pkcs8_passphrase(key, b"mypass" ).unwrap(); |
944 | |
945 | let rsa = Rsa::generate(2048).unwrap(); |
946 | let pkey = PKey::from_rsa(rsa).unwrap(); |
947 | let der = pkey |
948 | .private_key_to_pkcs8_passphrase(Cipher::aes_128_cbc(), b"mypass" ) |
949 | .unwrap(); |
950 | let pkey2 = PKey::private_key_from_pkcs8_passphrase(&der, b"mypass" ).unwrap(); |
951 | assert_eq!( |
952 | pkey.private_key_to_der().unwrap(), |
953 | pkey2.private_key_to_der().unwrap() |
954 | ); |
955 | } |
956 | |
957 | #[test ] |
958 | fn test_encrypted_pkcs8_callback() { |
959 | let mut password_queried = false; |
960 | let key = include_bytes!("../test/pkcs8.der" ); |
961 | PKey::private_key_from_pkcs8_callback(key, |password| { |
962 | password_queried = true; |
963 | password[..6].copy_from_slice(b"mypass" ); |
964 | Ok(6) |
965 | }) |
966 | .unwrap(); |
967 | assert!(password_queried); |
968 | } |
969 | |
970 | #[test ] |
971 | fn test_private_key_from_pem() { |
972 | let key = include_bytes!("../test/key.pem" ); |
973 | PKey::private_key_from_pem(key).unwrap(); |
974 | } |
975 | |
976 | #[test ] |
977 | fn test_public_key_from_pem() { |
978 | let key = include_bytes!("../test/key.pem.pub" ); |
979 | PKey::public_key_from_pem(key).unwrap(); |
980 | } |
981 | |
982 | #[test ] |
983 | fn test_public_key_from_der() { |
984 | let key = include_bytes!("../test/key.der.pub" ); |
985 | PKey::public_key_from_der(key).unwrap(); |
986 | } |
987 | |
988 | #[test ] |
989 | fn test_private_key_from_der() { |
990 | let key = include_bytes!("../test/key.der" ); |
991 | PKey::private_key_from_der(key).unwrap(); |
992 | } |
993 | |
994 | #[test ] |
995 | fn test_pem() { |
996 | let key = include_bytes!("../test/key.pem" ); |
997 | let key = PKey::private_key_from_pem(key).unwrap(); |
998 | |
999 | let priv_key = key.private_key_to_pem_pkcs8().unwrap(); |
1000 | let pub_key = key.public_key_to_pem().unwrap(); |
1001 | |
1002 | // As a super-simple verification, just check that the buffers contain |
1003 | // the `PRIVATE KEY` or `PUBLIC KEY` strings. |
1004 | assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY" )); |
1005 | assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY" )); |
1006 | } |
1007 | |
1008 | #[test ] |
1009 | fn test_rsa_accessor() { |
1010 | let rsa = Rsa::generate(2048).unwrap(); |
1011 | let pkey = PKey::from_rsa(rsa).unwrap(); |
1012 | pkey.rsa().unwrap(); |
1013 | assert_eq!(pkey.id(), Id::RSA); |
1014 | assert!(pkey.dsa().is_err()); |
1015 | } |
1016 | |
1017 | #[test ] |
1018 | fn test_dsa_accessor() { |
1019 | let dsa = Dsa::generate(2048).unwrap(); |
1020 | let pkey = PKey::from_dsa(dsa).unwrap(); |
1021 | pkey.dsa().unwrap(); |
1022 | assert_eq!(pkey.id(), Id::DSA); |
1023 | assert!(pkey.rsa().is_err()); |
1024 | } |
1025 | |
1026 | #[test ] |
1027 | #[cfg (not(boringssl))] |
1028 | fn test_dh_accessor() { |
1029 | let dh = include_bytes!("../test/dhparams.pem" ); |
1030 | let dh = Dh::params_from_pem(dh).unwrap(); |
1031 | let pkey = PKey::from_dh(dh).unwrap(); |
1032 | pkey.dh().unwrap(); |
1033 | assert_eq!(pkey.id(), Id::DH); |
1034 | assert!(pkey.rsa().is_err()); |
1035 | } |
1036 | |
1037 | #[test ] |
1038 | fn test_ec_key_accessor() { |
1039 | let ec_key = EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1040 | let pkey = PKey::from_ec_key(ec_key).unwrap(); |
1041 | pkey.ec_key().unwrap(); |
1042 | assert_eq!(pkey.id(), Id::EC); |
1043 | assert!(pkey.rsa().is_err()); |
1044 | } |
1045 | |
1046 | #[test ] |
1047 | fn test_rsa_conversion() { |
1048 | let rsa = Rsa::generate(2048).unwrap(); |
1049 | let pkey: PKey<Private> = rsa.clone().try_into().unwrap(); |
1050 | let rsa_: Rsa<Private> = pkey.try_into().unwrap(); |
1051 | // Eq is missing |
1052 | assert_eq!(rsa.p(), rsa_.p()); |
1053 | assert_eq!(rsa.q(), rsa_.q()); |
1054 | } |
1055 | |
1056 | #[test ] |
1057 | fn test_dsa_conversion() { |
1058 | let dsa = Dsa::generate(2048).unwrap(); |
1059 | let pkey: PKey<Private> = dsa.clone().try_into().unwrap(); |
1060 | let dsa_: Dsa<Private> = pkey.try_into().unwrap(); |
1061 | // Eq is missing |
1062 | assert_eq!(dsa.priv_key(), dsa_.priv_key()); |
1063 | } |
1064 | |
1065 | #[test ] |
1066 | fn test_ec_key_conversion() { |
1067 | let group = crate::ec::EcGroup::from_curve_name(crate::nid::Nid::X9_62_PRIME256V1).unwrap(); |
1068 | let ec_key = EcKey::generate(&group).unwrap(); |
1069 | let pkey: PKey<Private> = ec_key.clone().try_into().unwrap(); |
1070 | let ec_key_: EcKey<Private> = pkey.try_into().unwrap(); |
1071 | // Eq is missing |
1072 | assert_eq!(ec_key.private_key(), ec_key_.private_key()); |
1073 | } |
1074 | |
1075 | #[test ] |
1076 | #[cfg (any(ossl110, libressl360))] |
1077 | fn test_security_bits() { |
1078 | let group = crate::ec::EcGroup::from_curve_name(crate::nid::Nid::SECP521R1).unwrap(); |
1079 | let ec_key = EcKey::generate(&group).unwrap(); |
1080 | let pkey: PKey<Private> = ec_key.try_into().unwrap(); |
1081 | |
1082 | assert_eq!(pkey.security_bits(), 256); |
1083 | } |
1084 | |
1085 | #[test ] |
1086 | #[cfg (not(boringssl))] |
1087 | fn test_dh_conversion() { |
1088 | let dh_params = include_bytes!("../test/dhparams.pem" ); |
1089 | let dh_params = Dh::params_from_pem(dh_params).unwrap(); |
1090 | let dh = dh_params.generate_key().unwrap(); |
1091 | |
1092 | // Clone is missing for Dh, save the parameters |
1093 | let p = dh.prime_p().to_owned().unwrap(); |
1094 | let q = dh.prime_q().map(|q| q.to_owned().unwrap()); |
1095 | let g = dh.generator().to_owned().unwrap(); |
1096 | |
1097 | let pkey: PKey<Private> = dh.try_into().unwrap(); |
1098 | let dh_: Dh<Private> = pkey.try_into().unwrap(); |
1099 | |
1100 | // Eq is missing |
1101 | assert_eq!(&p, dh_.prime_p()); |
1102 | assert_eq!(q, dh_.prime_q().map(|q| q.to_owned().unwrap())); |
1103 | assert_eq!(&g, dh_.generator()); |
1104 | } |
1105 | |
1106 | #[cfg (any(ossl111, boringssl, libressl370))] |
1107 | fn test_raw_public_key(gen: fn() -> Result<PKey<Private>, ErrorStack>, key_type: Id) { |
1108 | // Generate a new key |
1109 | let key = gen().unwrap(); |
1110 | |
1111 | // Get the raw bytes, and create a new key from the raw bytes |
1112 | let raw = key.raw_public_key().unwrap(); |
1113 | let from_raw = PKey::public_key_from_raw_bytes(&raw, key_type).unwrap(); |
1114 | |
1115 | // Compare the der encoding of the original and raw / restored public key |
1116 | assert_eq!( |
1117 | key.public_key_to_der().unwrap(), |
1118 | from_raw.public_key_to_der().unwrap() |
1119 | ); |
1120 | } |
1121 | |
1122 | #[cfg (any(ossl111, boringssl, libressl370))] |
1123 | fn test_raw_private_key(gen: fn() -> Result<PKey<Private>, ErrorStack>, key_type: Id) { |
1124 | // Generate a new key |
1125 | let key = gen().unwrap(); |
1126 | |
1127 | // Get the raw bytes, and create a new key from the raw bytes |
1128 | let raw = key.raw_private_key().unwrap(); |
1129 | let from_raw = PKey::private_key_from_raw_bytes(&raw, key_type).unwrap(); |
1130 | |
1131 | // Compare the der encoding of the original and raw / restored public key |
1132 | assert_eq!( |
1133 | key.private_key_to_pkcs8().unwrap(), |
1134 | from_raw.private_key_to_pkcs8().unwrap() |
1135 | ); |
1136 | } |
1137 | |
1138 | #[cfg (any(ossl111, boringssl, libressl370))] |
1139 | #[test ] |
1140 | fn test_raw_public_key_bytes() { |
1141 | test_raw_public_key(PKey::generate_x25519, Id::X25519); |
1142 | test_raw_public_key(PKey::generate_ed25519, Id::ED25519); |
1143 | #[cfg (all(not(boringssl), not(libressl370)))] |
1144 | test_raw_public_key(PKey::generate_x448, Id::X448); |
1145 | #[cfg (all(not(boringssl), not(libressl370)))] |
1146 | test_raw_public_key(PKey::generate_ed448, Id::ED448); |
1147 | } |
1148 | |
1149 | #[cfg (any(ossl111, boringssl, libressl370))] |
1150 | #[test ] |
1151 | fn test_raw_private_key_bytes() { |
1152 | test_raw_private_key(PKey::generate_x25519, Id::X25519); |
1153 | test_raw_private_key(PKey::generate_ed25519, Id::ED25519); |
1154 | #[cfg (all(not(boringssl), not(libressl370)))] |
1155 | test_raw_private_key(PKey::generate_x448, Id::X448); |
1156 | #[cfg (all(not(boringssl), not(libressl370)))] |
1157 | test_raw_private_key(PKey::generate_ed448, Id::ED448); |
1158 | } |
1159 | |
1160 | #[cfg (ossl111)] |
1161 | #[test ] |
1162 | fn test_raw_hmac() { |
1163 | let mut test_bytes = vec![0u8; 32]; |
1164 | rand_bytes(&mut test_bytes).unwrap(); |
1165 | |
1166 | let hmac_key = PKey::hmac(&test_bytes).unwrap(); |
1167 | assert!(hmac_key.raw_public_key().is_err()); |
1168 | |
1169 | let key_bytes = hmac_key.raw_private_key().unwrap(); |
1170 | assert_eq!(key_bytes, test_bytes); |
1171 | } |
1172 | |
1173 | #[cfg (ossl111)] |
1174 | #[test ] |
1175 | fn test_raw_key_fail() { |
1176 | // Getting a raw byte representation will not work with Nist curves |
1177 | let group = crate::ec::EcGroup::from_curve_name(Nid::SECP256K1).unwrap(); |
1178 | let ec_key = EcKey::generate(&group).unwrap(); |
1179 | let pkey = PKey::from_ec_key(ec_key).unwrap(); |
1180 | assert!(pkey.raw_private_key().is_err()); |
1181 | assert!(pkey.raw_public_key().is_err()); |
1182 | } |
1183 | |
1184 | #[cfg (ossl300)] |
1185 | #[test ] |
1186 | fn test_ec_gen() { |
1187 | let key = PKey::ec_gen("prime256v1" ).unwrap(); |
1188 | assert!(key.ec_key().is_ok()); |
1189 | } |
1190 | |
1191 | #[test ] |
1192 | fn test_public_eq() { |
1193 | let rsa = Rsa::generate(2048).unwrap(); |
1194 | let pkey1 = PKey::from_rsa(rsa).unwrap(); |
1195 | |
1196 | let group = crate::ec::EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1197 | let ec_key = EcKey::generate(&group).unwrap(); |
1198 | let pkey2 = PKey::from_ec_key(ec_key).unwrap(); |
1199 | |
1200 | assert!(!pkey1.public_eq(&pkey2)); |
1201 | assert!(Error::get().is_none()); |
1202 | } |
1203 | } |
1204 | |