diff mbox series

[kirkstone,1/1] openssh: fix CVE-2023-48795

Message ID 20240117070817.1099249-1-meenali.gupta@windriver.com
State Rejected
Delegated to: Steve Sakoman
Headers show
Series [kirkstone,1/1] openssh: fix CVE-2023-48795 | expand

Commit Message

mgupta1 Jan. 17, 2024, 7:08 a.m. UTC
From: Meenali Gupta <meenali.gupta@windriver.com>

A flaw was found in the SSH channel integrity.By manipulating sequence
numbers during the handshake,an attacker can remove the initial messages
on the secure channel without causing a MAC failure. For example,an attacker
could disable the ping extension and thus disable the new countermeasure in
OpenSSH 9.5 against keystroke timing attacks.

This CVE fix included function kex_proposal_populate_entries in kex.c file which
is not present in 8.9p, so ignored this change.

Signed-off-by: Meenali Gupta <meenali.gupta@windriver.com>
---
 .../openssh/openssh/CVE-2023-48795.patch      | 503 ++++++++++++++++++
 .../openssh/openssh_8.9p1.bb                  |   1 +
 2 files changed, 504 insertions(+)
 create mode 100644 meta/recipes-connectivity/openssh/openssh/CVE-2023-48795.patch

Comments

Vijay Anusuri Jan. 17, 2024, 8:02 a.m. UTC | #1
Hi Meenali Gupta,

Already CVE-2023-48795 patch for openssh recipe has been merged to
kirkstone branch.

Please find the below links

https://git.openembedded.org/openembedded-core-contrib/commit/?h=stable/kirkstone-nut&id=df5dc8d67e67a2aebf1a552c3e22374e305270bf

https://lists.openembedded.org/g/openembedded-core/message/192819

Thanks & Regards,
Vijay

On Wed, Jan 17, 2024 at 12:38 PM Meenali Gupta via lists.openembedded.org
<meenali.gupta=windriver.com@lists.openembedded.org> wrote:

