[openssh-commits] [openssh] 05/14: upstream: Add WarnWeakCrypto to sshd

git+noreply at mindrot.org git+noreply at mindrot.org
Wed Sep 16 11:15:59 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 813f670ccc086aeb48ca6bf701e6a73c098a65bb
Author: djm at openbsd.org <djm at openbsd.org>
AuthorDate: Wed Sep 16 00:29:44 2026 +0000

    upstream: Add WarnWeakCrypto to sshd
    
    This option was previously available for the client only. This adds it to
    sshd, so allow logging of non-PQ key exchanges.
    
    ok markus, deraadt
    
    OpenBSD-Commit-ID: 524564b82a7a20a4ff984c948fb75aa2b0f9b707
---
 kex.c          | 37 ++++++++++++++++++++++++++++++++++++-
 kex.h          |  7 ++++++-
 monitor_wrap.c |  3 ++-
 packet.c       | 12 +++++++++---
 servconf.c     | 17 ++++++++++++++++-
 servconf.h     |  5 +++--
 sshconnect.c   |  8 ++++++--
 sshd-auth.c    |  3 ++-
 sshd_config.5  | 16 +++++++++++++++-
 9 files changed, 95 insertions(+), 13 deletions(-)

diff --git a/kex.c b/kex.c
index b2c3d9720..af9108b7b 100644
--- a/kex.c
+++ b/kex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex.c,v 1.194 2026/05/31 04:44:38 djm Exp $ */
+/* $OpenBSD: kex.c,v 1.195 2026/09/16 00:29:44 djm Exp $ */
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
  *
@@ -289,6 +289,40 @@ kex_set_server_sig_algs(struct ssh *ssh, const char *allowed_algs)
 		ssh->kex->server_sig_algs = xstrdup("");
 }
 
+void
+kex_set_warn_weak_crypto(struct ssh *ssh, int warn_weak_crypto)
+{
+	if (ssh != NULL && ssh->kex != NULL)
+		ssh->kex->warn_weak_crypto = warn_weak_crypto != 0;
+}
+
+void
+kex_check_warn_weak_crypto(struct ssh *ssh)
+{
+	char remote_id[512];
+	int rekeyed = 0;
+
+	if (ssh == NULL || ssh->kex == NULL || ssh->kex->name == NULL ||
+	    !ssh->kex->warn_weak_crypto || ssh->kex->non_pq_kex_warned)
+		return;
+	if (kex_is_pq_from_name(ssh->kex->name)) {
+		ssh->kex->pq_kex_negotiated = 1;
+		return;
+	}
+
+	if (ssh->kex->pq_kex_negotiated)
+		rekeyed = 1;
+	if (!rekeyed && !ssh->kex->server)
+		return; /* client logs initial KEX warning separately */
+
+	sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
+	logit("WARNING: %sconnection%s%s is not using a post-quantum "
+	    "key exchange algorithm: \"%s\"", rekeyed ? "rekeyed " : "",
+	    ssh->kex->server ? " from " : "",
+	    ssh->kex->server ? remote_id : "", ssh->kex->name);
+	ssh->kex->non_pq_kex_warned = 1;
+}
+
 static int
 kex_compose_ext_info_server(struct ssh *ssh, struct sshbuf *m)
 {
@@ -567,6 +601,7 @@ kex_input_newkeys(int type, uint32_t seq, struct ssh *ssh)
 	kex->flags &= ~KEX_INITIAL;
 	sshbuf_reset(kex->peer);
 	kex->flags &= ~(KEX_INIT_SENT|KEX_INIT_RECVD);
+	kex_check_warn_weak_crypto(ssh);
 	return 0;
 }
 
diff --git a/kex.h b/kex.h
index 9816b1d83..4cd6e0b83 100644
--- a/kex.h
+++ b/kex.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex.h,v 1.134 2026/08/08 07:27:54 djm Exp $ */
+/* $OpenBSD: kex.h,v 1.135 2026/09/16 00:29:44 djm Exp $ */
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -164,6 +164,9 @@ struct kex {
 	struct sshkey *initial_hostkey;
 	sig_atomic_t done;
 	u_int	flags;
+	u_int	warn_weak_crypto;
+	u_int	pq_kex_negotiated;
+	u_int	non_pq_kex_warned;
 	int	hash_alg;
 	int	ec_nid;
 	char	*failed_choice;
@@ -223,6 +226,8 @@ 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 *);
+void	 kex_set_warn_weak_crypto(struct ssh *, int);
+void	 kex_check_warn_weak_crypto(struct ssh *);
 
 int	 kexgex_client(struct ssh *);
 int	 kexgex_server(struct ssh *);
