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,
57};
58#[cfg(feature = "fips")]
59use crate::ec::validate_ec_evp_key;
60#[cfg(not(feature = "fips"))]
61use crate::ec::verify_evp_key_nid;
62use crate::ec::{encoding, evp_key_generate};
63use crate::error::{KeyRejected, Unspecified};
64use crate::hex;
65pub use ephemeral::{agree_ephemeral, EphemeralPrivateKey};
66
67use crate::aws_lc::{
68 EVP_PKEY_derive, EVP_PKEY_derive_init, EVP_PKEY_derive_set_peer, EVP_PKEY_get0_EC_KEY,
69 NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, EVP_PKEY, EVP_PKEY_EC, EVP_PKEY_X25519,
70 NID_X25519,
71};
72
73use crate::buffer::Buffer;
74use crate::ec;
75use crate::ec::encoding::rfc5915::parse_rfc5915_private_key;
76use crate::encoding::{
77 AsBigEndian, AsDer, Curve25519SeedBin, EcPrivateKeyBin, EcPrivateKeyRfc5915Der,
78 EcPublicKeyCompressedBin, EcPublicKeyUncompressedBin, Pkcs8V1Der, PublicKeyX509Der,
79};
80use crate::evp_pkey::No_EVP_PKEY_CTX_consumer;
81use crate::fips::indicator_check;
82use crate::pkcs8::Version;
83use crate::ptr::LcPtr;
84use core::fmt;
85use core::fmt::{Debug, Formatter};
86use core::ptr::null_mut;
87
88#[allow(non_camel_case_types)]
89#[derive(PartialEq, Eq)]
90enum AlgorithmID {
91 ECDH_P256,
92 ECDH_P384,
93 ECDH_P521,
94 X25519,
95}
96
97impl AlgorithmID {
98 #[inline]
99 const fn nid(&self) -> i32 {
100 match self {
101 AlgorithmID::ECDH_P256 => NID_X9_62_prime256v1,
102 AlgorithmID::ECDH_P384 => NID_secp384r1,
103 AlgorithmID::ECDH_P521 => NID_secp521r1,
104 AlgorithmID::X25519 => NID_X25519,
105 }
106 }
107
108 #[inline]
110 const fn pub_key_len(&self) -> usize {
111 match self {
112 AlgorithmID::ECDH_P256 => ec::uncompressed_public_key_size_bytes(256),
113 AlgorithmID::ECDH_P384 => ec::uncompressed_public_key_size_bytes(384),
114 AlgorithmID::ECDH_P521 => ec::uncompressed_public_key_size_bytes(521),
115 AlgorithmID::X25519 => 32,
116 }
117 }
118
119 #[inline]
120 const fn private_key_len(&self) -> usize {
121 match self {
122 AlgorithmID::ECDH_P256 | AlgorithmID::X25519 => 32,
123 AlgorithmID::ECDH_P384 => 48,
124 AlgorithmID::ECDH_P521 => 66,
125 }
126 }
127}
128
129impl Debug for AlgorithmID {
130 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
131 let output = match self {
132 AlgorithmID::ECDH_P256 => "curve: P256",
133 AlgorithmID::ECDH_P384 => "curve: P384",
134 AlgorithmID::ECDH_P521 => "curve: P521",
135 AlgorithmID::X25519 => "curve: Curve25519",
136 };
137 f.write_str(output)
138 }
139}
140
141#[derive(PartialEq, Eq)]
143pub struct Algorithm {
144 id: AlgorithmID,
145}
146
147impl Debug for Algorithm {
148 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
149 f.write_str(&format!("Algorithm {{ {:?} }}", self.id))
150 }
151}
152
153pub const ECDH_P256: Algorithm = Algorithm {
155 id: AlgorithmID::ECDH_P256,
156};
157
158pub const ECDH_P384: Algorithm = Algorithm {
160 id: AlgorithmID::ECDH_P384,
161};
162
163pub const ECDH_P521: Algorithm = Algorithm {
165 id: AlgorithmID::ECDH_P521,
166};
167
168pub const X25519: Algorithm = Algorithm {
177 id: AlgorithmID::X25519,
178};
179
180#[allow(non_camel_case_types)]
181enum KeyInner {
182 ECDH_P256(LcPtr<EVP_PKEY>),
183 ECDH_P384(LcPtr<EVP_PKEY>),
184 ECDH_P521(LcPtr<EVP_PKEY>),
185 X25519(LcPtr<EVP_PKEY>),
186}
187
188impl Clone for KeyInner {
189 fn clone(&self) -> KeyInner {
190 match self {
191 KeyInner::ECDH_P256(evp_pkey) => KeyInner::ECDH_P256(evp_pkey.clone()),
192 KeyInner::ECDH_P384(evp_pkey) => KeyInner::ECDH_P384(evp_pkey.clone()),
193 KeyInner::ECDH_P521(evp_pkey) => KeyInner::ECDH_P521(evp_pkey.clone()),
194 KeyInner::X25519(evp_pkey) => KeyInner::X25519(evp_pkey.clone()),
195 }
196 }
197}
198
199pub struct PrivateKey {
203 inner_key: KeyInner,
204}
205
206impl KeyInner {
207 #[inline]
208 fn algorithm(&self) -> &'static Algorithm {
209 match self {
210 KeyInner::ECDH_P256(..) => &ECDH_P256,
211 KeyInner::ECDH_P384(..) => &ECDH_P384,
212 KeyInner::ECDH_P521(..) => &ECDH_P521,
213 KeyInner::X25519(..) => &X25519,
214 }
215 }
216
217 fn get_evp_pkey(&self) -> &LcPtr<EVP_PKEY> {
218 match self {
219 KeyInner::ECDH_P256(evp_pkey)
220 | KeyInner::ECDH_P384(evp_pkey)
221 | KeyInner::ECDH_P521(evp_pkey)
222 | KeyInner::X25519(evp_pkey) => evp_pkey,
223 }
224 }
225}
226
227unsafe impl Send for PrivateKey {}
228
229unsafe impl Sync for PrivateKey {}
236
237impl Debug for PrivateKey {
238 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
239 f.write_str(&format!(
240 "PrivateKey {{ algorithm: {:?} }}",
241 self.inner_key.algorithm()
242 ))
243 }
244}
245
246impl PrivateKey {
247 fn new(alg: &'static Algorithm, evp_pkey: LcPtr<EVP_PKEY>) -> Self {
248 match alg.id {
249 AlgorithmID::X25519 => Self {
250 inner_key: KeyInner::X25519(evp_pkey),
251 },
252 AlgorithmID::ECDH_P256 => Self {
253 inner_key: KeyInner::ECDH_P256(evp_pkey),
254 },
255 AlgorithmID::ECDH_P384 => Self {
256 inner_key: KeyInner::ECDH_P384(evp_pkey),
257 },
258 AlgorithmID::ECDH_P521 => Self {
259 inner_key: KeyInner::ECDH_P521(evp_pkey),
260 },
261 }
262 }
263
264 #[inline]
265 pub fn generate(alg: &'static Algorithm) -> Result<Self, Unspecified> {
275 let evp_pkey = match alg.id {
276 AlgorithmID::X25519 => generate_x25519()?,
277 _ => evp_key_generate(alg.id.nid())?,
278 };
279 Ok(Self::new(alg, evp_pkey))
280 }
281
282 pub fn from_private_key_der(
295 alg: &'static Algorithm,
296 key_bytes: &[u8],
297 ) -> Result<Self, KeyRejected> {
298 if AlgorithmID::X25519 == alg.id {
299 return Err(KeyRejected::invalid_encoding());
300 }
301 let evp_pkey = LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(key_bytes, EVP_PKEY_EC)
302 .or(parse_rfc5915_private_key(key_bytes, alg.id.nid()))?;
303 #[cfg(not(feature = "fips"))]
304 verify_evp_key_nid(&evp_pkey.as_const(), alg.id.nid())?;
305 #[cfg(feature = "fips")]
306 validate_ec_evp_key(&evp_pkey.as_const(), alg.id.nid())?;
307
308 Ok(Self::new(alg, evp_pkey))
309 }
310
311 pub fn from_private_key(
320 alg: &'static Algorithm,
321 key_bytes: &[u8],
322 ) -> Result<Self, KeyRejected> {
323 if key_bytes.len() != alg.id.private_key_len() {
324 return Err(KeyRejected::wrong_algorithm());
325 }
326 let evp_pkey = if AlgorithmID::X25519 == alg.id {
327 LcPtr::<EVP_PKEY>::parse_raw_private_key(key_bytes, EVP_PKEY_X25519)?
328 } else {
329 parse_sec1_private_bn(key_bytes, alg.id.nid())?
330 };
331 Ok(Self::new(alg, evp_pkey))
332 }
333
334 #[cfg(test)]
335 #[allow(missing_docs, clippy::missing_errors_doc)]
336 pub fn generate_for_test(
337 alg: &'static Algorithm,
338 rng: &dyn crate::rand::SecureRandom,
339 ) -> Result<Self, Unspecified> {
340 match alg.id {
341 AlgorithmID::X25519 => {
342 let mut priv_key = [0u8; AlgorithmID::X25519.private_key_len()];
343 rng.fill(&mut priv_key)?;
344 Self::from_x25519_private_key(&priv_key)
345 }
346 AlgorithmID::ECDH_P256 => {
347 let mut priv_key = [0u8; AlgorithmID::ECDH_P256.private_key_len()];
348 rng.fill(&mut priv_key)?;
349 Self::from_p256_private_key(&priv_key)
350 }
351 AlgorithmID::ECDH_P384 => {
352 let mut priv_key = [0u8; AlgorithmID::ECDH_P384.private_key_len()];
353 rng.fill(&mut priv_key)?;
354 Self::from_p384_private_key(&priv_key)
355 }
356 AlgorithmID::ECDH_P521 => {
357 let mut priv_key = [0u8; AlgorithmID::ECDH_P521.private_key_len()];
358 rng.fill(&mut priv_key)?;
359 Self::from_p521_private_key(&priv_key)
360 }
361 }
362 }
363
364 #[cfg(test)]
365 fn from_x25519_private_key(
366 priv_key: &[u8; AlgorithmID::X25519.private_key_len()],
367 ) -> Result<Self, Unspecified> {
368 let pkey = LcPtr::<EVP_PKEY>::parse_raw_private_key(priv_key, EVP_PKEY_X25519)?;
369
370 Ok(PrivateKey {
371 inner_key: KeyInner::X25519(pkey),
372 })
373 }
374
375 #[cfg(test)]
376 fn from_p256_private_key(priv_key: &[u8]) -> Result<Self, Unspecified> {
377 let pkey = parse_sec1_private_bn(priv_key, ECDH_P256.id.nid())?;
378 Ok(PrivateKey {
379 inner_key: KeyInner::ECDH_P256(pkey),
380 })
381 }
382
383 #[cfg(test)]
384 fn from_p384_private_key(priv_key: &[u8]) -> Result<Self, Unspecified> {
385 let pkey = parse_sec1_private_bn(priv_key, ECDH_P384.id.nid())?;
386 Ok(PrivateKey {
387 inner_key: KeyInner::ECDH_P384(pkey),
388 })
389 }
390
391 #[cfg(test)]
392 fn from_p521_private_key(priv_key: &[u8]) -> Result<Self, Unspecified> {
393 let pkey = parse_sec1_private_bn(priv_key, ECDH_P521.id.nid())?;
394 Ok(PrivateKey {
395 inner_key: KeyInner::ECDH_P521(pkey),
396 })
397 }
398
399 pub fn compute_public_key(&self) -> Result<PublicKey, Unspecified> {
404 match &self.inner_key {
405 KeyInner::ECDH_P256(evp_pkey)
406 | KeyInner::ECDH_P384(evp_pkey)
407 | KeyInner::ECDH_P521(evp_pkey) => {
408 let mut public_key = [0u8; MAX_PUBLIC_KEY_LEN];
409 let len = marshal_sec1_public_point_into_buffer(&mut public_key, evp_pkey, false)?;
410 Ok(PublicKey {
411 inner_key: self.inner_key.clone(),
412 key_bytes: public_key,
413 len,
414 })
415 }
416 KeyInner::X25519(priv_key) => {
417 let mut buffer = [0u8; MAX_PUBLIC_KEY_LEN];
418 let out_len = priv_key
419 .as_const()
420 .marshal_raw_public_to_buffer(&mut buffer)?;
421 Ok(PublicKey {
422 inner_key: self.inner_key.clone(),
423 key_bytes: buffer,
424 len: out_len,
425 })
426 }
427 }
428 }
429
430 #[inline]
432 #[must_use]
433 pub fn algorithm(&self) -> &'static Algorithm {
434 self.inner_key.algorithm()
435 }
436}
437
438impl AsDer<EcPrivateKeyRfc5915Der<'static>> for PrivateKey {
439 fn as_der(&self) -> Result<EcPrivateKeyRfc5915Der<'static>, Unspecified> {
446 if AlgorithmID::X25519 == self.inner_key.algorithm().id {
447 return Err(Unspecified);
448 }
449
450 let mut outp = null_mut::<u8>();
451 let ec_key = {
452 self.inner_key
453 .get_evp_pkey()
454 .project_const_lifetime(unsafe {
455 |evp_pkey| EVP_PKEY_get0_EC_KEY(*evp_pkey.as_const())
456 })?
457 };
458 let length = usize::try_from(unsafe { aws_lc::i2d_ECPrivateKey(*ec_key, &mut outp) })
459 .map_err(|_| Unspecified)?;
460 let mut outp = LcPtr::new(outp)?;
461 Ok(EcPrivateKeyRfc5915Der::take_from_slice(unsafe {
462 core::slice::from_raw_parts_mut(*outp.as_mut(), length)
463 }))
464 }
465}
466
467impl AsDer<Pkcs8V1Der<'static>> for PrivateKey {
468 fn as_der(&self) -> Result<Pkcs8V1Der<'static>, Unspecified> {
475 if AlgorithmID::X25519 == self.inner_key.algorithm().id {
476 return Err(Unspecified);
477 }
478
479 Ok(Pkcs8V1Der::new(
480 self.inner_key
481 .get_evp_pkey()
482 .as_const()
483 .marshal_rfc5208_private_key(Version::V1)?,
484 ))
485 }
486}
487
488impl AsBigEndian<EcPrivateKeyBin<'static>> for PrivateKey {
489 fn as_be_bytes(&self) -> Result<EcPrivateKeyBin<'static>, Unspecified> {
496 if AlgorithmID::X25519 == self.inner_key.algorithm().id {
497 return Err(Unspecified);
498 }
499 let buffer = marshal_sec1_private_key(self.inner_key.get_evp_pkey())?;
500 Ok(EcPrivateKeyBin::new(buffer))
501 }
502}
503
504impl AsBigEndian<Curve25519SeedBin<'static>> for PrivateKey {
505 fn as_be_bytes(&self) -> Result<Curve25519SeedBin<'static>, Unspecified> {
512 if AlgorithmID::X25519 != self.inner_key.algorithm().id {
513 return Err(Unspecified);
514 }
515 let evp_pkey = self.inner_key.get_evp_pkey();
516 Ok(Curve25519SeedBin::new(
517 evp_pkey.as_const().marshal_raw_private_key()?,
518 ))
519 }
520}
521
522pub(crate) fn generate_x25519() -> Result<LcPtr<EVP_PKEY>, Unspecified> {
523 LcPtr::<EVP_PKEY>::generate(EVP_PKEY_X25519, No_EVP_PKEY_CTX_consumer)
524}
525
526const MAX_PUBLIC_KEY_LEN: usize = ec::PUBLIC_KEY_MAX_LEN;
527
528pub struct PublicKey {
530 inner_key: KeyInner,
531 key_bytes: [u8; MAX_PUBLIC_KEY_LEN],
532 len: usize,
533}
534
535impl PublicKey {
536 #[must_use]
538 pub fn algorithm(&self) -> &'static Algorithm {
539 self.inner_key.algorithm()
540 }
541}
542
543unsafe impl Send for PublicKey {}
544unsafe impl Sync for PublicKey {}
545
546impl Debug for PublicKey {
547 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
548 f.write_str(&format!(
549 "PublicKey {{ algorithm: {:?}, bytes: \"{}\" }}",
550 self.inner_key.algorithm(),
551 hex::encode(&self.key_bytes[0..self.len])
552 ))
553 }
554}
555
556impl AsRef<[u8]> for PublicKey {
557 fn as_ref(&self) -> &[u8] {
561 &self.key_bytes[0..self.len]
562 }
563}
564
565impl Clone for PublicKey {
566 fn clone(&self) -> Self {
567 PublicKey {
568 inner_key: self.inner_key.clone(),
569 key_bytes: self.key_bytes,
570 len: self.len,
571 }
572 }
573}
574
575impl AsDer<PublicKeyX509Der<'static>> for PublicKey {
576 fn as_der(&self) -> Result<PublicKeyX509Der<'static>, crate::error::Unspecified> {
580 match &self.inner_key {
581 KeyInner::ECDH_P256(evp_pkey)
582 | KeyInner::ECDH_P384(evp_pkey)
583 | KeyInner::ECDH_P521(evp_pkey)
584 | KeyInner::X25519(evp_pkey) => {
585 let der = evp_pkey.as_const().marshal_rfc5280_public_key()?;
586 Ok(PublicKeyX509Der::from(Buffer::new(der)))
587 }
588 }
589 }
590}
591
592impl AsBigEndian<EcPublicKeyCompressedBin<'static>> for PublicKey {
593 fn as_be_bytes(&self) -> Result<EcPublicKeyCompressedBin<'static>, crate::error::Unspecified> {
597 let evp_pkey = match &self.inner_key {
598 KeyInner::ECDH_P256(evp_pkey)
599 | KeyInner::ECDH_P384(evp_pkey)
600 | KeyInner::ECDH_P521(evp_pkey) => evp_pkey,
601 KeyInner::X25519(_) => return Err(Unspecified),
602 };
603 let pub_point = marshal_sec1_public_point(evp_pkey, true)?;
604 Ok(EcPublicKeyCompressedBin::new(pub_point))
605 }
606}
607
608impl AsBigEndian<EcPublicKeyUncompressedBin<'static>> for PublicKey {
609 fn as_be_bytes(
616 &self,
617 ) -> Result<EcPublicKeyUncompressedBin<'static>, crate::error::Unspecified> {
618 if self.algorithm().id == AlgorithmID::X25519 {
619 return Err(Unspecified);
620 }
621
622 let mut buffer = vec![0u8; self.len];
623 buffer.copy_from_slice(&self.key_bytes[0..self.len]);
624
625 Ok(EcPublicKeyUncompressedBin::new(buffer))
626 }
627}
628
629#[derive(Clone)]
631pub struct UnparsedPublicKey<B: AsRef<[u8]>> {
632 alg: &'static Algorithm,
633 bytes: B,
634}
635
636impl<B: Copy + AsRef<[u8]>> Copy for UnparsedPublicKey<B> {}
637
638impl<B: Debug + AsRef<[u8]>> Debug for UnparsedPublicKey<B> {
639 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
640 f.write_str(&format!(
641 "UnparsedPublicKey {{ algorithm: {:?}, bytes: {:?} }}",
642 self.alg,
643 hex::encode(self.bytes.as_ref())
644 ))
645 }
646}
647
648impl<B: AsRef<[u8]>> UnparsedPublicKey<B> {
649 pub fn new(algorithm: &'static Algorithm, bytes: B) -> Self {
651 UnparsedPublicKey {
652 alg: algorithm,
653 bytes,
654 }
655 }
656
657 pub fn algorithm(&self) -> &'static Algorithm {
659 self.alg
660 }
661
662 pub fn bytes(&self) -> &B {
664 &self.bytes
665 }
666}
667
668#[inline]
696#[allow(clippy::missing_panics_doc)]
697pub fn agree<B: AsRef<[u8]>, F, R, E>(
698 my_private_key: &PrivateKey,
699 peer_public_key: &UnparsedPublicKey<B>,
700 error_value: E,
701 kdf: F,
702) -> Result<R, E>
703where
704 F: FnOnce(&[u8]) -> Result<R, E>,
705{
706 let expected_alg = my_private_key.algorithm();
707 let expected_nid = expected_alg.id.nid();
708
709 if peer_public_key.alg != expected_alg {
710 return Err(error_value);
711 }
712
713 let peer_pub_bytes = peer_public_key.bytes.as_ref();
714
715 let mut buffer = [0u8; MAX_AGREEMENT_SECRET_LEN];
716
717 let secret: &[u8] = match &my_private_key.inner_key {
718 KeyInner::X25519(priv_key) => {
719 x25519_diffie_hellman(&mut buffer, priv_key, peer_pub_bytes).or(Err(error_value))?
720 }
721 KeyInner::ECDH_P256(priv_key)
722 | KeyInner::ECDH_P384(priv_key)
723 | KeyInner::ECDH_P521(priv_key) => {
724 ec_key_ecdh(&mut buffer, priv_key, peer_pub_bytes, expected_nid).or(Err(error_value))?
725 }
726 };
727 kdf(secret)
728}
729
730const MAX_AGREEMENT_SECRET_LEN: usize = AlgorithmID::ECDH_P521.private_key_len();
732
733#[inline]
734#[allow(clippy::needless_pass_by_value)]
735fn ec_key_ecdh<'a>(
736 buffer: &'a mut [u8; MAX_AGREEMENT_SECRET_LEN],
737 priv_key: &LcPtr<EVP_PKEY>,
738 peer_pub_key_bytes: &[u8],
739 nid: i32,
740) -> Result<&'a [u8], Unspecified> {
741 let mut pub_key = encoding::parse_ec_public_key(peer_pub_key_bytes, nid)?;
742
743 let mut pkey_ctx = priv_key.create_EVP_PKEY_CTX()?;
744
745 if 1 != unsafe { EVP_PKEY_derive_init(*pkey_ctx.as_mut()) } {
746 return Err(Unspecified);
747 }
748
749 if 1 != unsafe { EVP_PKEY_derive_set_peer(*pkey_ctx.as_mut(), *pub_key.as_mut()) } {
750 return Err(Unspecified);
751 }
752
753 let mut out_key_len = buffer.len();
754
755 if 1 != indicator_check!(unsafe {
756 EVP_PKEY_derive(*pkey_ctx.as_mut(), buffer.as_mut_ptr(), &mut out_key_len)
757 }) {
758 return Err(Unspecified);
759 }
760
761 if 0 == out_key_len {
762 return Err(Unspecified);
763 }
764
765 Ok(&buffer[0..out_key_len])
766}
767
768#[inline]
769fn x25519_diffie_hellman<'a>(
770 buffer: &'a mut [u8; MAX_AGREEMENT_SECRET_LEN],
771 priv_key: &LcPtr<EVP_PKEY>,
772 peer_pub_key: &[u8],
773) -> Result<&'a [u8], ()> {
774 let mut pkey_ctx = priv_key.create_EVP_PKEY_CTX()?;
775
776 if 1 != unsafe { EVP_PKEY_derive_init(*pkey_ctx.as_mut()) } {
777 return Err(());
778 }
779
780 let mut pub_key = try_parse_x25519_public_key_bytes(peer_pub_key)?;
781
782 if 1 != unsafe { EVP_PKEY_derive_set_peer(*pkey_ctx.as_mut(), *pub_key.as_mut()) } {
783 return Err(());
784 }
785
786 let mut out_key_len = buffer.len();
787
788 if 1 != indicator_check!(unsafe {
789 EVP_PKEY_derive(*pkey_ctx.as_mut(), buffer.as_mut_ptr(), &mut out_key_len)
790 }) {
791 return Err(());
792 }
793
794 debug_assert!(out_key_len == AlgorithmID::X25519.pub_key_len());
795
796 Ok(&buffer[0..AlgorithmID::X25519.pub_key_len()])
797}
798
799pub(crate) fn try_parse_x25519_public_key_bytes(
800 key_bytes: &[u8],
801) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
802 LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(key_bytes, EVP_PKEY_X25519)
803 .or(try_parse_x25519_public_key_raw_bytes(key_bytes))
804}
805
806fn try_parse_x25519_public_key_raw_bytes(key_bytes: &[u8]) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
807 let expected_pub_key_len = X25519.id.pub_key_len();
808 if key_bytes.len() != expected_pub_key_len {
809 return Err(Unspecified);
810 }
811
812 Ok(LcPtr::<EVP_PKEY>::parse_raw_public_key(
813 key_bytes,
814 EVP_PKEY_X25519,
815 )?)
816}
817
818#[cfg(test)]
819mod tests {
820 use crate::agreement::{
821 agree, Algorithm, PrivateKey, PublicKey, UnparsedPublicKey, ECDH_P256, ECDH_P384,
822 ECDH_P521, X25519,
823 };
824 use crate::encoding::{
825 AsBigEndian, AsDer, Curve25519SeedBin, EcPrivateKeyBin, EcPrivateKeyRfc5915Der,
826 EcPublicKeyCompressedBin, EcPublicKeyUncompressedBin, Pkcs8V1Der, PublicKeyX509Der,
827 };
828 use crate::{rand, test};
829
830 #[test]
831 fn test_agreement_x25519() {
832 let alg = &X25519;
833 let peer_public = UnparsedPublicKey::new(
834 alg,
835 test::from_dirty_hex(
836 "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c",
837 ),
838 );
839
840 let my_private = test::from_dirty_hex(
841 "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
842 );
843
844 let my_private = {
845 let rng = test::rand::FixedSliceRandom { bytes: &my_private };
846 PrivateKey::generate_for_test(alg, &rng).unwrap()
847 };
848
849 let my_public = test::from_dirty_hex(
850 "1c9fd88f45606d932a80c71824ae151d15d73e77de38e8e000852e614fae7019",
851 );
852 let output = test::from_dirty_hex(
853 "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552",
854 );
855
856 assert_eq!(my_private.algorithm(), alg);
857
858 let be_private_key_buffer: Curve25519SeedBin = my_private.as_be_bytes().unwrap();
859 let be_private_key =
860 PrivateKey::from_private_key(&X25519, be_private_key_buffer.as_ref()).unwrap();
861 {
862 let result = agree(&be_private_key, &peer_public, (), |key_material| {
863 assert_eq!(key_material, &output[..]);
864 Ok(())
865 });
866 assert_eq!(result, Ok(()));
867 }
868
869 let computed_public = my_private.compute_public_key().unwrap();
870 assert_eq!(computed_public.as_ref(), &my_public[..]);
871
872 assert_eq!(computed_public.algorithm(), alg);
873 {
874 let result = agree(&my_private, &peer_public, (), |key_material| {
875 assert_eq!(key_material, &output[..]);
876 Ok(())
877 });
878 assert_eq!(result, Ok(()));
879 }
880 {
881 let result = agree(&my_private, &peer_public, (), |key_material| {
882 assert_eq!(key_material, &output[..]);
883 Ok(())
884 });
885 assert_eq!(result, Ok(()));
886 }
887 }
888
889 #[test]
890 fn test_agreement_invalid_keys() {
891 fn test_with_key(alg: &'static Algorithm, my_private_key: &PrivateKey, test_key: &[u8]) {
892 assert!(PrivateKey::from_private_key(alg, test_key).is_err());
893 assert!(PrivateKey::from_private_key_der(alg, test_key).is_err());
894 assert!(agree(
895 my_private_key,
896 &UnparsedPublicKey::new(alg, test_key),
897 (),
898 |_| Ok(())
899 )
900 .is_err());
901 }
902
903 let alg_variants: [&'static Algorithm; 4] = [&X25519, &ECDH_P256, &ECDH_P384, &ECDH_P521];
904
905 for alg in alg_variants {
906 let my_private_key = PrivateKey::generate(alg).unwrap();
907
908 let empty_key = [];
909 test_with_key(alg, &my_private_key, &empty_key);
910
911 let wrong_size_key: [u8; 31] = [
912 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
913 23, 24, 25, 26, 27, 28, 29, 30,
914 ];
915 test_with_key(alg, &my_private_key, &wrong_size_key);
916 }
917 }
918
919 #[test]
920 fn test_agreement_ecdh_p256() {
921 let alg = &ECDH_P256;
922 let peer_public = UnparsedPublicKey::new(
923 alg,
924 test::from_dirty_hex(
925 "04D12DFB5289C8D4F81208B70270398C342296970A0BCCB74C736FC7554494BF6356FBF3CA366CC23E8157854C13C58D6AAC23F046ADA30F8353E74F33039872AB",
926 ),
927 );
928 assert_eq!(peer_public.algorithm(), alg);
929 assert_eq!(peer_public.bytes(), &peer_public.bytes);
930
931 let my_private = test::from_dirty_hex(
932 "C88F01F510D9AC3F70A292DAA2316DE544E9AAB8AFE84049C62A9C57862D1433",
933 );
934
935 let my_private = {
936 let rng = test::rand::FixedSliceRandom { bytes: &my_private };
937 PrivateKey::generate_for_test(alg, &rng).unwrap()
938 };
939
940 let my_public = test::from_dirty_hex(
941 "04DAD0B65394221CF9B051E1FECA5787D098DFE637FC90B9EF945D0C37725811805271A0461CDB8252D61F1C456FA3E59AB1F45B33ACCF5F58389E0577B8990BB3",
942 );
943 let output = test::from_dirty_hex(
944 "D6840F6B42F6EDAFD13116E0E12565202FEF8E9ECE7DCE03812464D04B9442DE",
945 );
946
947 assert_eq!(my_private.algorithm(), alg);
948
949 let be_private_key_buffer: EcPrivateKeyBin = my_private.as_be_bytes().unwrap();
950 let be_private_key =
951 PrivateKey::from_private_key(&ECDH_P256, be_private_key_buffer.as_ref()).unwrap();
952 {
953 let result = agree(&be_private_key, &peer_public, (), |key_material| {
954 assert_eq!(key_material, &output[..]);
955 Ok(())
956 });
957 assert_eq!(result, Ok(()));
958 }
959
960 let der_private_key_buffer: EcPrivateKeyRfc5915Der = my_private.as_der().unwrap();
961 let der_private_key =
962 PrivateKey::from_private_key_der(&ECDH_P256, der_private_key_buffer.as_ref()).unwrap();
963 {
964 let result = agree(&der_private_key, &peer_public, (), |key_material| {
965 assert_eq!(key_material, &output[..]);
966 Ok(())
967 });
968 assert_eq!(result, Ok(()));
969 }
970
971 let pkcs8_private_key_buffer: Pkcs8V1Der = my_private.as_der().unwrap();
972 let pkcs8_private_key =
973 PrivateKey::from_private_key_der(&ECDH_P256, pkcs8_private_key_buffer.as_ref())
974 .unwrap();
975 {
976 let result = agree(&pkcs8_private_key, &peer_public, (), |key_material| {
977 assert_eq!(key_material, &output[..]);
978 Ok(())
979 });
980 assert_eq!(result, Ok(()));
981 }
982
983 let computed_public = my_private.compute_public_key().unwrap();
984 assert_eq!(computed_public.as_ref(), &my_public[..]);
985
986 assert_eq!(computed_public.algorithm(), alg);
987
988 {
989 let result = agree(&my_private, &peer_public, (), |key_material| {
990 assert_eq!(key_material, &output[..]);
991 Ok(())
992 });
993 assert_eq!(result, Ok(()));
994 }
995
996 {
997 let result = agree(&my_private, &peer_public, (), |key_material| {
998 assert_eq!(key_material, &output[..]);
999 Ok(())
1000 });
1001 assert_eq!(result, Ok(()));
1002 }
1003 }
1004
1005 #[test]
1006 fn test_agreement_ecdh_p384() {
1007 let alg = &ECDH_P384;
1008 let peer_public = UnparsedPublicKey::new(
1009 alg,
1010 test::from_dirty_hex(
1011 "04E558DBEF53EECDE3D3FCCFC1AEA08A89A987475D12FD950D83CFA41732BC509D0D1AC43A0336DEF96FDA41D0774A3571DCFBEC7AACF3196472169E838430367F66EEBE3C6E70C416DD5F0C68759DD1FFF83FA40142209DFF5EAAD96DB9E6386C",
1012 ),
1013 );
1014
1015 let my_private = test::from_dirty_hex(
1016 "099F3C7034D4A2C699884D73A375A67F7624EF7C6B3C0F160647B67414DCE655E35B538041E649EE3FAEF896783AB194",
1017 );
1018
1019 let my_private = {
1020 let rng = test::rand::FixedSliceRandom { bytes: &my_private };
1021 PrivateKey::generate_for_test(alg, &rng).unwrap()
1022 };
1023
1024 let my_public = test::from_dirty_hex(
1025 "04667842D7D180AC2CDE6F74F37551F55755C7645C20EF73E31634FE72B4C55EE6DE3AC808ACB4BDB4C88732AEE95F41AA9482ED1FC0EEB9CAFC4984625CCFC23F65032149E0E144ADA024181535A0F38EEB9FCFF3C2C947DAE69B4C634573A81C",
1026 );
1027 let output = test::from_dirty_hex(
1028 "11187331C279962D93D604243FD592CB9D0A926F422E47187521287E7156C5C4D603135569B9E9D09CF5D4A270F59746",
1029 );
1030
1031 assert_eq!(my_private.algorithm(), alg);
1032
1033 let be_private_key_buffer: EcPrivateKeyBin = my_private.as_be_bytes().unwrap();
1034 let be_private_key =
1035 PrivateKey::from_private_key(&ECDH_P384, be_private_key_buffer.as_ref()).unwrap();
1036 {
1037 let result = agree(&be_private_key, &peer_public, (), |key_material| {
1038 assert_eq!(key_material, &output[..]);
1039 Ok(())
1040 });
1041 assert_eq!(result, Ok(()));
1042 }
1043
1044 let der_private_key_buffer: EcPrivateKeyRfc5915Der = my_private.as_der().unwrap();
1045 let der_private_key =
1046 PrivateKey::from_private_key_der(&ECDH_P384, der_private_key_buffer.as_ref()).unwrap();
1047 {
1048 let result = agree(&der_private_key, &peer_public, (), |key_material| {
1049 assert_eq!(key_material, &output[..]);
1050 Ok(())
1051 });
1052 assert_eq!(result, Ok(()));
1053 }
1054
1055 let computed_public = my_private.compute_public_key().unwrap();
1056 assert_eq!(computed_public.as_ref(), &my_public[..]);
1057
1058 assert_eq!(computed_public.algorithm(), alg);
1059
1060 {
1061 let result = agree(&my_private, &peer_public, (), |key_material| {
1062 assert_eq!(key_material, &output[..]);
1063 Ok(())
1064 });
1065 assert_eq!(result, Ok(()));
1066 }
1067 }
1068
1069 #[test]
1070 fn test_agreement_ecdh_p521() {
1071 let alg = &ECDH_P521;
1072 let peer_public = UnparsedPublicKey::new(
1073 alg,
1074 test::from_dirty_hex(
1075 "0401a32099b02c0bd85371f60b0dd20890e6c7af048c8179890fda308b359dbbc2b7a832bb8c6526c4af99a7ea3f0b3cb96ae1eb7684132795c478ad6f962e4a6f446d017627357b39e9d7632a1370b3e93c1afb5c851b910eb4ead0c9d387df67cde85003e0e427552f1cd09059aad0262e235cce5fba8cedc4fdc1463da76dcd4b6d1a46",
1076 ),
1077 );
1078
1079 let my_private = test::from_dirty_hex(
1080 "00df14b1f1432a7b0fb053965fd8643afee26b2451ecb6a8a53a655d5fbe16e4c64ce8647225eb11e7fdcb23627471dffc5c2523bd2ae89957cba3a57a23933e5a78",
1081 );
1082
1083 let my_private = {
1084 let rng = test::rand::FixedSliceRandom { bytes: &my_private };
1085 PrivateKey::generate_for_test(alg, &rng).unwrap()
1086 };
1087
1088 let my_public = test::from_dirty_hex(
1089 "04004e8583bbbb2ecd93f0714c332dff5ab3bc6396e62f3c560229664329baa5138c3bb1c36428abd4e23d17fcb7a2cfcc224b2e734c8941f6f121722d7b6b9415457601cf0874f204b0363f020864672fadbf87c8811eb147758b254b74b14fae742159f0f671a018212bbf25b8519e126d4cad778cfff50d288fd39ceb0cac635b175ec0",
1090 );
1091 let output = test::from_dirty_hex(
1092 "01aaf24e5d47e4080c18c55ea35581cd8da30f1a079565045d2008d51b12d0abb4411cda7a0785b15d149ed301a3697062f42da237aa7f07e0af3fd00eb1800d9c41",
1093 );
1094
1095 assert_eq!(my_private.algorithm(), alg);
1096
1097 let be_private_key_buffer: EcPrivateKeyBin = my_private.as_be_bytes().unwrap();
1098 let be_private_key =
1099 PrivateKey::from_private_key(&ECDH_P521, be_private_key_buffer.as_ref()).unwrap();
1100 {
1101 let result = agree(&be_private_key, &peer_public, (), |key_material| {
1102 assert_eq!(key_material, &output[..]);
1103 Ok(())
1104 });
1105 assert_eq!(result, Ok(()));
1106 }
1107
1108 let der_private_key_buffer: EcPrivateKeyRfc5915Der = my_private.as_der().unwrap();
1109 let der_private_key =
1110 PrivateKey::from_private_key_der(&ECDH_P521, der_private_key_buffer.as_ref()).unwrap();
1111 {
1112 let result = agree(&der_private_key, &peer_public, (), |key_material| {
1113 assert_eq!(key_material, &output[..]);
1114 Ok(())
1115 });
1116 assert_eq!(result, Ok(()));
1117 }
1118
1119 let computed_public = my_private.compute_public_key().unwrap();
1120 assert_eq!(computed_public.as_ref(), &my_public[..]);
1121
1122 assert_eq!(computed_public.algorithm(), alg);
1123 {
1124 let result = agree(&my_private, &peer_public, (), |key_material| {
1125 assert_eq!(key_material, &output[..]);
1126 Ok(())
1127 });
1128 assert_eq!(result, Ok(()));
1129 }
1130 {
1131 let result = agree(&my_private, &peer_public, (), |key_material| {
1132 assert_eq!(key_material, &output[..]);
1133 Ok(())
1134 });
1135 assert_eq!(result, Ok(()));
1136 }
1137 }
1138
1139 #[test]
1140 fn agreement_traits() {
1141 use crate::test;
1142 use regex::{self, Regex};
1143
1144 let rng = rand::SystemRandom::new();
1145 let private_key = PrivateKey::generate_for_test(&ECDH_P256, &rng).unwrap();
1146
1147 test::compile_time_assert_send::<PrivateKey>();
1148 test::compile_time_assert_sync::<PrivateKey>();
1149
1150 assert_eq!(
1151 format!("{:?}", &private_key),
1152 "PrivateKey { algorithm: Algorithm { curve: P256 } }"
1153 );
1154
1155 let ephemeral_private_key = PrivateKey::generate_for_test(&ECDH_P256, &rng).unwrap();
1156
1157 test::compile_time_assert_send::<PrivateKey>();
1158 test::compile_time_assert_sync::<PrivateKey>();
1159
1160 assert_eq!(
1161 format!("{:?}", &ephemeral_private_key),
1162 "PrivateKey { algorithm: Algorithm { curve: P256 } }"
1163 );
1164
1165 let public_key = private_key.compute_public_key().unwrap();
1166 let pubkey_re = Regex::new(
1167 "PublicKey \\{ algorithm: Algorithm \\{ curve: P256 \\}, bytes: \"[0-9a-f]+\" \\}",
1168 )
1169 .unwrap();
1170 let pubkey_debug = format!("{:?}", &public_key);
1171
1172 assert!(
1173 pubkey_re.is_match(&pubkey_debug),
1174 "pubkey_debug: {pubkey_debug}"
1175 );
1176
1177 #[allow(clippy::redundant_clone)]
1178 let pubkey_clone = public_key.clone();
1179 assert_eq!(public_key.as_ref(), pubkey_clone.as_ref());
1180 assert_eq!(pubkey_debug, format!("{:?}", &pubkey_clone));
1181
1182 test::compile_time_assert_clone::<PublicKey>();
1183 test::compile_time_assert_send::<PublicKey>();
1184 test::compile_time_assert_sync::<PublicKey>();
1185
1186 let _: &dyn core::fmt::Debug = &public_key;
1190
1191 test::compile_time_assert_clone::<UnparsedPublicKey<&[u8]>>();
1192 test::compile_time_assert_copy::<UnparsedPublicKey<&[u8]>>();
1193 test::compile_time_assert_sync::<UnparsedPublicKey<&[u8]>>();
1194
1195 test::compile_time_assert_clone::<UnparsedPublicKey<Vec<u8>>>();
1196 test::compile_time_assert_sync::<UnparsedPublicKey<Vec<u8>>>();
1197
1198 let bytes = [0x01, 0x02, 0x03];
1199
1200 let unparsed_public_key = UnparsedPublicKey::new(&X25519, &bytes);
1201 let unparsed_pubkey_clone = unparsed_public_key;
1202 assert_eq!(
1203 format!("{unparsed_public_key:?}"),
1204 r#"UnparsedPublicKey { algorithm: Algorithm { curve: Curve25519 }, bytes: "010203" }"#
1205 );
1206 assert_eq!(
1207 format!("{unparsed_pubkey_clone:?}"),
1208 r#"UnparsedPublicKey { algorithm: Algorithm { curve: Curve25519 }, bytes: "010203" }"#
1209 );
1210
1211 let unparsed_public_key = UnparsedPublicKey::new(&X25519, Vec::from(bytes));
1212 #[allow(clippy::redundant_clone)]
1213 let unparsed_pubkey_clone = unparsed_public_key.clone();
1214 assert_eq!(
1215 format!("{unparsed_public_key:?}"),
1216 r#"UnparsedPublicKey { algorithm: Algorithm { curve: Curve25519 }, bytes: "010203" }"#
1217 );
1218 assert_eq!(
1219 format!("{unparsed_pubkey_clone:?}"),
1220 r#"UnparsedPublicKey { algorithm: Algorithm { curve: Curve25519 }, bytes: "010203" }"#
1221 );
1222 }
1223
1224 #[test]
1225 fn test_agreement_random() {
1226 let test_algorithms = [&ECDH_P256, &ECDH_P384, &ECDH_P521, &X25519];
1227
1228 for alg in test_algorithms {
1229 test_agreement_random_helper(alg);
1230 }
1231 }
1232
1233 fn test_agreement_random_helper(alg: &'static Algorithm) {
1234 let peer_private = PrivateKey::generate(alg).unwrap();
1235 let my_private = PrivateKey::generate(alg).unwrap();
1236
1237 let peer_public_keys =
1238 public_key_formats_helper(&peer_private.compute_public_key().unwrap());
1239
1240 let my_public_keys = public_key_formats_helper(&my_private.compute_public_key().unwrap());
1241
1242 let mut results: Vec<Vec<u8>> = Vec::new();
1243
1244 for peer_public in peer_public_keys {
1245 let peer_public = UnparsedPublicKey::new(alg, peer_public);
1246 let result = agree(&my_private, &peer_public, (), |key_material| {
1247 results.push(key_material.to_vec());
1248 Ok(())
1249 });
1250 assert_eq!(result, Ok(()));
1251 }
1252
1253 for my_public in my_public_keys {
1254 let my_public = UnparsedPublicKey::new(alg, my_public);
1255 let result = agree(&peer_private, &my_public, (), |key_material| {
1256 results.push(key_material.to_vec());
1257 Ok(())
1258 });
1259 assert_eq!(result, Ok(()));
1260 }
1261
1262 let key_types_tested = match alg.id {
1263 crate::agreement::AlgorithmID::ECDH_P256
1264 | crate::agreement::AlgorithmID::ECDH_P384
1265 | crate::agreement::AlgorithmID::ECDH_P521 => 4,
1266 crate::agreement::AlgorithmID::X25519 => 2,
1267 };
1268
1269 assert_eq!(results.len(), key_types_tested * 2); assert_eq!(results[0..key_types_tested], results[key_types_tested..]);
1272 }
1273
1274 fn public_key_formats_helper(public_key: &PublicKey) -> Vec<Vec<u8>> {
1275 let verify_ec_raw_traits = matches!(
1276 public_key.algorithm().id,
1277 crate::agreement::AlgorithmID::ECDH_P256
1278 | crate::agreement::AlgorithmID::ECDH_P384
1279 | crate::agreement::AlgorithmID::ECDH_P521
1280 );
1281
1282 let mut public_keys = Vec::<Vec<u8>>::new();
1283 public_keys.push(public_key.as_ref().into());
1284
1285 if verify_ec_raw_traits {
1286 let raw = AsBigEndian::<EcPublicKeyCompressedBin>::as_be_bytes(public_key).unwrap();
1287 public_keys.push(raw.as_ref().into());
1288 let raw = AsBigEndian::<EcPublicKeyUncompressedBin>::as_be_bytes(public_key).unwrap();
1289 public_keys.push(raw.as_ref().into());
1290 }
1291
1292 let peer_x509 = AsDer::<PublicKeyX509Der>::as_der(public_key).unwrap();
1293 public_keys.push(peer_x509.as_ref().into());
1294
1295 public_keys
1296 }
1297
1298 #[test]
1299 fn private_key_drop() {
1300 let private_key = PrivateKey::generate(&ECDH_P256).unwrap();
1301 let public_key = private_key.compute_public_key().unwrap();
1302 drop(private_key);
1304 let _ = AsBigEndian::<EcPublicKeyCompressedBin>::as_be_bytes(&public_key).unwrap();
1305 let _ = AsBigEndian::<EcPublicKeyUncompressedBin>::as_be_bytes(&public_key).unwrap();
1306 let _ = AsDer::<PublicKeyX509Der>::as_der(&public_key).unwrap();
1307 }
1308}