summaryrefslogtreecommitdiffstats
path: root/meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-11.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-11.patch')
-rw-r--r--meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-11.patch307
1 files changed, 307 insertions, 0 deletions
diff --git a/meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-11.patch b/meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-11.patch
new file mode 100644
index 0000000000..c300393ebf
--- /dev/null
+++ b/meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-11.patch
@@ -0,0 +1,307 @@
+From 2b3b369c8cf71f9ef5942a5e074e6f86e7ca1e0c Mon Sep 17 00:00:00 2001
+From: "djm@openbsd.org" <djm@openbsd.org>
+Date: Sun, 19 Dec 2021 22:09:23 +0000
+Subject: [PATCH 11/12] upstream: ssh-agent side of binding
+
+record session ID/hostkey/forwarding status for each active socket.
+
+Attempt to parse data-to-be-signed at signature request time and extract
+session ID from the blob if it is a pubkey userauth request.
+
+ok markus@
+
+OpenBSD-Commit-ID: a80fd41e292b18b67508362129e9fed549abd318
+
+Upstream-Status: Backport [https://github.com/openssh/openssh-portable/commit/4c1e3ce85e183a9d0c955c88589fed18e4d6a058]
+CVE: CVE-2023-38408
+Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com>
+---
+ authfd.h | 3 +
+ ssh-agent.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++---
+ 2 files changed, 170 insertions(+), 8 deletions(-)
+
+diff --git a/authfd.h b/authfd.h
+index c3bf625..9cc9807 100644
+--- a/authfd.h
++++ b/authfd.h
+@@ -76,6 +76,9 @@ int ssh_agent_sign(int sock, const struct sshkey *key,
+ #define SSH2_AGENTC_ADD_ID_CONSTRAINED 25
+ #define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26
+
++/* generic extension mechanism */
++#define SSH_AGENTC_EXTENSION 27
++
+ #define SSH_AGENT_CONSTRAIN_LIFETIME 1
+ #define SSH_AGENT_CONSTRAIN_CONFIRM 2
+ #define SSH_AGENT_CONSTRAIN_MAXSIGN 3
+diff --git a/ssh-agent.c b/ssh-agent.c
+index 7f1e14b..01c7f2b 100644
+--- a/ssh-agent.c
++++ b/ssh-agent.c
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: ssh-agent.c,v 1.275 2021/01/29 06:29:46 djm Exp $ */
++/* $OpenBSD: ssh-agent.c,v 1.280 2021/12/19 22:09:23 djm Exp $ */
+ /*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+@@ -98,9 +98,15 @@
+ #endif
+
+ /* Maximum accepted message length */
+-#define AGENT_MAX_LEN (256*1024)
++#define AGENT_MAX_LEN (256*1024)
+ /* Maximum bytes to read from client socket */
+-#define AGENT_RBUF_LEN (4096)
++#define AGENT_RBUF_LEN (4096)
++/* Maximum number of recorded session IDs/hostkeys per connection */
++#define AGENT_MAX_SESSION_IDS 16
++/* Maximum size of session ID */
++#define AGENT_MAX_SID_LEN 128
++
++/* XXX store hostkey_sid in a refcounted tree */
+
+ typedef enum {
+ AUTH_UNUSED = 0,
+@@ -108,12 +114,20 @@ typedef enum {
+ AUTH_CONNECTION = 2,
+ } sock_type;
+
++struct hostkey_sid {
++ struct sshkey *key;
++ struct sshbuf *sid;
++ int forwarded;
++};
++
+ typedef struct socket_entry {
+ int fd;
+ sock_type type;
+ struct sshbuf *input;
+ struct sshbuf *output;
+ struct sshbuf *request;
++ size_t nsession_ids;
++ struct hostkey_sid *session_ids;
+ } SocketEntry;
+
+ u_int sockets_alloc = 0;
+@@ -174,10 +188,17 @@ static int restrict_websafe = 1;
+ static void
+ close_socket(SocketEntry *e)
+ {
++ size_t i;
++
+ close(e->fd);
+ sshbuf_free(e->input);
+ sshbuf_free(e->output);
+ sshbuf_free(e->request);
++ for (i = 0; i < e->nsession_ids; i++) {
++ sshkey_free(e->session_ids[i].key);
++ sshbuf_free(e->session_ids[i].sid);
++ }
++ free(e->session_ids);
+ memset(e, '\0', sizeof(*e));
+ e->fd = -1;
+ e->type = AUTH_UNUSED;
+@@ -423,6 +444,18 @@ check_websafe_message_contents(struct sshkey *key, struct sshbuf *data)
+ return 0;
+ }
+
++static int
++buf_equal(const struct sshbuf *a, const struct sshbuf *b)
++{
++ if (sshbuf_ptr(a) == NULL || sshbuf_ptr(b) == NULL)
++ return SSH_ERR_INVALID_ARGUMENT;
++ if (sshbuf_len(a) != sshbuf_len(b))
++ return SSH_ERR_INVALID_FORMAT;
++ if (timingsafe_bcmp(sshbuf_ptr(a), sshbuf_ptr(b), sshbuf_len(a)) != 0)
++ return SSH_ERR_INVALID_FORMAT;
++ return 0;
++}
++
+ /* ssh2 only */
+ static void
+ process_sign_request2(SocketEntry *e)
+@@ -431,8 +464,8 @@ process_sign_request2(SocketEntry *e)
+ size_t i, slen = 0;
+ u_int compat = 0, flags;
+ int r, ok = -1;
+- char *fp = NULL;
+- struct sshbuf *msg = NULL, *data = NULL;
++ char *fp = NULL, *user = NULL, *sig_dest = NULL;
++ struct sshbuf *msg = NULL, *data = NULL, *sid = NULL;
+ struct sshkey *key = NULL;
+ struct identity *id;
+ struct notifier_ctx *notifier = NULL;
+@@ -452,7 +485,33 @@ process_sign_request2(SocketEntry *e)
+ verbose("%s: %s key not found", __func__, sshkey_type(key));
+ goto send;
+ }
+- if (id->confirm && confirm_key(id, NULL) != 0) {
++ /*
++ * If session IDs were recorded for this socket, then use them to
++ * annotate the confirmation messages with the host keys.
++ */
++ if (e->nsession_ids > 0 &&
++ parse_userauth_request(data, key, &user, &sid) == 0) {
++ /*
++ * session ID from userauth request should match the final
++ * ID in the list recorded in the socket, unless the ssh
++ * client at that point lacks the binding extension (or if
++ * an attacker is trying to steal use of the agent).
++ */
++ i = e->nsession_ids - 1;
++ if (buf_equal(sid, e->session_ids[i].sid) == 0) {
++ if ((fp = sshkey_fingerprint(e->session_ids[i].key,
++ SSH_FP_HASH_DEFAULT, SSH_FP_DEFAULT)) == NULL)
++ fatal("%s: fingerprint failed", __func__);
++ debug3("%s: destination %s %s (slot %zu)", __func__,
++ sshkey_type(e->session_ids[i].key), fp, i);
++ xasprintf(&sig_dest, "public key request for "
++ "target user \"%s\" to %s %s", user,
++ sshkey_type(e->session_ids[i].key), fp);
++ free(fp);
++ fp = NULL;
++ }
++ }//
++ if (id->confirm && confirm_key(id, sig_dest) != 0) {
+ verbose("%s: user refused key", __func__);
+ goto send;
+ }
+@@ -467,8 +526,10 @@ process_sign_request2(SocketEntry *e)
+ SSH_FP_DEFAULT)) == NULL)
+ fatal("%s: fingerprint failed", __func__);
+ notifier = notify_start(0,
+- "Confirm user presence for key %s %s",
+- sshkey_type(id->key), fp);
++ "Confirm user presence for key %s %s%s%s",
++ sshkey_type(id->key), fp,
++ sig_dest == NULL ? "" : "\n",
++ sig_dest == NULL ? "" : sig_dest);
+ }
+ }
+ if ((r = sshkey_sign(id->key, &signature, &slen,
+@@ -492,11 +553,14 @@ process_sign_request2(SocketEntry *e)
+ if ((r = sshbuf_put_stringb(e->output, msg)) != 0)
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
+
++ sshbuf_free(sid);
+ sshbuf_free(data);
+ sshbuf_free(msg);
+ sshkey_free(key);
+ free(fp);
+ free(signature);
++ free(sig_dest);
++ free(user);
+ }
+
+ /* shared */
+@@ -925,6 +989,98 @@ send:
+ }
+ #endif /* ENABLE_PKCS11 */
+
++static int
++process_ext_session_bind(SocketEntry *e)
++{
++ int r, sid_match, key_match;
++ struct sshkey *key = NULL;
++ struct sshbuf *sid = NULL, *sig = NULL;
++ char *fp = NULL;
++ u_char fwd;
++ size_t i;
++
++ debug2("%s: entering", __func__);
++ if ((r = sshkey_froms(e->request, &key)) != 0 ||
++ (r = sshbuf_froms(e->request, &sid)) != 0 ||
++ (r = sshbuf_froms(e->request, &sig)) != 0 ||
++ (r = sshbuf_get_u8(e->request, &fwd)) != 0) {
++ error("%s: parse: %s", __func__, ssh_err(r));
++ goto out;
++ }
++ if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
++ SSH_FP_DEFAULT)) == NULL)
++ fatal("%s: fingerprint failed", __func__);
++ /* check signature with hostkey on session ID */
++ if ((r = sshkey_verify(key, sshbuf_ptr(sig), sshbuf_len(sig),
++ sshbuf_ptr(sid), sshbuf_len(sid), NULL, 0, NULL)) != 0) {
++ error("%s: sshkey_verify for %s %s: %s", __func__, sshkey_type(key), fp, ssh_err(r));
++ goto out;
++ }
++ /* check whether sid/key already recorded */
++ for (i = 0; i < e->nsession_ids; i++) {
++ sid_match = buf_equal(sid, e->session_ids[i].sid) == 0;
++ key_match = sshkey_equal(key, e->session_ids[i].key);
++ if (sid_match && key_match) {
++ debug("%s: session ID already recorded for %s %s", __func__,
++ sshkey_type(key), fp);
++ r = 0;
++ goto out;
++ } else if (sid_match) {
++ error("%s: session ID recorded against different key "
++ "for %s %s", __func__, sshkey_type(key), fp);
++ r = -1;
++ goto out;
++ }
++ /*
++ * new sid with previously-seen key can happen, e.g. multiple
++ * connections to the same host.
++ */
++ }
++ /* record new key/sid */
++ if (e->nsession_ids >= AGENT_MAX_SESSION_IDS) {
++ error("%s: too many session IDs recorded", __func__);
++ goto out;
++ }
++ e->session_ids = xrecallocarray(e->session_ids, e->nsession_ids,
++ e->nsession_ids + 1, sizeof(*e->session_ids));
++ i = e->nsession_ids++;
++ debug("%s: recorded %s %s (slot %zu of %d)", __func__, sshkey_type(key), fp, i,
++ AGENT_MAX_SESSION_IDS);
++ e->session_ids[i].key = key;
++ e->session_ids[i].forwarded = fwd != 0;
++ key = NULL; /* transferred */
++ /* can't transfer sid; it's refcounted and scoped to request's life */
++ if ((e->session_ids[i].sid = sshbuf_new()) == NULL)
++ fatal("%s: sshbuf_new", __func__);
++ if ((r = sshbuf_putb(e->session_ids[i].sid, sid)) != 0)
++ fatal("%s: sshbuf_putb session ID: %s", __func__, ssh_err(r));
++ /* success */
++ r = 0;
++ out:
++ sshkey_free(key);
++ sshbuf_free(sid);
++ sshbuf_free(sig);
++ return r == 0 ? 1 : 0;
++}
++
++static void
++process_extension(SocketEntry *e)
++{
++ int r, success = 0;
++ char *name;
++
++ debug2("%s: entering", __func__);
++ if ((r = sshbuf_get_cstring(e->request, &name, NULL)) != 0) {
++ error("%s: parse: %s", __func__, ssh_err(r));
++ goto send;
++ }
++ if (strcmp(name, "session-bind@openssh.com") == 0)
++ success = process_ext_session_bind(e);
++ else
++ debug("%s: unsupported extension \"%s\"", __func__, name);
++send:
++ send_status(e, success);
++}
+ /*
+ * dispatch incoming message.
+ * returns 1 on success, 0 for incomplete messages or -1 on error.
+@@ -1019,6 +1175,9 @@ process_message(u_int socknum)
+ process_remove_smartcard_key(e);
+ break;
+ #endif /* ENABLE_PKCS11 */
++ case SSH_AGENTC_EXTENSION:
++ process_extension(e);
++ break;
+ default:
+ /* Unknown message. Respond with failure. */
+ error("Unknown message %d", type);
+--
+2.41.0