summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--PROTOCOL21
-rw-r--r--auth2.c8
-rw-r--r--kex.c233
-rw-r--r--kex.h7
-rw-r--r--monitor_wrap.c4
-rw-r--r--sshconnect2.c50
-rw-r--r--sshd.c4
7 files changed, 260 insertions, 67 deletions
diff --git a/PROTOCOL b/PROTOCOL
index ded935eb..1894d573 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -163,6 +163,25 @@ b) After sending or receiving a SSH2_MSG_NEWKEYS message, reset the
duration of the connection (i.e. not just the first
SSH2_MSG_NEWKEYS).
+1.10 transport: SSH2_MSG_EXT_INFO during user authentication
+
+This protocol extension allows the SSH2_MSG_EXT_INFO to be sent
+during user authentication. RFC8308 does allow a second
+SSH2_MSG_EXT_INFO notification, but it may only be sent at the end
+of user authentication and this is too late to signal per-user
+server signature algorithms.
+
+Support for receiving the SSH2_MSG_EXT_INFO message during user
+authentication is signalled by the client including a
+"ext-info-in-auth@openssh.com" key via its initial SSH2_MSG_EXT_INFO
+set after the SSH2_MSG_NEWKEYS message.
+
+A server that supports this extension MAY send a second
+SSH2_MSG_EXT_INFO message any time after the client's first
+SSH2_MSG_USERAUTH_REQUEST, regardless of whether it succeed or fails.
+The client SHOULD be prepared to update the server-sig-algs that
+it received during an earlier SSH2_MSG_EXT_INFO with the later one.
+
2. Connection protocol changes
2.1. connection: Channel write close extension "eow@openssh.com"
@@ -771,4 +790,4 @@ master instance and later clients.
OpenSSH extends the usual agent protocol. These changes are documented
in the PROTOCOL.agent file.
-$OpenBSD: PROTOCOL,v 1.50 2023/12/18 14:45:17 djm Exp $
+$OpenBSD: PROTOCOL,v 1.51 2023/12/18 14:45:49 djm Exp $
diff --git a/auth2.c b/auth2.c
index c628999e..271789a7 100644
--- a/auth2.c
+++ b/auth2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2.c,v 1.167 2023/08/28 09:48:11 djm Exp $ */
+/* $OpenBSD: auth2.c,v 1.168 2023/12/18 14:45:49 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@@ -57,6 +57,7 @@
#endif
#include "monitor_wrap.h"
#include "digest.h"
+#include "kex.h"
/* import */
extern ServerOptions options;
@@ -172,6 +173,8 @@ do_authentication2(struct ssh *ssh)
Authctxt *authctxt = ssh->authctxt;
ssh_dispatch_init(ssh, &dispatch_protocol_error);
+ if (ssh->kex->ext_info_c)
+ ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_input_ext_info);
ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_REQUEST, &input_service_request);
ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt->success);
ssh->authctxt = NULL;
@@ -211,6 +214,7 @@ input_service_request(int type, u_int32_t seq, struct ssh *ssh)
debug("bad service request %s", service);
ssh_packet_disconnect(ssh, "bad service request %s", service);
}
+ ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &dispatch_protocol_error);
r = 0;
out:
free(service);
@@ -313,6 +317,8 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
if (use_privsep)
mm_inform_authserv(service, style);
userauth_banner(ssh);
+ if ((r = kex_server_update_ext_info(ssh)) != 0)
+ fatal_fr(r, "kex_server_update_ext_info failed");
if (auth2_setup_methods_lists(authctxt) != 0)
ssh_packet_disconnect(ssh,
"no authentication methods enabled");
diff --git a/kex.c b/kex.c
index d478ff6e..cbb2af59 100644
--- a/kex.c
+++ b/kex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex.c,v 1.183 2023/12/18 14:45:17 djm Exp $ */
+/* $OpenBSD: kex.c,v 1.184 2023/12/18 14:45:49 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
@@ -353,7 +353,7 @@ kex_proposal_populate_entries(struct ssh *ssh, char *prop[PROPOSAL_MAX],
if (kexalgos == NULL)
kexalgos = defprop[PROPOSAL_KEX_ALGS];
if ((cp = kex_names_cat(kexalgos, ssh->kex->server ?
- "kex-strict-s-v00@openssh.com" :
+ "ext-info-s,kex-strict-s-v00@openssh.com" :
"ext-info-c,kex-strict-c-v00@openssh.com")) == NULL)
fatal_f("kex_names_cat");
@@ -505,37 +505,139 @@ kex_reset_dispatch(struct ssh *ssh)
SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error);
}
+void
+kex_set_server_sig_algs(struct ssh *ssh, const char *allowed_algs)
+{
+ char *alg, *oalgs, *algs, *sigalgs;
+ const char *sigalg;
+
+ /*
+ * NB. allowed algorithms may contain certificate algorithms that
+ * map to a specific plain signature type, e.g.
+ * rsa-sha2-512-cert-v01@openssh.com => rsa-sha2-512
+ * We need to be careful here to match these, retain the mapping
+ * and only add each signature algorithm once.
+ */
+ if ((sigalgs = sshkey_alg_list(0, 1, 1, ',')) == NULL)
+ fatal_f("sshkey_alg_list failed");
+ oalgs = algs = xstrdup(allowed_algs);
+ free(ssh->kex->server_sig_algs);
+ ssh->kex->server_sig_algs = NULL;
+ for ((alg = strsep(&algs, ",")); alg != NULL && *alg != '\0';
+ (alg = strsep(&algs, ","))) {
+ if ((sigalg = sshkey_sigalg_by_name(alg)) == NULL)
+ continue;
+ if (!has_any_alg(sigalg, sigalgs))
+ continue;
+ /* Don't add an algorithm twice. */
+ if (ssh->kex->server_sig_algs != NULL &&
+ has_any_alg(sigalg, ssh->kex->server_sig_algs))
+ continue;
+ xextendf(&ssh->kex->server_sig_algs, ",", "%s", sigalg);
+ }
+ free(oalgs);
+ free(sigalgs);
+ if (ssh->kex->server_sig_algs == NULL)
+ ssh->kex->server_sig_algs = xstrdup("");
+}
+
static int
-kex_send_ext_info(struct ssh *ssh)
+kex_compose_ext_info_server(struct ssh *ssh, struct sshbuf *m)
{
int r;
- char *algs;
- debug("Sending SSH2_MSG_EXT_INFO");
- if ((algs = sshkey_alg_list(0, 1, 1, ',')) == NULL)
+ if (ssh->kex->server_sig_algs == NULL &&
+ (ssh->kex->server_sig_algs = sshkey_alg_list(0, 1, 1, ',')) == NULL)
return SSH_ERR_ALLOC_FAIL;
- /* XXX filter algs list by allowed pubkey/hostbased types */
- if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 ||
- (r = sshpkt_put_u32(ssh, 3)) != 0 ||
- (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 ||
- (r = sshpkt_put_cstring(ssh, algs)) != 0 ||
- (r = sshpkt_put_cstring(ssh,
+ if ((r = sshbuf_put_u32(m, 3)) != 0 ||
+ (r = sshbuf_put_cstring(m, "server-sig-algs")) != 0 ||
+ (r = sshbuf_put_cstring(m, ssh->kex->server_sig_algs)) != 0 ||
+ (r = sshbuf_put_cstring(m,
"publickey-hostbound@openssh.com")) != 0 ||
- (r = sshpkt_put_cstring(ssh, "0")) != 0 ||
- (r = sshpkt_put_cstring(ssh, "ping@openssh.com")) != 0 ||
- (r = sshpkt_put_cstring(ssh, "0")) != 0 ||
- (r = sshpkt_send(ssh)) != 0) {
+ (r = sshbuf_put_cstring(m, "0")) != 0 ||
+ (r = sshbuf_put_cstring(m, "ping@openssh.com")) != 0 ||
+ (r = sshbuf_put_cstring(m, "0")) != 0) {
+ error_fr(r, "compose");
+ return r;
+ }
+ return 0;
+}
+
+static int
+kex_compose_ext_info_client(struct ssh *ssh, struct sshbuf *m)
+{
+ int r;
+
+ if ((r = sshbuf_put_u32(m, 1)) != 0 ||
+ (r = sshbuf_put_cstring(m, "ext-info-in-auth@openssh.com")) != 0 ||
+ (r = sshbuf_put_cstring(m, "0")) != 0) {
error_fr(r, "compose");
goto out;
}
/* success */
r = 0;
out:
- free(algs);
+ return r;
+}
+
+static int
+kex_maybe_send_ext_info(struct ssh *ssh)
+{
+ int r;
+ struct sshbuf *m = NULL;
+
+ if ((ssh->kex->flags & KEX_INITIAL) == 0)
+ return 0;
+ if (!ssh->kex->ext_info_c && !ssh->kex->ext_info_s)
+ return 0;
+
+ /* Compose EXT_INFO packet. */
+ if ((m = sshbuf_new()) == NULL)
+ fatal_f("sshbuf_new failed");
+ if (ssh->kex->ext_info_c &&
+ (r = kex_compose_ext_info_server(ssh, m)) != 0)
+ goto fail;
+ if (ssh->kex->ext_info_s &&
+ (r = kex_compose_ext_info_client(ssh, m)) != 0)
+ goto fail;
+
+ /* Send the actual KEX_INFO packet */
+ debug("Sending SSH2_MSG_EXT_INFO");
+ if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 ||
+ (r = sshpkt_putb(ssh, m)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0) {
+ error_f("send EXT_INFO");
+ goto fail;
+ }
+
+ r = 0;
+
+ fail:
+ sshbuf_free(m);
return r;
}
int
+kex_server_update_ext_info(struct ssh *ssh)
+{
+ int r;
+
+ if ((ssh->kex->flags & KEX_HAS_EXT_INFO_IN_AUTH) == 0)
+ return 0;
+
+ debug_f("Sending SSH2_MSG_EXT_INFO");
+ if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 ||
+ (r = sshpkt_put_u32(ssh, 1)) != 0 ||
+ (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 ||
+ (r = sshpkt_put_cstring(ssh, ssh->kex->server_sig_algs)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0) {
+ error_f("send EXT_INFO");
+ return r;
+ }
+ return 0;
+}
+
+int
kex_send_newkeys(struct ssh *ssh)
{
int r;
@@ -546,9 +648,8 @@ kex_send_newkeys(struct ssh *ssh)
return r;
debug("SSH2_MSG_NEWKEYS sent");
ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys);
- if (ssh->kex->ext_info_c && (ssh->kex->flags & KEX_INITIAL) != 0)
- if ((r = kex_send_ext_info(ssh)) != 0)
- return r;
+ if ((r = kex_maybe_send_ext_info(ssh)) != 0)
+ return r;
debug("expecting SSH2_MSG_NEWKEYS");
return 0;
}
@@ -570,10 +671,61 @@ kex_ext_info_check_ver(struct kex *kex, const char *name,
return 0;
}
+static int
+kex_ext_info_client_parse(struct ssh *ssh, const char *name,
+ const u_char *value, size_t vlen)
+{
+ int r;
+
+ /* NB. some messages are only accepted in the initial EXT_INFO */
+ if (strcmp(name, "server-sig-algs") == 0) {
+ /* Ensure no \0 lurking in value */
+ if (memchr(value, '\0', vlen) != NULL) {
+ error_f("nul byte in %s", name);
+ return SSH_ERR_INVALID_FORMAT;
+ }
+ debug_f("%s=<%s>", name, value);
+ free(ssh->kex->server_sig_algs);
+ ssh->kex->server_sig_algs = xstrdup((const char *)value);
+ } else if (ssh->kex->ext_info_received == 1 &&
+ strcmp(name, "publickey-hostbound@openssh.com") == 0) {
+ if ((r = kex_ext_info_check_ver(ssh->kex, name, value, vlen,
+ "0", KEX_HAS_PUBKEY_HOSTBOUND)) != 0) {
+ return r;
+ }
+ } else if (ssh->kex->ext_info_received == 1 &&
+ strcmp(name, "ping@openssh.com") == 0) {
+ if ((r = kex_ext_info_check_ver(ssh->kex, name, value, vlen,
+ "0", KEX_HAS_PING)) != 0) {
+ return r;
+ }
+ } else
+ debug_f("%s (unrecognised)", name);
+
+ return 0;
+}
+
+static int
+kex_ext_info_server_parse(struct ssh *ssh, const char *name,
+ const u_char *value, size_t vlen)
+{
+ int r;
+
+ if (strcmp(name, "ext-info-in-auth@openssh.com") == 0) {
+ if ((r = kex_ext_info_check_ver(ssh->kex, name, value, vlen,
+ "0", KEX_HAS_EXT_INFO_IN_AUTH)) != 0) {
+ return r;
+ }
+ } else
+ debug_f("%s (unrecognised)", name);
+ return 0;
+}
+
int
kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
{
struct kex *kex = ssh->kex;
+ const int max_ext_info = kex->server ? 1 : 2;
u_int32_t i, ninfo;
char *name;
u_char *val;
@@ -581,6 +733,10 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
int r;
debug("SSH2_MSG_EXT_INFO received");
+ if (++kex->ext_info_received > max_ext_info) {
+ error("too many SSH2_MSG_EXT_INFO messages sent by peer");
+ return dispatch_protocol_error(type, seq, ssh);
+ }
ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error);
if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0)
return r;
@@ -596,34 +752,16 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
free(name);
return r;
}
- if (strcmp(name, "server-sig-algs") == 0) {
- /* Ensure no \0 lurking in value */
- if (memchr(val, '\0', vlen) != NULL) {
- error_f("nul byte in %s", name);
- free(name);
- free(val);
- return SSH_ERR_INVALID_FORMAT;
- }
- debug_f("%s=<%s>", name, val);
- kex->server_sig_algs = val;
- val = NULL;
- } else if (strcmp(name,
- "publickey-hostbound@openssh.com") == 0) {
- if ((r = kex_ext_info_check_ver(kex, name, val, vlen,
- "0", KEX_HAS_PUBKEY_HOSTBOUND)) != 0) {
- free(name);
- free(val);
+ debug3_f("extension %s", name);
+ if (kex->server) {
+ if ((r = kex_ext_info_server_parse(ssh, name,
+ val, vlen)) != 0)
return r;
- }
- } else if (strcmp(name, "ping@openssh.com") == 0) {
- if ((r = kex_ext_info_check_ver(kex, name, val, vlen,
- "0", KEX_HAS_PING)) != 0) {
- free(name);
- free(val);
+ } else {
+ if ((r = kex_ext_info_client_parse(ssh, name,
+ val, vlen)) != 0)
return r;
- }
- } else
- debug_f("%s (unrecognised)", name);
+ }
free(name);
free(val);
}
@@ -637,6 +775,8 @@ kex_input_newkeys(int type, u_int32_t seq, struct ssh *ssh)
int r;
debug("SSH2_MSG_NEWKEYS received");
+ if (kex->ext_info_c && (kex->flags & KEX_INITIAL) != 0)
+ ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_input_ext_info);
ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error);
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
if ((r = sshpkt_get_end(ssh)) != 0)
@@ -1044,6 +1184,7 @@ kex_choose_conf(struct ssh *ssh, uint32_t seq)
kex->kex_strict = kexalgs_contains(peer,
"kex-strict-c-v00@openssh.com");
} else {
+ kex->ext_info_s = kexalgs_contains(peer, "ext-info-s");
kex->kex_strict = kexalgs_contains(peer,
"kex-strict-s-v00@openssh.com");
}
diff --git a/kex.h b/kex.h
index 272ebb43..ba3a6a4e 100644
--- a/kex.h
+++ b/kex.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex.h,v 1.120 2023/12/18 14:45:17 djm Exp $ */
+/* $OpenBSD: kex.h,v 1.121 2023/12/18 14:45:49 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -112,6 +112,7 @@ enum kex_exchange {
#define KEX_RSA_SHA2_256_SUPPORTED 0x0008 /* only set in server for now */
#define KEX_RSA_SHA2_512_SUPPORTED 0x0010 /* only set in server for now */
#define KEX_HAS_PING 0x0020
+#define KEX_HAS_EXT_INFO_IN_AUTH 0x0040
struct sshenc {
char *name;
@@ -149,7 +150,9 @@ struct kex {
u_int kex_type;
char *server_sig_algs;
int ext_info_c;
+ int ext_info_s;
int kex_strict;
+ int ext_info_received;
struct sshbuf *my;
struct sshbuf *peer;
struct sshbuf *client_version;
@@ -209,6 +212,8 @@ int kex_protocol_error(int, u_int32_t, struct ssh *);
int kex_derive_keys(struct ssh *, u_char *, u_int, const struct sshbuf *);
int kex_send_newkeys(struct ssh *);
int kex_start_rekex(struct ssh *);
+int kex_server_update_ext_info(struct ssh *);
+void kex_set_server_sig_algs(struct ssh *, const char *);
int kexgex_client(struct ssh *);
int kexgex_server(struct ssh *);
diff --git a/monitor_wrap.c b/monitor_wrap.c
index 3533cf06..6270d139 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor_wrap.c,v 1.128 2023/03/31 00:44:29 dtucker Exp $ */
+/* $OpenBSD: monitor_wrap.c,v 1.129 2023/12/18 14:45:49 djm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -340,8 +340,8 @@ out:
log_verbose_add(options.log_verbose[i]);
process_permitopen(ssh, &options);
process_channel_timeouts(ssh, &options);
+ kex_set_server_sig_algs(ssh, options.pubkey_accepted_algos);
free(newopts);
-
sshbuf_free(m);
return (pw);
diff --git a/sshconnect2.c b/sshconnect2.c
index 0cccbcc4..fab1e36b 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect2.c,v 1.370 2023/12/18 14:45:17 djm Exp $ */
+/* $OpenBSD: sshconnect2.c,v 1.371 2023/12/18 14:45:49 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Damien Miller. All rights reserved.
@@ -459,10 +459,8 @@ ssh_userauth2(struct ssh *ssh, const char *local_user,
authctxt.mech_tried = 0;
#endif
authctxt.agent_fd = -1;
- pubkey_prepare(ssh, &authctxt);
- if (authctxt.method == NULL) {
+ if (authctxt.method == NULL)
fatal_f("internal error: cannot send userauth none request");
- }
if ((r = sshpkt_start(ssh, SSH2_MSG_SERVICE_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, "ssh-userauth")) != 0 ||
@@ -521,7 +519,9 @@ input_userauth_service_accept(int type, u_int32_t seq, struct ssh *ssh)
/* initial userauth request */
userauth_none(ssh);
- ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_error);
+ /* accept EXT_INFO at any time during userauth */
+ ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, ssh->kex->ext_info_s ?
+ &kex_input_ext_info : &input_userauth_error);
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);
@@ -1678,10 +1678,10 @@ pubkey_prepare(struct ssh *ssh, Authctxt *authctxt)
struct identity *id, *id2, *tmp;
struct idlist agent, files, *preferred;
struct sshkey *key;
- int agent_fd = -1, i, r, found;
+ int disallowed, agent_fd = -1, i, r, found;
size_t j;
struct ssh_identitylist *idlist;
- char *ident;
+ char *cp, *ident;
TAILQ_INIT(&agent); /* keys from the agent */
TAILQ_INIT(&files); /* keys from the config file */
@@ -1799,16 +1799,30 @@ pubkey_prepare(struct ssh *ssh, Authctxt *authctxt)
TAILQ_CONCAT(preferred, &files, next);
/* finally, filter by PubkeyAcceptedAlgorithms */
TAILQ_FOREACH_SAFE(id, preferred, next, id2) {
- if (id->key != NULL && !key_type_allowed_by_config(id->key)) {
- debug("Skipping %s key %s - "
- "corresponding algo not in PubkeyAcceptedAlgorithms",
- sshkey_ssh_name(id->key), id->filename);
- TAILQ_REMOVE(preferred, id, next);
- sshkey_free(id->key);
- free(id->filename);
- memset(id, 0, sizeof(*id));
+ disallowed = 0;
+ cp = NULL;
+ if (id->key == NULL)
continue;
+ if (!key_type_allowed_by_config(id->key)) {
+ debug("Skipping %s key %s - corresponding algorithm "
+ "not in PubkeyAcceptedAlgorithms",
+ sshkey_ssh_name(id->key), id->filename);
+ disallowed = 1;
+ } else if (ssh->kex->server_sig_algs != NULL &&
+ (cp = key_sig_algorithm(ssh, id->key)) == NULL) {
+ debug("Skipping %s key %s - corresponding algorithm "
+ "not supported by server",
+ sshkey_ssh_name(id->key), id->filename);
+ disallowed = 1;
}
+ free(cp);
+ if (!disallowed)
+ continue;
+ /* remove key */
+ TAILQ_REMOVE(preferred, id, next);
+ sshkey_free(id->key);
+ free(id->filename);
+ memset(id, 0, sizeof(*id));
}
/* List the keys we plan on using */
TAILQ_FOREACH_SAFE(id, preferred, next, id2) {
@@ -1854,6 +1868,12 @@ userauth_pubkey(struct ssh *ssh)
Identity *id;
int sent = 0;
char *ident;
+ static int prepared;
+
+ if (!prepared) {
+ pubkey_prepare(ssh, authctxt);
+ prepared = 1;
+ }
while ((id = TAILQ_FIRST(&authctxt->keys))) {
if (id->tried++)
diff --git a/sshd.c b/sshd.c
index 8524808f..9cbe9229 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshd.c,v 1.600 2023/03/08 04:43:12 guenther Exp $ */
+/* $OpenBSD: sshd.c,v 1.601 2023/12/18 14:45:49 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -2405,7 +2405,9 @@ do_ssh2_kex(struct ssh *ssh)
/* start key exchange */
if ((r = kex_setup(ssh, myproposal)) != 0)
fatal_r(r, "kex_setup");
+ kex_set_server_sig_algs(ssh, options.pubkey_accepted_algos);
kex = ssh->kex;
+
#ifdef WITH_OPENSSL
kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server;
kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server;