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