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