mirror of
https://github.com/openssh/openssh-portable.git
synced 2026-11-06 05:16:43 +00:00
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:
1 parent
6f9cd19af0
commit
eab9166136
6 files changed
+4643
-2111
No files matched your search
+4
-4
@@ -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
@@ -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);
|
||||
|
||||
+7
-20
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user