Skip to content

Commit 7399095

Browse files
Add Ed448 signature support and implement related structures
1 parent d961f5b commit 7399095

File tree

3 files changed

+116
-3
lines changed

3 files changed

+116
-3
lines changed

src/sign.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,16 @@ pub fn any_ecdsa_type(der: &PrivateKeyDer<'_>) -> Result<Arc<dyn SigningKey>, ru
8888
#[allow(unused_variables)]
8989
#[cfg(feature = "sign-eddsa")]
9090
pub fn any_eddsa_type(der: &PrivateKeyDer<'_>) -> Result<Arc<dyn SigningKey>, rustls::Error> {
91-
// TODO: Add support for Ed448
9291
#[cfg(all(feature = "der", feature = "eddsa-ed25519"))]
9392
if let Ok(key) = eddsa::ed25519::Ed25519SigningKey::try_from(der) {
9493
return Ok(Arc::new(key) as _);
9594
}
9695

96+
#[cfg(all(feature = "der", feature = "eddsa-ed448"))]
97+
if let Ok(key) = eddsa::ed448::Ed448SigningKey::try_from(der) {
98+
return Ok(Arc::new(key) as _);
99+
}
100+
97101
Err(rustls::Error::General("not supported".into()))
98102
}
99103

src/sign/eddsa.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1-
#[cfg(feature = "ed25519")]
2-
pub mod ed25519;
1+
#[cfg(feature = "ed25519")]
2+
pub mod ed25519;
3+
4+
#[cfg(feature = "ed448")]
5+
pub mod ed448;

src/sign/eddsa/ed448.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#[cfg(feature = "alloc")]
2+
use alloc::{boxed::Box, sync::Arc, vec::Vec};
3+
#[cfg(all(feature = "alloc", feature = "der"))]
4+
use alloc::{format, string::ToString};
5+
6+
use ed448_goldilocks::{Signature, SigningKey};
7+
use rustls::{SignatureAlgorithm, SignatureScheme, sign::Signer};
8+
use signature::{SignatureEncoding, Signer as SignatureSigner};
9+
10+
#[cfg(feature = "der")]
11+
use pki_types::PrivateKeyDer;
12+
13+
// Wrapper for Ed448 signature to implement SignatureEncoding
14+
#[derive(Debug, Clone)]
15+
pub struct Ed448Signature(Signature);
16+
17+
impl SignatureEncoding for Ed448Signature {
18+
type Repr = [u8; 114]; // Ed448 signature is 114 bytes
19+
20+
fn to_bytes(&self) -> Self::Repr {
21+
self.0.to_bytes()
22+
}
23+
24+
fn encoded_len(&self) -> usize {
25+
114
26+
}
27+
}
28+
29+
impl TryFrom<&[u8]> for Ed448Signature {
30+
type Error = signature::Error;
31+
32+
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
33+
Signature::from_slice(bytes)
34+
.map(Self)
35+
.map_err(|_| signature::Error::new())
36+
}
37+
}
38+
39+
impl From<Ed448Signature> for [u8; 114] {
40+
fn from(sig: Ed448Signature) -> Self {
41+
sig.0.to_bytes()
42+
}
43+
}
44+
45+
#[derive(Debug)]
46+
pub struct Ed448SigningKey(Arc<SigningKey>);
47+
48+
#[cfg(feature = "der")]
49+
impl TryFrom<&PrivateKeyDer<'_>> for Ed448SigningKey {
50+
type Error = rustls::Error;
51+
52+
fn try_from(value: &PrivateKeyDer<'_>) -> Result<Self, Self::Error> {
53+
let pkey = match value {
54+
#[cfg(feature = "pkcs8")]
55+
PrivateKeyDer::Pkcs8(der) => {
56+
use pkcs8::DecodePrivateKey;
57+
SigningKey::from_pkcs8_der(der.secret_pkcs8_der())
58+
.map_err(|e| format!("failed to decrypt private key: {e}"))
59+
}
60+
61+
// Per RFC 8410, only PKCS#8 is supported for ED448 keys
62+
// https://datatracker.ietf.org/doc/html/rfc8410#section-7
63+
PrivateKeyDer::Sec1(_) => Err("ED448 does not support SEC 1 key".to_string()),
64+
PrivateKeyDer::Pkcs1(_) => Err("ED448 does not support PKCS#1 key".to_string()),
65+
_ => Err("not supported".into()),
66+
};
67+
pkey.map(|kp| Self(Arc::new(kp)))
68+
.map_err(rustls::Error::General)
69+
}
70+
}
71+
72+
impl rustls::sign::SigningKey for Ed448SigningKey {
73+
fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> {
74+
const SCHEME: SignatureScheme = SignatureScheme::ED448;
75+
if offered.contains(&SCHEME) {
76+
Some(Box::new(Ed448Signer {
77+
key: self.0.clone(),
78+
scheme: SCHEME,
79+
}))
80+
} else {
81+
None
82+
}
83+
}
84+
85+
fn algorithm(&self) -> SignatureAlgorithm {
86+
SignatureAlgorithm::ED448
87+
}
88+
}
89+
90+
// Custom signer for Ed448
91+
#[derive(Debug)]
92+
pub struct Ed448Signer {
93+
key: Arc<SigningKey>,
94+
scheme: SignatureScheme,
95+
}
96+
97+
impl Signer for Ed448Signer {
98+
fn sign(&self, message: &[u8]) -> Result<Vec<u8>, rustls::Error> {
99+
let sig = self.key.sign(message);
100+
Ok(sig.to_bytes().to_vec())
101+
}
102+
103+
fn scheme(&self) -> SignatureScheme {
104+
self.scheme
105+
}
106+
}

0 commit comments

Comments
 (0)