1mod ephemeral;
53
54use crate::ec::encoding::sec1::{
55 marshal_sec1_private_key, marshal_sec1_public_point, marshal_sec1_public_point_into_buffer,
56 parse_sec1_private_bn, parse_sec1_public_point,
57};
58#[cfg(not(feature = "fips"))]
59use crate::ec::verify_evp_key_nid;
60use crate::ec::{evp_key_generate, validate_ec_evp_key};
61use crate::error::{KeyRejected, Unspecified};
62use crate::hex;
63pub use ephemeral::{agree_ephemeral, EphemeralPrivateKey};
64
65use crate::aws_lc::{
66 i2d_ECPrivateKey, EVP_PKEY_get0_EC_KEY, NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1,
67 EVP_PKEY, EVP_PKEY_EC, EVP_PKEY_X25519, NID_X25519,
68};
69
70use crate::buffer::Buffer;
71use crate::ec;
72use crate::ec::encoding::rfc5915::parse_rfc5915_private_key;
73use crate::encoding::{
74 AsBigEndian, AsDer, Curve25519SeedBin, EcPrivateKeyBin, EcPrivateKeyRfc5915Der,
75 EcPublicKeyCompressedBin, EcPublicKeyUncompressedBin, Pkcs8V1Der, PublicKeyX509Der,
76};
77use crate::evp_pkey::No_EVP_PKEY_CTX_consumer;
78use crate::pkcs8::Version;
79use crate::ptr::LcPtr;
80use core::fmt;
81use core::fmt::{Debug, Formatter};
82use core::ptr::null_mut;
83
84#[allow(non_camel_case_types)]
85#[derive(PartialEq, Eq)]
86enum AlgorithmID {
87 ECDH_P256,
88 ECDH_P384,
89 ECDH_P521,
90 X25519,
91}
92
93impl AlgorithmID {
94 #[inline]
95 const fn nid(&self) -> i32 {
96 match self {
97 AlgorithmID::ECDH_P256 => NID_X9_62_prime256v1,
98 AlgorithmID::ECDH_P384 => NID_secp384r1,
99 AlgorithmID::ECDH_P521 => NID_secp521r1,
100 AlgorithmID::X25519 => NID_X25519,
101 }
102 }
103
104 #[inline]
106 const fn pub_key_len(&self) -> usize {
107 match self {
108 AlgorithmID::ECDH_P256 => ec::uncompressed_public_key_size_bytes(256),
109 AlgorithmID::ECDH_P384 => ec::uncompressed_public_key_size_bytes(384),
110 AlgorithmID::ECDH_P521 => ec::uncompressed_public_key_size_bytes(521),
111 AlgorithmID::X25519 => 32,
112 }
113 }
114
115 #[inline]
116 const fn private_key_len(&self) -> usize {
117 match self {
118 AlgorithmID::ECDH_P256 | AlgorithmID::X25519 => 32,
119 AlgorithmID::ECDH_P384 => 48,
120 AlgorithmID::ECDH_P521 => 66,
121 }
122 }
123}
124
125impl Debug for AlgorithmID {
126 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
127 let output = match self {
128 AlgorithmID::ECDH_P256 => "curve: P256",
129 AlgorithmID::ECDH_P384 => "curve: P384",
130 AlgorithmID::ECDH_P521 => "curve: P521",
131 AlgorithmID::X25519 => "curve: Curve25519",
132 };
133 f.write_str(output)
134 }
135}
136
137#[derive(PartialEq, Eq)]
139pub struct Algorithm {
140 id: AlgorithmID,
141}
142
143impl Debug for Algorithm {
144 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
145 f.write_str(&format!("Algorithm {{ {:?} }}", self.id))
146 }
147}
148
149pub const ECDH_P256: Algorithm = Algorithm {
151 id: AlgorithmID::ECDH_P256,
152};
153
154pub const ECDH_P384: Algorithm = Algorithm {
156 id: AlgorithmID::ECDH_P384,
157};
158
159pub const ECDH_P521: Algorithm = Algorithm {
161 id: AlgorithmID::ECDH_P521,
162};
163
164pub const X25519: Algorithm = Algorithm {
173 id: AlgorithmID::X25519,
174};
175
176#[allow(non_camel_case_types)]
177enum KeyInner {
178 ECDH_P256(LcPtr<EVP_PKEY>),
179 ECDH_P384(LcPtr<EVP_PKEY>),
180 ECDH_P521(LcPtr<EVP_PKEY>),
181 X25519(LcPtr<EVP_PKEY>),
182}
183
184impl Clone for KeyInner {
185 fn clone(&self) -> KeyInner {
186 match self {
187 KeyInner::ECDH_P256(evp_pkey) => KeyInner::ECDH_P256(evp_pkey.clone()),
188 KeyInner::ECDH_P384(evp_pkey) => KeyInner::ECDH_P384(evp_pkey.clone()),
189 KeyInner::ECDH_P521(evp_pkey) => KeyInner::ECDH_P521(evp_pkey.clone()),
190 KeyInner::X25519(evp_pkey) => KeyInner::X25519(evp_pkey.clone()),
191 }
192 }
193}
194
195pub struct PrivateKey {
199 inner_key: KeyInner,
200}
201
202impl KeyInner {
203 #[inline]
204 fn algorithm(&self) -> &'static Algorithm {
205 match self {
206 KeyInner::ECDH_P256(..) => &ECDH_P256,
207 KeyInner::ECDH_P384(..) => &ECDH_P384,
208 KeyInner::ECDH_P521(..) => &ECDH_P521,
209 KeyInner::X25519(..) => &X25519,
210 }
211 }
212
213 fn get_evp_pkey(&self) -> &LcPtr<EVP_PKEY> {
214 match self {
215 KeyInner::ECDH_P256(evp_pkey)
216 | KeyInner::ECDH_P384(evp_pkey)
217 | KeyInner::ECDH_P521(evp_pkey)
218 | KeyInner::X25519(evp_pkey) => evp_pkey,
219 }
220 }
221}
222
223unsafe impl Send for PrivateKey {}
231unsafe impl Sync for PrivateKey {}
232
233impl Debug for PrivateKey {
234 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
235 f.write_str(&format!(
236 "PrivateKey {{ algorithm: {:?} }}",
237 self.inner_key.algorithm()
238 ))
239 }
240}
241
242impl PrivateKey {
243 fn new(alg: &'static Algorithm, evp_pkey: LcPtr<EVP_PKEY>) -> Self {
244 match alg.id {
245 AlgorithmID::X25519 => Self {
246 inner_key: KeyInner::X25519(evp_pkey),
247 },
248 AlgorithmID::ECDH_P256 => Self {
249 inner_key: KeyInner::ECDH_P256(evp_pkey),
250 },
251 AlgorithmID::ECDH_P384 => Self {
252 inner_key: KeyInner::ECDH_P384(evp_pkey),
253 },
254 AlgorithmID::ECDH_P521 => Self {
255 inner_key: KeyInner::ECDH_P521(evp_pkey),
256 },
257 }
258 }
259
260 #[inline]
261 pub fn generate(alg: &'static Algorithm) -> Result<Self, Unspecified> {
271 let evp_pkey = match alg.id {
272 AlgorithmID::X25519 => generate_x25519()?,
273 _ => evp_key_generate(alg.id.nid())?,
274 };
275 Ok(Self::new(alg, evp_pkey))
276 }
277
278 pub fn from_private_key_der(
291 alg: &'static Algorithm,
292 key_bytes: &[u8],
293 ) -> Result<Self, KeyRejected> {
294 if AlgorithmID::X25519 == alg.id {
295 return Err(KeyRejected::invalid_encoding());
296 }
297 let evp_pkey = LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(key_bytes, EVP_PKEY_EC)
298 .or(parse_rfc5915_private_key(key_bytes, alg.id.nid()))?;
299 #[cfg(not(feature = "fips"))]
300 verify_evp_key_nid(&evp_pkey.as_const(), alg.id.nid())?;
301 #[cfg(feature = "fips")]
302 validate_ec_evp_key(&evp_pkey.as_const(), alg.id.nid())?;
303
304 Ok(Self::new(alg, evp_pkey))
305 }
306
307 pub fn from_private_key(
316 alg: &'static Algorithm,
317 key_bytes: &[u8],
318 ) -> Result<Self, KeyRejected> {
319 if key_bytes.len() != alg.id.private_key_len() {
320 return Err(KeyRejected::wrong_algorithm());
321 }
322 let evp_pkey = if AlgorithmID::X25519 == alg.id {
323 LcPtr::<EVP_PKEY>::parse_raw_private_key(key_bytes, EVP_PKEY_X25519)?
324 } else {
325 parse_sec1_private_bn(key_bytes, alg.id.nid())?
326 };
327 Ok(Self::new(alg, evp_pkey))
328 }
329
330 #[cfg(test)]
331 #[allow(missing_docs, clippy::missing_errors_doc)]
332 pub fn generate_for_test(
333 alg: &'static Algorithm,
334 rng: &dyn crate::rand::SecureRandom,
335 ) -> Result<Self, Unspecified> {
336 match alg.id {
337 AlgorithmID::X25519 => {
338 let mut priv_key = [0u8; AlgorithmID::X25519.private_key_len()];
339 rng.fill(&mut priv_key)?;
340 Self::from_x25519_private_key(&priv_key)
341 }
342 AlgorithmID::ECDH_P256 => {
343 let mut priv_key = [0u8; AlgorithmID::ECDH_P256.private_key_len()];
344 rng.fill(&mut priv_key)?;
345 Self::from_p256_private_key(&priv_key)
346 }
347 AlgorithmID::ECDH_P384 => {
348 let mut priv_key = [0u8; AlgorithmID::ECDH_P384.private_key_len()];
349 rng.fill(&mut priv_key)?;
350 Self::from_p384_private_key(&priv_key)
351 }
352 AlgorithmID::ECDH_P521 => {
353 let mut priv_key = [0u8; AlgorithmID::ECDH_P521.private_key_len()];
354 rng.fill(&mut priv_key)?;
355 Self::from_p521_private_key(&priv_key)
356 }
357 }
358 }
359
360 #[cfg(test)]
361 fn from_x25519_private_key(
362 priv_key: &[u8; AlgorithmID::X25519.private_key_len()],
363 ) -> Result<Self, Unspecified> {
364 let pkey = LcPtr::<EVP_PKEY>::parse_raw_private_key(priv_key, EVP_PKEY_X25519)?;
365
366 Ok(PrivateKey {
367 inner_key: KeyInner::X25519(pkey),
368 })
369 }
370
371 #[cfg(test)]
372 fn from_p256_private_key(priv_key: &[u8]) -> Result<Self, Unspecified> {
373 let pkey = parse_sec1_private_bn(priv_key, ECDH_P256.id.nid())?;
374 Ok(PrivateKey {
375 inner_key: KeyInner::ECDH_P256(pkey),
376 })
377 }
378
379 #[cfg(test)]
380 fn from_p384_private_key(priv_key: &[u8]) -> Result<Self, Unspecified> {
381 let pkey = parse_sec1_private_bn(priv_key, ECDH_P384.id.nid())?;
382 Ok(PrivateKey {
383 inner_key: KeyInner::ECDH_P384(pkey),
384 })
385 }
386
387 #[cfg(test)]
388 fn from_p521_private_key(priv_key: &[u8]) -> Result<Self, Unspecified> {
389 let pkey = parse_sec1_private_bn(priv_key, ECDH_P521.id.nid())?;
390 Ok(PrivateKey {
391 inner_key: KeyInner::ECDH_P521(pkey),
392 })
393 }
394
395 pub fn compute_public_key(&self) -> Result<PublicKey, Unspecified> {
400 match &self.inner_key {
401 KeyInner::ECDH_P256(evp_pkey)
402 | KeyInner::ECDH_P384(evp_pkey)
403 | KeyInner::ECDH_P521(evp_pkey) => {
404 let mut public_key = [0u8; MAX_PUBLIC_KEY_LEN];
405 let len = marshal_sec1_public_point_into_buffer(&mut public_key, evp_pkey, false)?;
406 Ok(PublicKey {
407 inner_key: self.inner_key.clone(),
408 key_bytes: public_key,
409 len,
410 })
411 }
412 KeyInner::X25519(priv_key) => {
413 let mut buffer = [0u8; MAX_PUBLIC_KEY_LEN];
414 let out_len = priv_key
415 .as_const()
416 .marshal_raw_public_to_buffer(&mut buffer)?;
417 Ok(PublicKey {
418 inner_key: self.inner_key.clone(),
419 key_bytes: buffer,
420 len: out_len,
421 })
422 }
423 }
424 }
425
426 #[inline]
428 #[must_use]
429 pub fn algorithm(&self) -> &'static Algorithm {
430 self.inner_key.algorithm()
431 }
432}
433
434impl AsDer<EcPrivateKeyRfc5915Der<'static>> for PrivateKey {
435 fn as_der(&self) -> Result<EcPrivateKeyRfc5915Der<'static>, Unspecified> {
442 if AlgorithmID::X25519 == self.inner_key.algorithm().id {
443 return Err(Unspecified);
444 }
445
446 let mut outp = null_mut::<u8>();
447 let ec_key = {
448 self.inner_key
449 .get_evp_pkey()
450 .project_const_lifetime(unsafe {
451 |evp_pkey| EVP_PKEY_get0_EC_KEY(*evp_pkey.as_const())
452 })?
453 };
454 let length = usize::try_from(unsafe { i2d_ECPrivateKey(*ec_key, &mut outp) })
455 .map_err(|_| Unspecified)?;
456 let mut outp = LcPtr::new(outp)?;
457 Ok(EcPrivateKeyRfc5915Der::take_from_slice(unsafe {
458 core::slice::from_raw_parts_mut(*outp.as_mut(), length)
459 }))
460 }
461}
462
463impl AsDer<Pkcs8V1Der<'static>> for PrivateKey {
464 fn as_der(&self) -> Result<Pkcs8V1Der<'static>, Unspecified> {
471 if AlgorithmID::X25519 == self.inner_key.algorithm().id {
472 return Err(Unspecified);
473 }
474
475 Ok(Pkcs8V1Der::new(
476 self.inner_key
477 .get_evp_pkey()
478 .as_const()
479 .marshal_rfc5208_private_key(Version::V1)?,
480 ))
481 }
482}
483
484impl AsBigEndian<EcPrivateKeyBin<'static>> for PrivateKey {
485 fn as_be_bytes(&self) -> Result<EcPrivateKeyBin<'static>, Unspecified> {
492 if AlgorithmID::X25519 == self.inner_key.algorithm().id {
493 return Err(Unspecified);
494 }
495 let buffer = marshal_sec1_private_key(self.inner_key.get_evp_pkey())?;
496 Ok(EcPrivateKeyBin::new(buffer))
497 }
498}
499
500impl AsBigEndian<Curve25519SeedBin<'static>> for PrivateKey {
501 fn as_be_bytes(&self) -> Result<Curve25519SeedBin<'static>, Unspecified> {
508 if AlgorithmID::X25519 != self.inner_key.algorithm().id {
509 return Err(Unspecified);
510 }
511 let evp_pkey = self.inner_key.get_evp_pkey();
512 Ok(Curve25519SeedBin::new(
513 evp_pkey.as_const().marshal_raw_private_key()?,
514 ))
515 }
516}
517
518pub(crate) fn generate_x25519() -> Result<LcPtr<EVP_PKEY>, Unspecified> {
519 LcPtr::<EVP_PKEY>::generate(EVP_PKEY_X25519, No_EVP_PKEY_CTX_consumer)
520}
521
522const MAX_PUBLIC_KEY_LEN: usize = ec::PUBLIC_KEY_MAX_LEN;
523
524pub struct PublicKey {
526 inner_key: KeyInner,
527 key_bytes: [u8; MAX_PUBLIC_KEY_LEN],
528 len: usize,
529}
530
531impl PublicKey {
532 #[must_use]
534 pub fn algorithm(&self) -> &'static Algorithm {
535 self.inner_key.algorithm()
536 }
537}
538
539unsafe impl Send for PublicKey {}
547unsafe impl Sync for PublicKey {}
548
549impl Debug for PublicKey {
550 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
551 f.write_str(&format!(
552 "PublicKey {{ algorithm: {:?}, bytes: \"{}\" }}",
553 self.inner_key.algorithm(),
554 hex::encode(&self.key_bytes[0..self.len])
555 ))
556 }
557}
558
559impl AsRef<[u8]> for PublicKey {
560 fn as_ref(&self) -> &[u8] {
564 &self.key_bytes[0..self.len]
565 }
566}
567
568impl Clone for PublicKey {
569 fn clone(&self) -> Self {
570 PublicKey {
571 inner_key: self.inner_key.clone(),
572 key_bytes: self.key_bytes,
573 len: self.len,
574 }
575 }
576}
577
578impl AsDer<PublicKeyX509Der<'static>> for PublicKey {
579 fn as_der(&self) -> Result<PublicKeyX509Der<'static>, crate::error::Unspecified> {
583 match &self.inner_key {
584 KeyInner::ECDH_P256(evp_pkey)
585 | KeyInner::ECDH_P384(evp_pkey)
586 | KeyInner::ECDH_P521(evp_pkey)
587 | KeyInner::X25519(evp_pkey) => {
588 let der = evp_pkey.as_const().marshal_rfc5280_public_key()?;
589 Ok(PublicKeyX509Der::from(Buffer::new(der)))
590 }
591 }
592 }
593}
594
595impl AsBigEndian<EcPublicKeyCompressedBin<'static>> for PublicKey {
596 fn as_be_bytes(&self) -> Result<EcPublicKeyCompressedBin<'static>, crate::error::Unspecified> {
600 let evp_pkey = match &self.inner_key {
601 KeyInner::ECDH_P256(evp_pkey)
602 | KeyInner::ECDH_P384(evp_pkey)
603 | KeyInner::ECDH_P521(evp_pkey) => evp_pkey,
604 KeyInner::X25519(_) => return Err(Unspecified),
605 };
606 let pub_point = marshal_sec1_public_point(evp_pkey, true)?;
607 Ok(EcPublicKeyCompressedBin::new(pub_point))
608 }
609}
610
611impl AsBigEndian<EcPublicKeyUncompressedBin<'static>> for PublicKey {
612 fn as_be_bytes(
619 &self,
620 ) -> Result<EcPublicKeyUncompressedBin<'static>, crate::error::Unspecified> {
621 if self.algorithm().id == AlgorithmID::X25519 {
622 return Err(Unspecified);
623 }
624
625 let mut buffer = vec![0u8; self.len];
626 buffer.copy_from_slice(&self.key_bytes[0..self.len]);
627
628 Ok(EcPublicKeyUncompressedBin::new(buffer))
629 }
630}
631
632#[derive(Clone)]
634pub struct UnparsedPublicKey<B: AsRef<[u8]>> {
635 alg: &'static Algorithm,
636 bytes: B,
637}
638
639impl<B: Copy + AsRef<[u8]>> Copy for UnparsedPublicKey<B> {}
640
641impl<B: Debug + AsRef<[u8]>> Debug for UnparsedPublicKey<B> {
642 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
643 f.write_str(&format!(
644 "UnparsedPublicKey {{ algorithm: {:?}, bytes: {:?} }}",
645 self.alg,
646 hex::encode(self.bytes.as_ref())
647 ))
648 }
649}
650
651impl<B: AsRef<[u8]>> UnparsedPublicKey<B> {
652 pub fn new(algorithm: &'static Algorithm, bytes: B) -> Self {
654 UnparsedPublicKey {
655 alg: algorithm,
656 bytes,
657 }
658 }
659
660 pub fn algorithm(&self) -> &'static Algorithm {
662 self.alg
663 }
664
665 pub fn bytes(&self) -> &B {
667 &self.bytes
668 }
669}
670
671#[derive(Debug, Clone)]
677pub struct ParsedPublicKey {
678 format: ParsedPublicKeyFormat,
679 nid: i32,
680 key: LcPtr<EVP_PKEY>,
681 bytes: Box<[u8]>,
682}
683
684unsafe impl Send for ParsedPublicKey {}
692unsafe impl Sync for ParsedPublicKey {}
693
694#[derive(Clone, Copy, PartialEq, Eq, Debug)]
695#[non_exhaustive]
700pub enum ParsedPublicKeyFormat {
701 X509,
703 Uncompressed,
705 Compressed,
707 Hybrid,
709 Raw,
711 Unknown,
713}
714
715impl ParsedPublicKey {
717 fn nid(&self) -> i32 {
718 self.nid
719 }
720
721 #[must_use]
723 pub fn format(&self) -> ParsedPublicKeyFormat {
724 self.format
725 }
726
727 pub(crate) fn key(&self) -> &LcPtr<EVP_PKEY> {
728 &self.key
729 }
730
731 #[must_use]
733 #[allow(non_upper_case_globals)]
734 pub fn alg(&self) -> &'static Algorithm {
735 match self.nid() {
736 NID_X25519 => &X25519,
737 NID_X9_62_prime256v1 => &ECDH_P256,
738 NID_secp384r1 => &ECDH_P384,
739 NID_secp521r1 => &ECDH_P521,
740 _ => unreachable!("Unreachable agreement algorithm nid: {}", self.nid()),
741 }
742 }
743}
744
745impl ParsedPublicKey {
746 #[allow(non_upper_case_globals)]
747 pub(crate) fn new(bytes: impl AsRef<[u8]>, nid: i32) -> Result<Self, KeyRejected> {
748 let bytes = bytes.as_ref().to_vec().into_boxed_slice();
749 if bytes.is_empty() {
750 return Err(KeyRejected::unspecified());
751 }
752 match nid {
753 NID_X25519 => {
754 let format: ParsedPublicKeyFormat;
755 let key = if let Ok(evp_pkey) =
756 LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(&bytes, EVP_PKEY_X25519)
757 {
758 format = ParsedPublicKeyFormat::X509;
759 evp_pkey
760 } else {
761 format = ParsedPublicKeyFormat::Raw;
762 try_parse_x25519_public_key_raw_bytes(&bytes)?
763 };
764
765 Ok(ParsedPublicKey {
766 format,
767 nid,
768 key,
769 bytes,
770 })
771 }
772 NID_X9_62_prime256v1 | NID_secp384r1 | NID_secp521r1 => {
773 let format: ParsedPublicKeyFormat;
774 let key = if let Ok(evp_pkey) =
775 LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(&bytes, EVP_PKEY_EC)
776 {
777 validate_ec_evp_key(&evp_pkey.as_const(), nid)?;
778 format = ParsedPublicKeyFormat::X509;
779 evp_pkey
780 } else if let Ok(evp_pkey) = parse_sec1_public_point(&bytes, nid) {
781 format = match bytes[0] {
782 0x02 | 0x03 => ParsedPublicKeyFormat::Compressed,
783 0x04 => ParsedPublicKeyFormat::Uncompressed,
784 0x06 | 0x07 => ParsedPublicKeyFormat::Hybrid,
785 _ => ParsedPublicKeyFormat::Unknown,
786 };
787 evp_pkey
788 } else {
789 return Err(KeyRejected::invalid_encoding());
790 };
791
792 Ok(ParsedPublicKey {
793 format,
794 nid,
795 key,
796 bytes,
797 })
798 }
799 _ => Err(KeyRejected::unspecified()),
800 }
801 }
802}
803
804impl AsRef<[u8]> for ParsedPublicKey {
805 fn as_ref(&self) -> &[u8] {
807 &self.bytes
808 }
809}
810
811impl<B: AsRef<[u8]>> UnparsedPublicKey<B> {
812 #[allow(dead_code)]
813 fn parse(&self) -> Result<ParsedPublicKey, KeyRejected> {
814 ParsedPublicKey::new(&self.bytes, self.alg.id.nid())
815 }
816}
817
818impl<B: AsRef<[u8]>> TryFrom<&UnparsedPublicKey<B>> for ParsedPublicKey {
819 type Error = KeyRejected;
820 fn try_from(upk: &UnparsedPublicKey<B>) -> Result<Self, Self::Error> {
821 upk.parse()
822 }
823}
824
825impl<B: AsRef<[u8]>> TryFrom<UnparsedPublicKey<B>> for ParsedPublicKey {
826 type Error = KeyRejected;
827 fn try_from(upk: UnparsedPublicKey<B>) -> Result<Self, Self::Error> {
828 upk.parse()
829 }
830}
831
832#[inline]
860#[allow(clippy::missing_panics_doc)]
861pub fn agree<B: TryInto<ParsedPublicKey>, F, R, E>(
862 my_private_key: &PrivateKey,
863 peer_public_key: B,
864 error_value: E,
865 kdf: F,
866) -> Result<R, E>
867where
868 F: FnOnce(&[u8]) -> Result<R, E>,
869{
870 let expected_alg = my_private_key.algorithm();
871
872 let parse_result = peer_public_key.try_into();
873
874 if let Ok(peer_pub_key) = parse_result {
875 if peer_pub_key.alg() != expected_alg {
876 return Err(error_value);
877 }
878 let secret = my_private_key
879 .inner_key
880 .get_evp_pkey()
881 .agree(peer_pub_key.key())
882 .or(Err(error_value))?;
883
884 kdf(secret.as_ref())
885 } else {
886 Err(error_value)
887 }
888}
889
890fn try_parse_x25519_public_key_raw_bytes(key_bytes: &[u8]) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
891 let expected_pub_key_len = X25519.id.pub_key_len();
892 if key_bytes.len() != expected_pub_key_len {
893 return Err(KeyRejected::invalid_encoding());
894 }
895
896 LcPtr::<EVP_PKEY>::parse_raw_public_key(key_bytes, EVP_PKEY_X25519)
897}
898
899#[cfg(test)]
900mod agreement_tests;
901#[cfg(test)]
902mod parsed_public_key_tests;