diff --git a/monitor_wrap.c b/monitor_wrap.c
index 859e10f72..3d68f804f 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor_wrap.c,v 1.149 2026/09/16 00:13:58 djm Exp $ */
+/* $OpenBSD: monitor_wrap.c,v 1.150 2026/09/16 00:29:44 djm Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos at citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus at openbsd.org>
@@ -386,6 +386,7 @@ out:
 	channel_set_tcp_keepalives(ssh,
 	    options.tcp_keep_alive == SSH_KEEPALIVES_ALL);
 	kex_set_server_sig_algs(ssh, options.pubkey_accepted_algos);
+	kex_set_warn_weak_crypto(ssh, options.warn_weak_crypto);
 	ssh_packet_set_rekey_limits(ssh, options.rekey_limit,
 	    options.rekey_interval);
 	sshbuf_free(m);
diff --git a/packet.c b/packet.c
index 1909a6670..fe78097d2 100644
--- a/packet.c
+++ b/packet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.342 2026/09/14 02:40:27 djm Exp $ */
+/* $OpenBSD: packet.c,v 1.343 2026/09/16 00:29:44 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -2432,7 +2432,10 @@ kex_to_blob(struct sshbuf *m, struct kex *kex)
 	    (r = sshbuf_put_stringb(m, kex->client_version)) != 0 ||
 	    (r = sshbuf_put_stringb(m, kex->server_version)) != 0 ||
 	    (r = sshbuf_put_stringb(m, kex->session_id)) != 0 ||
-	    (r = sshbuf_put_u32(m, kex->flags)) != 0)
+	    (r = sshbuf_put_u32(m, kex->flags)) != 0 ||
+	    (r = sshbuf_put_u32(m, kex->warn_weak_crypto)) != 0 ||
+	    (r = sshbuf_put_u32(m, kex->pq_kex_negotiated)) != 0 ||
+	    (r = sshbuf_put_u32(m, kex->non_pq_kex_warned)) != 0)
 		return r;
 	return 0;
 }
@@ -2606,7 +2609,10 @@ kex_from_blob(struct sshbuf *m, struct kex **kexp)
 	    (r = sshbuf_get_stringb(m, kex->client_version)) != 0 ||
 	    (r = sshbuf_get_stringb(m, kex->server_version)) != 0 ||
 	    (r = sshbuf_get_stringb(m, kex->session_id)) != 0 ||
-	    (r = sshbuf_get_u32(m, &kex->flags)) != 0)
+	    (r = sshbuf_get_u32(m, &kex->flags)) != 0 ||
+	    (r = sshbuf_get_u32(m, &kex->warn_weak_crypto)) != 0 ||
+	    (r = sshbuf_get_u32(m, &kex->pq_kex_negotiated)) != 0 ||
+	    (r = sshbuf_get_u32(m, &kex->non_pq_kex_warned)) != 0)
 		goto out;
 	if (kex->we_need > 1024) {
 		r = SSH_ERR_INVALID_FORMAT;
diff --git a/servconf.c b/servconf.c
index becf72b81..e7826958f 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.c,v 1.455 2026/09/16 00:25:50 djm Exp $ */
+/* $OpenBSD: servconf.c,v 1.456 2026/09/16 00:29:44 djm Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -1107,6 +1107,13 @@ static const struct multistate multistate_keepalives[] = {
 	{ "no",				SSH_KEEPALIVES_OFF },
 	{ "transport",			SSH_KEEPALIVES_TRANSPORT },
 	{ "all",			SSH_KEEPALIVES_ALL },
+};
+static const struct multistate multistate_warnweakcrypto[] = {
+	{ "true",			1 },
+	{ "false",			0 },
+	{ "yes",			1 },
+	{ "no",				0 },
+	{ "no-pq-kex",			0 },
 	{ NULL, -1 }
 };
 
@@ -2606,6 +2613,11 @@ process_server_config_line_depth(ServerOptions *options, char *line,
 		multistate_ptr = multistate_flag;
 		goto parse_multistate;
 
+	case sWarnWeakCrypto:
+		intptr = &options->warn_weak_crypto;
+		multistate_ptr = multistate_warnweakcrypto;
+		goto parse_multistate;
+
 	case sDeprecated:
 	case sIgnore:
 	case sUnsupported:
@@ -4140,6 +4152,8 @@ fmt_intarg(ServerOpCodes code, int val)
 		return fmt_multistate_int(val, multistate_ignore_rhosts);
 	case sTCPKeepAlive:
 		return fmt_multistate_int(val, multistate_keepalives);
+	case sWarnWeakCrypto:
+		return fmt_multistate_int(val, multistate_warnweakcrypto);
 	case sFingerprintHash:
 		return ssh_digest_alg_name(val);
 	default:
@@ -4334,6 +4348,7 @@ dump_config(ServerOptions *o)
 	dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
 	dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
 	dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info);
+	dump_cfg_fmtint(sWarnWeakCrypto, o->warn_weak_crypto);
 	dump_cfg_fmtint(sRefuseConnection, o->refuse_connection);
 
 	/* string arguments */
