upstream: switch from SUPERCOP ed25519 to libsodium

The libsodium implementation includes a number of strictness and
malleability checks over the original reference implementation we
have used to this point.

libsodium also offers a more traditional "detached" signature
verification API (SUPERCOP required the signature to be contiguous
with the signed data). Switch to this and avoid a bunch of fiddly
code.

ok markus, deraadt

OpenBSD-Commit-ID: ea9c958435790c391b031bd9f0599f1ebf48d516
This commit is contained in:
djm@openbsd.org authored and Damien Miller committed 2026-09-16 10:58:41 +10:00
1 parent 6f9cd19af0
commit eab9166136
6 files changed
+4643 -2111

No files matched your search

+4 -4
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: crypto_api.h,v 1.12 2026/07/16 04:12:50 djm Exp $ */
/* $OpenBSD: crypto_api.h,v 1.13 2026/09/16 00:43:00 djm Exp $ */
/*
* Assembled from generated headers and source files by Markus Friedl.
@@ -61,12 +61,12 @@ crypto_hash_sha512(unsigned char *out, const unsigned char *in,
#define crypto_sign_ed25519_SEEDBYTES 32U
#define crypto_sign_ed25519_BYTES 64U
int crypto_sign_ed25519(unsigned char *, unsigned long long *,
int crypto_sign_ed25519_detached(unsigned char *, unsigned long long *,
const unsigned char *, unsigned long long, const unsigned char *);
int crypto_sign_ed25519_open(unsigned char *, unsigned long long *,
int crypto_sign_ed25519_verify_detached(const unsigned char *,
const unsigned char *, unsigned long long, const unsigned char *);
int crypto_sign_ed25519_keypair(unsigned char *, unsigned char *);
int crypto_sign_ed25519_keypair_from_seed(unsigned char *, unsigned char *,
int crypto_sign_ed25519_seed_keypair(unsigned char *, unsigned char *,
const unsigned char *);
#define crypto_kem_sntrup761_PUBLICKEYBYTES 1158
+14 -39
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: ed25519-openssl.c,v 1.3 2026/06/29 02:08:55 djm Exp $ */
/* $OpenBSD: ed25519-openssl.c,v 1.4 2026/09/16 00:43:00 djm Exp $ */
/*
* Copyright (c) 2025 OpenSSH
*
@@ -16,8 +16,8 @@
*/
/*
* OpenSSL-based implementation of Ed25519 crypto_sign API
* Alternative to the internal SUPERCOP-based implementation in ed25519.c
* OpenSSL-based implementation of the Ed25519 crypto_sign API.
* Alternative to the internal libsodium-based implementation in ed25519.c.
*/
#include "includes.h"
@@ -96,7 +96,7 @@ out:
}
int
crypto_sign_ed25519_keypair_from_seed(unsigned char *pk, unsigned char *sk,
crypto_sign_ed25519_seed_keypair(unsigned char *pk, unsigned char *sk,
const unsigned char *seed)
{
EVP_PKEY *pkey = NULL;
@@ -128,7 +128,7 @@ out:
}
int
crypto_sign_ed25519(unsigned char *sm, unsigned long long *smlen,
crypto_sign_ed25519_detached(unsigned char *sig, unsigned long long *siglenp,
const unsigned char *m, unsigned long long mlen,
const unsigned char *sk)
{
@@ -154,7 +154,7 @@ crypto_sign_ed25519(unsigned char *sm, unsigned long long *smlen,
goto out;
}
siglen = crypto_sign_ed25519_BYTES;
if (EVP_DigestSign(mdctx, sm, &siglen, m, mlen) != 1) {
if (EVP_DigestSign(mdctx, sig, &siglen, m, mlen) != 1) {
debug3_f("EVP_DigestSign failed");
goto out;
}
@@ -163,14 +163,8 @@ crypto_sign_ed25519(unsigned char *sm, unsigned long long *smlen,
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;
if (siglenp != NULL)
*siglenp = siglen;
ret = 0;
out:
@@ -180,31 +174,16 @@ out:
}
int
crypto_sign_ed25519_open(unsigned char *m, unsigned long long *mlen,
const unsigned char *sm, unsigned long long smlen,
crypto_sign_ed25519_verify_detached(const unsigned char *sig,
const unsigned char *m, unsigned long long mlen,
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;
}
if (smlen - crypto_sign_ed25519_BYTES > SIZE_MAX) {
debug3_f("signed message too long: %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);
if (mlen > SIZE_MAX) {
debug3_f("message too long: %llu", mlen);
return -1;
}
@@ -223,16 +202,12 @@ crypto_sign_ed25519_open(unsigned char *m, unsigned long long *mlen,
debug3_f("EVP_DigestVerifyInit failed");
goto out;
}
if (EVP_DigestVerify(mdctx, sm, crypto_sign_ed25519_BYTES,
msg, msglen) != 1) {
if (EVP_DigestVerify(mdctx, sig, crypto_sign_ed25519_BYTES,
m, (size_t)mlen) != 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);
+4598 -1983
View File
File diff suppressed because it is too large. Load diff
+7 -20
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: ssh-ed25519-sk.c,v 1.16 2026/02/14 00:18:34 jsg Exp $ */
/* $OpenBSD: ssh-ed25519-sk.c,v 1.17 2026/09/16 00:43:00 djm Exp $ */
/*
* Copyright (c) 2019 Markus Friedl. All rights reserved.
*
@@ -129,14 +129,11 @@ ssh_ed25519_sk_verify(const struct sshkey *key,
struct sshbuf *encoded = NULL;
char *ktype = NULL;
const u_char *sigblob;
const u_char *sm;
u_char *m = NULL;
u_char apphash[32];
u_char msghash[32];
u_char sig_flags;
u_int sig_counter;
size_t len;
unsigned long long smlen = 0, mlen = 0;
int r = SSH_ERR_INTERNAL_ERROR;
int ret;
struct sshkey_sig_details *details = NULL;
@@ -175,7 +172,7 @@ ssh_ed25519_sk_verify(const struct sshkey *key,
r = SSH_ERR_UNEXPECTED_TRAILING_DATA;
goto out;
}
if (len > crypto_sign_ed25519_BYTES) {
if (len != crypto_sign_ed25519_BYTES) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
@@ -202,8 +199,7 @@ ssh_ed25519_sk_verify(const struct sshkey *key,
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (sshbuf_put(encoded, sigblob, len) != 0 ||
sshbuf_put(encoded, apphash, sizeof(apphash)) != 0 ||
if (sshbuf_put(encoded, apphash, sizeof(apphash)) != 0 ||
sshbuf_put_u8(encoded, sig_flags) != 0 ||
sshbuf_put_u32(encoded, sig_counter) != 0 ||
sshbuf_put(encoded, msghash, sizeof(msghash)) != 0) {
@@ -214,22 +210,15 @@ ssh_ed25519_sk_verify(const struct sshkey *key,
fprintf(stderr, "%s: signed buf:\n", __func__);
sshbuf_dump(encoded, stderr);
#endif
sm = sshbuf_ptr(encoded);
smlen = sshbuf_len(encoded);
mlen = smlen;
if ((m = malloc(smlen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen,
if ((ret = crypto_sign_ed25519_verify_detached(sigblob,
sshbuf_ptr(encoded), sshbuf_len(encoded),
key->ed25519_pk)) != 0) {
debug2_f("crypto_sign_ed25519_open failed: %d", ret);
debug2_f("crypto_sign_ed25519_verify_detached failed: %d", ret);
}
if (ret != 0 || mlen != smlen - len) {
if (ret != 0) {
r = SSH_ERR_SIGNATURE_INVALID;
goto out;
}
/* XXX compare 'm' and 'sm + len' ? */
/* success */
r = 0;
if (detailsp != NULL) {
@@ -237,8 +226,6 @@ ssh_ed25519_sk_verify(const struct sshkey *key,
details = NULL;
}
out:
if (m != NULL)
freezero(m, smlen); /* NB mlen may be invalid if r != 0 */
sshkey_sig_details_free(details);
sshbuf_free(b);
sshbuf_free(encoded);
+12 -37
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: ssh-ed25519.c,v 1.23 2026/07/30 03:39:39 djm Exp $ */
/* $OpenBSD: ssh-ed25519.c,v 1.24 2026/09/16 00:43:00 djm Exp $ */
/*
* Copyright (c) 2013 Markus Friedl <markus@openbsd.org>
*
@@ -148,9 +148,8 @@ ssh_ed25519_sign(struct sshkey *key,
const u_char *data, size_t datalen,
const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
{
u_char *sig = NULL;
size_t slen = 0;
unsigned long long smlen;
u_char sig[crypto_sign_ed25519_BYTES];
unsigned long long siglen = 0;
int r, ret;
if (lenp != NULL)
@@ -160,26 +159,22 @@ ssh_ed25519_sign(struct sshkey *key,
if (key == NULL ||
sshkey_type_plain(key->type) != KEY_ED25519 ||
key->ed25519_sk == NULL ||
datalen >= INT_MAX - crypto_sign_ed25519_BYTES)
key->ed25519_sk == NULL)
return SSH_ERR_INVALID_ARGUMENT;
smlen = slen = datalen + crypto_sign_ed25519_BYTES;
if ((sig = malloc(slen)) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((ret = crypto_sign_ed25519(sig, &smlen, data, datalen,
key->ed25519_sk)) != 0 || smlen <= datalen) {
if ((ret = crypto_sign_ed25519_detached(sig, &siglen, data, datalen,
key->ed25519_sk)) != 0 || siglen != sizeof(sig)) {
r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */
goto out;
}
if ((r = ssh_ed25519_encode_store_sig(sig, smlen - datalen,
if ((r = ssh_ed25519_encode_store_sig(sig, siglen,
sigp, lenp)) != 0)
goto out;
/* success */
r = 0;
out:
freezero(sig, slen);
explicit_bzero(sig, sizeof(sig));
return r;
}
@@ -233,15 +228,12 @@ ssh_ed25519_verify(const struct sshkey *key,
struct sshbuf *b = NULL;
char *ktype = NULL;
const u_char *sigblob;
u_char *sm = NULL, *m = NULL;
size_t len;
unsigned long long smlen = 0, mlen = 0;
int r, ret;
if (key == NULL ||
sshkey_type_plain(key->type) != KEY_ED25519 ||
key->ed25519_pk == NULL ||
dlen >= INT_MAX - crypto_sign_ed25519_BYTES ||
sig == NULL || siglen == 0)
return SSH_ERR_INVALID_ARGUMENT;
@@ -258,38 +250,21 @@ ssh_ed25519_verify(const struct sshkey *key,
r = SSH_ERR_UNEXPECTED_TRAILING_DATA;
goto out;
}
if (len > crypto_sign_ed25519_BYTES) {
if (len != crypto_sign_ed25519_BYTES) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if (dlen >= SIZE_MAX - len) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
smlen = len + dlen;
mlen = smlen;
if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(sm, sigblob, len);
memcpy(sm+len, data, dlen);
if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen,
if ((ret = crypto_sign_ed25519_verify_detached(sigblob, data, dlen,
key->ed25519_pk)) != 0) {
debug2_f("crypto_sign_ed25519_open failed: %d", ret);
debug2_f("crypto_sign_ed25519_verify_detached failed: %d", ret);
}
if (ret != 0 || mlen != dlen) {
if (ret != 0) {
r = SSH_ERR_SIGNATURE_INVALID;
goto out;
}
/* XXX compare 'm' and 'data' ? */
/* success */
r = 0;
out:
if (sm != NULL)
freezero(sm, smlen);
if (m != NULL)
freezero(m, smlen); /* NB mlen may be invalid if r != 0 */
sshbuf_free(b);
free(ktype);
return r;
+8 -28
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: ssh-mldsa-eddsa.c,v 1.5 2026/09/02 00:37:59 djm Exp $ */
/* $OpenBSD: ssh-mldsa-eddsa.c,v 1.6 2026/09/16 00:43:00 djm Exp $ */
/*
* Copyright (c) 2026 Damien Miller <djm@mindrot.org>
*
@@ -75,7 +75,7 @@ crypto_sign_mldsa44_ed25519_keygen_seeded(uint8_t pk[MLDSA44_ED25519_PK_SZ],
if (crypto_sign_mldsa44_keypair_seeded(pk, mldsa_sk, mldsa_seed) != 0)
goto out;
if (crypto_sign_ed25519_keypair_from_seed(ed25519_pk, ed25519_sk,
if (crypto_sign_ed25519_seed_keypair(ed25519_pk, ed25519_sk,
ed25519_seed) != 0)
goto out;
@@ -168,23 +168,16 @@ crypto_sign_mldsa44_ed25519_sign(uint8_t sig[MLDSA44_ED25519_SIG_SZ],
goto out;
/* Expand Ed25519 key from seed */
if (crypto_sign_ed25519_keypair_from_seed(ed25519_pk, ed25519_sk,
if (crypto_sign_ed25519_seed_keypair(ed25519_pk, ed25519_sk,
sk + MLDSA44_SEEDBYTES) != 0)
goto out;
/* Sign with Ed25519 */
uint8_t *sm = malloc(m_prime_len + crypto_sign_ed25519_BYTES);
if (sm == NULL)
if (crypto_sign_ed25519_detached(sig + MLDSA44_SIGBYTES, &smlen,
m_prime, m_prime_len, ed25519_sk) != 0 ||
smlen != crypto_sign_ed25519_BYTES)
goto out;
if (crypto_sign_ed25519(sm, &smlen, m_prime, m_prime_len,
ed25519_sk) != 0) {
free(sm);
goto out;
}
memcpy(sig + MLDSA44_SIGBYTES, sm, crypto_sign_ed25519_BYTES);
free(sm);
r = 0;
out:
free(m_prime);
@@ -202,8 +195,6 @@ crypto_sign_mldsa44_ed25519_verify(const uint8_t sig[MLDSA44_ED25519_SIG_SZ],
{
uint8_t *m_prime = NULL;
size_t m_prime_len = 0;
uint8_t *sm = NULL, *m = NULL;
unsigned long long smlen, mlen;
int r = -1;
if (construct_m_prime(&m_prime, &m_prime_len, msg, msglen,
@@ -217,24 +208,13 @@ crypto_sign_mldsa44_ed25519_verify(const uint8_t sig[MLDSA44_ED25519_SIG_SZ],
goto out;
/* Verify Ed25519 */
smlen = m_prime_len + crypto_sign_ed25519_BYTES;
mlen = smlen;
if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL)
goto out;
memcpy(sm, sig + MLDSA44_SIGBYTES, crypto_sign_ed25519_BYTES);
memcpy(sm + crypto_sign_ed25519_BYTES, m_prime, m_prime_len);
if (crypto_sign_ed25519_open(m, &mlen, sm, smlen,
pk + MLDSA44_PUBLICKEYBYTES) != 0)
goto out;
if (mlen != m_prime_len)
if (crypto_sign_ed25519_verify_detached(sig + MLDSA44_SIGBYTES,
m_prime, m_prime_len, pk + MLDSA44_PUBLICKEYBYTES) != 0)
goto out;
r = 0;
out:
free(m_prime);
free(sm);
free(m);
return r;
}