[pbs-devel] [PATCH proxmox v2 02/12] auth-api: move to Ed25519 signatures

Stefan Sterz s.sterz at proxmox.com
Wed Mar 6 13:35:59 CET 2024


previously we used P-256 as the curve of our choice for ec signatures.
however, in the meantime Ed25519 has become a lot more wide-spread.
this simplifies our ec generation code significantly while keeping the
same security level. Ed25519 was also specifically designed and
reviewed to avoid implementation errors likely making it a more secure
choice

note that Ed25519 as a signature scheme always uses sha512, so signing
or verifying with a chosen digest is not supported.

as this mostly affects newly generated keys, this should not break any
existing setups.

Signed-off-by: Stefan Sterz <s.sterz at proxmox.com>
---
 proxmox-auth-api/src/auth_key.rs | 52 +++++++++++++++++++-------------
 proxmox-auth-api/src/ticket.rs   |  2 +-
 2 files changed, 32 insertions(+), 22 deletions(-)

diff --git a/proxmox-auth-api/src/auth_key.rs b/proxmox-auth-api/src/auth_key.rs
index 32120a3..f7a83bb 100644
--- a/proxmox-auth-api/src/auth_key.rs
+++ b/proxmox-auth-api/src/auth_key.rs
@@ -1,10 +1,8 @@
 //! Auth key handling.
 
 use anyhow::{bail, format_err, Error};
-use openssl::ec::{EcGroup, EcKey};
 use openssl::hash::MessageDigest;
-use openssl::nid::Nid;
-use openssl::pkey::{HasPublic, PKey, PKeyRef, Private, Public};
+use openssl::pkey::{HasPublic, Id, PKey, PKeyRef, Private, Public};
 use openssl::rsa::Rsa;
 use openssl::sign::{Signer, Verifier};
 
@@ -33,14 +31,9 @@ impl PrivateKey {
 
     /// Generate a new EC auth key.
     pub fn generate_ec() -> Result<Self, Error> {
-        let nid = Nid::X9_62_PRIME256V1;
-        let group = EcGroup::from_curve_name(nid)
-            .map_err(|err| format_err!("failed to get P-256 group - {err}"))?;
-        let ec = EcKey::generate(&group)
-            .map_err(|err| format_err!("failed to generate EC key for testing - {err}"))?;
         Ok(Self {
-            key: PKey::from_ec_key(ec)
-                .map_err(|err| format_err!("failed to get PKey for EC key - {err}"))?,
+            key: PKey::generate_ed25519()
+                .map_err(|err| format_err!("failed to generate EC PKey - {err}"))?,
         })
     }
 
@@ -59,9 +52,10 @@ impl PrivateKey {
                 .map_err(|err| format_err!("failed to encode rsa private key as PEM - {err}"));
         }
 
-        if let Ok(ec) = self.key.ec_key() {
-            return ec
-                .private_key_to_pem()
+        if self.key.id() == Id::ED25519 {
+            return self
+                .key
+                .private_key_to_pem_pkcs8()
                 .map_err(|err| format_err!("failed to encode ec private key as PEM - {err}"));
         }
 
@@ -77,8 +71,9 @@ impl PrivateKey {
                 .map_err(|err| format_err!("failed to encode rsa public key as PEM - {err}"));
         }
 
-        if let Ok(ec) = self.key.ec_key() {
-            return ec
+        if self.key.id() == Id::ED25519 {
+            return self
+                .key
                 .public_key_to_pem()
                 .map_err(|err| format_err!("failed to encode ec public key as PEM - {err}"));
         }
@@ -92,8 +87,15 @@ impl PrivateKey {
     }
 
     pub(self) fn sign(&self, digest: MessageDigest, data: &[u8]) -> Result<Vec<u8>, Error> {
-        Signer::new(digest, &self.key)
-            .map_err(|e| format_err!("could not create private key signer - {e}"))?
+        let mut signer = if self.key.id() == Id::ED25519 {
+            // ed25519 does not support signing with digest
+            Signer::new_without_digest(&self.key)
+        } else {
+            Signer::new(digest, &self.key)
+        }
+        .map_err(|e| format_err!("could not create private key signer - {e}"))?;
+
+        signer
             .sign_oneshot_to_vec(data)
             .map_err(|e| format_err!("could not sign with private key - {e}"))
     }
@@ -121,8 +123,9 @@ impl PublicKey {
                 .map_err(|err| format_err!("failed to encode rsa public key as PEM - {err}"));
         }
 
-        if let Ok(ec) = self.key.ec_key() {
-            return ec
+        if self.key.id() == Id::ED25519 {
+            return self
+                .key
                 .public_key_to_pem()
                 .map_err(|err| format_err!("failed to encode ec public key as PEM - {err}"));
         }
@@ -192,8 +195,15 @@ impl Keyring {
             signature: &[u8],
             data: &[u8],
         ) -> Result<bool, Error> {
-            Verifier::new(digest, key)
-                .map_err(|err| format_err!("failed to create openssl verifier - {err}"))?
+            let mut verifier = if key.id() == Id::ED25519 {
+                // ed25519 does not support digests
+                Verifier::new_without_digest(key)
+            } else {
+                Verifier::new(digest, key)
+            }
+            .map_err(|err| format_err!("failed to create openssl verifier - {err}"))?;
+
+            verifier
                 .verify_oneshot(signature, data)
                 .map_err(|err| format_err!("openssl error verifying data - {err}"))
         }
diff --git a/proxmox-auth-api/src/ticket.rs b/proxmox-auth-api/src/ticket.rs
index 81054f8..c8fc667 100644
--- a/proxmox-auth-api/src/ticket.rs
+++ b/proxmox-auth-api/src/ticket.rs
@@ -300,7 +300,7 @@ mod test {
     }
 
     #[test]
-    fn test_tickets_ecdsa() {
+    fn test_tickets_ed25519() {
         let keyring = Keyring::generate_new_ec().expect("failed to generate EC key for testing");
 
         simple_test(&keyring, Some("secret aad data"), |_| true);
-- 
2.39.2





More information about the pbs-devel mailing list