[openssh-commits] [openssh] 02/06: upstream: ssh: implement mlkem768nistp256-sha256; ok djm@
git+noreply at mindrot.org
git+noreply at mindrot.org
Thu Jul 30 13:49:49 AEST 2026
This is an automated email from the git hooks/post-receive script.
djm pushed a commit to branch master
in repository openssh.
commit 786cb6a14cede4c1bfcf7a1989b53c9a28c8bee4
Author: markus at openbsd.org <markus at openbsd.org>
AuthorDate: Mon Jul 27 12:28:52 2026 +0000
upstream: ssh: implement mlkem768nistp256-sha256; ok djm@
OpenBSD-Commit-ID: f5daafce2fcb44684606197873dab4cd189524a9
---
Makefile.in | 2 +-
kex-names.c | 4 +-
kex.h | 13 ++-
kexecdh.c | 8 +-
kexgen.c | 13 ++-
kexmlkem768ecdh.c | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
monitor.c | 3 +-
ssh-keyscan.c | 3 +-
ssh_api.c | 4 +-
sshconnect2.c | 3 +-
sshd-auth.c | 3 +-
11 files changed, 344 insertions(+), 15 deletions(-)
diff --git a/Makefile.in b/Makefile.in
index da59bcc10..e9503e7b7 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -105,7 +105,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
libcrux-mlkem-mldsa.o ssh-mldsa-eddsa.o \
hmac.o ed25519.o ed25519-openssl.o \
kex.o kex-names.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
- kexgexc.o kexgexs.o \
+ kexgexc.o kexgexs.o kexmlkem768ecdh.o \
kexsntrup761x25519.o kexmlkem768x25519.o sntrup761.o kexgen.o \
sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \
sshbuf-io.o misc-agent.o ssherr-libcrypto.o
diff --git a/kex-names.c b/kex-names.c
index 751f06cea..cb189431d 100644
--- a/kex-names.c
+++ b/kex-names.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex-names.c,v 1.7 2026/02/14 00:18:34 jsg Exp $ */
+/* $OpenBSD: kex-names.c,v 1.8 2026/07/27 12:28:52 markus Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
@@ -70,6 +70,8 @@ static const struct kexalg kexalgs[] = {
{ KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,
SSH_DIGEST_SHA512, KEX_NOT_PQ },
# endif /* OPENSSL_HAS_NISTP521 */
+ { KEX_MLKEM768NISTP256_SHA256, KEX_KEM_MLKEM768ECDH_SHA256,
+ NID_X9_62_prime256v1, SSH_DIGEST_SHA256, KEX_IS_PQ },
#endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
#if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL)
diff --git a/kex.h b/kex.h
index a4d50f1a3..8677f2709 100644
--- a/kex.h
+++ b/kex.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex.h,v 1.130 2026/05/31 04:44:38 djm Exp $ */
+/* $OpenBSD: kex.h,v 1.131 2026/07/27 12:28:52 markus Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -65,6 +65,7 @@
#define KEX_SNTRUP761X25519_SHA512 "sntrup761x25519-sha512"
#define KEX_SNTRUP761X25519_SHA512_OLD "sntrup761x25519-sha512 at openssh.com"
#define KEX_MLKEM768X25519_SHA256 "mlkem768x25519-sha256"
+#define KEX_MLKEM768NISTP256_SHA256 "mlkem768nistp256-sha256"
#define COMP_NONE 0
#define COMP_DELAYED 2
@@ -103,6 +104,7 @@ enum kex_exchange {
KEX_C25519_SHA256,
KEX_KEM_SNTRUP761X25519_SHA512,
KEX_KEM_MLKEM768X25519_SHA256,
+ KEX_KEM_MLKEM768ECDH_SHA256,
KEX_MAX
};
@@ -239,6 +241,9 @@ int kex_dh_enc(struct kex *, const struct sshbuf *, struct sshbuf **,
struct sshbuf **);
int kex_dh_dec(struct kex *, const struct sshbuf *, struct sshbuf **);
+int kex_ecdh_dec_key_group(struct kex *, const struct sshbuf *, EC_KEY *key,
+ const EC_GROUP *, struct sshbuf **);
+
int kex_ecdh_keypair(struct kex *);
int kex_ecdh_enc(struct kex *, const struct sshbuf *, struct sshbuf **,
struct sshbuf **);
@@ -261,6 +266,12 @@ int kex_kem_mlkem768x25519_enc(struct kex *, const struct sshbuf *,
int kex_kem_mlkem768x25519_dec(struct kex *, const struct sshbuf *,
struct sshbuf **);
+int kex_kem_mlkem768ecdh_keypair(struct kex *);
+int kex_kem_mlkem768ecdh_enc(struct kex *, const struct sshbuf *,
+ struct sshbuf **, struct sshbuf **);
+int kex_kem_mlkem768ecdh_dec(struct kex *, const struct sshbuf *,
+ struct sshbuf **);
+
int kex_dh_keygen(struct kex *);
int kex_dh_compute_key(struct kex *, BIGNUM *, struct sshbuf *);
diff --git a/kexecdh.c b/kexecdh.c
index 6a9058cdc..beded1255 100644
--- a/kexecdh.c
+++ b/kexecdh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexecdh.c,v 1.12 2026/02/14 00:18:34 jsg Exp $ */
+/* $OpenBSD: kexecdh.c,v 1.13 2026/07/27 12:28:52 markus Exp $ */
/*
* Copyright (c) 2010 Damien Miller. All rights reserved.
* Copyright (c) 2019 Markus Friedl. All rights reserved.
@@ -41,10 +41,6 @@
#include "sshbuf.h"
#include "ssherr.h"
-static int
-kex_ecdh_dec_key_group(struct kex *, const struct sshbuf *, EC_KEY *key,
- const EC_GROUP *, struct sshbuf **);
-
int
kex_ecdh_keypair(struct kex *kex)
{
@@ -133,7 +129,7 @@ kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob,
return r;
}
-static int
+int
kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob,
EC_KEY *key, const EC_GROUP *group, struct sshbuf **shared_secretp)
{
diff --git a/kexgen.c b/kexgen.c
index 5643bc831..b6bd438b5 100644
--- a/kexgen.c
+++ b/kexgen.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexgen.c,v 1.12 2026/03/03 09:57:25 dtucker Exp $ */
+/* $OpenBSD: kexgen.c,v 1.13 2026/07/27 12:28:52 markus Exp $ */
/*
* Copyright (c) 2019 Markus Friedl. All rights reserved.
*
@@ -123,6 +123,9 @@ kex_gen_client(struct ssh *ssh)
case KEX_KEM_MLKEM768X25519_SHA256:
r = kex_kem_mlkem768x25519_keypair(kex);
break;
+ case KEX_KEM_MLKEM768ECDH_SHA256:
+ r = kex_kem_mlkem768ecdh_keypair(kex);
+ break;
default:
r = SSH_ERR_INVALID_ARGUMENT;
break;
@@ -199,6 +202,10 @@ input_kex_gen_reply(int type, uint32_t seq, struct ssh *ssh)
r = kex_kem_mlkem768x25519_dec(kex, server_blob,
&shared_secret);
break;
+ case KEX_KEM_MLKEM768ECDH_SHA256:
+ r = kex_kem_mlkem768ecdh_dec(kex, server_blob,
+ &shared_secret);
+ break;
default:
r = SSH_ERR_INVALID_ARGUMENT;
break;
@@ -323,6 +330,10 @@ input_kex_gen_init(int type, uint32_t seq, struct ssh *ssh)
r = kex_kem_mlkem768x25519_enc(kex, client_pubkey,
&server_pubkey, &shared_secret);
break;
+ case KEX_KEM_MLKEM768ECDH_SHA256:
+ r = kex_kem_mlkem768ecdh_enc(kex, client_pubkey,
+ &server_pubkey, &shared_secret);
+ break;
default:
r = SSH_ERR_INVALID_ARGUMENT;
break;
diff --git a/kexmlkem768ecdh.c b/kexmlkem768ecdh.c
new file mode 100644
index 000000000..94c2aeae4
--- /dev/null
+++ b/kexmlkem768ecdh.c
@@ -0,0 +1,303 @@
+/* $OpenBSD: kexmlkem768ecdh.c,v */
+/*
+ * Copyright (c) 2025 Markus Friedl. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <signal.h>
+#include <endian.h>
+
+#include "sshkey.h"
+#include "kex.h"
+#include "sshbuf.h"
+#include "digest.h"
+#include "ssherr.h"
+
+int
+kex_kem_mlkem768ecdh_keypair(struct kex *kex)
+{
+ struct sshbuf *buf = NULL;
+ struct sshbuf *ec_blob = NULL;
+ EC_KEY *client_key = NULL;
+ const EC_GROUP *group;
+ const EC_POINT *public_key;
+ u_char *cp = NULL;
+ size_t need;
+ int r = SSH_ERR_INTERNAL_ERROR;
+
+ if ((buf = sshbuf_new()) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ need = MLKEM768_PUBLICKEYBYTES;
+ if ((r = sshbuf_reserve(buf, need, &cp)) != 0)
+ goto out;
+ if (crypto_kem_mlkem768_keypair(cp, kex->mlkem768_client_key) != 0) {
+ r = SSH_ERR_INTERNAL_ERROR;
+ goto out;
+ }
+#ifdef DEBUG_KEXECDH
+ dump_digest("client public key mlkem768:", cp,
+ MLKEM768_PUBLICKEYBYTES);
+#endif
+ if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ if (EC_KEY_generate_key(client_key) != 1) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ group = EC_KEY_get0_group(client_key);
+ public_key = EC_KEY_get0_public_key(client_key);
+
+ if ((ec_blob = sshbuf_new()) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ if ((r = sshbuf_put_ec(ec_blob, public_key, group)) != 0 ||
+ (r = sshbuf_get_u32(ec_blob, NULL)) != 0 ||
+ (r = sshbuf_putb(buf, ec_blob)) != 0)
+ goto out;
+#ifdef DEBUG_KEXECDH
+ fputs("client private key EC:\n", stderr);
+ sshkey_dump_ec_key(client_key);
+#endif
+ /* success */
+ r = 0;
+ kex->ec_client_key = client_key;
+ kex->ec_group = group;
+ client_key = NULL; /* owned by the kex */
+ kex->client_pub = buf;
+ buf = NULL;
+ out:
+ sshbuf_free(buf);
+ sshbuf_free(ec_blob);
+ EC_KEY_free(client_key);
+ return r;
+}
+
+int
+kex_kem_mlkem768ecdh_enc(struct kex *kex,
+ const struct sshbuf *client_blob, struct sshbuf **server_blobp,
+ struct sshbuf **shared_secretp)
+{
+ const EC_GROUP *group;
+ const EC_POINT *pub_key;
+ EC_KEY *server_key = NULL;
+ struct sshbuf *ec_pub = NULL;
+ struct sshbuf *ec_blob = NULL;
+ struct sshbuf *ec_shared = NULL;
+ struct sshbuf *server_blob = NULL;
+ struct sshbuf *buf = NULL;
+ const u_char *client_pub;
+ u_char hash[SSH_DIGEST_MAX_LENGTH];
+ u_char ct[MLKEM768_CIPHERTEXTBYTES];
+ u_char shared_secret[MLKEM768_BYTES];
+ size_t need;
+ int r = SSH_ERR_INTERNAL_ERROR;
+
+ *server_blobp = NULL;
+ *shared_secretp = NULL;
+
+ /* client_blob contains both KEM and ECDH client pubkeys */
+ need = MLKEM768_PUBLICKEYBYTES;
+ if (sshbuf_len(client_blob) <= need) {
+ r = SSH_ERR_SIGNATURE_INVALID;
+ goto out;
+ }
+ client_pub = sshbuf_ptr(client_blob);
+#ifdef DEBUG_KEXECDH
+ dump_digest("client public key mlkem768:", client_pub,
+ MLKEM768_PUBLICKEYBYTES);
+#endif
+
+ /* allocate buffer for concatenation of KEM key and ECDH shared key */
+ /* the buffer will be hashed and the result is the shared secret */
+ if ((buf = sshbuf_new()) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ /* allocate space for encrypted KEM key and ECDH pub key */
+ if ((server_blob = sshbuf_new()) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ /* generate and encrypt KEM key with client key */
+ if (crypto_kem_mlkem768_enc(ct, shared_secret, client_pub) != 0) {
+ r = SSH_ERR_INTERNAL_ERROR;
+ goto out;
+ }
+ if ((r = sshbuf_put(buf, shared_secret, sizeof(shared_secret))) != 0 ||
+ (r = sshbuf_put(server_blob, ct, sizeof(ct))) != 0)
+ goto out;
+
+ client_pub += MLKEM768_PUBLICKEYBYTES;
+ if ((ec_pub = sshbuf_from(client_pub, sshbuf_len(client_blob) -
+ MLKEM768_PUBLICKEYBYTES)) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ /* generate ECDH key pair */
+ if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ if (EC_KEY_generate_key(server_key) != 1) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ group = EC_KEY_get0_group(server_key);
+#ifdef DEBUG_KEXECDH
+ fputs("server private key EC:\n", stderr);
+ sshkey_dump_ec_key(server_key);
+#endif
+ /* store server pubkey after ciphertext */
+ pub_key = EC_KEY_get0_public_key(server_key);
+ if ((ec_blob = sshbuf_new()) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ if ((r = sshbuf_put_ec(ec_blob, pub_key, group)) != 0 ||
+ (r = sshbuf_get_u32(ec_blob, NULL)) != 0 ||
+ (r = sshbuf_putb(server_blob, ec_blob)) != 0)
+ goto out;
+
+ /* append ECDH shared key */
+ if ((r = kex_ecdh_dec_key_group(kex, ec_pub, server_key, group,
+ &ec_shared)) != 0 ||
+ (r = sshbuf_putb(buf, ec_shared)) != 0)
+ goto out;
+
+ if ((r = ssh_digest_buffer(kex->hash_alg, buf, hash, sizeof(hash))) != 0)
+ goto out;
+#ifdef DEBUG_KEXECDH
+ dump_digest("server cipher text:", ct, sizeof(ct));
+ dump_digest("server kem key:", shared_secret, sizeof(shared_secret));
+ dump_digest("concatenation of KEM key and ECDH shared key:",
+ sshbuf_ptr(buf), sshbuf_len(buf));
+#endif
+ /* string-encoded hash is resulting shared secret */
+ sshbuf_reset(buf);
+ if ((r = sshbuf_put_string(buf, hash,
+ ssh_digest_bytes(kex->hash_alg))) != 0)
+ goto out;
+#ifdef DEBUG_KEXECDH
+ dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
+#endif
+ /* success */
+ r = 0;
+ *server_blobp = server_blob;
+ *shared_secretp = buf;
+ server_blob = NULL;
+ buf = NULL;
+ out:
+ explicit_bzero(hash, sizeof(hash));
+ explicit_bzero(shared_secret, sizeof(shared_secret));
+ EC_KEY_free(server_key);
+ sshbuf_free(ec_pub);
+ sshbuf_free(ec_blob);
+ sshbuf_free(ec_shared);
+ sshbuf_free(server_blob);
+ sshbuf_free(buf);
+ return r;
+}
+
+int
+kex_kem_mlkem768ecdh_dec(struct kex *kex,
+ const struct sshbuf *server_blob, struct sshbuf **shared_secretp)
+{
+ struct sshbuf *buf = NULL;
+ struct sshbuf *ec_pub = NULL;
+ struct sshbuf *ec_shared = NULL;
+ u_char shared_secret[MLKEM768_BYTES];
+ const u_char *ciphertext, *server_pub;
+ u_char hash[SSH_DIGEST_MAX_LENGTH];
+ size_t need;
+ int r;
+
+ *shared_secretp = NULL;
+
+ need = MLKEM768_CIPHERTEXTBYTES;
+ if (sshbuf_len(server_blob) <= need) {
+ r = SSH_ERR_SIGNATURE_INVALID;
+ goto out;
+ }
+ ciphertext = sshbuf_ptr(server_blob);
+ server_pub = ciphertext + MLKEM768_CIPHERTEXTBYTES;
+#ifdef DEBUG_KEXECDH
+ dump_digest("server cipher text (dec):", ciphertext,
+ MLKEM768_CIPHERTEXTBYTES);
+#endif
+ /* hash concatenation of KEM key and ECDH shared key */
+ if ((buf = sshbuf_new()) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ if (crypto_kem_mlkem768_dec(shared_secret, ciphertext,
+ kex->mlkem768_client_key) != 0) {
+ r = SSH_ERR_INTERNAL_ERROR;
+ goto out;
+ }
+ if ((r = sshbuf_put(buf, shared_secret, sizeof(shared_secret))) != 0)
+ goto out;
+ if ((ec_pub = sshbuf_from(server_pub, sshbuf_len(server_blob) - need))
+ == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ if ((r = kex_ecdh_dec(kex, ec_pub, &ec_shared)) != 0 ||
+ (r = sshbuf_putb(buf, ec_shared)) != 0)
+ goto out;
+ if ((r = ssh_digest_buffer(kex->hash_alg, buf,
+ hash, sizeof(hash))) != 0)
+ goto out;
+#ifdef DEBUG_KEXECDH
+ dump_digest("client kem key:", shared_secret, sizeof(shared_secret));
+ dump_digest("concatenation of KEM key and ECDH shared key:",
+ sshbuf_ptr(buf), sshbuf_len(buf));
+#endif
+ sshbuf_reset(buf);
+ if ((r = sshbuf_put_string(buf, hash,
+ ssh_digest_bytes(kex->hash_alg))) != 0)
+ goto out;
+#ifdef DEBUG_KEXECDH
+ dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
+#endif
+ /* success */
+ r = 0;
+ *shared_secretp = buf;
+ buf = NULL;
+ out:
+ explicit_bzero(hash, sizeof(hash));
+ explicit_bzero(shared_secret, sizeof(shared_secret));
+ EC_KEY_free(kex->ec_client_key);
+ kex->ec_client_key = NULL;
+ sshbuf_free(ec_pub);
+ sshbuf_free(ec_shared);
+ sshbuf_free(buf);
+ return r;
+}
diff --git a/monitor.c b/monitor.c
index 0b865fd68..013deae5f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor.c,v 1.257 2026/07/09 02:22:10 djm Exp $ */
+/* $OpenBSD: monitor.c,v 1.258 2026/07/27 12:28:52 markus Exp $ */
/*
* Copyright 2002 Niels Provos <provos at citi.umich.edu>
* Copyright 2002 Markus Friedl <markus at openbsd.org>
@@ -1876,6 +1876,7 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor)
kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
# ifdef OPENSSL_HAS_ECC
kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
+ kex->kex[KEX_KEM_MLKEM768ECDH_SHA256] = kex_gen_server;
# endif
#endif /* WITH_OPENSSL */
kex->kex[KEX_C25519_SHA256] = kex_gen_server;
diff --git a/ssh-keyscan.c b/ssh-keyscan.c
index ddaf8dfb1..1c473913d 100644
--- a/ssh-keyscan.c
+++ b/ssh-keyscan.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keyscan.c,v 1.168 2026/06/14 03:59:34 djm Exp $ */
+/* $OpenBSD: ssh-keyscan.c,v 1.169 2026/07/27 12:28:52 markus Exp $ */
/*
* Copyright 1995, 1996 by David Mazieres <dm at lcs.mit.edu>.
*
@@ -297,6 +297,7 @@ keygrab_ssh2(con *c)
c->c_ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
c->c_ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client;
c->c_ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_client;
+ c->c_ssh->kex->kex[KEX_KEM_MLKEM768ECDH_SHA256] = kex_gen_client;
ssh_set_verify_host_key_callback(c->c_ssh, key_print_wrapper);
/*
* do the key-exchange until an error occurs or until
diff --git a/ssh_api.c b/ssh_api.c
index 38ac17da1..4d1e2cd1a 100644
--- a/ssh_api.c
+++ b/ssh_api.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh_api.c,v 1.34 2026/03/03 09:57:25 dtucker Exp $ */
+/* $OpenBSD: ssh_api.c,v 1.35 2026/07/27 12:28:52 markus Exp $ */
/*
* Copyright (c) 2012 Markus Friedl. All rights reserved.
*
@@ -135,6 +135,7 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params)
ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_server;
ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server;
ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server;
+ ssh->kex->kex[KEX_KEM_MLKEM768ECDH_SHA256] = kex_gen_server;
ssh->kex->load_host_public_key=&_ssh_host_public_key;
ssh->kex->load_host_private_key=&_ssh_host_private_key;
ssh->kex->sign=&_ssh_host_key_sign;
@@ -154,6 +155,7 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params)
ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client;
ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_client;
+ ssh->kex->kex[KEX_KEM_MLKEM768ECDH_SHA256] = kex_gen_client;
ssh->kex->verify_host_key =&_ssh_verify_host_key;
}
*sshp = ssh;
diff --git a/sshconnect2.c b/sshconnect2.c
index ef2c23da8..f46f29937 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect2.c,v 1.389 2026/07/21 06:17:42 djm Exp $ */
+/* $OpenBSD: sshconnect2.c,v 1.390 2026/07/27 12:28:52 markus Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Damien Miller. All rights reserved.
@@ -277,6 +277,7 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr_storage *hostaddr,
ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client;
ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_client;
+ ssh->kex->kex[KEX_KEM_MLKEM768ECDH_SHA256] = kex_gen_client;
ssh->kex->verify_host_key=&verify_host_key_callback;
ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done);
diff --git a/sshd-auth.c b/sshd-auth.c
index 83178e868..0005e4cf9 100644
--- a/sshd-auth.c
+++ b/sshd-auth.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshd-auth.c,v 1.17 2026/07/21 06:17:42 djm Exp $ */
+/* $OpenBSD: sshd-auth.c,v 1.18 2026/07/27 12:28:52 markus Exp $ */
/*
* SSH2 implementation:
* Privilege Separation:
@@ -808,6 +808,7 @@ do_ssh2_kex(struct ssh *ssh)
kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
# ifdef OPENSSL_HAS_ECC
kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
+ kex->kex[KEX_KEM_MLKEM768ECDH_SHA256] = kex_gen_server;
# endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
kex->kex[KEX_C25519_SHA256] = kex_gen_server;
--
To stop receiving notification emails like this one, please contact
djm at mindrot.org.
More information about the openssh-commits
mailing list