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