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 #[corresponds(EVP_PKEY_assign_DSA)]
389 pub fn from_dsa(dsa: Dsa<T>) -> Result<PKey<T>, ErrorStack> {
390 unsafe {
391 let evp = cvt_p(ffi::EVP_PKEY_new())?;
392 let pkey = PKey::from_ptr(evp);
393 cvt(ffi::EVP_PKEY_assign(
394 pkey.0,
395 ffi::EVP_PKEY_DSA,
396 dsa.as_ptr().cast(),
397 ))?;
398 mem::forget(dsa);
399 Ok(pkey)
400 }
401 }
402
403 #[corresponds(EVP_PKEY_assign_DH)]
405 pub fn from_dh(dh: Dh<T>) -> Result<PKey<T>, ErrorStack>
406 where
407 T: HasParams,
408 {
409 unsafe {
410 let evp = cvt_p(ffi::EVP_PKEY_new())?;
411 let pkey = PKey::from_ptr(evp);
412 cvt(ffi::EVP_PKEY_assign(
413 pkey.0,
414 ffi::EVP_PKEY_DH,
415 dh.as_ptr().cast(),
416 ))?;
417 mem::forget(dh);
418 Ok(pkey)
419 }
420 }
421}
422
423impl PKey<Private> {
424 fn from_raw_private_key(id: Id, key: &[u8]) -> Result<PKey<Private>, ErrorStack> {
425 unsafe {
426 ffi::init();
427 let alg = raw_key_algorithm(id)?;
428 cvt_p(ffi::EVP_PKEY_from_raw_private_key(
429 alg,
430 key.as_ptr(),
431 key.len(),
432 ))
433 .map(|p| PKey::from_ptr(p))
434 }
435 }
436
437 pub fn from_ed25519_private_key(key: &[u8]) -> Result<PKey<Private>, ErrorStack> {
441 Self::from_raw_private_key(Id::ED25519, key)
442 }
443
444 pub fn from_x25519_private_key(key: &[u8]) -> Result<PKey<Private>, ErrorStack> {
448 Self::from_raw_private_key(Id::X25519, key)
449 }
450
451 private_key_from_pem! {
452 #[corresponds(PEM_read_bio_PrivateKey)]
454 private_key_from_pem,
455
456 #[corresponds(PEM_read_bio_PrivateKey)]
458 private_key_from_pem_passphrase,
459
460 #[corresponds(PEM_read_bio_PrivateKey)]
464 private_key_from_pem_callback,
465 PKey<Private>,
466 ffi::PEM_read_bio_PrivateKey
467 }
468
469 from_der! {
470 #[corresponds(d2i_AutoPrivateKey)]
476 private_key_from_der,
477 PKey<Private>,
478 ffi::d2i_AutoPrivateKey,
479 ::libc::c_long
480 }
481
482 pub fn private_key_from_pkcs8(der: &[u8]) -> Result<PKey<Private>, ErrorStack> {
486 unsafe {
487 ffi::init();
488 let len = der.len().min(c_long::MAX as usize) as c_long;
489 let p8inf = cvt_p(ffi::d2i_PKCS8_PRIV_KEY_INFO(
490 ptr::null_mut(),
491 &mut der.as_ptr(),
492 len,
493 ))?;
494 let res = cvt_p(ffi::EVP_PKCS82PKEY(p8inf)).map(|p| PKey::from_ptr(p));
495 ffi::PKCS8_PRIV_KEY_INFO_free(p8inf);
496 res
497 }
498 }
499
500 pub fn private_key_from_pkcs8_callback<F>(
506 der: &[u8],
507 callback: F,
508 ) -> Result<PKey<Private>, ErrorStack>
509 where
510 F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>,
511 {
512 unsafe {
513 ffi::init();
514 let mut cb = CallbackState::new(callback);
515 let bio = MemBioSlice::new(der)?;
516 cvt_p(ffi::d2i_PKCS8PrivateKey_bio(
517 bio.as_ptr(),
518 ptr::null_mut(),
519 Some(invoke_passwd_cb::<F>),
520 std::ptr::addr_of_mut!(cb).cast(),
521 ))
522 .map(|p| PKey::from_ptr(p))
523 }
524 }
525
526 pub fn private_key_from_pkcs8_passphrase(
533 der: &[u8],
534 passphrase: &[u8],
535 ) -> Result<PKey<Private>, ErrorStack> {
536 unsafe {
537 ffi::init();
538 let bio = MemBioSlice::new(der)?;
539 let passphrase = CString::new(passphrase).map_err(ErrorStack::internal_error)?;
540 cvt_p(ffi::d2i_PKCS8PrivateKey_bio(
541 bio.as_ptr(),
542 ptr::null_mut(),
543 None,
544 passphrase.as_ptr().cast_mut().cast(),
545 ))
546 .map(|p| PKey::from_ptr(p))
547 }
548 }
549}
550
551impl PKey<Public> {
552 fn from_raw_public_key(id: Id, key: &[u8]) -> Result<PKey<Public>, ErrorStack> {
553 unsafe {
554 ffi::init();
555 let alg = raw_key_algorithm(id)?;
556 cvt_p(ffi::EVP_PKEY_from_raw_public_key(
557 alg,
558 key.as_ptr(),
559 key.len(),
560 ))
561 .map(|p| PKey::from_ptr(p))
562 }
563 }
564
565 pub fn from_ed25519_public_key(key: &[u8]) -> Result<PKey<Public>, ErrorStack> {
569 Self::from_raw_public_key(Id::ED25519, key)
570 }
571
572 pub fn from_x25519_public_key(key: &[u8]) -> Result<PKey<Public>, ErrorStack> {
576 Self::from_raw_public_key(Id::X25519, key)
577 }
578
579 from_pem! {
580 #[corresponds(PEM_read_bio_PUBKEY)]
584 public_key_from_pem,
585 PKey<Public>,
586 ffi::PEM_read_bio_PUBKEY
587 }
588
589 from_der! {
590 #[corresponds(d2i_PUBKEY)]
592 public_key_from_der,
593 PKey<Public>,
594 ffi::d2i_PUBKEY,
595 ::libc::c_long
596 }
597}
598
599use crate::ffi::EVP_PKEY_up_ref;
600
601fn raw_key_algorithm(id: Id) -> Result<*const ffi::EVP_PKEY_ALG, ErrorStack> {
602 let alg = unsafe {
603 match id {
604 Id::ED25519 => ffi::EVP_pkey_ed25519(),
605 Id::X25519 => ffi::EVP_pkey_x25519(),
606 _ => {
607 return Err(ErrorStack::internal_error_str(
608 "unsupported raw key algorithm",
609 ));
610 }
611 }
612 };
613 if alg.is_null() {
614 Err(ErrorStack::internal_error_str("missing raw key algorithm"))
615 } else {
616 Ok(alg)
617 }
618}
619
620#[cfg(test)]
621mod tests {
622 use hex::FromHex as _;
623
624 use crate::bn::BigNum;
625 use crate::dh::Dh;
626 use crate::dsa::Dsa;
627 use crate::ec::EcKey;
628 use crate::nid::Nid;
629 use crate::rsa::Rsa;
630 use crate::symm::Cipher;
631
632 use super::*;
633
634 #[test]
635 fn test_to_password() {
636 let rsa = Rsa::generate(2048).unwrap();
637 let pkey = PKey::from_rsa(rsa).unwrap();
638 let pem = pkey
639 .private_key_to_pem_pkcs8_passphrase(Cipher::aes_128_cbc(), b"foobar")
640 .unwrap();
641 PKey::private_key_from_pem_passphrase(&pem, b"foobar").unwrap();
642 assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err());
643 }
644
645 #[test]
646 fn test_unencrypted_pkcs8() {
647 let key = include_bytes!("../test/pkcs8-nocrypt.der");
648 PKey::private_key_from_pkcs8(key).unwrap();
649 }
650
651 #[test]
652 fn test_encrypted_pkcs8_passphrase() {
653 let key = include_bytes!("../test/pkcs8.der");
654 PKey::private_key_from_pkcs8_passphrase(key, b"mypass").unwrap();
655 }
656
657 #[test]
658 fn test_encrypted_pkcs8_callback() {
659 let mut password_queried = false;
660 let key = include_bytes!("../test/pkcs8.der");
661 PKey::private_key_from_pkcs8_callback(key, |password| {
662 password_queried = true;
663 password[..6].copy_from_slice(b"mypass");
664 Ok(6)
665 })
666 .unwrap();
667 assert!(password_queried);
668 }
669
670 #[test]
671 fn test_private_key_from_pem() {
672 let key = include_bytes!("../test/key.pem");
673 PKey::private_key_from_pem(key).unwrap();
674 }
675
676 #[test]
677 fn test_public_key_from_pem() {
678 let key = include_bytes!("../test/key.pem.pub");
679 PKey::public_key_from_pem(key).unwrap();
680 }
681
682 #[test]
683 fn test_public_key_from_der() {
684 let key = include_bytes!("../test/key.der.pub");
685 PKey::public_key_from_der(key).unwrap();
686 }
687
688 #[test]
689 fn test_private_key_from_der() {
690 let key = include_bytes!("../test/key.der");
691 PKey::private_key_from_der(key).unwrap();
692 }
693
694 #[test]
695 fn test_pem() {
696 let key = include_bytes!("../test/key.pem");
697 let key = PKey::private_key_from_pem(key).unwrap();
698
699 let priv_key = key.private_key_to_pem_pkcs8().unwrap();
700 let pub_key = key.public_key_to_pem().unwrap();
701
702 assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY"));
705 assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY"));
706 }
707
708 #[test]
709 fn test_der_pkcs8() {
710 let key = include_bytes!("../test/key.der");
711 let key = PKey::private_key_from_der(key).unwrap();
712
713 let priv_key = key.private_key_to_der_pkcs8().unwrap();
714
715 assert_eq!(hex::encode(&priv_key[4..=6]), "020100"); assert_eq!(hex::encode(&priv_key[9..=19]), "06092a864886f70d010101"); }
719
720 #[test]
721 fn test_rsa_accessor() {
722 let rsa = Rsa::generate(2048).unwrap();
723 let pkey = PKey::from_rsa(rsa).unwrap();
724 pkey.rsa().unwrap();
725 assert_eq!(pkey.id(), Id::RSA);
726 assert!(pkey.dsa().is_err());
727 }
728
729 #[test]
730 fn test_ec_key_accessor() {
731 let ec_key = EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
732 let pkey = PKey::from_ec_key(ec_key).unwrap();
733 pkey.ec_key().unwrap();
734 assert_eq!(pkey.id(), Id::EC);
735 assert!(pkey.rsa().is_err());
736 }
737
738 #[test]
739 fn test_dsa_from_and_accessor() {
740 let dsa = Dsa::generate(2048).unwrap();
741 let pkey = PKey::from_dsa(dsa).unwrap();
742 pkey.dsa().unwrap();
743 assert_eq!(pkey.id(), Id::DSA);
744 assert!(pkey.rsa().is_err());
745 assert!(pkey.ec_key().is_err());
746 }
747
748 #[test]
749 fn test_dh_from_and_accessor() {
750 let p = BigNum::from_hex_str(
751 "87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF\
752 4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B47\
753 58C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B6\
754 3ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5\
755 140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710\
756 C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597",
757 )
758 .unwrap();
759 let g = BigNum::from_hex_str(
760 "3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED\
761 4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A\
762 57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5\
763 045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E\
764 052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67E\
765 B6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659",
766 )
767 .unwrap();
768 let q = BigNum::from_hex_str(
769 "8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3",
770 )
771 .unwrap();
772 let dh = Dh::from_params(p, g, q).unwrap();
773
774 let pkey = PKey::from_dh(dh).unwrap();
775 pkey.dh().unwrap();
776 assert_eq!(pkey.id(), Id::DH);
777 assert!(pkey.rsa().is_err());
778 assert!(pkey.ec_key().is_err());
779 }
780
781 #[test]
782 fn test_raw_accessors() {
783 const ED25519_PRIVATE_KEY_DER: &str = concat!(
784 "302e020100300506032b6570042204207c8c6497f9960d5595d7815f550569e5",
785 "f77764ac97e63e339aaa68cc1512b683"
786 );
787 let pkey =
788 PKey::private_key_from_der(&Vec::from_hex(ED25519_PRIVATE_KEY_DER).unwrap()).unwrap();
789 assert_eq!(pkey.id(), Id::ED25519);
790
791 let priv_len = pkey.raw_private_key_len().unwrap();
792 assert_eq!(priv_len, 32);
793 let mut raw_private_key_buf = [0; 40];
794 let raw_private_key = pkey.raw_private_key(&mut raw_private_key_buf).unwrap();
795 assert_eq!(raw_private_key.len(), 32);
796 assert_ne!(raw_private_key, [0; 32]);
797 pkey.raw_private_key(&mut [0; 5])
798 .expect_err("buffer too small");
799
800 let pub_len = pkey.raw_public_key_len().unwrap();
801 assert_eq!(pub_len, 32);
802 let mut raw_public_key_buf = [0; 40];
803 let raw_public_key = pkey.raw_public_key(&mut raw_public_key_buf).unwrap();
804 assert_eq!(raw_public_key.len(), 32);
805 assert_ne!(raw_public_key, [0; 32]);
806 assert_ne!(raw_public_key, raw_private_key);
807 pkey.raw_public_key(&mut [0; 5])
808 .expect_err("buffer too small");
809 }
810
811 #[test]
812 fn test_ed25519_from_raw_private_public() {
813 const ED25519_PRIVATE_KEY_DER: &str = concat!(
814 "302e020100300506032b6570042204207c8c6497f9960d5595d7815f550569e5",
815 "f77764ac97e63e339aaa68cc1512b683"
816 );
817 let pkey =
818 PKey::private_key_from_der(&Vec::from_hex(ED25519_PRIVATE_KEY_DER).unwrap()).unwrap();
819 let mut raw_private = [0_u8; 32];
820 pkey.raw_private_key(&mut raw_private).unwrap();
821 let mut raw_public = [0_u8; 32];
822 pkey.raw_public_key(&mut raw_public).unwrap();
823
824 let from_private = PKey::from_ed25519_private_key(&raw_private).unwrap();
825 assert_eq!(from_private.id(), Id::ED25519);
826 let from_public = PKey::from_ed25519_public_key(&raw_public).unwrap();
827 assert_eq!(from_public.id(), Id::ED25519);
828 }
829
830 #[test]
831 fn test_x25519_from_raw_private_public() {
832 let private_a = [1_u8; 32];
833 let private_b = [2_u8; 32];
834 let pkey_a = PKey::from_x25519_private_key(&private_a).unwrap();
835 let pkey_b = PKey::from_x25519_private_key(&private_b).unwrap();
836 assert_eq!(pkey_a.id(), Id::X25519);
837 assert_eq!(pkey_b.id(), Id::X25519);
838
839 let mut public_a = [0_u8; 32];
840 let mut public_b = [0_u8; 32];
841 pkey_a.raw_public_key(&mut public_a).unwrap();
842 pkey_b.raw_public_key(&mut public_b).unwrap();
843
844 let public_key_a = PKey::from_x25519_public_key(&public_a).unwrap();
845 let public_key_b = PKey::from_x25519_public_key(&public_b).unwrap();
846 assert_eq!(public_key_a.id(), Id::X25519);
847 assert_eq!(public_key_b.id(), Id::X25519);
848 }
849}