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