> From: Meenali Gupta <meenali.gupta@windriver.com>
>
> A flaw was found in the SSH channel integrity.By manipulating sequence
> numbers during the handshake,an attacker can remove the initial messages
> on the secure channel without causing a MAC failure. For example,an
> attacker
> could disable the ping extension and thus disable the new countermeasure in
> OpenSSH 9.5 against keystroke timing attacks.
>
> This CVE fix included function kex_proposal_populate_entries in kex.c file
> which
> is not present in 8.9p, so ignored this change.
>
> Signed-off-by: Meenali Gupta <meenali.gupta@windriver.com>
> ---
>  .../openssh/openssh/CVE-2023-48795.patch      | 503 ++++++++++++++++++
>  .../openssh/openssh_8.9p1.bb                  |   1 +
>  2 files changed, 504 insertions(+)
>  create mode 100644
> meta/recipes-connectivity/openssh/openssh/CVE-2023-48795.patch
>
> diff --git
> a/meta/recipes-connectivity/openssh/openssh/CVE-2023-48795.patch
> b/meta/recipes-connectivity/openssh/openssh/CVE-2023-48795.patch
> new file mode 100644
> index 0000000000..b1b16d5641
> --- /dev/null
> +++ b/meta/recipes-connectivity/openssh/openssh/CVE-2023-48795.patch
> @@ -0,0 +1,503 @@
> +From 1edb00c58f8a6875fad6a497aa2bacf37f9e6cd5 Mon Sep 17 00:00:00 2001
> +From: "djm@openbsd.org" <djm@openbsd.org>
> +Date: Mon, 18 Dec 2023 14:45:17 +0000
> +Subject: [PATCH] upstream: implement "strict key exchange" in ssh and sshd
> + This adds a protocol extension to improve the integrity of the SSH
> transport
> + protocol, particular in and around the initial key exchange (KEX) phase.
> +
> +Full details of the extension are in the PROTOCOL file.
> +
> +with markus@
> +
> +OpenBSD-Commit-ID: 2a66ac962f0a630d7945fee54004ed9e9c439f14
> +
> +CVE: CVE-2023-48795
> +Upstream-Status: Backport [
> https://github.com/openssh/openssh-portable/commit/1edb00c58f8a6875fad6a497aa2bacf37f9e6cd5
> ]
> +
> +Signed-off-by: Meenali Gupta <meenali.gupta@windriver.com>
> +---
> + PROTOCOL      |  28 +++++++++++++-
> + kex.c         |  71 +++++++++++++++++++++-------------
> + kex.h         |   3 +-
> + packet.c      | 103 +++++++++++++++++++++++++++++---------------------
> + packet.h      |   3 +-
> + sshconnect2.c |  12 ++----
> + 6 files changed, 137 insertions(+), 83 deletions(-)
> +
> +diff --git a/PROTOCOL b/PROTOCOL
> +index e6a7d60..68912ce 100644
> +--- a/PROTOCOL
> ++++ b/PROTOCOL
> +@@ -102,6 +102,32 @@ OpenSSH supports the use of ECDH in Curve25519 for
> key exchange as
> + described at:
> +
> http://git.libssh.org/users/aris/libssh.git/plain/doc/curve25519-sha256@libssh.org.txt?h=curve25519
> +
> ++1.9 transport: strict key exchange extension
> ++
> ++OpenSSH supports a number of transport-layer hardening measures under
> ++a "strict KEX" feature. This feature is signalled similarly to the
> ++RFC8308 ext-info feature: by including a additional algorithm in the
> ++initiial SSH2_MSG_KEXINIT kex_algorithms field. The client may append
> ++"kex-strict-c-v00@openssh.com" to its kex_algorithms and the server
> ++may append "kex-strict-s-v00@openssh.com". These pseudo-algorithms
> ++are only valid in the initial SSH2_MSG_KEXINIT and MUST be ignored
> ++if they are present in subsequent SSH2_MSG_KEXINIT packets.
> ++
> ++When an endpoint that supports this extension observes this algorithm
> ++name in a peer's KEXINIT packet, it MUST make the following changes to
> ++the the protocol:
> ++
> ++a) During initial KEX, terminate the connection if any unexpected or
> ++   out-of-sequence packet is received. This includes terminating the
> ++   connection if the first packet received is not SSH2_MSG_KEXINIT.
> ++   Unexpected packets for the purpose of strict KEX include messages
> ++   that are otherwise valid at any time during the connection such as
> ++   SSH2_MSG_DEBUG and SSH2_MSG_IGNORE.
> ++b) After sending or receiving a SSH2_MSG_NEWKEYS message, reset the
> ++   packet sequence number to zero. This behaviour persists for the
> ++   duration of the connection (i.e. not just the first
> ++   SSH2_MSG_NEWKEYS).
> ++
> + 2. Connection protocol changes
> +
> + 2.1. connection: Channel write close extension "eow@openssh.com"
> +@@ -612,4 +638,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.43 2021/12/19 22:15:42 djm Exp $
> ++$OpenBSD: PROTOCOL,v 1.50 2023/12/18 14:45:17 djm Exp $
> +diff --git a/kex.c b/kex.c
> +index 0bcd27d..da16568 100644
> +--- a/kex.c
> ++++ b/kex.c
> +@@ -1,4 +1,4 @@
> +-/* $OpenBSD: kex.c,v 1.172 2022/02/01 23:32:51 djm Exp $ */
> ++/* $OpenBSD: kex.c,v 1.183 2023/12/18 14:45:17 djm Exp $ */
> + /*
> +  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
> +  *
> +@@ -63,7 +63,7 @@
> + #include "digest.h"
> +
> + /* prototype */
> +-static int kex_choose_conf(struct ssh *);
> ++static int kex_choose_conf(struct ssh *, uint32_t seq);
> + static int kex_input_newkeys(int, u_int32_t, struct ssh *);
> +
> + static const char * const proposal_names[PROPOSAL_MAX] = {
> +@@ -175,6 +175,18 @@ kex_names_valid(const char *names)
> +       return 1;
> + }
> +
> ++/* returns non-zero if proposal contains any algorithm from algs */
> ++static int
> ++has_any_alg(const char *proposal, const char *algs)
> ++{
> ++      char *cp;
> ++
> ++      if ((cp = match_list(proposal, algs, NULL)) == NULL)
> ++              return 0;
> ++      free(cp);
> ++      return 1;
> ++}
> ++
> + /*
> +  * Concatenate algorithm names, avoiding duplicates in the process.
> +  * Caller must free returned string.
> +@@ -182,7 +194,7 @@ kex_names_valid(const char *names)
> + char *
> + kex_names_cat(const char *a, const char *b)
> + {
> +-      char *ret = NULL, *tmp = NULL, *cp, *p, *m;
> ++      char *ret = NULL, *tmp = NULL, *cp, *p;
> +       size_t len;
> +
> +       if (a == NULL || *a == '\0')
> +@@ -199,10 +211,8 @@ kex_names_cat(const char *a, const char *b)
> +       }
> +       strlcpy(ret, a, len);
> +       for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp,
> ","))) {
> +-              if ((m = match_list(ret, p, NULL)) != NULL) {
> +-                      free(m);
> ++              if (has_any_alg(ret, p))
> +                       continue; /* Algorithm already present */
> +-              }
> +               if (strlcat(ret, ",", len) >= len ||
> +                   strlcat(ret, p, len) >= len) {
> +                       free(tmp);
> +@@ -410,7 +420,12 @@ kex_protocol_error(int type, u_int32_t seq, struct
> ssh *ssh)
> + {
> +       int r;
> +
> +-      error("kex protocol error: type %d seq %u", type, seq);
> ++      /* If in strict mode, any unexpected message is an error */
> ++      if ((ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict) {
> ++              ssh_packet_disconnect(ssh, "strict KEX violation: "
> ++                  "unexpected packet type %u (seqnr %u)", type, seq);
> ++      }
> ++      error_f("type %u seq %u", type, seq);
> +       if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
> +           (r = sshpkt_put_u32(ssh, seq)) != 0 ||
> +           (r = sshpkt_send(ssh)) != 0)
> +@@ -496,7 +511,7 @@ kex_input_ext_info(int type, u_int32_t seq, struct
> ssh *ssh)
> +                       /* Ensure no \0 lurking in value */
> +                       if (memchr(val, '\0', vlen) != NULL) {
> +                               error_f("nul byte in %s", name);
> +-                              return SSH_ERR_INVALID_FORMAT;
> ++                              return dispatch_protocol_error(type, seq,
> ssh);
> +                       }
> +                       debug_f("%s=<%s>", name, val);
> +                       kex->server_sig_algs = val;
> +@@ -600,7 +615,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh
> *ssh)
> +               error_f("no kex");
> +               return SSH_ERR_INTERNAL_ERROR;
> +       }
> +-      ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL);
> ++      ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_protocol_error);
> +       ptr = sshpkt_ptr(ssh, &dlen);
> +       if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0)
> +               return r;
> +@@ -636,7 +651,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh
> *ssh)
> +       if (!(kex->flags & KEX_INIT_SENT))
> +               if ((r = kex_send_kexinit(ssh)) != 0)
> +                       return r;
> +-      if ((r = kex_choose_conf(ssh)) != 0)
> ++      if ((r = kex_choose_conf(ssh, seq)) != 0)
> +               return r;
> +
> +       if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL)
> +@@ -900,20 +915,14 @@ proposals_match(char *my[PROPOSAL_MAX], char
> *peer[PROPOSAL_MAX])
> +       return (1);
> + }
> +
> +-/* returns non-zero if proposal contains any algorithm from algs */
> + static int
> +-has_any_alg(const char *proposal, const char *algs)
> ++kexalgs_contains(char **peer, const char *ext)
> + {
> +-      char *cp;
> +-
> +-      if ((cp = match_list(proposal, algs, NULL)) == NULL)
> +-              return 0;
> +-      free(cp);
> +-      return 1;
> ++      return has_any_alg(peer[PROPOSAL_KEX_ALGS], ext);
> + }
> +
> + static int
> +-kex_choose_conf(struct ssh *ssh)
> ++kex_choose_conf(struct ssh *ssh, uint32_t seq)
> + {
> +       struct kex *kex = ssh->kex;
> +       struct newkeys *newkeys;
> +@@ -938,13 +947,23 @@ kex_choose_conf(struct ssh *ssh)
> +               sprop=peer;
> +       }
> +
> +-      /* Check whether client supports ext_info_c */
> +-      if (kex->server && (kex->flags & KEX_INITIAL)) {
> +-              char *ext;
> +-
> +-              ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS],
> NULL);
> +-              kex->ext_info_c = (ext != NULL);
> +-              free(ext);
> ++      /* Check whether peer supports ext_info/kex_strict */
> ++      if ((kex->flags & KEX_INITIAL) != 0) {
> ++              if (kex->server) {
> ++                      kex->ext_info_c = kexalgs_contains(peer,
> "ext-info-c");
> ++                      kex->kex_strict = kexalgs_contains(peer,
> ++                          "kex-strict-c-v00@openssh.com");
> ++              } else {
> ++                      kex->kex_strict = kexalgs_contains(peer,
> ++                          "kex-strict-s-v00@openssh.com");
> ++              }
> ++              if (kex->kex_strict) {
> ++                      debug3_f("will use strict KEX ordering");
> ++                      if (seq != 0)
> ++                              ssh_packet_disconnect(ssh,
> ++                                  "strict KEX violation: "
> ++                                  "KEXINIT was not the first packet");
> ++              }
> +       }
> +
> +       /* Check whether client supports rsa-sha2 algorithms */
> +diff --git a/kex.h b/kex.h
> +index c353295..c27f9d8 100644
> +--- a/kex.h
> ++++ b/kex.h
> +@@ -1,4 +1,4 @@
> +-/* $OpenBSD: kex.h,v 1.117 2022/01/06 21:55:23 djm Exp $ */
> ++/* $OpenBSD: kex.h,v 1.120 2023/12/18 14:45:17 djm Exp $ */
> +
> + /*
> +  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
> +@@ -148,6 +148,7 @@ struct kex {
> +       u_int   kex_type;
> +       char    *server_sig_algs;
> +       int     ext_info_c;
> ++      int     kex_strict;
> +       struct sshbuf *my;
> +       struct sshbuf *peer;
> +       struct sshbuf *client_version;
> +diff --git a/packet.c b/packet.c
> +index bde6c10..322a8c2 100644
> +--- a/packet.c
> ++++ b/packet.c
> +@@ -1,4 +1,4 @@
> +-/* $OpenBSD: packet.c,v 1.307 2022/01/22 00:49:34 djm Exp $ */
> ++/* $OpenBSD: packet.c,v 1.313 2023/12/18 14:45:17 djm Exp $ */
> + /*
> +  * Author: Tatu Ylonen <ylo@cs.hut.fi>
> +  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
> +@@ -1205,8 +1205,13 @@ ssh_packet_send2_wrapped(struct ssh *ssh)
> +       sshbuf_dump(state->output, stderr);
> + #endif
> +       /* increment sequence number for outgoing packets */
> +-      if (++state->p_send.seqnr == 0)
> ++      if (++state->p_send.seqnr == 0) {
> ++              if ((ssh->kex->flags & KEX_INITIAL) != 0) {
> ++                      ssh_packet_disconnect(ssh, "outgoing sequence
> number "
> ++                          "wrapped during initial key exchange");
> ++              }
> +               logit("outgoing seqnr wraps around");
> ++      }
> +       if (++state->p_send.packets == 0)
> +               if (!(ssh->compat & SSH_BUG_NOREKEY))
> +                       return SSH_ERR_NEED_REKEY;
> +@@ -1214,6 +1219,11 @@ ssh_packet_send2_wrapped(struct ssh *ssh)
> +       state->p_send.bytes += len;
> +       sshbuf_reset(state->outgoing_packet);
> +
> ++      if (type == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) {
> ++              debug_f("resetting send seqnr %u", state->p_send.seqnr);
> ++              state->p_send.seqnr = 0;
> ++      }
> ++
> +       if (type == SSH2_MSG_NEWKEYS)
> +               r = ssh_set_newkeys(ssh, MODE_OUT);
> +       else if (type == SSH2_MSG_USERAUTH_SUCCESS && state->server_side)
> +@@ -1342,8 +1352,7 @@ ssh_packet_read_seqnr(struct ssh *ssh, u_char
> *typep, u_int32_t *seqnr_p)
> +       /* Stay in the loop until we have received a complete packet. */
> +       for (;;) {
> +               /* Try to read a packet from the buffer. */
> +-              r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p);
> +-              if (r != 0)
> ++              if ((r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p))
> != 0)
> +                       break;
> +               /* If we got a packet, return it. */
> +               if (*typep != SSH_MSG_NONE)
> +@@ -1414,29 +1423,6 @@ ssh_packet_read(struct ssh *ssh)
> +       return type;
> + }
> +
> +-/*
> +- * Waits until a packet has been received, verifies that its type matches
> +- * that given, and gives a fatal error and exits if there is a mismatch.
> +- */
> +-
> +-int
> +-ssh_packet_read_expect(struct ssh *ssh, u_int expected_type)
> +-{
> +-      int r;
> +-      u_char type;
> +-
> +-      if ((r = ssh_packet_read_seqnr(ssh, &type, NULL)) != 0)
> +-              return r;
> +-      if (type != expected_type) {
> +-              if ((r = sshpkt_disconnect(ssh,
> +-                  "Protocol error: expected packet type %d, got %d",
> +-                  expected_type, type)) != 0)
> +-                      return r;
> +-              return SSH_ERR_PROTOCOL_ERROR;
> +-      }
> +-      return 0;
> +-}
> +-
> + static int
> + ssh_packet_read_poll2_mux(struct ssh *ssh, u_char *typep, u_int32_t
> *seqnr_p)
> + {
> +@@ -1627,10 +1613,16 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char
> *typep, u_int32_t *seqnr_p)
> +               if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0)
> +                       goto out;
> +       }
> ++
> +       if (seqnr_p != NULL)
> +               *seqnr_p = state->p_read.seqnr;
> +-      if (++state->p_read.seqnr == 0)
> ++      if (++state->p_read.seqnr == 0) {
> ++              if ((ssh->kex->flags & KEX_INITIAL) != 0) {
> ++                      ssh_packet_disconnect(ssh, "incoming sequence
> number "
> ++                          "wrapped during initial key exchange");
> ++              }
> +               logit("incoming seqnr wraps around");
> ++      }
> +       if (++state->p_read.packets == 0)
> +               if (!(ssh->compat & SSH_BUG_NOREKEY))
> +                       return SSH_ERR_NEED_REKEY;
> +@@ -1696,6 +1688,10 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char
> *typep, u_int32_t *seqnr_p)
> + #endif
> +       /* reset for next packet */
> +       state->packlen = 0;
> ++      if (*typep == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) {
> ++              debug_f("resetting read seqnr %u", state->p_read.seqnr);
> ++              state->p_read.seqnr = 0;
> ++      }
> +
> +       if ((r = ssh_packet_check_rekey(ssh)) != 0)
> +               return r;
> +@@ -1716,10 +1712,39 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh,
> u_char *typep, u_int32_t *seqnr_p)
> +               r = ssh_packet_read_poll2(ssh, typep, seqnr_p);
> +               if (r != 0)
> +                       return r;
> +-              if (*typep) {
> +-                      state->keep_alive_timeouts = 0;
> +-                      DBG(debug("received packet type %d", *typep));
> ++              if (*typep == 0) {
> ++                      /* no message ready */
> ++                      return 0;
> +               }
> ++              state->keep_alive_timeouts = 0;
> ++              DBG(debug("received packet type %d", *typep));
> ++
> ++              /* Always process disconnect messages */
> ++              if (*typep == SSH2_MSG_DISCONNECT) {
> ++                      if ((r = sshpkt_get_u32(ssh, &reason)) != 0 ||
> ++                          (r = sshpkt_get_string(ssh, &msg, NULL)) != 0)
> ++                              return r;
> ++                      /* Ignore normal client exit notifications */
> ++                      do_log2(ssh->state->server_side &&
> ++                          reason == SSH2_DISCONNECT_BY_APPLICATION ?
> ++                          SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR,
> ++                          "Received disconnect from %s port %d:"
> ++                          "%u: %.400s", ssh_remote_ipaddr(ssh),
> ++                          ssh_remote_port(ssh), reason, msg);
> ++                      free(msg);
> ++                      return SSH_ERR_DISCONNECTED;
> ++              }
> ++
> ++              /*
> ++               * Do not implicitly handle any messages here during
> initial
> ++               * KEX when in strict mode. They will be need to be allowed
> ++               * explicitly by the KEX dispatch table or they will
> generate
> ++               * protocol errors.
> ++               */
> ++              if (ssh->kex != NULL &&
> ++                  (ssh->kex->flags & KEX_INITIAL) &&
> ssh->kex->kex_strict)
> ++                      return 0;
> ++              /* Implicitly handle transport-level messages */
> +               switch (*typep) {
> +               case SSH2_MSG_IGNORE:
> +                       debug3("Received SSH2_MSG_IGNORE");
> +@@ -1734,19 +1759,6 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char
> *typep, u_int32_t *seqnr_p)
> +                       debug("Remote: %.900s", msg);
> +                       free(msg);
> +                       break;
> +-              case SSH2_MSG_DISCONNECT:
> +-                      if ((r = sshpkt_get_u32(ssh, &reason)) != 0 ||
> +-                          (r = sshpkt_get_string(ssh, &msg, NULL)) != 0)
> +-                              return r;
> +-                      /* Ignore normal client exit notifications */
> +-                      do_log2(ssh->state->server_side &&
> +-                          reason == SSH2_DISCONNECT_BY_APPLICATION ?
> +-                          SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR,
> +-                          "Received disconnect from %s port %d:"
> +-                          "%u: %.400s", ssh_remote_ipaddr(ssh),
> +-                          ssh_remote_port(ssh), reason, msg);
> +-                      free(msg);
> +-                      return SSH_ERR_DISCONNECTED;
> +               case SSH2_MSG_UNIMPLEMENTED:
> +                       if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0)
> +                               return r;
> +@@ -2211,6 +2223,7 @@ kex_to_blob(struct sshbuf *m, struct kex *kex)
> +           (r = sshbuf_put_u32(m, kex->hostkey_type)) != 0 ||
> +           (r = sshbuf_put_u32(m, kex->hostkey_nid)) != 0 ||
> +           (r = sshbuf_put_u32(m, kex->kex_type)) != 0 ||
> ++          (r = sshbuf_put_u32(m, kex->kex_strict)) != 0 ||
> +           (r = sshbuf_put_stringb(m, kex->my)) != 0 ||
> +           (r = sshbuf_put_stringb(m, kex->peer)) != 0 ||
> +           (r = sshbuf_put_stringb(m, kex->client_version)) != 0 ||
> +@@ -2373,6 +2386,7 @@ kex_from_blob(struct sshbuf *m, struct kex **kexp)
> +           (r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_type)) != 0 ||
> +           (r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_nid)) != 0 ||
> +           (r = sshbuf_get_u32(m, &kex->kex_type)) != 0 ||
> ++          (r = sshbuf_get_u32(m, &kex->kex_strict)) != 0 ||
> +           (r = sshbuf_get_stringb(m, kex->my)) != 0 ||
> +           (r = sshbuf_get_stringb(m, kex->peer)) != 0 ||
> +           (r = sshbuf_get_stringb(m, kex->client_version)) != 0 ||
> +@@ -2701,6 +2715,7 @@ sshpkt_disconnect(struct ssh *ssh, const char
> *fmt,...)
> +       vsnprintf(buf, sizeof(buf), fmt, args);
> +       va_end(args);
> +
> ++      debug2_f("sending SSH2_MSG_DISCONNECT: %s", buf);
> +       if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 ||
> +           (r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0
> ||
> +           (r = sshpkt_put_cstring(ssh, buf)) != 0 ||
> +diff --git a/packet.h b/packet.h
> +index 176488b..3e03f53 100644
> +--- a/packet.h
> ++++ b/packet.h
> +@@ -1,4 +1,4 @@
> +-/* $OpenBSD: packet.h,v 1.94 2022/01/22 00:49:34 djm Exp $ */
> ++/* $OpenBSD: packet.h,v 1.96 2023/12/18 14:45:17 djm Exp $ */
> +
> + /*
> +  * Author: Tatu Ylonen <ylo@cs.hut.fi>
> +@@ -124,7 +124,6 @@ int         ssh_packet_send2_wrapped(struct ssh *);
> + int    ssh_packet_send2(struct ssh *);
> +
> + int      ssh_packet_read(struct ssh *);
> +-int    ssh_packet_read_expect(struct ssh *, u_int type);
> + int      ssh_packet_read_poll(struct ssh *);
> + int ssh_packet_read_poll2(struct ssh *, u_char *, u_int32_t *seqnr_p);
> + int    ssh_packet_process_incoming(struct ssh *, const char *buf, u_int
> len);
> +diff --git a/sshconnect2.c b/sshconnect2.c
> +index b25225e..1deaa5e 100644
> +--- a/sshconnect2.c
> ++++ b/sshconnect2.c
> +@@ -1,4 +1,4 @@
> +-/* $OpenBSD: sshconnect2.c,v 1.356 2022/02/01 23:32:51 djm Exp $ */
> ++/* $OpenBSD: sshconnect2.c,v 1.370 2023/12/18 14:45:17 djm Exp $ */
> + /*
> +  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
> +  * Copyright (c) 2008 Damien Miller.  All rights reserved.
> +@@ -363,7 +363,6 @@ struct cauthmethod {
> + };
> +
> + static int input_userauth_service_accept(int, u_int32_t, struct ssh *);
> +-static int input_userauth_ext_info(int, u_int32_t, struct ssh *);
> + static int input_userauth_success(int, u_int32_t, struct ssh *);
> + static int input_userauth_failure(int, u_int32_t, struct ssh *);
> + static int input_userauth_banner(int, u_int32_t, struct ssh *);
> +@@ -477,7 +476,7 @@ ssh_userauth2(struct ssh *ssh, const char *local_user,
> +
> +       ssh->authctxt = &authctxt;
> +       ssh_dispatch_init(ssh, &input_userauth_error);
> +-      ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info);
> ++      ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, kex_input_ext_info);
> +       ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT,
> &input_userauth_service_accept);
> +       ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt.success); /*
> loop until success */
> +       pubkey_cleanup(ssh);
> +@@ -530,12 +529,6 @@ input_userauth_service_accept(int type, u_int32_t
> seq, struct ssh *ssh)
> + }
> +
> + /* ARGSUSED */
> +-static int
> +-input_userauth_ext_info(int type, u_int32_t seqnr, struct ssh *ssh)
> +-{
> +-      return kex_input_ext_info(type, seqnr, ssh);
> +-}
> +-
> + void
> + userauth(struct ssh *ssh, char *authlist)
> + {
> +@@ -617,6 +610,7 @@ input_userauth_success(int type, u_int32_t seq,
> struct ssh *ssh)
> +       free(authctxt->methoddata);
> +       authctxt->methoddata = NULL;
> +       authctxt->success = 1;                  /* break out */
> ++      ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, dispatch_protocol_error);
> +       return 0;
> + }
> +
> +--
> +2.40.0
> diff --git a/meta/recipes-connectivity/openssh/openssh_8.9p1.bb
> b/meta/recipes-connectivity/openssh/openssh_8.9p1.bb
> index 3f3cd2a908..91f04bf08b 100644
> --- a/meta/recipes-connectivity/openssh/openssh_8.9p1.bb
> +++ b/meta/recipes-connectivity/openssh/openssh_8.9p1.bb
> @@ -33,6 +33,7 @@ SRC_URI = "
> http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-${PV}.tar
>             file://CVE-2023-38408-0002.patch \
>             file://CVE-2023-38408-0003.patch \
>             file://CVE-2023-38408-0004.patch \
> +           file://CVE-2023-48795.patch \
>             "
>  SRC_URI[sha256sum] =
> "fd497654b7ab1686dac672fb83dfb4ba4096e8b5ffcdaccd262380ae58bec5e7"
>
> --
> 2.40.0
>
>
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#193892):
> https://lists.openembedded.org/g/openembedded-core/message/193892
> Mute This Topic: https://lists.openembedded.org/mt/103781431/7301997
> Group Owner: openembedded-core+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [
> vanusuri@mvista.com]
> -=-=-=-=-=-=-=-=-=-=-=-
>
>
diff mbox series