diff --git a/servconf.h b/servconf.h
index e54e56c62..f31668549 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.h,v 1.182 2026/09/16 00:25:50 djm Exp $ */
+/* $OpenBSD: servconf.h,v 1.183 2026/09/16 00:29:44 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
@@ -241,7 +241,8 @@ SSHCONF_INT(unused_connection_timeout, UnusedConnectionTimeout, SSHCFG_ALL, NULL
 SSHCONF_STRING(sshd_session_path, SshdSessionPath, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \
 SSHCONF_STRING(sshd_auth_path, SshdAuthPath, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \
 SSHCONF_INTFLAG(refuse_connection, RefuseConnection, SSHCFG_ALL, 0, SSHCFG_COPY_MATCH) \
-SSHCONF_STRING(agent_socket_path, AgentSocketPath, SSHCFG_ALL, SSHCFG_COPY_MATCH)
+SSHCONF_STRING(agent_socket_path, AgentSocketPath, SSHCFG_ALL, SSHCFG_COPY_MATCH) \
+SSHCONF_INT(warn_weak_crypto, WarnWeakCrypto, SSHCFG_GLOBAL, multistate_warnweakcrypto, 1, SSHCFG_COPY_NONE)
 
 #define SSHD_CONFIG_ENTRIES_LEGACY \
 SSHCONF_DEPRECATE(ServerKeyBits, SSHCFG_GLOBAL, SSHCONF_DEPRECATED) \
diff --git a/sshconnect.c b/sshconnect.c
index c8f8e24e1..3349d8e39 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.c,v 1.385 2026/09/16 00:13:58 djm Exp $ */
+/* $OpenBSD: sshconnect.c,v 1.386 2026/09/16 00:29:44 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -1657,10 +1657,14 @@ ssh_login(struct ssh *ssh, Sensitive *sensitive, const char *orighost,
 	/* authenticate user */
 	debug("Authenticating to %s:%d as '%s'", host, port, server_user);
 	ssh_kex2(ssh, host, hostaddr, port, cinfo);
+	kex_set_warn_weak_crypto(ssh, options.warn_weak_crypto &&
+	    !options.kex_algorithms_set);
 	if (!options.kex_algorithms_set && ssh->kex != NULL &&
 	    ssh->kex->name != NULL && options.warn_weak_crypto &&
-	    !kex_is_pq_from_name(ssh->kex->name))
+	    !kex_is_pq_from_name(ssh->kex->name)) {
 		warn_nonpq_kex();
+		ssh->kex->non_pq_kex_warned = 1;
+	}
 	ssh_userauth2(ssh, local_user, server_user, host, sensitive);
 	free(local_user);
 	free(host);
diff --git a/sshd-auth.c b/sshd-auth.c
index f1ff432be..3adf1a41e 100644
--- a/sshd-auth.c
+++ b/sshd-auth.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshd-auth.c,v 1.19 2026/09/16 00:13:58 djm Exp $ */
+/* $OpenBSD: sshd-auth.c,v 1.20 2026/09/16 00:29:44 djm Exp $ */
 /*
  * SSH2 implementation:
  * Privilege Separation:
@@ -798,6 +798,7 @@ do_ssh2_kex(struct ssh *ssh)
 	if ((r = kex_setup(ssh, myproposal)) != 0)
 		fatal_r(r, "kex_setup");
 	kex_set_server_sig_algs(ssh, options.pubkey_accepted_algos);
+	kex_set_warn_weak_crypto(ssh, options.warn_weak_crypto);
 	kex = ssh->kex;
 
 #ifdef WITH_OPENSSL
diff --git a/sshd_config.5 b/sshd_config.5
index bfd208901..f446f094e 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -33,7 +33,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: sshd_config.5,v 1.406 2026/09/16 00:25:50 djm Exp $
+.\" $OpenBSD: sshd_config.5,v 1.407 2026/09/16 00:29:44 djm Exp $
 .Dd $Mdocdate: September 16 2026 $
 .Dt SSHD_CONFIG 5
 .Os
@@ -2147,6 +2147,20 @@ Optionally specifies additional text to append to the SSH protocol banner
 sent by the server upon connection.
 The default is
 .Cm none .
+.It Cm WarnWeakCrypto
+Controls whether warnings are logged when the cryptographic algorithms
+negotiated for the connection are weak or otherwise recommended against.
+Warnings may be disabled by turning off a specific warning or by disabling
+all warnings.
+Warnings about connections that don't use a post-quantum key exchange
+may be disabled using the
+.Cm no-pq-kex
+flag.
+.Cm no
+will disable all warnings.
+The default, equivalent to
+.Cm yes ,
+is to enable all warnings.
 .It Cm X11DisplayOffset
 Specifies the first display number available for
 .Xr sshd 8 Ns 's

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


More information about the openssh-commits mailing list