1#![allow(clippy::missing_safety_doc)]
43use crate::bio::{MemBio, MemBioSlice};
44#[cfg(ossl110)]
45use crate::cipher::CipherRef;
46use crate::dh::Dh;
47use crate::dsa::Dsa;
48use crate::ec::EcKey;
49use crate::error::ErrorStack;
50#[cfg(ossl300)]
51use crate::lib_ctx::LibCtxRef;
52#[cfg(any(ossl110, boringssl, libressl370, awslc))]
53use crate::pkey_ctx::PkeyCtx;
54use crate::rsa::Rsa;
55use crate::symm::Cipher;
56use crate::util::{invoke_passwd_cb, CallbackState};
57use crate::{cvt, cvt_p};
58use foreign_types::{ForeignType, ForeignTypeRef};
59use libc::{c_int, c_long};
60use openssl_macros::corresponds;
61use std::convert::{TryFrom, TryInto};
62use std::ffi::{CStr, CString};
63use std::fmt;
64#[cfg(all(not(any(boringssl, awslc)), ossl110))]
65use std::mem;
66use std::ptr;
67
68pub enum Params {}
70
71pub enum Public {}
73
74pub enum Private {}
76
77#[derive(Debug, Copy, Clone, PartialEq, Eq)]
79pub struct Id(c_int);
80
81impl Id {
82 pub const RSA: Id = Id(ffi::EVP_PKEY_RSA);
83 #[cfg(any(ossl111, libressl, boringssl, awslc))]
84 pub const RSA_PSS: Id = Id(ffi::EVP_PKEY_RSA_PSS);
85 #[cfg(not(boringssl))]
86 pub const HMAC: Id = Id(ffi::EVP_PKEY_HMAC);
87 #[cfg(not(any(boringssl, awslc)))]
88 pub const CMAC: Id = Id(ffi::EVP_PKEY_CMAC);
89 pub const DSA: Id = Id(ffi::EVP_PKEY_DSA);
90 pub const DH: Id = Id(ffi::EVP_PKEY_DH);
91 #[cfg(ossl110)]
92 pub const DHX: Id = Id(ffi::EVP_PKEY_DHX);
93 pub const EC: Id = Id(ffi::EVP_PKEY_EC);
94 #[cfg(ossl111)]
95 pub const SM2: Id = Id(ffi::EVP_PKEY_SM2);
96
97 #[cfg(any(ossl110, boringssl, libressl360, awslc))]
98 pub const HKDF: Id = Id(ffi::EVP_PKEY_HKDF);
99
100 #[cfg(any(ossl111, boringssl, libressl370, awslc))]
101 pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519);
102 #[cfg(ossl111)]
103 pub const ED448: Id = Id(ffi::EVP_PKEY_ED448);
104 #[cfg(any(ossl111, boringssl, libressl370, awslc))]
105 pub const X25519: Id = Id(ffi::EVP_PKEY_X25519);
106 #[cfg(ossl111)]
107 pub const X448: Id = Id(ffi::EVP_PKEY_X448);
108 #[cfg(ossl111)]
109 pub const POLY1305: Id = Id(ffi::EVP_PKEY_POLY1305);
110
111 pub const fn from_raw(value: c_int) -> Id {
113 Id(value)
114 }
115
116 #[allow(clippy::trivially_copy_pass_by_ref)]
118 pub fn as_raw(&self) -> c_int {
119 self.0
120 }
121}
122
123#[derive(Debug, Copy, Clone, PartialEq, Eq)]
130pub struct KeyType(&'static CStr);
131
132impl KeyType {
133 pub const RSA: KeyType = KeyType(c"RSA");
134 pub const RSA_PSS: KeyType = KeyType(c"RSA-PSS");
135 pub const DSA: KeyType = KeyType(c"DSA");
136 pub const DH: KeyType = KeyType(c"DH");
137 pub const EC: KeyType = KeyType(c"EC");
138 pub const ED25519: KeyType = KeyType(c"ED25519");
139 pub const ED448: KeyType = KeyType(c"ED448");
140 pub const X25519: KeyType = KeyType(c"X25519");
141 pub const X448: KeyType = KeyType(c"X448");
142 pub const HMAC: KeyType = KeyType(c"HMAC");
143 pub const CMAC: KeyType = KeyType(c"CMAC");
144 pub const ML_DSA_44: KeyType = KeyType(c"ML-DSA-44");
145 pub const ML_DSA_65: KeyType = KeyType(c"ML-DSA-65");
146 pub const ML_DSA_87: KeyType = KeyType(c"ML-DSA-87");
147 pub const ML_KEM_512: KeyType = KeyType(c"ML-KEM-512");
148 pub const ML_KEM_768: KeyType = KeyType(c"ML-KEM-768");
149 pub const ML_KEM_1024: KeyType = KeyType(c"ML-KEM-1024");
150
151 #[cfg(ossl300)]
153 pub(crate) fn as_cstr(&self) -> &'static CStr {
154 self.0
155 }
156}
157
158pub unsafe trait HasParams {}
160
161unsafe impl HasParams for Params {}
162
163unsafe impl<T> HasParams for T where T: HasPublic {}
164
165pub unsafe trait HasPublic {}
167
168unsafe impl HasPublic for Public {}
169
170unsafe impl<T> HasPublic for T where T: HasPrivate {}
171
172pub unsafe trait HasPrivate {}
174
175unsafe impl HasPrivate for Private {}
176
177generic_foreign_type_and_impl_send_sync! {
178 type CType = ffi::EVP_PKEY;
179 fn drop = ffi::EVP_PKEY_free;
180
181 pub struct PKey<T>;
183 pub struct PKeyRef<T>;
185}
186
187impl<T> ToOwned for PKeyRef<T> {
188 type Owned = PKey<T>;
189
190 fn to_owned(&self) -> PKey<T> {
191 unsafe {
192 EVP_PKEY_up_ref(self.as_ptr());
193 PKey::from_ptr(self.as_ptr())
194 }
195 }
196}
197
198impl<T> PKeyRef<T> {
199 #[corresponds(EVP_PKEY_get1_RSA)]
201 pub fn rsa(&self) -> Result<Rsa<T>, ErrorStack> {
202 unsafe {
203 let rsa = cvt_p(ffi::EVP_PKEY_get1_RSA(self.as_ptr()))?;
204 Ok(Rsa::from_ptr(rsa))
205 }
206 }
207
208 #[corresponds(EVP_PKEY_get1_DSA)]
210 pub fn dsa(&self) -> Result<Dsa<T>, ErrorStack> {
211 unsafe {
212 let dsa = cvt_p(ffi::EVP_PKEY_get1_DSA(self.as_ptr()))?;
213 Ok(Dsa::from_ptr(dsa))
214 }
215 }
216
217 #[corresponds(EVP_PKEY_get1_DH)]
219 pub fn dh(&self) -> Result<Dh<T>, ErrorStack> {
220 unsafe {
221 let dh = cvt_p(ffi::EVP_PKEY_get1_DH(self.as_ptr()))?;
222 Ok(Dh::from_ptr(dh))
223 }
224 }
225
226 #[corresponds(EVP_PKEY_get1_EC_KEY)]
228 pub fn ec_key(&self) -> Result<EcKey<T>, ErrorStack> {
229 unsafe {
230 let ec_key = cvt_p(ffi::EVP_PKEY_get1_EC_KEY(self.as_ptr()))?;
231 Ok(EcKey::from_ptr(ec_key))
232 }
233 }
234
235 #[corresponds(EVP_PKEY_id)]
241 pub fn id(&self) -> Id {
242 unsafe { Id::from_raw(ffi::EVP_PKEY_id(self.as_ptr())) }
243 }
244
245 #[corresponds(EVP_PKEY_is_a)]
252 #[cfg(ossl300)]
253 pub fn is_a(&self, key_type: KeyType) -> bool {
254 unsafe { ffi::EVP_PKEY_is_a(self.as_ptr(), key_type.as_cstr().as_ptr()) == 1 }
255 }
256
257 #[corresponds(EVP_PKEY_size)]
259 pub fn size(&self) -> usize {
260 unsafe { ffi::EVP_PKEY_size(self.as_ptr()) as usize }
261 }
262}
263
264impl<T> PKeyRef<T>
265where
266 T: HasPublic,
267{
268 to_pem! {
269 #[corresponds(PEM_write_bio_PUBKEY)]
273 public_key_to_pem,
274 ffi::PEM_write_bio_PUBKEY
275 }
276
277 to_der! {
278 #[corresponds(i2d_PUBKEY)]
280 public_key_to_der,
281 ffi::i2d_PUBKEY
282 }
283
284 #[corresponds(EVP_PKEY_bits)]
289 pub fn bits(&self) -> u32 {
290 unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as u32 }
291 }
292
293 #[corresponds(EVP_PKEY_security_bits)]
297 #[cfg(any(ossl110, libressl360))]
298 pub fn security_bits(&self) -> u32 {
299 unsafe { ffi::EVP_PKEY_security_bits(self.as_ptr()) as u32 }
300 }
301
302 #[corresponds(EVP_PKEY_cmp)]
304 pub fn public_eq<U>(&self, other: &PKeyRef<U>) -> bool
305 where
306 U: HasPublic,
307 {
308 let res = unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 };
309 let _ = ErrorStack::get();
312 res
313 }
314
315 #[corresponds(EVP_PKEY_get_raw_public_key)]
320 #[cfg(any(ossl111, boringssl, libressl370, awslc))]
321 pub fn raw_public_key(&self) -> Result<Vec<u8>, ErrorStack> {
322 unsafe {
323 let mut len = 0;
324 cvt(ffi::EVP_PKEY_get_raw_public_key(
325 self.as_ptr(),
326 ptr::null_mut(),
327 &mut len,
328 ))?;
329 let mut buf = vec![0u8; len];
330 cvt(ffi::EVP_PKEY_get_raw_public_key(
331 self.as_ptr(),
332 buf.as_mut_ptr(),
333 &mut len,
334 ))?;
335 buf.truncate(len);
336 Ok(buf)
337 }
338 }
339}
340
341impl<T> PKeyRef<T>
342where
343 T: HasPrivate,
344{
345 private_key_to_pem! {
346 #[corresponds(PEM_write_bio_PKCS8PrivateKey)]
350 private_key_to_pem_pkcs8,
351 #[corresponds(PEM_write_bio_PKCS8PrivateKey)]
355 private_key_to_pem_pkcs8_passphrase,
356 ffi::PEM_write_bio_PKCS8PrivateKey
357 }
358
359 to_der! {
360 #[corresponds(i2d_PrivateKey)]
362 private_key_to_der,
363 ffi::i2d_PrivateKey
364 }
365
366 #[corresponds(EVP_PKEY_get_raw_private_key)]
371 #[cfg(any(ossl111, boringssl, libressl370, awslc))]
372 pub fn raw_private_key(&self) -> Result<Vec<u8>, ErrorStack> {
373 unsafe {
374 let mut len = 0;
375 cvt(ffi::EVP_PKEY_get_raw_private_key(
376 self.as_ptr(),
377 ptr::null_mut(),
378 &mut len,
379 ))?;
380 let mut buf = vec![0u8; len];
381 cvt(ffi::EVP_PKEY_get_raw_private_key(
382 self.as_ptr(),
383 buf.as_mut_ptr(),
384 &mut len,
385 ))?;
386 buf.truncate(len);
387 Ok(buf)
388 }
389 }
390
391 #[corresponds(EVP_PKEY_get_params)]
403 #[cfg(ossl350)]
404 pub fn seed_into(&self, buf: &mut [u8]) -> Result<usize, ErrorStack> {
405 unsafe {
406 let mut params = [
407 ffi::OSSL_PARAM_construct_octet_string(
408 c"seed".as_ptr(),
409 buf.as_mut_ptr() as *mut libc::c_void,
410 buf.len(),
411 ),
412 ffi::OSSL_PARAM_construct_end(),
413 ];
414 cvt(ffi::EVP_PKEY_get_params(self.as_ptr(), params.as_mut_ptr()))?;
415 if ffi::OSSL_PARAM_modified(¶ms[0]) == 0 {
419 return Err(ErrorStack::get());
420 }
421 Ok(params[0].return_size)
422 }
423 }
424
425 #[corresponds(i2d_PKCS8PrivateKey_bio)]
427 pub fn private_key_to_pkcs8(&self) -> Result<Vec<u8>, ErrorStack> {
428 unsafe {
429 let bio = MemBio::new()?;
430 cvt(ffi::i2d_PKCS8PrivateKey_bio(
431 bio.as_ptr(),
432 self.as_ptr(),
433 ptr::null(),
434 ptr::null_mut(),
435 0,
436 None,
437 ptr::null_mut(),
438 ))?;
439
440 Ok(bio.get_buf().to_owned())
441 }
442 }
443
444 #[corresponds(i2d_PKCS8PrivateKey_bio)]
447 pub fn private_key_to_pkcs8_passphrase(
448 &self,
449 cipher: Cipher,
450 passphrase: &[u8],
451 ) -> Result<Vec<u8>, ErrorStack> {
452 unsafe {
453 let bio = MemBio::new()?;
454 cvt(ffi::i2d_PKCS8PrivateKey_bio(
455 bio.as_ptr(),
456 self.as_ptr(),
457 cipher.as_ptr(),
458 passphrase.as_ptr() as *const _ as *mut _,
459 passphrase.len().try_into().unwrap(),
460 None,
461 ptr::null_mut(),
462 ))?;
463
464 Ok(bio.get_buf().to_owned())
465 }
466 }
467}
468
469impl<T> fmt::Debug for PKey<T> {
470 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
471 let alg = match self.id() {
472 Id::RSA => "RSA",
473 #[cfg(any(ossl111, libressl, boringssl, awslc))]
474 Id::RSA_PSS => "RSA-PSS",
475 #[cfg(not(boringssl))]
476 Id::HMAC => "HMAC",
477 #[cfg(not(any(boringssl, awslc)))]
478 Id::CMAC => "CMAC",
479 Id::DSA => "DSA",
480 Id::DH => "DH",
481 #[cfg(ossl110)]
482 Id::DHX => "DHX",
483 Id::EC => "EC",
484 #[cfg(ossl111)]
485 Id::SM2 => "SM2",
486 #[cfg(any(ossl110, boringssl, libressl360, awslc))]
487 Id::HKDF => "HKDF",
488 #[cfg(any(ossl111, boringssl, libressl370, awslc))]
489 Id::ED25519 => "Ed25519",
490 #[cfg(ossl111)]
491 Id::ED448 => "Ed448",
492 #[cfg(any(ossl111, boringssl, libressl370, awslc))]
493 Id::X25519 => "X25519",
494 #[cfg(ossl111)]
495 Id::X448 => "X448",
496 #[cfg(ossl111)]
497 Id::POLY1305 => "POLY1305",
498 _ => "unknown",
499 };
500 fmt.debug_struct("PKey").field("algorithm", &alg).finish()
501 }
503}
504
505impl<T> Clone for PKey<T> {
506 fn clone(&self) -> PKey<T> {
507 PKeyRef::to_owned(self)
508 }
509}
510
511impl<T> PKey<T> {
512 #[corresponds(EVP_PKEY_set1_RSA)]
514 pub fn from_rsa(rsa: Rsa<T>) -> Result<PKey<T>, ErrorStack> {
515 unsafe {
518 let evp = cvt_p(ffi::EVP_PKEY_new())?;
519 let pkey = PKey::from_ptr(evp);
520 cvt(ffi::EVP_PKEY_set1_RSA(pkey.0, rsa.as_ptr()))?;
521 Ok(pkey)
522 }
523 }
524
525 #[corresponds(EVP_PKEY_set1_DSA)]
527 pub fn from_dsa(dsa: Dsa<T>) -> Result<PKey<T>, ErrorStack> {
528 unsafe {
529 let evp = cvt_p(ffi::EVP_PKEY_new())?;
530 let pkey = PKey::from_ptr(evp);
531 cvt(ffi::EVP_PKEY_set1_DSA(pkey.0, dsa.as_ptr()))?;
532 Ok(pkey)
533 }
534 }
535
536 #[corresponds(EVP_PKEY_set1_DH)]
538 #[cfg(not(boringssl))]
539 pub fn from_dh(dh: Dh<T>) -> Result<PKey<T>, ErrorStack> {
540 unsafe {
541 let evp = cvt_p(ffi::EVP_PKEY_new())?;
542 let pkey = PKey::from_ptr(evp);
543 cvt(ffi::EVP_PKEY_set1_DH(pkey.0, dh.as_ptr()))?;
544 Ok(pkey)
545 }
546 }
547
548 #[cfg(all(not(any(boringssl, awslc)), ossl110))]
550 pub fn from_dhx(dh: Dh<T>) -> Result<PKey<T>, ErrorStack> {
551 unsafe {
552 let evp = cvt_p(ffi::EVP_PKEY_new())?;
553 let pkey = PKey::from_ptr(evp);
554 cvt(ffi::EVP_PKEY_assign(
555 pkey.0,
556 ffi::EVP_PKEY_DHX,
557 dh.as_ptr().cast(),
558 ))?;
559 mem::forget(dh);
560 Ok(pkey)
561 }
562 }
563
564 #[corresponds(EVP_PKEY_set1_EC_KEY)]
566 pub fn from_ec_key(ec_key: EcKey<T>) -> Result<PKey<T>, ErrorStack> {
567 unsafe {
568 let evp = cvt_p(ffi::EVP_PKEY_new())?;
569 let pkey = PKey::from_ptr(evp);
570 cvt(ffi::EVP_PKEY_set1_EC_KEY(pkey.0, ec_key.as_ptr()))?;
571 Ok(pkey)
572 }
573 }
574}
575
576impl PKey<Private> {
577 #[corresponds(EVP_PKEY_new_mac_key)]
583 #[cfg(not(boringssl))]
584 pub fn hmac(key: &[u8]) -> Result<PKey<Private>, ErrorStack> {
585 #[cfg(awslc)]
586 let key_len = key.len();
587 #[cfg(not(awslc))]
588 let key_len = key.len() as c_int;
589 unsafe {
590 assert!(key.len() <= c_int::MAX as usize);
591 let key = cvt_p(ffi::EVP_PKEY_new_mac_key(
592 ffi::EVP_PKEY_HMAC,
593 ptr::null_mut(),
594 key.as_ptr() as *const _,
595 key_len,
596 ))?;
597 Ok(PKey::from_ptr(key))
598 }
599 }
600
601 #[cfg(all(not(any(boringssl, awslc)), ossl110))]
609 #[allow(clippy::trivially_copy_pass_by_ref)]
610 pub fn cmac(cipher: &Cipher, key: &[u8]) -> Result<PKey<Private>, ErrorStack> {
611 let mut ctx = PkeyCtx::new_id(Id::CMAC)?;
612 ctx.keygen_init()?;
613 ctx.set_keygen_cipher(unsafe { CipherRef::from_ptr(cipher.as_ptr() as *mut _) })?;
614 ctx.set_keygen_mac_key(key)?;
615 ctx.keygen()
616 }
617
618 #[cfg(any(ossl111, boringssl, libressl370, awslc))]
619 fn generate_eddsa(id: Id) -> Result<PKey<Private>, ErrorStack> {
620 let mut ctx = PkeyCtx::new_id(id)?;
621 ctx.keygen_init()?;
622 ctx.keygen()
623 }
624
625 #[cfg(any(ossl111, boringssl, libressl370, awslc))]
649 pub fn generate_x25519() -> Result<PKey<Private>, ErrorStack> {
650 PKey::generate_eddsa(Id::X25519)
651 }
652
653 #[cfg(ossl111)]
677 pub fn generate_x448() -> Result<PKey<Private>, ErrorStack> {
678 PKey::generate_eddsa(Id::X448)
679 }
680
681 #[cfg(any(ossl111, boringssl, libressl370, awslc))]
703 pub fn generate_ed25519() -> Result<PKey<Private>, ErrorStack> {
704 PKey::generate_eddsa(Id::ED25519)
705 }
706
707 #[cfg(ossl111)]
729 pub fn generate_ed448() -> Result<PKey<Private>, ErrorStack> {
730 PKey::generate_eddsa(Id::ED448)
731 }
732
733 #[corresponds(EVP_EC_gen)]
737 #[cfg(ossl300)]
738 pub fn ec_gen(curve: &str) -> Result<PKey<Private>, ErrorStack> {
739 ffi::init();
740
741 let curve = CString::new(curve).unwrap();
742 unsafe {
743 let ptr = cvt_p(ffi::EVP_EC_gen(curve.as_ptr()))?;
744 Ok(PKey::from_ptr(ptr))
745 }
746 }
747
748 private_key_from_pem! {
749 #[corresponds(PEM_read_bio_PrivateKey)]
751 private_key_from_pem,
752
753 #[corresponds(PEM_read_bio_PrivateKey)]
755 private_key_from_pem_passphrase,
756
757 #[corresponds(PEM_read_bio_PrivateKey)]
761 private_key_from_pem_callback,
762 PKey<Private>,
763 ffi::PEM_read_bio_PrivateKey
764 }
765
766 from_der! {
767 #[corresponds(d2i_AutoPrivateKey)]
773 private_key_from_der,
774 PKey<Private>,
775 ffi::d2i_AutoPrivateKey
776 }
777
778 pub fn private_key_from_pkcs8(der: &[u8]) -> Result<PKey<Private>, ErrorStack> {
782 unsafe {
783 ffi::init();
784 let len = der.len().min(c_long::MAX as usize) as c_long;
785 let p8inf = cvt_p(ffi::d2i_PKCS8_PRIV_KEY_INFO(
786 ptr::null_mut(),
787 &mut der.as_ptr(),
788 len,
789 ))?;
790 let res = cvt_p(ffi::EVP_PKCS82PKEY(p8inf)).map(|p| PKey::from_ptr(p));
791 ffi::PKCS8_PRIV_KEY_INFO_free(p8inf);
792 res
793 }
794 }
795
796 #[corresponds(d2i_PKCS8PrivateKey_bio)]
802 pub fn private_key_from_pkcs8_callback<F>(
803 der: &[u8],
804 callback: F,
805 ) -> Result<PKey<Private>, ErrorStack>
806 where
807 F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>,
808 {
809 unsafe {
810 ffi::init();
811 let mut cb = CallbackState::new(callback);
812 let bio = MemBioSlice::new(der)?;
813 cvt_p(ffi::d2i_PKCS8PrivateKey_bio(
814 bio.as_ptr(),
815 ptr::null_mut(),
816 Some(invoke_passwd_cb::<F>),
817 &mut cb as *mut _ as *mut _,
818 ))
819 .map(|p| PKey::from_ptr(p))
820 }
821 }
822
823 #[corresponds(d2i_PKCS8PrivateKey_bio)]
830 pub fn private_key_from_pkcs8_passphrase(
831 der: &[u8],
832 passphrase: &[u8],
833 ) -> Result<PKey<Private>, ErrorStack> {
834 unsafe {
835 ffi::init();
836 let bio = MemBioSlice::new(der)?;
837 let passphrase = CString::new(passphrase).unwrap();
838 cvt_p(ffi::d2i_PKCS8PrivateKey_bio(
839 bio.as_ptr(),
840 ptr::null_mut(),
841 None,
842 passphrase.as_ptr() as *const _ as *mut _,
843 ))
844 .map(|p| PKey::from_ptr(p))
845 }
846 }
847
848 #[corresponds(EVP_PKEY_new_raw_private_key)]
852 #[cfg(any(ossl111, boringssl, libressl370, awslc))]
853 pub fn private_key_from_raw_bytes(
854 bytes: &[u8],
855 key_type: Id,
856 ) -> Result<PKey<Private>, ErrorStack> {
857 unsafe {
858 ffi::init();
859 cvt_p(ffi::EVP_PKEY_new_raw_private_key(
860 key_type.as_raw(),
861 ptr::null_mut(),
862 bytes.as_ptr(),
863 bytes.len(),
864 ))
865 .map(|p| PKey::from_ptr(p))
866 }
867 }
868
869 #[corresponds(EVP_PKEY_new_raw_private_key_ex)]
876 #[cfg(ossl300)]
877 pub fn private_key_from_raw_bytes_ex(
878 ctx: Option<&LibCtxRef>,
879 key_type: KeyType,
880 properties: Option<&CStr>,
881 bytes: &[u8],
882 ) -> Result<PKey<Private>, ErrorStack> {
883 unsafe {
884 ffi::init();
885 cvt_p(ffi::EVP_PKEY_new_raw_private_key_ex(
886 ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr),
887 key_type.as_cstr().as_ptr(),
888 properties.map_or(ptr::null(), |s| s.as_ptr()),
889 bytes.as_ptr(),
890 bytes.len(),
891 ))
892 .map(|p| PKey::from_ptr(p))
893 }
894 }
895
896 #[corresponds(EVP_PKEY_fromdata)]
907 #[cfg(ossl350)]
908 pub fn private_key_from_seed(
909 ctx: Option<&LibCtxRef>,
910 key_type: KeyType,
911 properties: Option<&CStr>,
912 seed: &[u8],
913 ) -> Result<PKey<Private>, ErrorStack> {
914 let mut builder = crate::ossl_param::OsslParamBuilder::new()?;
915 builder.add_octet_string(c"seed", seed)?;
916 let params = builder.to_param()?;
917 unsafe {
918 ffi::init();
919 let pkey_ctx = cvt_p(ffi::EVP_PKEY_CTX_new_from_name(
920 ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr),
921 key_type.as_cstr().as_ptr(),
922 properties.map_or(ptr::null(), |s| s.as_ptr()),
923 ))?;
924 let pkey_ctx = PkeyCtx::<Private>::from_ptr(pkey_ctx);
926 cvt(ffi::EVP_PKEY_fromdata_init(pkey_ctx.as_ptr()))?;
927 let mut pkey: *mut ffi::EVP_PKEY = ptr::null_mut();
928 cvt(ffi::EVP_PKEY_fromdata(
929 pkey_ctx.as_ptr(),
930 &mut pkey,
931 ffi::EVP_PKEY_KEYPAIR,
932 params.as_ptr(),
933 ))?;
934 Ok(PKey::from_ptr(pkey))
935 }
936 }
937}
938
939impl PKey<Public> {
940 private_key_from_pem! {
941 #[corresponds(PEM_read_bio_PUBKEY)]
945 public_key_from_pem,
946
947 #[corresponds(PEM_read_bio_PUBKEY)]
949 public_key_from_pem_passphrase,
950
951 #[corresponds(PEM_read_bio_PrivateKey)]
955 public_key_from_pem_callback,
956 PKey<Public>,
957 ffi::PEM_read_bio_PUBKEY
958 }
959
960 from_der! {
961 #[corresponds(d2i_PUBKEY)]
963 public_key_from_der,
964 PKey<Public>,
965 ffi::d2i_PUBKEY
966 }
967
968 #[corresponds(EVP_PKEY_new_raw_public_key)]
972 #[cfg(any(ossl111, boringssl, libressl370, awslc))]
973 pub fn public_key_from_raw_bytes(
974 bytes: &[u8],
975 key_type: Id,
976 ) -> Result<PKey<Public>, ErrorStack> {
977 unsafe {
978 ffi::init();
979 cvt_p(ffi::EVP_PKEY_new_raw_public_key(
980 key_type.as_raw(),
981 ptr::null_mut(),
982 bytes.as_ptr(),
983 bytes.len(),
984 ))
985 .map(|p| PKey::from_ptr(p))
986 }
987 }
988
989 #[corresponds(EVP_PKEY_new_raw_public_key_ex)]
996 #[cfg(ossl300)]
997 pub fn public_key_from_raw_bytes_ex(
998 ctx: Option<&LibCtxRef>,
999 key_type: KeyType,
1000 properties: Option<&CStr>,
1001 bytes: &[u8],
1002 ) -> Result<PKey<Public>, ErrorStack> {
1003 unsafe {
1004 ffi::init();
1005 cvt_p(ffi::EVP_PKEY_new_raw_public_key_ex(
1006 ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr),
1007 key_type.as_cstr().as_ptr(),
1008 properties.map_or(ptr::null(), |s| s.as_ptr()),
1009 bytes.as_ptr(),
1010 bytes.len(),
1011 ))
1012 .map(|p| PKey::from_ptr(p))
1013 }
1014 }
1015}
1016
1017use ffi::EVP_PKEY_up_ref;
1018
1019impl<T> TryFrom<EcKey<T>> for PKey<T> {
1020 type Error = ErrorStack;
1021
1022 fn try_from(ec_key: EcKey<T>) -> Result<PKey<T>, ErrorStack> {
1023 PKey::from_ec_key(ec_key)
1024 }
1025}
1026
1027impl<T> TryFrom<PKey<T>> for EcKey<T> {
1028 type Error = ErrorStack;
1029
1030 fn try_from(pkey: PKey<T>) -> Result<EcKey<T>, ErrorStack> {
1031 pkey.ec_key()
1032 }
1033}
1034
1035impl<T> TryFrom<Rsa<T>> for PKey<T> {
1036 type Error = ErrorStack;
1037
1038 fn try_from(rsa: Rsa<T>) -> Result<PKey<T>, ErrorStack> {
1039 PKey::from_rsa(rsa)
1040 }
1041}
1042
1043impl<T> TryFrom<PKey<T>> for Rsa<T> {
1044 type Error = ErrorStack;
1045
1046 fn try_from(pkey: PKey<T>) -> Result<Rsa<T>, ErrorStack> {
1047 pkey.rsa()
1048 }
1049}
1050
1051impl<T> TryFrom<Dsa<T>> for PKey<T> {
1052 type Error = ErrorStack;
1053
1054 fn try_from(dsa: Dsa<T>) -> Result<PKey<T>, ErrorStack> {
1055 PKey::from_dsa(dsa)
1056 }
1057}
1058
1059impl<T> TryFrom<PKey<T>> for Dsa<T> {
1060 type Error = ErrorStack;
1061
1062 fn try_from(pkey: PKey<T>) -> Result<Dsa<T>, ErrorStack> {
1063 pkey.dsa()
1064 }
1065}
1066
1067#[cfg(not(boringssl))]
1068impl<T> TryFrom<Dh<T>> for PKey<T> {
1069 type Error = ErrorStack;
1070
1071 fn try_from(dh: Dh<T>) -> Result<PKey<T>, ErrorStack> {
1072 PKey::from_dh(dh)
1073 }
1074}
1075
1076impl<T> TryFrom<PKey<T>> for Dh<T> {
1077 type Error = ErrorStack;
1078
1079 fn try_from(pkey: PKey<T>) -> Result<Dh<T>, ErrorStack> {
1080 pkey.dh()
1081 }
1082}
1083
1084#[cfg(test)]
1085mod tests {
1086 use std::convert::TryInto;
1087
1088 #[cfg(not(boringssl))]
1089 use crate::dh::Dh;
1090 use crate::dsa::Dsa;
1091 use crate::ec::EcKey;
1092 use crate::error::Error;
1093 use crate::nid::Nid;
1094 use crate::rsa::Rsa;
1095 use crate::symm::Cipher;
1096
1097 use super::*;
1098
1099 #[cfg(any(ossl111, awslc))]
1100 use crate::rand::rand_bytes;
1101
1102 #[test]
1103 fn test_to_password() {
1104 let rsa = Rsa::generate(2048).unwrap();
1105 let pkey = PKey::from_rsa(rsa).unwrap();
1106 let pem = pkey
1107 .private_key_to_pem_pkcs8_passphrase(Cipher::aes_128_cbc(), b"foobar")
1108 .unwrap();
1109 PKey::private_key_from_pem_passphrase(&pem, b"foobar").unwrap();
1110 assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err());
1111 }
1112
1113 #[test]
1114 fn test_unencrypted_pkcs8() {
1115 let key = include_bytes!("../test/pkcs8-nocrypt.der");
1116 let pkey = PKey::private_key_from_pkcs8(key).unwrap();
1117 let serialized = pkey.private_key_to_pkcs8().unwrap();
1118 let pkey2 = PKey::private_key_from_pkcs8(&serialized).unwrap();
1119
1120 assert_eq!(
1121 pkey2.private_key_to_der().unwrap(),
1122 pkey.private_key_to_der().unwrap()
1123 );
1124 }
1125
1126 #[test]
1127 fn test_encrypted_pkcs8_passphrase() {
1128 let key = include_bytes!("../test/pkcs8.der");
1129 PKey::private_key_from_pkcs8_passphrase(key, b"mypass").unwrap();
1130
1131 let rsa = Rsa::generate(2048).unwrap();
1132 let pkey = PKey::from_rsa(rsa).unwrap();
1133 let der = pkey
1134 .private_key_to_pkcs8_passphrase(Cipher::aes_128_cbc(), b"mypass")
1135 .unwrap();
1136 let pkey2 = PKey::private_key_from_pkcs8_passphrase(&der, b"mypass").unwrap();
1137 assert_eq!(
1138 pkey.private_key_to_der().unwrap(),
1139 pkey2.private_key_to_der().unwrap()
1140 );
1141 }
1142
1143 #[test]
1144 fn test_encrypted_pkcs8_callback() {
1145 let mut password_queried = false;
1146 let key = include_bytes!("../test/pkcs8.der");
1147 PKey::private_key_from_pkcs8_callback(key, |password| {
1148 password_queried = true;
1149 password[..6].copy_from_slice(b"mypass");
1150 Ok(6)
1151 })
1152 .unwrap();
1153 assert!(password_queried);
1154 }
1155
1156 #[test]
1157 fn test_private_key_from_pem() {
1158 let key = include_bytes!("../test/key.pem");
1159 PKey::private_key_from_pem(key).unwrap();
1160 }
1161
1162 #[test]
1163 fn test_public_key_from_pem() {
1164 let key = include_bytes!("../test/key.pem.pub");
1165 PKey::public_key_from_pem(key).unwrap();
1166 }
1167
1168 #[test]
1169 fn test_public_key_from_der() {
1170 let key = include_bytes!("../test/key.der.pub");
1171 PKey::public_key_from_der(key).unwrap();
1172 }
1173
1174 #[test]
1175 fn test_private_key_from_der() {
1176 let key = include_bytes!("../test/key.der");
1177 PKey::private_key_from_der(key).unwrap();
1178 }
1179
1180 #[test]
1181 fn test_pem() {
1182 let key = include_bytes!("../test/key.pem");
1183 let key = PKey::private_key_from_pem(key).unwrap();
1184
1185 let priv_key = key.private_key_to_pem_pkcs8().unwrap();
1186 let pub_key = key.public_key_to_pem().unwrap();
1187
1188 assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY"));
1191 assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY"));
1192 }
1193
1194 #[test]
1195 fn test_rsa_accessor() {
1196 let rsa = Rsa::generate(2048).unwrap();
1197 let pkey = PKey::from_rsa(rsa).unwrap();
1198 pkey.rsa().unwrap();
1199 assert_eq!(pkey.id(), Id::RSA);
1200 assert!(pkey.dsa().is_err());
1201 }
1202
1203 #[test]
1204 fn test_dsa_accessor() {
1205 let dsa = Dsa::generate(2048).unwrap();
1206 let pkey = PKey::from_dsa(dsa).unwrap();
1207 pkey.dsa().unwrap();
1208 assert_eq!(pkey.id(), Id::DSA);
1209 assert!(pkey.rsa().is_err());
1210 }
1211
1212 #[test]
1213 #[cfg(not(boringssl))]
1214 fn test_dh_accessor() {
1215 let dh = include_bytes!("../test/dhparams.pem");
1216 let dh = Dh::params_from_pem(dh).unwrap();
1217 let pkey = PKey::from_dh(dh).unwrap();
1218 pkey.dh().unwrap();
1219 assert_eq!(pkey.id(), Id::DH);
1220 assert!(pkey.rsa().is_err());
1221 }
1222
1223 #[test]
1224 fn test_ec_key_accessor() {
1225 let ec_key = EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1226 let pkey = PKey::from_ec_key(ec_key).unwrap();
1227 pkey.ec_key().unwrap();
1228 assert_eq!(pkey.id(), Id::EC);
1229 assert!(pkey.rsa().is_err());
1230 }
1231
1232 #[test]
1233 fn test_rsa_conversion() {
1234 let rsa = Rsa::generate(2048).unwrap();
1235 let pkey: PKey<Private> = rsa.clone().try_into().unwrap();
1236 let rsa_: Rsa<Private> = pkey.try_into().unwrap();
1237 assert_eq!(rsa.p(), rsa_.p());
1239 assert_eq!(rsa.q(), rsa_.q());
1240 }
1241
1242 #[test]
1243 fn test_dsa_conversion() {
1244 let dsa = Dsa::generate(2048).unwrap();
1245 let pkey: PKey<Private> = dsa.clone().try_into().unwrap();
1246 let dsa_: Dsa<Private> = pkey.try_into().unwrap();
1247 assert_eq!(dsa.priv_key(), dsa_.priv_key());
1249 }
1250
1251 #[test]
1252 fn test_ec_key_conversion() {
1253 let group = crate::ec::EcGroup::from_curve_name(crate::nid::Nid::X9_62_PRIME256V1).unwrap();
1254 let ec_key = EcKey::generate(&group).unwrap();
1255 let pkey: PKey<Private> = ec_key.clone().try_into().unwrap();
1256 let ec_key_: EcKey<Private> = pkey.try_into().unwrap();
1257 assert_eq!(ec_key.private_key(), ec_key_.private_key());
1259 }
1260
1261 #[test]
1262 #[cfg(any(ossl110, libressl360))]
1263 fn test_security_bits() {
1264 let group = crate::ec::EcGroup::from_curve_name(crate::nid::Nid::SECP521R1).unwrap();
1265 let ec_key = EcKey::generate(&group).unwrap();
1266 let pkey: PKey<Private> = ec_key.try_into().unwrap();
1267
1268 assert_eq!(pkey.security_bits(), 256);
1269 }
1270
1271 #[test]
1272 #[cfg(not(boringssl))]
1273 fn test_dh_conversion() {
1274 let dh_params = include_bytes!("../test/dhparams.pem");
1275 let dh_params = Dh::params_from_pem(dh_params).unwrap();
1276 let dh = dh_params.generate_key().unwrap();
1277
1278 let p = dh.prime_p().to_owned().unwrap();
1280 let q = dh.prime_q().map(|q| q.to_owned().unwrap());
1281 let g = dh.generator().to_owned().unwrap();
1282
1283 let pkey: PKey<Private> = dh.try_into().unwrap();
1284 let dh_: Dh<Private> = pkey.try_into().unwrap();
1285
1286 assert_eq!(&p, dh_.prime_p());
1288 assert_eq!(q, dh_.prime_q().map(|q| q.to_owned().unwrap()));
1289 assert_eq!(&g, dh_.generator());
1290 }
1291
1292 #[cfg(any(ossl111, boringssl, libressl370, awslc))]
1293 fn test_raw_public_key(gen: fn() -> Result<PKey<Private>, ErrorStack>, key_type: Id) {
1294 let key = gen().unwrap();
1296
1297 let raw = key.raw_public_key().unwrap();
1299 let from_raw = PKey::public_key_from_raw_bytes(&raw, key_type).unwrap();
1300
1301 assert_eq!(
1303 key.public_key_to_der().unwrap(),
1304 from_raw.public_key_to_der().unwrap()
1305 );
1306 }
1307
1308 #[cfg(any(ossl111, boringssl, libressl370, awslc))]
1309 fn test_raw_private_key(gen: fn() -> Result<PKey<Private>, ErrorStack>, key_type: Id) {
1310 let key = gen().unwrap();
1312
1313 let raw = key.raw_private_key().unwrap();
1315 let from_raw = PKey::private_key_from_raw_bytes(&raw, key_type).unwrap();
1316
1317 assert_eq!(
1319 key.private_key_to_pkcs8().unwrap(),
1320 from_raw.private_key_to_pkcs8().unwrap()
1321 );
1322 }
1323
1324 #[cfg(any(ossl111, boringssl, libressl370, awslc))]
1325 #[test]
1326 fn test_raw_public_key_bytes() {
1327 test_raw_public_key(PKey::generate_x25519, Id::X25519);
1328 test_raw_public_key(PKey::generate_ed25519, Id::ED25519);
1329 #[cfg(not(any(libressl, boringssl, awslc)))]
1330 test_raw_public_key(PKey::generate_x448, Id::X448);
1331 #[cfg(not(any(libressl, boringssl, awslc)))]
1332 test_raw_public_key(PKey::generate_ed448, Id::ED448);
1333 }
1334
1335 #[cfg(any(ossl111, boringssl, libressl370, awslc))]
1336 #[test]
1337 fn test_raw_private_key_bytes() {
1338 test_raw_private_key(PKey::generate_x25519, Id::X25519);
1339 test_raw_private_key(PKey::generate_ed25519, Id::ED25519);
1340 #[cfg(not(any(libressl, boringssl, awslc)))]
1341 test_raw_private_key(PKey::generate_x448, Id::X448);
1342 #[cfg(not(any(libressl, boringssl, awslc)))]
1343 test_raw_private_key(PKey::generate_ed448, Id::ED448);
1344 }
1345
1346 #[cfg(any(ossl111, awslc))]
1347 #[test]
1348 fn test_raw_hmac() {
1349 let mut test_bytes = vec![0u8; 32];
1350 rand_bytes(&mut test_bytes).unwrap();
1351
1352 let hmac_key = PKey::hmac(&test_bytes).unwrap();
1353 assert!(hmac_key.raw_public_key().is_err());
1354
1355 let key_bytes = hmac_key.raw_private_key().unwrap();
1356 assert_eq!(key_bytes, test_bytes);
1357 }
1358
1359 #[cfg(any(ossl111, awslc))]
1360 #[test]
1361 fn test_raw_key_fail() {
1362 let group = crate::ec::EcGroup::from_curve_name(Nid::SECP256K1).unwrap();
1364 let ec_key = EcKey::generate(&group).unwrap();
1365 let pkey = PKey::from_ec_key(ec_key).unwrap();
1366 assert!(pkey.raw_private_key().is_err());
1367 assert!(pkey.raw_public_key().is_err());
1368 }
1369
1370 #[cfg(ossl300)]
1371 #[test]
1372 fn test_is_a() {
1373 let rsa = Rsa::generate(2048).unwrap();
1374 let pkey = PKey::from_rsa(rsa).unwrap();
1375 assert!(pkey.is_a(KeyType::RSA));
1376 assert!(!pkey.is_a(KeyType::EC));
1377 assert!(!pkey.is_a(KeyType::ML_DSA_65));
1378
1379 let ed = PKey::generate_ed25519().unwrap();
1380 assert!(ed.is_a(KeyType::ED25519));
1381 assert!(!ed.is_a(KeyType::X25519));
1382 }
1383
1384 #[cfg(ossl300)]
1385 #[test]
1386 fn test_raw_public_key_from_bytes_ex() {
1387 let key = PKey::generate_ed25519().unwrap();
1388 let raw = key.raw_public_key().unwrap();
1389 let from_raw =
1390 PKey::public_key_from_raw_bytes_ex(None, KeyType::ED25519, None, &raw).unwrap();
1391 assert_eq!(
1392 key.public_key_to_der().unwrap(),
1393 from_raw.public_key_to_der().unwrap()
1394 );
1395 assert!(from_raw.is_a(KeyType::ED25519));
1396
1397 assert!(PKey::public_key_from_raw_bytes_ex(None, KeyType::ED25519, None, &[]).is_err());
1399 }
1400
1401 #[cfg(ossl300)]
1402 #[test]
1403 fn test_raw_private_key_from_bytes_ex() {
1404 let key = PKey::generate_ed25519().unwrap();
1405 let raw = key.raw_private_key().unwrap();
1406 let from_raw =
1407 PKey::private_key_from_raw_bytes_ex(None, KeyType::ED25519, None, &raw).unwrap();
1408 assert_eq!(
1409 key.private_key_to_pkcs8().unwrap(),
1410 from_raw.private_key_to_pkcs8().unwrap()
1411 );
1412 }
1413
1414 #[cfg(ossl300)]
1415 #[test]
1416 fn test_ec_gen() {
1417 let key = PKey::ec_gen("prime256v1").unwrap();
1418 assert!(key.ec_key().is_ok());
1419 }
1420
1421 #[cfg(ossl350)]
1422 #[test]
1423 fn test_private_key_from_seed_mldsa() {
1424 let xi = hex::decode("f696484048ec21f96cf50a56d0759c448f3779752f0383d37449690694cf7a68")
1428 .unwrap();
1429 let key = PKey::private_key_from_seed(None, KeyType::ML_DSA_65, None, &xi).unwrap();
1430 assert!(key.is_a(KeyType::ML_DSA_65));
1431 let expected_pk = "e50d03fff3b3a70961abbb92a390008dec1283f603f50cdbaaa3d00bd659bc767c3f24ec864ceb07b865aa148647698df8e63f244c4de08affc0210f1560f64822961972463e403bbe97ce7a539fc013527558ad824202a90b1e9a045d89a51c3a31d0330f2099d0f5e0b9e8de8d1e340c91d6a0f61cb8a6548e2614a1b6a2ad80f4e567f0f134700b1563ccaab71f28e7bf509858d85218166dd9a0e1dfad4bee180b4cdaf6e37623558f64fd124d3d7543aade0b28fb8f193159cea7dfb172174b6c25375c9c1903636bfaa41791b1f2f16158020806a1d95979f678a46a209a8780345d2d092c52b576b5e263e870570cc1084058676fbddb2c93bc87fd81a90f7081c04fb299415f761966614aedeea40386f0dbe97512956c3f16c3e210a364de926e37374637d95d0420de7f2f72365392a6d4392018762cd6aa4d6ec629f6d0605ab86862a34c3f1fb55695ae35e736404044aad617d192e8ff07a16f5c6291c2edb0bf1d601a6b08f1c9b444e31570113124cd20eeb299d30a4546243a9f20ed36fa963edab2f494cd92f766633b97237ccc3485387f4344839f4656fbf1eb7f4f24712f432f3b74df325747405bc9ee39f42f87653322f1d23c92c981953fc107570053ce46b6741410a99cdb1888d33943e191c0a395085b9d14a3fbdc58a3ea16706c937ea44aebc9764df142010eab022c40b28e63da853ae03843bfe02eed35331571ec89895c1ea2256cb7591e63c7a5870455663ef9804b84d524470a08cda9bbbfd07ba6537473163cf030849c5f31679c610d56d5e31c0e73f23098d3a19dd39afe507e25d053e7d5b0d9b18c53b153c2d5b162558939a6e24e7ba02d1d736b6a4c93a4f3bc50d4ab16ef350b411e6f4a734be03242fd67ee47eb4ec3d453d1a9254c4e02f68a366702ef2875932b72125ee81da1c10a336b4a4990a5e36f0b59b00e3471c56314d6e92bcb7bacd6219fd99c1ca50c3342ce62cd98be9458a17cf243c60c09b106e86fab345a997f7b46d4ac1c790c37dbdb93d29c532a5cb097a30f92d47c460ec8345b17ba5db77c1a6533a9448a353663f187517a399583b2f98cb0a8dc3f64d049716a5c8aee6ede0bb6958fc70f2fce706f20622d35e9ff2a1c30dd5e71bebe4a33fd74ab768cd34a2d9ec59845a8f38b5dd6c0008b678876e493c9afc2396a16721142803f1f38c579036858a25a1a1abfae94c7dc1ecb26c1d3b4d96209be238360fc8554e33f5fba2b92abf207b677d433b58275366b836be7081d7b50f9d29652c836ffb11596317cb3aaaf4ed41441298fb386fbd9237227bb7529bf5eeb7711bc6936cd4fba98b8404dd1e8650a3a1bf29869835797b9537db1afc0f4339ad3b296401100520dd43d2cd453534f1df776c0aa184f2e5cb658fee5b54bb44d9ee13b3486c37b1fea4284327ce15400ecd93a0c01852d045c3c7af348d4786845984fde0d086c115d4fcbcfee73688ef61601ce3560d6db6f0a6be4dc05640c575a2d24a6a5b5d697ecc3a6844bf7405f68c5450b1d67b5dfcfcc8f878d787f7f57d3875fdf345f1730f9e7493e9a4acacb7b8832b0141a1bdb082a95d8be8f5280035f42f05f9ecf663fa5d03b056c43bc39ba1a6f7375961c4e94830c51e276cc4bc826518f84f51e8ea6f59a3d12ad9d5ef2ca6db70155cabd655713641a885551ab65a358d2e7baf68a39567ba2278d9493562aa4e903ad6f304d2752064d8dbc8a2bf53e24d2f77e47da1d0519212148daf2cb99453b44c7337db46390a6d67d0bbdfa980bfca35d68df1e904168f64fd6b22710eac8bab8757a9e3bb43c5f907949cddecf0321d728a2bbb74e6cc4959c1516c9b2981150f054ec05bd3844e99a7788d5d018c2dc4642969059601a6928963500f085c84cda6454dfc4be63ba82182104499d778e0e998e1cf9086d7990ed03704753f10cb4df6076341f1d556aae9a15ade459e74817fa1d9cb8d0a816afc5947c81368bda9c3a587565b3c39199bf3e24254c601c43002c37b83e43116f25ebfb206d081d81c34618e53aba8ef65af1c5dff402839d71c0319cb7696922088cb9ab3f2eee8ea79228ae12dc9aa1db9acd1309d7171b47a7043fe73cfb4e6b11a3da910f5e5e734c26b41a93452848e735d1679963a413d69a0d275ba10693fb922d8f8c32310dee718125b29d1366201399eb253ba5a1fed099f9df91e3c59c16dfe8f7074045760527327e1e5852537ae96962553b69d85da962a5a6789d19fe585e257012132a7c91feaf4c58a4fa7c126fe68406f34ebf1f371adb4b30514b18dd6e7e659df07776238e48cb7fabd08b5f6a9fc05a7ffbf019a2632c257bf79636994c807fa2f513f60940800e290c2e684d9162858bca138a8634e23b1bb4b49f77af7eb717a79b2f293f814849a8d7e0aae2a734259395c4bf6a3a8deb37a0638121a9dcf83dfecd0c6c58a8eb05c4706e395a869c3ce01d42e31466fba05a45e4181dddb177fa20fef50a770d9da14cffb55ac3e829bd932eff759eeaeebd37d3ecb38f2046528affc969b008d2f9fad5acb4682f119011cbb4ffb11dae5d91dfe9ec7ba5142086e5c09eb398e3685413a394b385a5e377c4996848d862ed7f70b3bb75cff88cf89db9146ea82b5611569a8bb67dc95ab4135c2a427f12ba1c9b50cf86d1a238ba0c99c3d82dbc90dd0f7b281494df1a25848ecadfe915a95a43247bc5a55e1e2d90ed05f70be8b2e5fc9d5b";
1432 assert_eq!(hex::encode(key.raw_public_key().unwrap()), expected_pk);
1433
1434 assert!(PKey::private_key_from_seed(None, KeyType::ML_DSA_65, None, &[]).is_err());
1436 }
1437
1438 #[cfg(ossl350)]
1439 #[test]
1440 fn test_private_key_from_seed_mlkem() {
1441 let d = hex::decode("6dbbc4375136df3b07f7c70e639e223e177e7fd53b161b3f4d57791794f12624")
1445 .unwrap();
1446 let z = hex::decode("f696484048ec21f96cf50a56d0759c448f3779752f0383d37449690694cf7a68")
1447 .unwrap();
1448 let mut seed = d;
1449 seed.extend_from_slice(&z);
1450 let key = PKey::private_key_from_seed(None, KeyType::ML_KEM_768, None, &seed).unwrap();
1451 assert!(key.is_a(KeyType::ML_KEM_768));
1452 let expected_pk = "01f60af1dc8e6360ae78b59d4a5042eb9145a269046d6236b8304f305c2d9dcb189fe5a62df89b2f5a7bce3bbc753c1e78f730a99869f809aba856b676b707b26601d1d909bab32451494eb7d0a2153a6350b79789a9b115f83ea12037256562f06a1d5aba378da77039d3bdecaca8e6a22a49050a76300a0267cdb38b7ac77903c50ca53b99283cac6b95fba651b11a4d1a692e4072965060587669f253b1bb182e661446168ac60221894660020e9bb5f5b7124a0303e2543ea3ea6ce97a2482b255ca346fb27a847b33b93f3ab2d33064c6e6632d1a23f1144e907b246b479f4a5c928929a1e24150f5241258a5b67766a66f6a33846495907828ebe44ecc5b73124071ba479073910410a16d5d5696b48b194752979795772a91c348f502b37aa650983ebb89bf3c081ff273544129c9137a6e1834c8f2e7ce14c7870c53c05b9b94ecd38e6645911b0912336863ec168831f811881075cf38a59de4b5c738aa6ef03d779b295588cfb62491cc7b3e08b48473354f9ac8061c152a9e205997499b970b69bce66fe42bca2924ccdf0103d0a4c39193c2df25118d72b17aab26b0c60d4cd2c306ca4696c185de05035f4a09cf970aecc8cc93436f83b1aeaf452c41929a2eabc151938f74c93b858546df2264eeeab602e04a85c522f8fb1a5214afd8d4cae57a47b6f381a23126bd9917173128af917f1d483691c450d1151cfe9a1492d473ed862e27da92500c86a20019e9f975e4f54ad319ba2c5630c4014219d7ba235456fe530140193d662445e6a941d1e238567ba8d4d95ab1c7447d690821876d017270cfb169f2d792f03c800720697b410ab41c66f2b24585125655eb10aa1087ffcb7750cb887ad4467377500a6a7d3a82976b415a54469577b4138d919b03f4c9a4d3390bdcb6f1717a5fa4ab25a34f4ba5039bb22c7f3c234ea4427347aa7251464e631904d7cac4784f78b49d5f4a104a301809a779f6466131f9c62bb67147f4cd4973a6aa1c29ae6a8647b6268be089fe048ce990cd638743d285c889a707f581b63af41731f0246b054bc4b47aab01b6842a2709d02e8158ab90f48b69d136082b34cb0673b74aa3f54508ed029fb8f5045ee0639e150ee3b3c85f68a310ec0441980100b42abf2bad10d4a9e0c7b2bc5bbcaf73cbcdc49dc2c949111936779b178974a0392947745a47189bc3fa8a679c80af964a9f9b1b56577274a2a669d2da6704aa496af407fa1aa964cc3dc3140f5f959a7ea974bdb1b83e48a99c0a3e2d75b0669b5c1278962540609166266da18886fc237af30cefd569dbe399e6652e45f06a5dfc9a758a4987088ff8e38a3cf36b9d988f0e070b68d0b88f7bcc41306080d889780c7e238895ccaa4f3577225cca4c8a9330ce613e717798c9670924b271ac402b51538b8b5967ac490dcab5300e6c54d6a3632f3b973e4186ee1a7e2e85649185b26370c387235c4df28a9937a49d4078bf883f4e6346cb3251d9e13f1bda087b285afaa80e262641c5527b0a184b8bc84a62e577314658e2029d850064f7a7b81f253e7cc124a9c5b039dc9b179a80c2f6aee6ea0815172537331a57b505baa76ff5b4c1f0da754b6194f4b39a9b18730d3cdab925d691ed77a8db9927ea233ac2a12744fdc27e5d221b9369adb325d8";
1453 assert_eq!(hex::encode(key.raw_public_key().unwrap()), expected_pk);
1454
1455 assert!(PKey::private_key_from_seed(None, KeyType::ML_KEM_768, None, &[]).is_err());
1457 }
1458
1459 #[cfg(ossl350)]
1460 #[test]
1461 fn test_private_key_from_seed_invalid_algorithm() {
1462 let seed = [0u8; 64];
1463 assert!(
1464 PKey::private_key_from_seed(None, KeyType::RSA, None, &seed).is_err(),
1465 "Unexpectedly accepted a seed-only fromdata import",
1466 );
1467 }
1468
1469 #[cfg(ossl350)]
1470 #[test]
1471 fn test_seed_into_mldsa_roundtrip() {
1472 let xi = hex::decode("f696484048ec21f96cf50a56d0759c448f3779752f0383d37449690694cf7a68")
1473 .unwrap();
1474 let key = PKey::private_key_from_seed(None, KeyType::ML_DSA_65, None, &xi).unwrap();
1475
1476 let mut exact = [0u8; 32];
1478 let n = key.seed_into(&mut exact).unwrap();
1479 assert_eq!(n, 32);
1480 assert_eq!(&exact[..], &xi[..]);
1481
1482 let mut small = [0u8; 16];
1484 assert!(key.seed_into(&mut small).is_err());
1485
1486 let mut large = [0xaau8; 64];
1489 let n = key.seed_into(&mut large).unwrap();
1490 assert_eq!(n, 32);
1491 assert_eq!(&large[..32], &xi[..]);
1492 assert!(large[32..].iter().all(|&b| b == 0xaa));
1493 }
1494
1495 #[cfg(ossl350)]
1496 #[test]
1497 fn test_seed_into_mlkem_roundtrip() {
1498 let d = hex::decode("6dbbc4375136df3b07f7c70e639e223e177e7fd53b161b3f4d57791794f12624")
1499 .unwrap();
1500 let z = hex::decode("f696484048ec21f96cf50a56d0759c448f3779752f0383d37449690694cf7a68")
1501 .unwrap();
1502 let mut seed = d;
1503 seed.extend_from_slice(&z);
1504 let key = PKey::private_key_from_seed(None, KeyType::ML_KEM_768, None, &seed).unwrap();
1505 let mut buf = [0u8; 64];
1506 let n = key.seed_into(&mut buf).unwrap();
1507 assert_eq!(n, 64);
1508 assert_eq!(&buf[..], &seed[..]);
1509 }
1510
1511 #[cfg(ossl350)]
1513 #[test]
1514 fn test_seed_into_rejects_non_pq_algorithms() {
1515 let mut buf = [0u8; 64];
1516 let rsa = PKey::from_rsa(Rsa::generate(2048).unwrap()).unwrap();
1517 assert!(rsa.seed_into(&mut buf).is_err());
1518
1519 let ed = PKey::generate_ed25519().unwrap();
1520 assert!(ed.seed_into(&mut buf).is_err());
1521 }
1522
1523 #[test]
1524 fn test_public_eq() {
1525 let rsa = Rsa::generate(2048).unwrap();
1526 let pkey1 = PKey::from_rsa(rsa).unwrap();
1527
1528 let group = crate::ec::EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1529 let ec_key = EcKey::generate(&group).unwrap();
1530 let pkey2 = PKey::from_ec_key(ec_key).unwrap();
1531
1532 assert!(!pkey1.public_eq(&pkey2));
1533 assert!(Error::get().is_none());
1534 }
1535}