Patch

diff --git a/meta/recipes-connectivity/openssh/openssh/CVE-2023-48795.patch b/meta/recipes-connectivity/openssh/openssh/CVE-2023-48795.patch
new file mode 100644
index 0000000000..b1b16d5641
--- /dev/null
+++ b/meta/recipes-connectivity/openssh/openssh/CVE-2023-48795.patch
@@ -0,0 +1,503 @@ 
+From 1edb00c58f8a6875fad6a497aa2bacf37f9e6cd5 Mon Sep 17 00:00:00 2001
+From: "djm@openbsd.org" <djm@openbsd.org>
+Date: Mon, 18 Dec 2023 14:45:17 +0000
+Subject: [PATCH] upstream: implement "strict key exchange" in ssh and sshd
+ This adds a protocol extension to improve the integrity of the SSH transport
+ protocol, particular in and around the initial key exchange (KEX) phase.
+
+Full details of the extension are in the PROTOCOL file.
+
+with markus@
+
+OpenBSD-Commit-ID: 2a66ac962f0a630d7945fee54004ed9e9c439f14
+
+CVE: CVE-2023-48795
+Upstream-Status: Backport [https://github.com/openssh/openssh-portable/commit/1edb00c58f8a6875fad6a497aa2bacf37f9e6cd5]
+
+Signed-off-by: Meenali Gupta <meenali.gupta@windriver.com>
+---
+ PROTOCOL      |  28 +++++++++++++-
+ kex.c         |  71 +++++++++++++++++++++-------------
+ kex.h         |   3 +-
+ packet.c      | 103 +++++++++++++++++++++++++++++---------------------
+ packet.h      |   3 +-
+ sshconnect2.c |  12 ++----
+ 6 files changed, 137 insertions(+), 83 deletions(-)
+
+diff --git a/PROTOCOL b/PROTOCOL
+index e6a7d60..68912ce 100644
+--- a/PROTOCOL
++++ b/PROTOCOL
+@@ -102,6 +102,32 @@ OpenSSH supports the use of ECDH in Curve25519 for key exchange as
+ described at:
+ http://git.libssh.org/users/aris/libssh.git/plain/doc/curve25519-sha256@libssh.org.txt?h=curve25519
+
++1.9 transport: strict key exchange extension
++
++OpenSSH supports a number of transport-layer hardening measures under
++a "strict KEX" feature. This feature is signalled similarly to the
++RFC8308 ext-info feature: by including a additional algorithm in the
++initiial SSH2_MSG_KEXINIT kex_algorithms field. The client may append
++"kex-strict-c-v00@openssh.com" to its kex_algorithms and the server
++may append "kex-strict-s-v00@openssh.com". These pseudo-algorithms
++are only valid in the initial SSH2_MSG_KEXINIT and MUST be ignored
++if they are present in subsequent SSH2_MSG_KEXINIT packets.
++
++When an endpoint that supports this extension observes this algorithm
++name in a peer's KEXINIT packet, it MUST make the following changes to
++the the protocol:
++
++a) During initial KEX, terminate the connection if any unexpected or
++   out-of-sequence packet is received. This includes terminating the
++   connection if the first packet received is not SSH2_MSG_KEXINIT.
++   Unexpected packets for the purpose of strict KEX include messages
++   that are otherwise valid at any time during the connection such as
++   SSH2_MSG_DEBUG and SSH2_MSG_IGNORE.
++b) After sending or receiving a SSH2_MSG_NEWKEYS message, reset the
++   packet sequence number to zero. This behaviour persists for the
++   duration of the connection (i.e. not just the first
++   SSH2_MSG_NEWKEYS).
++
+ 2. Connection protocol changes
+
+ 2.1. connection: Channel write close extension "eow@openssh.com"
+@@ -612,4 +638,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.43 2021/12/19 22:15:42 djm Exp $
++$OpenBSD: PROTOCOL,v 1.50 2023/12/18 14:45:17 djm Exp $
+diff --git a/kex.c b/kex.c
+index 0bcd27d..da16568 100644
+--- a/kex.c
++++ b/kex.c
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: kex.c,v 1.172 2022/02/01 23:32:51 djm Exp $ */
++/* $OpenBSD: kex.c,v 1.183 2023/12/18 14:45:17 djm Exp $ */
+ /*
+  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
+  *
+@@ -63,7 +63,7 @@
+ #include "digest.h"
+
+ /* prototype */
+-static int kex_choose_conf(struct ssh *);
++static int kex_choose_conf(struct ssh *, uint32_t seq);
+ static int kex_input_newkeys(int, u_int32_t, struct ssh *);
+
+ static const char * const proposal_names[PROPOSAL_MAX] = {
+@@ -175,6 +175,18 @@ kex_names_valid(const char *names)
+	return 1;
+ }
+
++/* returns non-zero if proposal contains any algorithm from algs */
++static int
++has_any_alg(const char *proposal, const char *algs)
++{
++	char *cp;
++
++	if ((cp = match_list(proposal, algs, NULL)) == NULL)
++		return 0;
++	free(cp);
++	return 1;
++}
++
+ /*
+  * Concatenate algorithm names, avoiding duplicates in the process.
+  * Caller must free returned string.
+@@ -182,7 +194,7 @@ kex_names_valid(const char *names)
+ char *
+ kex_names_cat(const char *a, const char *b)
+ {
+-	char *ret = NULL, *tmp = NULL, *cp, *p, *m;
++	char *ret = NULL, *tmp = NULL, *cp, *p;
+	size_t len;
+
+	if (a == NULL || *a == '\0')
+@@ -199,10 +211,8 @@ kex_names_cat(const char *a, const char *b)
+	}
+	strlcpy(ret, a, len);
+	for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) {
+-		if ((m = match_list(ret, p, NULL)) != NULL) {
+-			free(m);
++		if (has_any_alg(ret, p))
+			continue; /* Algorithm already present */
+-		}
+		if (strlcat(ret, ",", len) >= len ||
+		    strlcat(ret, p, len) >= len) {
+			free(tmp);
+@@ -410,7 +420,12 @@ kex_protocol_error(int type, u_int32_t seq, struct ssh *ssh)
+ {
+	int r;
+
+-	error("kex protocol error: type %d seq %u", type, seq);
++	/* If in strict mode, any unexpected message is an error */
++	if ((ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict) {
++		ssh_packet_disconnect(ssh, "strict KEX violation: "
++		    "unexpected packet type %u (seqnr %u)", type, seq);
++	}
++	error_f("type %u seq %u", type, seq);
+	if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
+	    (r = sshpkt_put_u32(ssh, seq)) != 0 ||
+	    (r = sshpkt_send(ssh)) != 0)
+@@ -496,7 +511,7 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
+			/* Ensure no \0 lurking in value */
+			if (memchr(val, '\0', vlen) != NULL) {
+				error_f("nul byte in %s", name);
+-				return SSH_ERR_INVALID_FORMAT;
++				return dispatch_protocol_error(type, seq, ssh);
+			}
+			debug_f("%s=<%s>", name, val);
+			kex->server_sig_algs = val;
+@@ -600,7 +615,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh)
+		error_f("no kex");
+		return SSH_ERR_INTERNAL_ERROR;
+	}
+-	ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL);
++	ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_protocol_error);
+	ptr = sshpkt_ptr(ssh, &dlen);
+	if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0)
+		return r;
+@@ -636,7 +651,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh)
+	if (!(kex->flags & KEX_INIT_SENT))
+		if ((r = kex_send_kexinit(ssh)) != 0)
+			return r;
+-	if ((r = kex_choose_conf(ssh)) != 0)
++	if ((r = kex_choose_conf(ssh, seq)) != 0)
+		return r;
+
+	if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL)
+@@ -900,20 +915,14 @@ proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX])
+	return (1);
+ }
+
+-/* returns non-zero if proposal contains any algorithm from algs */
+ static int
+-has_any_alg(const char *proposal, const char *algs)
++kexalgs_contains(char **peer, const char *ext)
+ {
+-	char *cp;
+-
+-	if ((cp = match_list(proposal, algs, NULL)) == NULL)
+-		return 0;
+-	free(cp);
+-	return 1;
++	return has_any_alg(peer[PROPOSAL_KEX_ALGS], ext);
+ }
+
+ static int
+-kex_choose_conf(struct ssh *ssh)
++kex_choose_conf(struct ssh *ssh, uint32_t seq)
+ {
+	struct kex *kex = ssh->kex;
+	struct newkeys *newkeys;
+@@ -938,13 +947,23 @@ kex_choose_conf(struct ssh *ssh)
+		sprop=peer;
+	}
+
+-	/* Check whether client supports ext_info_c */
+-	if (kex->server && (kex->flags & KEX_INITIAL)) {
+-		char *ext;
+-
+-		ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL);
+-		kex->ext_info_c = (ext != NULL);
+-		free(ext);
++	/* Check whether peer supports ext_info/kex_strict */
++	if ((kex->flags & KEX_INITIAL) != 0) {
++		if (kex->server) {
++			kex->ext_info_c = kexalgs_contains(peer, "ext-info-c");
++			kex->kex_strict = kexalgs_contains(peer,
++			    "kex-strict-c-v00@openssh.com");
++		} else {
++			kex->kex_strict = kexalgs_contains(peer,
++			    "kex-strict-s-v00@openssh.com");
++		}
++		if (kex->kex_strict) {
++			debug3_f("will use strict KEX ordering");
++			if (seq != 0)
++				ssh_packet_disconnect(ssh,
++				    "strict KEX violation: "
++				    "KEXINIT was not the first packet");
++		}
+	}
+
+	/* Check whether client supports rsa-sha2 algorithms */
+diff --git a/kex.h b/kex.h
+index c353295..c27f9d8 100644
+--- a/kex.h
++++ b/kex.h
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: kex.h,v 1.117 2022/01/06 21:55:23 djm Exp $ */
++/* $OpenBSD: kex.h,v 1.120 2023/12/18 14:45:17 djm Exp $ */
+
+ /*
+  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
+@@ -148,6 +148,7 @@ struct kex {
+	u_int	kex_type;
+	char	*server_sig_algs;
+	int	ext_info_c;
++	int	kex_strict;
+	struct sshbuf *my;
+	struct sshbuf *peer;
+	struct sshbuf *client_version;
+diff --git a/packet.c b/packet.c
+index bde6c10..322a8c2 100644
+--- a/packet.c
++++ b/packet.c
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: packet.c,v 1.307 2022/01/22 00:49:34 djm Exp $ */
++/* $OpenBSD: packet.c,v 1.313 2023/12/18 14:45:17 djm Exp $ */
+ /*
+  * Author: Tatu Ylonen <ylo@cs.hut.fi>
+  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+@@ -1205,8 +1205,13 @@ ssh_packet_send2_wrapped(struct ssh *ssh)
+	sshbuf_dump(state->output, stderr);
+ #endif
+	/* increment sequence number for outgoing packets */
+-	if (++state->p_send.seqnr == 0)
++	if (++state->p_send.seqnr == 0) {
++		if ((ssh->kex->flags & KEX_INITIAL) != 0) {
++			ssh_packet_disconnect(ssh, "outgoing sequence number "
++			    "wrapped during initial key exchange");
++		}
+		logit("outgoing seqnr wraps around");
++	}
+	if (++state->p_send.packets == 0)
+		if (!(ssh->compat & SSH_BUG_NOREKEY))
+			return SSH_ERR_NEED_REKEY;
+@@ -1214,6 +1219,11 @@ ssh_packet_send2_wrapped(struct ssh *ssh)
+	state->p_send.bytes += len;
+	sshbuf_reset(state->outgoing_packet);
+
++	if (type == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) {
++		debug_f("resetting send seqnr %u", state->p_send.seqnr);
++		state->p_send.seqnr = 0;
++	}
++
+	if (type == SSH2_MSG_NEWKEYS)
+		r = ssh_set_newkeys(ssh, MODE_OUT);
+	else if (type == SSH2_MSG_USERAUTH_SUCCESS && state->server_side)
+@@ -1342,8 +1352,7 @@ ssh_packet_read_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
+	/* Stay in the loop until we have received a complete packet. */
+	for (;;) {
+		/* Try to read a packet from the buffer. */
+-		r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p);
+-		if (r != 0)
++		if ((r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p)) != 0)
+			break;
+		/* If we got a packet, return it. */
+		if (*typep != SSH_MSG_NONE)
+@@ -1414,29 +1423,6 @@ ssh_packet_read(struct ssh *ssh)
+	return type;
+ }
+
+-/*
+- * Waits until a packet has been received, verifies that its type matches
+- * that given, and gives a fatal error and exits if there is a mismatch.
+- */
+-
+-int
+-ssh_packet_read_expect(struct ssh *ssh, u_int expected_type)
+-{
+-	int r;
+-	u_char type;
+-
+-	if ((r = ssh_packet_read_seqnr(ssh, &type, NULL)) != 0)
+-		return r;
+-	if (type != expected_type) {
+-		if ((r = sshpkt_disconnect(ssh,
+-		    "Protocol error: expected packet type %d, got %d",
+-		    expected_type, type)) != 0)
+-			return r;
+-		return SSH_ERR_PROTOCOL_ERROR;
+-	}
+-	return 0;
+-}
+-
+ static int
+ ssh_packet_read_poll2_mux(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
+ {
+@@ -1627,10 +1613,16 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
+		if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0)
+			goto out;
+	}
++
+	if (seqnr_p != NULL)
+		*seqnr_p = state->p_read.seqnr;
+-	if (++state->p_read.seqnr == 0)
++	if (++state->p_read.seqnr == 0) {
++		if ((ssh->kex->flags & KEX_INITIAL) != 0) {
++			ssh_packet_disconnect(ssh, "incoming sequence number "
++			    "wrapped during initial key exchange");
++		}
+		logit("incoming seqnr wraps around");
++	}
+	if (++state->p_read.packets == 0)
+		if (!(ssh->compat & SSH_BUG_NOREKEY))
+			return SSH_ERR_NEED_REKEY;
+@@ -1696,6 +1688,10 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
+ #endif
+	/* reset for next packet */
+	state->packlen = 0;
++	if (*typep == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) {
++		debug_f("resetting read seqnr %u", state->p_read.seqnr);
++		state->p_read.seqnr = 0;
++	}
+
+	if ((r = ssh_packet_check_rekey(ssh)) != 0)
+		return r;
+@@ -1716,10 +1712,39 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
+		r = ssh_packet_read_poll2(ssh, typep, seqnr_p);
+		if (r != 0)
+			return r;
+-		if (*typep) {
+-			state->keep_alive_timeouts = 0;
+-			DBG(debug("received packet type %d", *typep));
++		if (*typep == 0) {
++			/* no message ready */
++			return 0;
+		}
++		state->keep_alive_timeouts = 0;
++		DBG(debug("received packet type %d", *typep));
++
++		/* Always process disconnect messages */
++		if (*typep == SSH2_MSG_DISCONNECT) {
++			if ((r = sshpkt_get_u32(ssh, &reason)) != 0 ||
++			    (r = sshpkt_get_string(ssh, &msg, NULL)) != 0)
++				return r;
++			/* Ignore normal client exit notifications */
++			do_log2(ssh->state->server_side &&
++			    reason == SSH2_DISCONNECT_BY_APPLICATION ?
++			    SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR,
++			    "Received disconnect from %s port %d:"
++			    "%u: %.400s", ssh_remote_ipaddr(ssh),
++			    ssh_remote_port(ssh), reason, msg);
++			free(msg);
++			return SSH_ERR_DISCONNECTED;
++		}
++
++		/*
++		 * Do not implicitly handle any messages here during initial
++		 * KEX when in strict mode. They will be need to be allowed
++		 * explicitly by the KEX dispatch table or they will generate
++		 * protocol errors.
++		 */
++		if (ssh->kex != NULL &&
++		    (ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict)
++			return 0;
++		/* Implicitly handle transport-level messages */
+		switch (*typep) {
+		case SSH2_MSG_IGNORE:
+			debug3("Received SSH2_MSG_IGNORE");
+@@ -1734,19 +1759,6 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
+			debug("Remote: %.900s", msg);
+			free(msg);
+			break;
+-		case SSH2_MSG_DISCONNECT:
+-			if ((r = sshpkt_get_u32(ssh, &reason)) != 0 ||
+-			    (r = sshpkt_get_string(ssh, &msg, NULL)) != 0)
+-				return r;
+-			/* Ignore normal client exit notifications */
+-			do_log2(ssh->state->server_side &&
+-			    reason == SSH2_DISCONNECT_BY_APPLICATION ?
+-			    SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR,
+-			    "Received disconnect from %s port %d:"
+-			    "%u: %.400s", ssh_remote_ipaddr(ssh),
+-			    ssh_remote_port(ssh), reason, msg);
+-			free(msg);
+-			return SSH_ERR_DISCONNECTED;
+		case SSH2_MSG_UNIMPLEMENTED:
+			if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0)
+				return r;
+@@ -2211,6 +2223,7 @@ kex_to_blob(struct sshbuf *m, struct kex *kex)
+	    (r = sshbuf_put_u32(m, kex->hostkey_type)) != 0 ||
+	    (r = sshbuf_put_u32(m, kex->hostkey_nid)) != 0 ||
+	    (r = sshbuf_put_u32(m, kex->kex_type)) != 0 ||
++	    (r = sshbuf_put_u32(m, kex->kex_strict)) != 0 ||
+	    (r = sshbuf_put_stringb(m, kex->my)) != 0 ||
+	    (r = sshbuf_put_stringb(m, kex->peer)) != 0 ||
+	    (r = sshbuf_put_stringb(m, kex->client_version)) != 0 ||
+@@ -2373,6 +2386,7 @@ kex_from_blob(struct sshbuf *m, struct kex **kexp)
+	    (r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_type)) != 0 ||
+	    (r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_nid)) != 0 ||
+	    (r = sshbuf_get_u32(m, &kex->kex_type)) != 0 ||
++	    (r = sshbuf_get_u32(m, &kex->kex_strict)) != 0 ||
+	    (r = sshbuf_get_stringb(m, kex->my)) != 0 ||
+	    (r = sshbuf_get_stringb(m, kex->peer)) != 0 ||
+	    (r = sshbuf_get_stringb(m, kex->client_version)) != 0 ||
+@@ -2701,6 +2715,7 @@ sshpkt_disconnect(struct ssh *ssh, const char *fmt,...)
+	vsnprintf(buf, sizeof(buf), fmt, args);
+	va_end(args);
+
++	debug2_f("sending SSH2_MSG_DISCONNECT: %s", buf);
+	if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 ||
+	    (r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 ||
+	    (r = sshpkt_put_cstring(ssh, buf)) != 0 ||
+diff --git a/packet.h b/packet.h
+index 176488b..3e03f53 100644
+--- a/packet.h
++++ b/packet.h
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: packet.h,v 1.94 2022/01/22 00:49:34 djm Exp $ */
++/* $OpenBSD: packet.h,v 1.96 2023/12/18 14:45:17 djm Exp $ */
+
+ /*
+  * Author: Tatu Ylonen <ylo@cs.hut.fi>
+@@ -124,7 +124,6 @@ int	 ssh_packet_send2_wrapped(struct ssh *);
+ int	 ssh_packet_send2(struct ssh *);
+
+ int      ssh_packet_read(struct ssh *);
+-int	 ssh_packet_read_expect(struct ssh *, u_int type);
+ int      ssh_packet_read_poll(struct ssh *);
+ int ssh_packet_read_poll2(struct ssh *, u_char *, u_int32_t *seqnr_p);
+ int	 ssh_packet_process_incoming(struct ssh *, const char *buf, u_int len);
+diff --git a/sshconnect2.c b/sshconnect2.c
+index b25225e..1deaa5e 100644
+--- a/sshconnect2.c
++++ b/sshconnect2.c
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: sshconnect2.c,v 1.356 2022/02/01 23:32:51 djm Exp $ */
++/* $OpenBSD: sshconnect2.c,v 1.370 2023/12/18 14:45:17 djm Exp $ */
+ /*
+  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+  * Copyright (c) 2008 Damien Miller.  All rights reserved.
+@@ -363,7 +363,6 @@ struct cauthmethod {
+ };
+
+ static int input_userauth_service_accept(int, u_int32_t, struct ssh *);
+-static int input_userauth_ext_info(int, u_int32_t, struct ssh *);
+ static int input_userauth_success(int, u_int32_t, struct ssh *);
+ static int input_userauth_failure(int, u_int32_t, struct ssh *);
+ static int input_userauth_banner(int, u_int32_t, struct ssh *);
+@@ -477,7 +476,7 @@ ssh_userauth2(struct ssh *ssh, const char *local_user,
+
+	ssh->authctxt = &authctxt;
+	ssh_dispatch_init(ssh, &input_userauth_error);
+-	ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info);
++	ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, kex_input_ext_info);
+	ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT, &input_userauth_service_accept);
+	ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt.success);	/* loop until success */
+	pubkey_cleanup(ssh);
+@@ -530,12 +529,6 @@ input_userauth_service_accept(int type, u_int32_t seq, struct ssh *ssh)
+ }
+
+ /* ARGSUSED */
+-static int
+-input_userauth_ext_info(int type, u_int32_t seqnr, struct ssh *ssh)
+-{
+-	return kex_input_ext_info(type, seqnr, ssh);
+-}
+-
+ void
+ userauth(struct ssh *ssh, char *authlist)
+ {
+@@ -617,6 +610,7 @@ input_userauth_success(int type, u_int32_t seq, struct ssh *ssh)
+	free(authctxt->methoddata);
+	authctxt->methoddata = NULL;
+	authctxt->success = 1;			/* break out */
++	ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, dispatch_protocol_error);
+	return 0;
+ }
+
+--
+2.40.0
diff --git a/meta/recipes-connectivity/openssh/openssh_8.9p1.bb b/meta/recipes-connectivity/openssh/openssh_8.9p1.bb
index 3f3cd2a908..91f04bf08b 100644
--- a/meta/recipes-connectivity/openssh/openssh_8.9p1.bb
+++ b/meta/recipes-connectivity/openssh/openssh_8.9p1.bb
@@ -33,6 +33,7 @@  SRC_URI = "http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-${PV}.tar
            file://CVE-2023-38408-0002.patch \
            file://CVE-2023-38408-0003.patch \
            file://CVE-2023-38408-0004.patch \
+           file://CVE-2023-48795.patch \
            "
 SRC_URI[sha256sum] = "fd497654b7ab1686dac672fb83dfb4ba4096e8b5ffcdaccd262380ae58bec5e7"