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)]
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#[allow(clippy::module_name_repetitions)]
119pub struct Ed25519KeyPair {
120 evp_pkey: LcPtr<EVP_PKEY>,
121 public_key: PublicKey,
122}
123
124impl Debug for Ed25519KeyPair {
125 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
126 f.write_str(&format!(
127 "Ed25519KeyPair {{ public_key: PublicKey(\"{}\") }}",
128 hex::encode(&self.public_key)
129 ))
130 }
131}
132
133#[derive(Clone)]
134#[allow(clippy::module_name_repetitions)]
135pub struct Seed<'a> {
137 bytes: Box<[u8]>,
138 phantom: PhantomData<&'a [u8]>,
139}
140
141impl AsBigEndian<Curve25519SeedBin<'static>> for Seed<'_> {
142 fn as_be_bytes(&self) -> Result<Curve25519SeedBin<'static>, Unspecified> {
149 Ok(Curve25519SeedBin::new(self.bytes.to_vec()))
150 }
151}
152
153impl Debug for Seed<'_> {
154 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
155 f.write_str("Ed25519Seed()")
156 }
157}
158
159#[derive(Clone)]
160#[allow(clippy::module_name_repetitions)]
161pub struct PublicKey {
163 evp_pkey: LcPtr<EVP_PKEY>,
164 public_key_bytes: [u8; ED25519_PUBLIC_KEY_LEN],
165}
166
167impl AsRef<[u8]> for PublicKey {
168 #[inline]
169 fn as_ref(&self) -> &[u8] {
171 &self.public_key_bytes
172 }
173}
174
175impl Debug for PublicKey {
176 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
177 f.write_str(&format!(
178 "PublicKey(\"{}\")",
179 hex::encode(self.public_key_bytes)
180 ))
181 }
182}
183
184unsafe impl Send for PublicKey {}
185unsafe impl Sync for PublicKey {}
186
187impl AsDer<PublicKeyX509Der<'static>> for PublicKey {
188 fn as_der(&self) -> Result<PublicKeyX509Der<'static>, crate::error::Unspecified> {
192 let der = self.evp_pkey.as_const().marshal_rfc5280_public_key()?;
198 Ok(PublicKeyX509Der::from(Buffer::new(der)))
199 }
200}
201
202impl KeyPair for Ed25519KeyPair {
203 type PublicKey = PublicKey;
204 #[inline]
205 fn public_key(&self) -> &Self::PublicKey {
206 &self.public_key
207 }
208}
209
210unsafe impl Send for Ed25519KeyPair {}
211unsafe impl Sync for Ed25519KeyPair {}
212
213pub(crate) fn generate_key() -> Result<LcPtr<EVP_PKEY>, Unspecified> {
214 LcPtr::<EVP_PKEY>::generate(EVP_PKEY_ED25519, No_EVP_PKEY_CTX_consumer)
215}
216
217impl Ed25519KeyPair {
218 pub fn generate() -> Result<Self, Unspecified> {
223 let evp_pkey = generate_key()?;
224
225 let mut public_key = [0u8; ED25519_PUBLIC_KEY_LEN];
226 let out_len: usize = evp_pkey
227 .as_const()
228 .marshal_raw_public_to_buffer(&mut public_key)?;
229 debug_assert_eq!(public_key.len(), out_len);
230
231 Ok(Self {
232 public_key: PublicKey {
233 public_key_bytes: public_key,
234 evp_pkey: evp_pkey.clone(),
235 },
236 evp_pkey,
237 })
238 }
239
240 pub fn generate_pkcs8(_rng: &dyn SecureRandom) -> Result<Document, Unspecified> {
263 let evp_pkey = generate_key()?;
264 Ok(Document::new(
265 evp_pkey
266 .as_const()
267 .marshal_rfc5208_private_key(Version::V2)?,
268 ))
269 }
270
271 pub fn to_pkcs8(&self) -> Result<Document, Unspecified> {
277 Ok(Document::new(
278 self.evp_pkey
279 .as_const()
280 .marshal_rfc5208_private_key(Version::V2)?,
281 ))
282 }
283
284 pub fn generate_pkcs8v1(_rng: &dyn SecureRandom) -> Result<Document, Unspecified> {
299 let evp_pkey = generate_key()?;
300 Ok(Document::new(
301 evp_pkey
302 .as_const()
303 .marshal_rfc5208_private_key(Version::V1)?,
304 ))
305 }
306
307 pub fn to_pkcs8v1(&self) -> Result<Document, Unspecified> {
313 Ok(Document::new(
314 self.evp_pkey
315 .as_const()
316 .marshal_rfc5208_private_key(Version::V1)?,
317 ))
318 }
319
320 pub fn from_seed_and_public_key(seed: &[u8], public_key: &[u8]) -> Result<Self, KeyRejected> {
334 let this = Self::from_seed_unchecked(seed)?;
335
336 constant_time::verify_slices_are_equal(public_key, &this.public_key.public_key_bytes)
337 .map_err(|_| KeyRejected::inconsistent_components())?;
338 Ok(this)
339 }
340
341 pub fn from_seed_unchecked(seed: &[u8]) -> Result<Self, KeyRejected> {
354 if seed.len() < ED25519_SEED_LEN {
355 return Err(KeyRejected::inconsistent_components());
356 }
357
358 let evp_pkey = LcPtr::<EVP_PKEY>::parse_raw_private_key(seed, EVP_PKEY_ED25519)?;
359
360 let mut derived_public_key = [0u8; ED25519_PUBLIC_KEY_LEN];
361 let out_len: usize = evp_pkey
362 .as_const()
363 .marshal_raw_public_to_buffer(&mut derived_public_key)?;
364 debug_assert_eq!(derived_public_key.len(), out_len);
365
366 Ok(Self {
367 public_key: PublicKey {
368 public_key_bytes: derived_public_key,
369 evp_pkey: evp_pkey.clone(),
370 },
371 evp_pkey,
372 })
373 }
374
375 pub fn from_pkcs8(pkcs8: &[u8]) -> Result<Self, KeyRejected> {
391 Self::parse_pkcs8(pkcs8)
392 }
393
394 pub fn from_pkcs8_maybe_unchecked(pkcs8: &[u8]) -> Result<Self, KeyRejected> {
410 Self::parse_pkcs8(pkcs8)
411 }
412
413 fn parse_pkcs8(pkcs8: &[u8]) -> Result<Self, KeyRejected> {
414 let evp_pkey = LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(pkcs8, EVP_PKEY_ED25519)?;
415
416 evp_pkey.as_const().validate_as_ed25519()?;
417
418 let mut public_key = [0u8; ED25519_PUBLIC_KEY_LEN];
419 let out_len: usize = evp_pkey
420 .as_const()
421 .marshal_raw_public_to_buffer(&mut public_key)?;
422 debug_assert_eq!(public_key.len(), out_len);
423
424 Ok(Self {
425 public_key: PublicKey {
426 public_key_bytes: public_key,
427 evp_pkey: evp_pkey.clone(),
428 },
429 evp_pkey,
430 })
431 }
432
433 #[inline]
441 #[must_use]
442 pub fn sign(&self, msg: &[u8]) -> Signature {
443 Self::try_sign(self, msg).expect("ED25519 signing failed")
444 }
445
446 #[inline]
454 pub fn try_sign(&self, msg: &[u8]) -> Result<Signature, Unspecified> {
455 let sig_bytes = self.evp_pkey.sign(msg, None, No_EVP_PKEY_CTX_consumer)?;
456
457 Ok(Signature::new(|slice| {
458 slice[0..ED25519_SIGNATURE_LEN].copy_from_slice(&sig_bytes);
459 ED25519_SIGNATURE_LEN
460 }))
461 }
462
463 pub fn seed(&self) -> Result<Seed<'static>, Unspecified> {
470 Ok(Seed {
471 bytes: self
472 .evp_pkey
473 .as_const()
474 .marshal_raw_private_key()?
475 .into_boxed_slice(),
476 phantom: PhantomData,
477 })
478 }
479}
480
481impl AsDer<Pkcs8V1Der<'static>> for Ed25519KeyPair {
482 fn as_der(&self) -> Result<Pkcs8V1Der<'static>, crate::error::Unspecified> {
487 Ok(Pkcs8V1Der::new(
488 self.evp_pkey
489 .as_const()
490 .marshal_rfc5208_private_key(Version::V1)?,
491 ))
492 }
493}
494
495impl AsDer<Pkcs8V2Der<'static>> for Ed25519KeyPair {
496 fn as_der(&self) -> Result<Pkcs8V2Der<'static>, crate::error::Unspecified> {
501 Ok(Pkcs8V2Der::new(
502 self.evp_pkey
503 .as_const()
504 .marshal_rfc5208_private_key(Version::V2)?,
505 ))
506 }
507}
508
509#[cfg(test)]
510mod tests {
511 use crate::ed25519::Ed25519KeyPair;
512 use crate::encoding::{AsBigEndian, AsDer, Pkcs8V1Der, Pkcs8V2Der, PublicKeyX509Der};
513 use crate::rand::SystemRandom;
514 use crate::signature::{KeyPair, UnparsedPublicKey, ED25519};
515 use crate::{hex, test};
516
517 #[test]
518 fn test_generate() {
519 const MESSAGE: &[u8] = b"test message";
520 let key_pair = Ed25519KeyPair::generate().unwrap();
521 let public_key = key_pair.public_key();
522 let signature = key_pair.sign(MESSAGE);
523 let unparsed_public_key = UnparsedPublicKey::new(&ED25519, public_key.as_ref());
524 unparsed_public_key
525 .verify(MESSAGE, signature.as_ref())
526 .unwrap();
527 }
528
529 #[test]
530 fn test_generate_pkcs8() {
531 let rng = SystemRandom::new();
532 let document = Ed25519KeyPair::generate_pkcs8(&rng).unwrap();
533 let kp1: Ed25519KeyPair = Ed25519KeyPair::from_pkcs8(document.as_ref()).unwrap();
534 assert_eq!(
535 document.as_ref(),
536 AsDer::<Pkcs8V2Der>::as_der(&kp1).unwrap().as_ref()
537 );
538 let kp2: Ed25519KeyPair =
539 Ed25519KeyPair::from_pkcs8_maybe_unchecked(document.as_ref()).unwrap();
540 assert_eq!(
541 kp1.seed().unwrap().as_be_bytes().unwrap().as_ref(),
542 kp2.seed().unwrap().as_be_bytes().unwrap().as_ref(),
543 );
544 assert_eq!(kp1.public_key.as_ref(), kp2.public_key.as_ref());
545
546 let document = Ed25519KeyPair::generate_pkcs8v1(&rng).unwrap();
547 let kp1: Ed25519KeyPair = Ed25519KeyPair::from_pkcs8(document.as_ref()).unwrap();
548 assert_eq!(
549 document.as_ref(),
550 AsDer::<Pkcs8V1Der>::as_der(&kp1).unwrap().as_ref()
551 );
552 let kp2: Ed25519KeyPair =
553 Ed25519KeyPair::from_pkcs8_maybe_unchecked(document.as_ref()).unwrap();
554 assert_eq!(
555 kp1.seed().unwrap().as_be_bytes().unwrap().as_ref(),
556 kp2.seed().unwrap().as_be_bytes().unwrap().as_ref(),
557 );
558 assert_eq!(kp1.public_key.as_ref(), kp2.public_key.as_ref());
559 let seed = kp1.seed().unwrap();
560 assert_eq!("Ed25519Seed()", format!("{seed:?}"));
561 }
562
563 #[test]
564 fn test_from_pkcs8() {
565 struct TestCase {
566 key: &'static str,
567 expected_public: &'static str,
568 }
569
570 for case in [
571 TestCase {
572 key: "302e020100300506032b6570042204209d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
573 expected_public: "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a",
574 },
575 TestCase {
576 key: "3051020101300506032b657004220420756434bd5b824753007a138d27abbc14b5cc786adb78fb62435e6419a2b2e72b8121000faccd81e57de15fa6343a7fbb43b2b93f28be6435100ae8bd633c6dfee3d198",
577 expected_public: "0faccd81e57de15fa6343a7fbb43b2b93f28be6435100ae8bd633c6dfee3d198",
578 },
579 TestCase {
580 key: "304f020100300506032b657004220420d4ee72dbf913584ad5b6d8f1f769f8ad3afe7c28cbf1d4fbe097a88f44755842a01f301d060a2a864886f70d01090914310f0c0d437572646c6520436861697273",
581 expected_public: "19bf44096984cdfe8541bac167dc3b96c85086aa30b6b6cb0c5c38ad703166e1",
582 },
583 TestCase {
584 key: "3072020101300506032b657004220420d4ee72dbf913584ad5b6d8f1f769f8ad3afe7c28cbf1d4fbe097a88f44755842a01f301d060a2a864886f70d01090914310f0c0d437572646c652043686169727381210019bf44096984cdfe8541bac167dc3b96c85086aa30b6b6cb0c5c38ad703166e1",
585 expected_public: "19bf44096984cdfe8541bac167dc3b96c85086aa30b6b6cb0c5c38ad703166e1",
586 }
587 ] {
588 let key_pair = Ed25519KeyPair::from_pkcs8(&test::from_dirty_hex(case.key)).unwrap();
589 assert_eq!(
590 format!(
591 r#"Ed25519KeyPair {{ public_key: PublicKey("{}") }}"#,
592 case.expected_public
593 ),
594 format!("{key_pair:?}")
595 );
596 let key_pair = Ed25519KeyPair::from_pkcs8_maybe_unchecked(&test::from_dirty_hex(case.key)).unwrap();
597 assert_eq!(
598 format!(
599 r#"Ed25519KeyPair {{ public_key: PublicKey("{}") }}"#,
600 case.expected_public
601 ),
602 format!("{key_pair:?}")
603 );
604 }
605 }
606
607 #[test]
608 fn test_public_key_as_der_x509() {
609 let key_pair = Ed25519KeyPair::from_pkcs8(&hex::decode("302e020100300506032b6570042204209d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60").unwrap()).unwrap();
610 let public_key = key_pair.public_key();
611 let x509der = AsDer::<PublicKeyX509Der>::as_der(public_key).unwrap();
612 assert_eq!(
613 x509der.as_ref(),
614 &[
615 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00, 0xd7, 0x5a,
616 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b, 0xfe, 0xd3, 0xc9, 0x64, 0x07, 0x3a,
617 0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6, 0x23, 0x25, 0xaf, 0x02, 0x1a, 0x68, 0xf7, 0x07,
618 0x51, 0x1a
619 ]
620 );
621 }
622}