1use core::fmt;
7use core::fmt::{Debug, Formatter};
8use std::marker::PhantomData;
9
10#[cfg(feature = "ring-sig-verify")]
11use untrusted::Input;
12
13use crate::aws_lc::{EVP_PKEY, EVP_PKEY_ED25519};
14
15use crate::buffer::Buffer;
16use crate::digest::Digest;
17use crate::encoding::{
18 AsBigEndian, AsDer, Curve25519SeedBin, Pkcs8V1Der, Pkcs8V2Der, PublicKeyX509Der,
19};
20use crate::error::{KeyRejected, Unspecified};
21use crate::evp_pkey::No_EVP_PKEY_CTX_consumer;
22use crate::pkcs8::{Document, Version};
23use crate::ptr::LcPtr;
24use crate::rand::SecureRandom;
25use crate::signature::{
26 KeyPair, ParsedPublicKey, ParsedVerificationAlgorithm, Signature, VerificationAlgorithm,
27};
28use crate::{constant_time, digest, hex, sealed};
29
30pub const ED25519_PUBLIC_KEY_LEN: usize = crate::aws_lc::ED25519_PUBLIC_KEY_LEN as usize;
32const ED25519_SIGNATURE_LEN: usize = crate::aws_lc::ED25519_SIGNATURE_LEN as usize;
33const ED25519_SEED_LEN: usize = 32;
34
35#[derive(Debug, Eq, PartialEq)]
37pub struct EdDSAParameters;
38
39impl sealed::Sealed for EdDSAParameters {}
40
41impl ParsedVerificationAlgorithm for EdDSAParameters {
42 fn parsed_verify_sig(
43 &self,
44 public_key: &ParsedPublicKey,
45 msg: &[u8],
46 signature: &[u8],
47 ) -> Result<(), Unspecified> {
48 public_key
49 .key()
50 .verify(msg, None, No_EVP_PKEY_CTX_consumer, signature)
51 }
52
53 fn parsed_verify_digest_sig(
54 &self,
55 _public_key: &ParsedPublicKey,
56 _digest: &Digest,
57 _signature: &[u8],
58 ) -> Result<(), Unspecified> {
59 Err(Unspecified)
60 }
61}
62
63impl VerificationAlgorithm for EdDSAParameters {
64 #[inline]
65 #[cfg(feature = "ring-sig-verify")]
66 fn verify(
67 &self,
68 public_key: Input<'_>,
69 msg: Input<'_>,
70 signature: Input<'_>,
71 ) -> Result<(), Unspecified> {
72 self.verify_sig(
73 public_key.as_slice_less_safe(),
74 msg.as_slice_less_safe(),
75 signature.as_slice_less_safe(),
76 )
77 }
78
79 fn verify_sig(
84 &self,
85 public_key: &[u8],
86 msg: &[u8],
87 signature: &[u8],
88 ) -> Result<(), Unspecified> {
89 let evp_pkey = parse_ed25519_public_key(public_key)?;
90 evp_pkey.verify(msg, None, No_EVP_PKEY_CTX_consumer, signature)
91 }
92
93 fn verify_digest_sig(
98 &self,
99 _public_key: &[u8],
100 _digest: &digest::Digest,
101 _signature: &[u8],
102 ) -> Result<(), Unspecified> {
103 Err(Unspecified)
104 }
105}
106
107pub(crate) fn parse_ed25519_public_key(key_bytes: &[u8]) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
108 if key_bytes.len() == ED25519_PUBLIC_KEY_LEN {
110 LcPtr::<EVP_PKEY>::parse_raw_public_key(key_bytes, EVP_PKEY_ED25519)
111 } else {
112 LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(key_bytes, EVP_PKEY_ED25519)
114 }
115}
116
117#[derive(Clone)]
119#[allow(clippy::module_name_repetitions)]
120pub struct Ed25519KeyPair {
121 evp_pkey: LcPtr<EVP_PKEY>,
122 public_key: PublicKey,
123}
124
125impl Debug for Ed25519KeyPair {
126 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
127 f.write_str(&format!(
128 "Ed25519KeyPair {{ public_key: PublicKey(\"{}\") }}",
129 hex::encode(&self.public_key)
130 ))
131 }
132}
133
134#[derive(Clone)]
135#[allow(clippy::module_name_repetitions)]
136pub struct Seed<'a> {
138 bytes: Box<[u8]>,
139 phantom: PhantomData<&'a [u8]>,
140}
141
142impl AsBigEndian<Curve25519SeedBin<'static>> for Seed<'_> {
143 fn as_be_bytes(&self) -> Result<Curve25519SeedBin<'static>, Unspecified> {
150 Ok(Curve25519SeedBin::new(self.bytes.to_vec()))
151 }
152}
153
154impl Debug for Seed<'_> {
155 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
156 f.write_str("Ed25519Seed()")
157 }
158}
159
160#[derive(Clone)]
161#[allow(clippy::module_name_repetitions)]
162pub struct PublicKey {
164 evp_pkey: LcPtr<EVP_PKEY>,
165 public_key_bytes: [u8; ED25519_PUBLIC_KEY_LEN],
166}
167
168impl AsRef<[u8]> for PublicKey {
169 #[inline]
170 fn as_ref(&self) -> &[u8] {
172 &self.public_key_bytes
173 }
174}
175
176impl Debug for PublicKey {
177 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
178 f.write_str(&format!(
179 "PublicKey(\"{}\")",
180 hex::encode(self.public_key_bytes)
181 ))
182 }
183}
184
185unsafe impl Send for PublicKey {}
186unsafe impl Sync for PublicKey {}
187
188impl AsDer<PublicKeyX509Der<'static>> for PublicKey {
189 fn as_der(&self) -> Result<PublicKeyX509Der<'static>, crate::error::Unspecified> {
193 let der = self.evp_pkey.as_const().marshal_rfc5280_public_key()?;
199 Ok(PublicKeyX509Der::from(Buffer::new(der)))
200 }
201}
202
203impl KeyPair for Ed25519KeyPair {
204 type PublicKey = PublicKey;
205 #[inline]
206 fn public_key(&self) -> &Self::PublicKey {
207 &self.public_key
208 }
209}
210
211unsafe impl Send for Ed25519KeyPair {}
212unsafe impl Sync for Ed25519KeyPair {}
213
214pub(crate) fn generate_key() -> Result<LcPtr<EVP_PKEY>, Unspecified> {
215 LcPtr::<EVP_PKEY>::generate(EVP_PKEY_ED25519, No_EVP_PKEY_CTX_consumer)
216}
217
218impl Ed25519KeyPair {
219 pub fn generate() -> Result<Self, Unspecified> {
224 let evp_pkey = generate_key()?;
225
226 let mut public_key = [0u8; ED25519_PUBLIC_KEY_LEN];
227 let out_len: usize = evp_pkey
228 .as_const()
229 .marshal_raw_public_to_buffer(&mut public_key)?;
230 debug_assert_eq!(public_key.len(), out_len);
231
232 Ok(Self {
233 public_key: PublicKey {
234 public_key_bytes: public_key,
235 evp_pkey: evp_pkey.clone(),
236 },
237 evp_pkey,
238 })
239 }
240
241 pub fn generate_pkcs8(_rng: &dyn SecureRandom) -> Result<Document, Unspecified> {
264 let evp_pkey = generate_key()?;
265 Ok(Document::new(
266 evp_pkey
267 .as_const()
268 .marshal_rfc5208_private_key(Version::V2)?,
269 ))
270 }
271
272 pub fn to_pkcs8(&self) -> Result<Document, Unspecified> {
278 Ok(Document::new(
279 self.evp_pkey
280 .as_const()
281 .marshal_rfc5208_private_key(Version::V2)?,
282 ))
283 }
284
285 pub fn generate_pkcs8v1(_rng: &dyn SecureRandom) -> Result<Document, Unspecified> {
300 let evp_pkey = generate_key()?;
301 Ok(Document::new(
302 evp_pkey
303 .as_const()
304 .marshal_rfc5208_private_key(Version::V1)?,
305 ))
306 }
307
308 pub fn to_pkcs8v1(&self) -> Result<Document, Unspecified> {
314 Ok(Document::new(
315 self.evp_pkey
316 .as_const()
317 .marshal_rfc5208_private_key(Version::V1)?,
318 ))
319 }
320
321 pub fn from_seed_and_public_key(seed: &[u8], public_key: &[u8]) -> Result<Self, KeyRejected> {
335 let this = Self::from_seed_unchecked(seed)?;
336
337 constant_time::verify_slices_are_equal(public_key, &this.public_key.public_key_bytes)
338 .map_err(|_| KeyRejected::inconsistent_components())?;
339 Ok(this)
340 }
341
342 pub fn from_seed_unchecked(seed: &[u8]) -> Result<Self, KeyRejected> {
355 if seed.len() < ED25519_SEED_LEN {
356 return Err(KeyRejected::inconsistent_components());
357 }
358
359 let evp_pkey = LcPtr::<EVP_PKEY>::parse_raw_private_key(seed, EVP_PKEY_ED25519)?;
360
361 let mut derived_public_key = [0u8; ED25519_PUBLIC_KEY_LEN];
362 let out_len: usize = evp_pkey
363 .as_const()
364 .marshal_raw_public_to_buffer(&mut derived_public_key)?;
365 debug_assert_eq!(derived_public_key.len(), out_len);
366
367 Ok(Self {
368 public_key: PublicKey {
369 public_key_bytes: derived_public_key,
370 evp_pkey: evp_pkey.clone(),
371 },
372 evp_pkey,
373 })
374 }
375
376 pub fn from_pkcs8(pkcs8: &[u8]) -> Result<Self, KeyRejected> {
392 Self::parse_pkcs8(pkcs8)
393 }
394
395 pub fn from_pkcs8_maybe_unchecked(pkcs8: &[u8]) -> Result<Self, KeyRejected> {
411 Self::parse_pkcs8(pkcs8)
412 }
413
414 fn parse_pkcs8(pkcs8: &[u8]) -> Result<Self, KeyRejected> {
415 let evp_pkey = LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(pkcs8, EVP_PKEY_ED25519)?;
416
417 evp_pkey.as_const().validate_as_ed25519()?;
418
419 let mut public_key = [0u8; ED25519_PUBLIC_KEY_LEN];
420 let out_len: usize = evp_pkey
421 .as_const()
422 .marshal_raw_public_to_buffer(&mut public_key)?;
423 debug_assert_eq!(public_key.len(), out_len);
424
425 Ok(Self {
426 public_key: PublicKey {
427 public_key_bytes: public_key,
428 evp_pkey: evp_pkey.clone(),
429 },
430 evp_pkey,
431 })
432 }
433
434 #[inline]
442 #[must_use]
443 pub fn sign(&self, msg: &[u8]) -> Signature {
444 Self::try_sign(self, msg).expect("ED25519 signing failed")
445 }
446
447 #[inline]
455 pub fn try_sign(&self, msg: &[u8]) -> Result<Signature, Unspecified> {
456 let sig_bytes = self.evp_pkey.sign(msg, None, No_EVP_PKEY_CTX_consumer)?;
457
458 Ok(Signature::new(|slice| {
459 slice[0..ED25519_SIGNATURE_LEN].copy_from_slice(&sig_bytes);
460 ED25519_SIGNATURE_LEN
461 }))
462 }
463
464 pub fn seed(&self) -> Result<Seed<'static>, Unspecified> {
471 Ok(Seed {
472 bytes: self
473 .evp_pkey
474 .as_const()
475 .marshal_raw_private_key()?
476 .into_boxed_slice(),
477 phantom: PhantomData,
478 })
479 }
480}
481
482impl AsDer<Pkcs8V1Der<'static>> for Ed25519KeyPair {
483 fn as_der(&self) -> Result<Pkcs8V1Der<'static>, crate::error::Unspecified> {
488 Ok(Pkcs8V1Der::new(
489 self.evp_pkey
490 .as_const()
491 .marshal_rfc5208_private_key(Version::V1)?,
492 ))
493 }
494}
495
496impl AsDer<Pkcs8V2Der<'static>> for Ed25519KeyPair {
497 fn as_der(&self) -> Result<Pkcs8V2Der<'static>, crate::error::Unspecified> {
502 Ok(Pkcs8V2Der::new(
503 self.evp_pkey
504 .as_const()
505 .marshal_rfc5208_private_key(Version::V2)?,
506 ))
507 }
508}
509
510#[cfg(test)]
511mod tests {
512 use crate::ed25519::Ed25519KeyPair;
513 use crate::encoding::{AsBigEndian, AsDer, Pkcs8V1Der, Pkcs8V2Der, PublicKeyX509Der};
514 use crate::rand::SystemRandom;
515 use crate::signature::{KeyPair, UnparsedPublicKey, ED25519};
516 use crate::{hex, test};
517
518 #[test]
519 fn test_generate() {
520 const MESSAGE: &[u8] = b"test message";
521 let key_pair = Ed25519KeyPair::generate().unwrap();
522 let public_key = key_pair.public_key();
523 let signature = key_pair.sign(MESSAGE);
524 let unparsed_public_key = UnparsedPublicKey::new(&ED25519, public_key.as_ref());
525 unparsed_public_key
526 .verify(MESSAGE, signature.as_ref())
527 .unwrap();
528 }
529
530 #[test]
531 fn test_generate_pkcs8() {
532 let rng = SystemRandom::new();
533 let document = Ed25519KeyPair::generate_pkcs8(&rng).unwrap();
534 let kp1: Ed25519KeyPair = Ed25519KeyPair::from_pkcs8(document.as_ref()).unwrap();
535 assert_eq!(
536 document.as_ref(),
537 AsDer::<Pkcs8V2Der>::as_der(&kp1).unwrap().as_ref()
538 );
539 let kp2: Ed25519KeyPair =
540 Ed25519KeyPair::from_pkcs8_maybe_unchecked(document.as_ref()).unwrap();
541 assert_eq!(
542 kp1.seed().unwrap().as_be_bytes().unwrap().as_ref(),
543 kp2.seed().unwrap().as_be_bytes().unwrap().as_ref(),
544 );
545 assert_eq!(kp1.public_key.as_ref(), kp2.public_key.as_ref());
546
547 let document = Ed25519KeyPair::generate_pkcs8v1(&rng).unwrap();
548 let kp1: Ed25519KeyPair = Ed25519KeyPair::from_pkcs8(document.as_ref()).unwrap();
549 assert_eq!(
550 document.as_ref(),
551 AsDer::<Pkcs8V1Der>::as_der(&kp1).unwrap().as_ref()
552 );
553 let kp2: Ed25519KeyPair =
554 Ed25519KeyPair::from_pkcs8_maybe_unchecked(document.as_ref()).unwrap();
555 assert_eq!(
556 kp1.seed().unwrap().as_be_bytes().unwrap().as_ref(),
557 kp2.seed().unwrap().as_be_bytes().unwrap().as_ref(),
558 );
559 assert_eq!(kp1.public_key.as_ref(), kp2.public_key.as_ref());
560 let seed = kp1.seed().unwrap();
561 assert_eq!("Ed25519Seed()", format!("{seed:?}"));
562 }
563
564 #[test]
565 fn test_from_pkcs8() {
566 struct TestCase {
567 key: &'static str,
568 expected_public: &'static str,
569 }
570
571 for case in [
572 TestCase {
573 key: "302e020100300506032b6570042204209d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
574 expected_public: "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a",
575 },
576 TestCase {
577 key: "3051020101300506032b657004220420756434bd5b824753007a138d27abbc14b5cc786adb78fb62435e6419a2b2e72b8121000faccd81e57de15fa6343a7fbb43b2b93f28be6435100ae8bd633c6dfee3d198",
578 expected_public: "0faccd81e57de15fa6343a7fbb43b2b93f28be6435100ae8bd633c6dfee3d198",
579 },
580 TestCase {
581 key: "304f020100300506032b657004220420d4ee72dbf913584ad5b6d8f1f769f8ad3afe7c28cbf1d4fbe097a88f44755842a01f301d060a2a864886f70d01090914310f0c0d437572646c6520436861697273",
582 expected_public: "19bf44096984cdfe8541bac167dc3b96c85086aa30b6b6cb0c5c38ad703166e1",
583 },
584 TestCase {
585 key: "3072020101300506032b657004220420d4ee72dbf913584ad5b6d8f1f769f8ad3afe7c28cbf1d4fbe097a88f44755842a01f301d060a2a864886f70d01090914310f0c0d437572646c652043686169727381210019bf44096984cdfe8541bac167dc3b96c85086aa30b6b6cb0c5c38ad703166e1",
586 expected_public: "19bf44096984cdfe8541bac167dc3b96c85086aa30b6b6cb0c5c38ad703166e1",
587 }
588 ] {
589 let key_pair = Ed25519KeyPair::from_pkcs8(&test::from_dirty_hex(case.key)).unwrap();
590 assert_eq!(
591 format!(
592 r#"Ed25519KeyPair {{ public_key: PublicKey("{}") }}"#,
593 case.expected_public
594 ),
595 format!("{key_pair:?}")
596 );
597 let key_pair = Ed25519KeyPair::from_pkcs8_maybe_unchecked(&test::from_dirty_hex(case.key)).unwrap();
598 assert_eq!(
599 format!(
600 r#"Ed25519KeyPair {{ public_key: PublicKey("{}") }}"#,
601 case.expected_public
602 ),
603 format!("{key_pair:?}")
604 );
605 }
606 }
607
608 #[test]
609 fn test_public_key_as_der_x509() {
610 let key_pair = Ed25519KeyPair::from_pkcs8(&hex::decode("302e020100300506032b6570042204209d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60").unwrap()).unwrap();
611 let public_key = key_pair.public_key();
612 let x509der = AsDer::<PublicKeyX509Der>::as_der(public_key).unwrap();
613 assert_eq!(
614 x509der.as_ref(),
615 &[
616 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00, 0xd7, 0x5a,
617 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b, 0xfe, 0xd3, 0xc9, 0x64, 0x07, 0x3a,
618 0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6, 0x23, 0x25, 0xaf, 0x02, 0x1a, 0x68, 0xf7, 0x07,
619 0x51, 0x1a
620 ]
621 );
622 }
623}