diff options
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.patch | 307 |
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 |