[openssh-commits] [openssh] branch master updated: upstream: support ed25519 signatures via libcrypto. Mostly by Jeremy

git+noreply at mindrot.org git+noreply at mindrot.org
Fri Oct 31 08:04:40 AEDT 2025


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

The following commit(s) were added to refs/heads/master by this push:
     new 266647c5f upstream: support ed25519 signatures via libcrypto. Mostly by Jeremy
266647c5f is described below

commit 266647c5f2075d397bd5ed5316450183eda73388
Author: djm at openbsd.org <djm at openbsd.org>
AuthorDate: Thu Oct 30 20:49:10 2025 +0000

    upstream: support ed25519 signatures via libcrypto. Mostly by Jeremy
    
    Allison Feedback tb@, ok tb@ markus@
    
    OpenBSD-Commit-ID: e8edf8adffd5975d05769dde897df882d7933526
---
 .depend           |   1 +
 Makefile.in       |   2 +-
 ed25519-openssl.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ed25519.c         |   4 ++
 4 files changed, 213 insertions(+), 1 deletion(-)

diff --git a/.depend b/.depend
index 660f515ca..cb8c28eac 100644
--- a/.depend
+++ b/.depend
@@ -51,6 +51,7 @@ digest-libc.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-c
 digest-openssl.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd- [...]
 dispatch.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpi [...]
 dns.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h o [...]
+ed25519-openssl.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd [...]
 ed25519.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid [...]
 entropy.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid [...]
 fatal.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h [...]
diff --git a/Makefile.in b/Makefile.in
index 66f159689..35a6fb15e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -102,7 +102,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
 	smult_curve25519_ref.o \
 	poly1305.o chacha.o cipher-chachapoly.o cipher-chachapoly-libcrypto.o \
 	ssh-ed25519.o digest-openssl.o digest-libc.o \
-	hmac.o ed25519.o hash.o \
+	hmac.o ed25519.o ed25519-openssl.o hash.o \
 	kex.o kex-names.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
 	kexgexc.o kexgexs.o \
 	kexsntrup761x25519.o kexmlkem768x25519.o sntrup761.o kexgen.o \
