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