1use crate::ffi;
44use crate::libc_types::{c_int, c_long};
45use foreign_types::{ForeignType, ForeignTypeRef};
46use openssl_macros::corresponds;
47use std::ffi::CString;
48use std::fmt;
49use std::mem;
50use std::ptr;
51
52use crate::bio::MemBioSlice;
53use crate::dh::Dh;
54use crate::dsa::Dsa;
55use crate::ec::EcKey;
56use crate::error::ErrorStack;
57use crate::rsa::Rsa;
58use crate::util::{invoke_passwd_cb, CallbackState};
59use crate::{cvt, cvt_0i, cvt_p};
60
61pub enum Params {}
63
64pub enum Public {}
66
67pub enum Private {}
69
70#[derive(Debug, Copy, Clone, PartialEq, Eq)]
72pub struct Id(c_int);
73
74impl Id {
75 pub const RSA: Id = Id(ffi::EVP_PKEY_RSA);
76 pub const RSAPSS: Id = Id(ffi::EVP_PKEY_RSA_PSS);
77 pub const DSA: Id = Id(ffi::EVP_PKEY_DSA);
78 pub const DH: Id = Id(ffi::EVP_PKEY_DH);
79 pub const EC: Id = Id(ffi::EVP_PKEY_EC);
80 pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519);
81 pub const ED448: Id = Id(ffi::EVP_PKEY_ED448);
82 pub const X25519: Id = Id(ffi::EVP_PKEY_X25519);
83 pub const X448: Id = Id(ffi::EVP_PKEY_X448);
84
85 #[must_use]
87 pub fn from_raw(value: c_int) -> Id {
88 Id(value)
89 }
90
91 #[allow(clippy::trivially_copy_pass_by_ref)]
93 #[must_use]
94 pub fn as_raw(&self) -> c_int {
95 self.0
96 }
97}
98
99#[allow(clippy::missing_safety_doc)]
101pub unsafe trait HasParams {}
102
103unsafe impl HasParams for Params {}
104
105unsafe impl<T> HasParams for T where T: HasPublic {}
106
107#[allow(clippy::missing_safety_doc)]
109pub unsafe trait HasPublic {}
110
111unsafe impl HasPublic for Public {}
112
113unsafe impl<T> HasPublic for T where T: HasPrivate {}
114
115#[allow(clippy::missing_safety_doc)]
117pub unsafe trait HasPrivate {}
118
119unsafe impl HasPrivate for Private {}
120
121generic_foreign_type_and_impl_send_sync! {
122 type CType = ffi::EVP_PKEY;
123 fn drop = ffi::EVP_PKEY_free;
124
125 pub struct PKey<T>;
127 pub struct PKeyRef<T>;
129}
130
131impl<T> ToOwned for PKeyRef<T> {
132 type Owned = PKey<T>;
133
134 fn to_owned(&self) -> PKey<T> {
135 unsafe {
136 EVP_PKEY_up_ref(self.as_ptr());
137 PKey::from_ptr(self.as_ptr())
138 }
139 }
140}
141
142impl<T> PKeyRef<T> {
143 #[corresponds(EVP_PKEY_get1_RSA)]
145 pub fn rsa(&self) -> Result<Rsa<T>, ErrorStack> {
146 unsafe {
147 let rsa = cvt_p(ffi::EVP_PKEY_get1_RSA(self.as_ptr()))?;
148 Ok(Rsa::from_ptr(rsa))
149 }
150 }
151
152 #[corresponds(EVP_PKEY_get1_DSA)]
154 pub fn dsa(&self) -> Result<Dsa<T>, ErrorStack> {
155 unsafe {
156 let dsa = cvt_p(ffi::EVP_PKEY_get1_DSA(self.as_ptr()))?;
157 Ok(Dsa::from_ptr(dsa))
158 }
159 }
160
161 #[corresponds(EVP_PKEY_get1_DH)]
163 pub fn dh(&self) -> Result<Dh<T>, ErrorStack> {
164 unsafe {
165 let dh = cvt_p(ffi::EVP_PKEY_get1_DH(self.as_ptr()))?;
166 Ok(Dh::from_ptr(dh))
167 }
168 }
169
170 #[corresponds(EVP_PKEY_get1_EC_KEY)]
172 pub fn ec_key(&self) -> Result<EcKey<T>, ErrorStack> {
173 unsafe {
174 let ec_key = cvt_p(ffi::EVP_PKEY_get1_EC_KEY(self.as_ptr()))?;
175 Ok(EcKey::from_ptr(ec_key))
176 }
177 }
178
179 #[corresponds(EVP_PKEY_id)]
181 #[must_use]
182 pub fn id(&self) -> Id {
183 unsafe { Id::from_raw(ffi::EVP_PKEY_id(self.as_ptr())) }
184 }
185
186 #[corresponds(EVP_PKEY_size)]
188 #[must_use]
189 pub fn size(&self) -> usize {
190 unsafe { ffi::EVP_PKEY_size(self.as_ptr()) as usize }
191 }
192}
193
194impl<T> PKeyRef<T>
195where
196 T: HasPublic,
197{
198 to_pem! {
199 #[corresponds(PEM_write_bio_PUBKEY)]
203 public_key_to_pem,
204 ffi::PEM_write_bio_PUBKEY
205 }
206
207 to_der! {
208 #[corresponds(i2d_PUBKEY)]
210 public_key_to_der,
211 ffi::i2d_PUBKEY
212 }
213
214 #[must_use]
219 pub fn bits(&self) -> u32 {
220 unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as u32 }
221 }
222
223 #[must_use]
225 pub fn public_eq<U>(&self, other: &PKeyRef<U>) -> bool
226 where
227 U: HasPublic,
228 {
229 unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 }
230 }
231
232 #[corresponds(EVP_PKEY_get_raw_public_key)]
234 pub fn raw_public_key_len(&self) -> Result<usize, ErrorStack> {
235 unsafe {
236 let mut size = 0;
237 _ = cvt_0i(ffi::EVP_PKEY_get_raw_public_key(
238 self.as_ptr(),
239 std::ptr::null_mut(),
240 &mut size,
241 ))?;
242 Ok(size)
243 }
244 }
245
246 #[corresponds(EVP_PKEY_get_raw_public_key)]
250 pub fn raw_public_key<'a>(&self, out: &'a mut [u8]) -> Result<&'a [u8], ErrorStack> {
251 unsafe {
252 let mut size = out.len();
253 _ = cvt_0i(ffi::EVP_PKEY_get_raw_public_key(
254 self.as_ptr(),
255 out.as_mut_ptr(),
256 &mut size,
257 ))?;
258 Ok(&out[..size])
259 }
260 }
261}
262
263impl<T> PKeyRef<T>
264where
265 T: HasPrivate,
266{
267 private_key_to_pem! {
268 #[corresponds(PEM_write_bio_PKCS8PrivateKey)]
272 private_key_to_pem_pkcs8,
273 #[corresponds(PEM_write_bio_PKCS8PrivateKey)]
277 private_key_to_pem_pkcs8_passphrase,
278 ffi::PEM_write_bio_PKCS8PrivateKey
279 }
280
281 to_der! {
282 #[corresponds(i2d_PrivateKey)]
284 private_key_to_der,
285 ffi::i2d_PrivateKey
286 }
287
288 private_key_to_pem! {
291 #[corresponds(i2d_PKCS8PrivateKey_bio)]
293 private_key_to_der_pkcs8,
294 #[corresponds(i2d_PKCS8PrivateKey_bio)]
296 private_key_to_der_pkcs8_passphrase,
297 ffi::i2d_PKCS8PrivateKey_bio
298 }
299
300 #[corresponds(EVP_PKEY_get_raw_private_key)]
302 pub fn raw_private_key_len(&self) -> Result<usize, ErrorStack> {
303 unsafe {
304 let mut size = 0;
305 _ = cvt_0i(ffi::EVP_PKEY_get_raw_private_key(
306 self.as_ptr(),
307 std::ptr::null_mut(),
308 &mut size,
309 ))?;
310 Ok(size)
311 }
312 }
313
314 #[corresponds(EVP_PKEY_get_raw_private_key)]
318 pub fn raw_private_key<'a>(&self, out: &'a mut [u8]) -> Result<&'a [u8], ErrorStack> {
319 unsafe {
320 let mut size = out.len();
321 _ = cvt_0i(ffi::EVP_PKEY_get_raw_private_key(
322 self.as_ptr(),
323 out.as_mut_ptr(),
324 &mut size,
325 ))?;
326 Ok(&out[..size])
327 }
328 }
329}
330
331impl<T> fmt::Debug for PKey<T> {
332 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
333 let alg = match self.id() {
334 Id::RSA => "RSA",
335 Id::RSAPSS => "RSAPSS",
336 Id::DSA => "DSA",
337 Id::DH => "DH",
338 Id::EC => "EC",
339 Id::ED25519 => "Ed25519",
340 Id::ED448 => "Ed448",
341 _ => "unknown",
342 };
343 fmt.debug_struct("PKey").field("algorithm", &alg).finish()
344 }
346}
347
348impl<T> Clone for PKey<T> {
349 fn clone(&self) -> PKey<T> {
350 PKeyRef::to_owned(self)
351 }
352}
353
354impl<T> PKey<T> {
355 #[corresponds(EVP_PKEY_assign_RSA)]
357 pub fn from_rsa(rsa: Rsa<T>) -> Result<PKey<T>, ErrorStack> {
358 unsafe {
359 let evp = cvt_p(ffi::EVP_PKEY_new())?;
360 let pkey = PKey::from_ptr(evp);
361 cvt(ffi::EVP_PKEY_assign(
362 pkey.0,
363 ffi::EVP_PKEY_RSA,
364 rsa.as_ptr().cast(),
365 ))?;
366 mem::forget(rsa);
367 Ok(pkey)
368 }
369 }
370
371 #[corresponds(EVP_PKEY_assign_EC_KEY)]
373 pub fn from_ec_key(ec_key: EcKey<T>) -> Result<PKey<T>, ErrorStack> {
374 unsafe {
375 let evp = cvt_p(ffi::EVP_PKEY_new())?;
376 let pkey = PKey::from_ptr(evp);
377 cvt(ffi::EVP_PKEY_assign(
378 pkey.0,
379 ffi::EVP_PKEY_EC,
380 ec_key.as_ptr().cast(),
381 ))?;
382 mem::forget(ec_key);
383 Ok(pkey)
384 }
385 }
386}
387
388impl PKey<Private> {
389 private_key_from_pem! {
390 #[corresponds(PEM_read_bio_PrivateKey)]
392 private_key_from_pem,
393
394 #[corresponds(PEM_read_bio_PrivateKey)]
396 private_key_from_pem_passphrase,
397
398 #[corresponds(PEM_read_bio_PrivateKey)]
402 private_key_from_pem_callback,
403 PKey<Private>,
404 ffi::PEM_read_bio_PrivateKey
405 }
406
407 from_der! {
408 #[corresponds(d2i_AutoPrivateKey)]
414 private_key_from_der,
415 PKey<Private>,
416 ffi::d2i_AutoPrivateKey,
417 ::libc::c_long
418 }
419
420 pub fn private_key_from_pkcs8(der: &[u8]) -> Result<PKey<Private>, ErrorStack> {
424 unsafe {
425 ffi::init();
426 let len = der.len().min(c_long::MAX as usize) as c_long;
427 let p8inf = cvt_p(ffi::d2i_PKCS8_PRIV_KEY_INFO(
428 ptr::null_mut(),
429 &mut der.as_ptr(),
430 len,
431 ))?;
432 let res = cvt_p(ffi::EVP_PKCS82PKEY(p8inf)).map(|p| PKey::from_ptr(p));
433 ffi::PKCS8_PRIV_KEY_INFO_free(p8inf);
434 res
435 }
436 }
437
438 pub fn private_key_from_pkcs8_callback<F>(
444 der: &[u8],
445 callback: F,
446 ) -> Result<PKey<Private>, ErrorStack>
447 where
448 F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>,
449 {
450 unsafe {
451 ffi::init();
452 let mut cb = CallbackState::new(callback);
453 let bio = MemBioSlice::new(der)?;
454 cvt_p(ffi::d2i_PKCS8PrivateKey_bio(
455 bio.as_ptr(),
456 ptr::null_mut(),
457 Some(invoke_passwd_cb::<F>),
458 std::ptr::addr_of_mut!(cb).cast(),
459 ))
460 .map(|p| PKey::from_ptr(p))
461 }
462 }
463
464 pub fn private_key_from_pkcs8_passphrase(
471 der: &[u8],
472 passphrase: &[u8],
473 ) -> Result<PKey<Private>, ErrorStack> {
474 unsafe {
475 ffi::init();
476 let bio = MemBioSlice::new(der)?;
477 let passphrase = CString::new(passphrase).map_err(ErrorStack::internal_error)?;
478 cvt_p(ffi::d2i_PKCS8PrivateKey_bio(
479 bio.as_ptr(),
480 ptr::null_mut(),
481 None,
482 passphrase.as_ptr().cast_mut().cast(),
483 ))
484 .map(|p| PKey::from_ptr(p))
485 }
486 }
487}
488
489impl PKey<Public> {
490 from_pem! {
491 #[corresponds(PEM_read_bio_PUBKEY)]
495 public_key_from_pem,
496 PKey<Public>,
497 ffi::PEM_read_bio_PUBKEY
498 }
499
500 from_der! {
501 #[corresponds(d2i_PUBKEY)]
503 public_key_from_der,
504 PKey<Public>,
505 ffi::d2i_PUBKEY,
506 ::libc::c_long
507 }
508}
509
510use crate::ffi::EVP_PKEY_up_ref;
511
512#[cfg(test)]
513mod tests {
514 use hex::FromHex as _;
515
516 use crate::ec::EcKey;
517 use crate::nid::Nid;
518 use crate::rsa::Rsa;
519 use crate::symm::Cipher;
520
521 use super::*;
522
523 #[test]
524 fn test_to_password() {
525 let rsa = Rsa::generate(2048).unwrap();
526 let pkey = PKey::from_rsa(rsa).unwrap();
527 let pem = pkey
528 .private_key_to_pem_pkcs8_passphrase(Cipher::aes_128_cbc(), b"foobar")
529 .unwrap();
530 PKey::private_key_from_pem_passphrase(&pem, b"foobar").unwrap();
531 assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err());
532 }
533
534 #[test]
535 fn test_unencrypted_pkcs8() {
536 let key = include_bytes!("../test/pkcs8-nocrypt.der");
537 PKey::private_key_from_pkcs8(key).unwrap();
538 }
539
540 #[test]
541 fn test_encrypted_pkcs8_passphrase() {
542 let key = include_bytes!("../test/pkcs8.der");
543 PKey::private_key_from_pkcs8_passphrase(key, b"mypass").unwrap();
544 }
545
546 #[test]
547 fn test_encrypted_pkcs8_callback() {
548 let mut password_queried = false;
549 let key = include_bytes!("../test/pkcs8.der");
550 PKey::private_key_from_pkcs8_callback(key, |password| {
551 password_queried = true;
552 password[..6].copy_from_slice(b"mypass");
553 Ok(6)
554 })
555 .unwrap();
556 assert!(password_queried);
557 }
558
559 #[test]
560 fn test_private_key_from_pem() {
561 let key = include_bytes!("../test/key.pem");
562 PKey::private_key_from_pem(key).unwrap();
563 }
564
565 #[test]
566 fn test_public_key_from_pem() {
567 let key = include_bytes!("../test/key.pem.pub");
568 PKey::public_key_from_pem(key).unwrap();
569 }
570
571 #[test]
572 fn test_public_key_from_der() {
573 let key = include_bytes!("../test/key.der.pub");
574 PKey::public_key_from_der(key).unwrap();
575 }
576
577 #[test]
578 fn test_private_key_from_der() {
579 let key = include_bytes!("../test/key.der");
580 PKey::private_key_from_der(key).unwrap();
581 }
582
583 #[test]
584 fn test_pem() {
585 let key = include_bytes!("../test/key.pem");
586 let key = PKey::private_key_from_pem(key).unwrap();
587
588 let priv_key = key.private_key_to_pem_pkcs8().unwrap();
589 let pub_key = key.public_key_to_pem().unwrap();
590
591 assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY"));
594 assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY"));
595 }
596
597 #[test]
598 fn test_der_pkcs8() {
599 let key = include_bytes!("../test/key.der");
600 let key = PKey::private_key_from_der(key).unwrap();
601
602 let priv_key = key.private_key_to_der_pkcs8().unwrap();
603
604 assert_eq!(hex::encode(&priv_key[4..=6]), "020100"); assert_eq!(hex::encode(&priv_key[9..=19]), "06092a864886f70d010101"); }
608
609 #[test]
610 fn test_rsa_accessor() {
611 let rsa = Rsa::generate(2048).unwrap();
612 let pkey = PKey::from_rsa(rsa).unwrap();
613 pkey.rsa().unwrap();
614 assert_eq!(pkey.id(), Id::RSA);
615 assert!(pkey.dsa().is_err());
616 }
617
618 #[test]
619 fn test_ec_key_accessor() {
620 let ec_key = EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
621 let pkey = PKey::from_ec_key(ec_key).unwrap();
622 pkey.ec_key().unwrap();
623 assert_eq!(pkey.id(), Id::EC);
624 assert!(pkey.rsa().is_err());
625 }
626
627 #[test]
628 fn test_raw_accessors() {
629 const ED25519_PRIVATE_KEY_DER: &str = concat!(
630 "302e020100300506032b6570042204207c8c6497f9960d5595d7815f550569e5",
631 "f77764ac97e63e339aaa68cc1512b683"
632 );
633 let pkey =
634 PKey::private_key_from_der(&Vec::from_hex(ED25519_PRIVATE_KEY_DER).unwrap()).unwrap();
635 assert_eq!(pkey.id(), Id::ED25519);
636
637 let priv_len = pkey.raw_private_key_len().unwrap();
638 assert_eq!(priv_len, 32);
639 let mut raw_private_key_buf = [0; 40];
640 let raw_private_key = pkey.raw_private_key(&mut raw_private_key_buf).unwrap();
641 assert_eq!(raw_private_key.len(), 32);
642 assert_ne!(raw_private_key, [0; 32]);
643 pkey.raw_private_key(&mut [0; 5])
644 .expect_err("buffer too small");
645
646 let pub_len = pkey.raw_public_key_len().unwrap();
647 assert_eq!(pub_len, 32);
648 let mut raw_public_key_buf = [0; 40];
649 let raw_public_key = pkey.raw_public_key(&mut raw_public_key_buf).unwrap();
650 assert_eq!(raw_public_key.len(), 32);
651 assert_ne!(raw_public_key, [0; 32]);
652 assert_ne!(raw_public_key, raw_private_key);
653 pkey.raw_public_key(&mut [0; 5])
654 .expect_err("buffer too small");
655 }
656}