diff --git a/ed25519-openssl.c b/ed25519-openssl.c
new file mode 100644
index 000000000..5d1e343d2
--- /dev/null
+++ b/ed25519-openssl.c
@@ -0,0 +1,207 @@
+/* $OpenBSD: ed25519-openssl.c,v 1.1 2025/10/30 20:49:10 djm Exp $ */
+/*
+ * Copyright (c) 2025 OpenSSH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * OpenSSL-based implementation of Ed25519 crypto_sign API
+ * Alternative to the internal SUPERCOP-based implementation in ed25519.c
+ */
+
+#include "includes.h"
+
+#ifdef OPENSSL_HAS_ED25519
+
+#include <sys/types.h>
+
+#include <string.h>
+#include <stdint.h>
+#include <limits.h>
+
+#include <openssl/evp.h>
+
+#include "crypto_api.h"
+#include "log.h"
+
+#if crypto_sign_ed25519_SECRETKEYBYTES <= crypto_sign_ed25519_PUBLICKEYBYTES
+#error "crypto_sign_ed25519_SECRETKEYBYTES < crypto_sign_ed25519_PUBLICKEYBYTES"
+#endif
+
+#define SSH_ED25519_RAW_SECRET_KEY_LEN \
+    (crypto_sign_ed25519_SECRETKEYBYTES - crypto_sign_ed25519_PUBLICKEYBYTES)
+
+int
+crypto_sign_ed25519_keypair(unsigned char *pk, unsigned char *sk)
+{
+	EVP_PKEY_CTX *ctx = NULL;
+	EVP_PKEY *pkey = NULL;
+	size_t pklen, sklen;
+	int ret = -1;
+
+	if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, NULL)) == NULL) {
+		debug3_f("EVP_PKEY_CTX_new_id failed");
+		goto out;
+	}
+	if (EVP_PKEY_keygen_init(ctx) <= 0) {
+		debug3_f("EVP_PKEY_keygen_init failed");
+		goto out;
+	}
+	if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
+		debug3_f("EVP_PKEY_keygen failed");
+		goto out;
+	}
+
+	/* Extract public key */
+	pklen = crypto_sign_ed25519_PUBLICKEYBYTES;
+	if (!EVP_PKEY_get_raw_public_key(pkey, pk, &pklen)) {
+		debug3_f("EVP_PKEY_get_raw_public_key failed");
+		goto out;
+	}
+	if (pklen != crypto_sign_ed25519_PUBLICKEYBYTES) {
+		debug3_f("public key length mismatch: %zu", pklen);
+		goto out;
+	}
+
+	sklen = SSH_ED25519_RAW_SECRET_KEY_LEN;
+	/* Extract private key (32 bytes seed) */
+	if (!EVP_PKEY_get_raw_private_key(pkey, sk, &sklen)) {
+		debug3_f("EVP_PKEY_get_raw_private_key failed");
+		goto out;
+	}
+	if (sklen != SSH_ED25519_RAW_SECRET_KEY_LEN) {
+		debug3_f("private key length mismatch: %zu", sklen);
+		goto out;
+	}
+
+	/* Append public key to secret key (SUPERCOP format compatibility) */
+	memcpy(sk + sklen, pk, crypto_sign_ed25519_PUBLICKEYBYTES);
+
+	ret = 0;
+out:
+	EVP_PKEY_free(pkey);
+	EVP_PKEY_CTX_free(ctx);
+	return ret;
+}
+
+int
+crypto_sign_ed25519(unsigned char *sm, unsigned long long *smlen,
+    const unsigned char *m, unsigned long long mlen,
+    const unsigned char *sk)
+{
+	EVP_PKEY *pkey = NULL;
+	EVP_MD_CTX *mdctx = NULL;
+	size_t siglen;
+	int ret = -1;
+
+	/* Create EVP_PKEY from secret key (first 32 bytes are the seed) */
+	if ((pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL,
+	    sk, SSH_ED25519_RAW_SECRET_KEY_LEN)) == NULL) {
+		debug3_f("EVP_PKEY_new_raw_private_key failed");
+		goto out;
+	}
+
+	/* Sign the message */
+	if ((mdctx = EVP_MD_CTX_new()) == NULL) {
+		debug3_f("EVP_MD_CTX_new failed");
+		goto out;
+	}
+	if (EVP_DigestSignInit(mdctx, NULL, NULL, NULL, pkey) != 1) {
+		debug3_f("EVP_DigestSignInit failed");
+		goto out;
+	}
+	siglen = crypto_sign_ed25519_BYTES;
+	if (EVP_DigestSign(mdctx, sm, &siglen, m, mlen) != 1) {
+		debug3_f("EVP_DigestSign failed");
+		goto out;
+	}
+	if (siglen != crypto_sign_ed25519_BYTES) {
+		debug3_f("signature length mismatch: %zu", siglen);
+		goto out;
+	}
+
+	/* Append message after signature (SUPERCOP format) */
+	if (mlen > ULLONG_MAX - siglen) {
+		debug3_f("message length overflow: siglen=%zu mlen=%llu",
+		    siglen, mlen);
+		goto out;
+	}
+	memmove(sm + siglen, m, mlen);
+	*smlen = siglen + mlen;
+
+	ret = 0;
+out:
+	EVP_MD_CTX_free(mdctx);
+	EVP_PKEY_free(pkey);
+	return ret;
+}
+
+int
+crypto_sign_ed25519_open(unsigned char *m, unsigned long long *mlen,
+    const unsigned char *sm, unsigned long long smlen,
+    const unsigned char *pk)
+{
+	EVP_PKEY *pkey = NULL;
+	EVP_MD_CTX *mdctx = NULL;
+	int ret = -1;
+	const unsigned char *msg;
+	size_t msglen;
+
+	if (smlen < crypto_sign_ed25519_BYTES) {
+		debug3_f("signed message bad length: %llu", smlen);
+		return -1;
+	}
+	/* Signature is first crypto_sign_ed25519_BYTES, message follows */
+	msg = sm + crypto_sign_ed25519_BYTES;
+	msglen = smlen - crypto_sign_ed25519_BYTES;
+
+	/* Make sure the message buffer is big enough. */
+	if (*mlen < msglen) {
+		debug_f("message bad length: %llu", *mlen);
+		return -1;
+	}
+
+	/* Create EVP_PKEY from public key */
+	if ((pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
+	    pk, crypto_sign_ed25519_PUBLICKEYBYTES)) == NULL) {
+		debug3_f("EVP_PKEY_new_raw_public_key failed");
+		goto out;
+	}
+
+	if ((mdctx = EVP_MD_CTX_new()) == NULL) {
+		debug3_f("EVP_MD_CTX_new failed");
+		goto out;
+	}
+	if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) <= 0) {
+		debug3_f("EVP_DigestVerifyInit failed");
+		goto out;
+	}
+	if (EVP_DigestVerify(mdctx, sm, crypto_sign_ed25519_BYTES,
+	    msg, msglen) != 1) {
+		debug3_f("EVP_DigestVerify failed");
+		goto out;
+	}
+
+	/* Copy message out */
+	*mlen = msglen;
+	memmove(m, msg, msglen);
+
+	ret = 0;
+out:
+	EVP_MD_CTX_free(mdctx);
+	EVP_PKEY_free(pkey);
+	return ret;
+}
+
+#endif /* OPENSSL_HAS_ED25519 */
diff --git a/ed25519.c b/ed25519.c
index 0e167ae1f..2452dff0f 100644
--- a/ed25519.c
+++ b/ed25519.c
@@ -11,6 +11,8 @@
 
 #include "includes.h"
 
+#ifndef OPENSSL_HAS_ED25519
+
 #include <string.h>
 
 #include "crypto_api.h"
@@ -2028,3 +2030,5 @@ badsig:
   memset(m,0,smlen);
   return -1;
 }
+
+#endif /* OPENSSL_HAS_ED25519 */

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list