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