diff options
3 files changed, 508 insertions, 0 deletions
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..6b2f927779 --- /dev/null +++ b/meta/recipes-connectivity/openssh/openssh/CVE-2023-48795.patch | |||
| @@ -0,0 +1,476 @@ | |||
| 1 | (modified to not remove ssh_packet_read_expect() and to add to | ||
| 2 | KexAlgorithms in sshd.c and sshconnect2.c as this version pre-dates | ||
| 3 | kex_proposal_populate_entries()) | ||
| 4 | |||
| 5 | Backport of: | ||
| 6 | |||
| 7 | From 1edb00c58f8a6875fad6a497aa2bacf37f9e6cd5 Mon Sep 17 00:00:00 2001 | ||
| 8 | From: "djm@openbsd.org" <djm@openbsd.org> | ||
| 9 | Date: Mon, 18 Dec 2023 14:45:17 +0000 | ||
| 10 | Subject: [PATCH] upstream: implement "strict key exchange" in ssh and sshd | ||
| 11 | |||
| 12 | This adds a protocol extension to improve the integrity of the SSH | ||
| 13 | transport protocol, particular in and around the initial key exchange | ||
| 14 | (KEX) phase. | ||
| 15 | |||
| 16 | Full details of the extension are in the PROTOCOL file. | ||
| 17 | |||
| 18 | with markus@ | ||
| 19 | |||
| 20 | OpenBSD-Commit-ID: 2a66ac962f0a630d7945fee54004ed9e9c439f14 | ||
| 21 | |||
| 22 | Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/openssh/tree/debian/patches/CVE-2023-48795.patch?h=ubuntu/jammy-security | ||
| 23 | Upstream commit https://github.com/openssh/openssh-portable/commit/1edb00c58f8a6875fad6a497aa2bacf37f9e6cd5] | ||
| 24 | CVE: CVE-2023-48795 | ||
| 25 | Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> | ||
| 26 | --- | ||
| 27 | PROTOCOL | 26 +++++++++++++++++ | ||
| 28 | kex.c | 72 +++++++++++++++++++++++++++++++---------------- | ||
| 29 | kex.h | 1 + | ||
| 30 | packet.c | 78 ++++++++++++++++++++++++++++++++++++++------------- | ||
| 31 | sshconnect2.c | 14 +++------ | ||
| 32 | sshd.c | 7 +++-- | ||
| 33 | 6 files changed, 142 insertions(+), 56 deletions(-) | ||
| 34 | |||
| 35 | diff --git a/PROTOCOL b/PROTOCOL | ||
| 36 | index e6a7d60..971f01e 100644 | ||
| 37 | --- a/PROTOCOL | ||
| 38 | +++ b/PROTOCOL | ||
| 39 | @@ -102,6 +102,32 @@ OpenSSH supports the use of ECDH in Curve25519 for key exchange as | ||
| 40 | described at: | ||
| 41 | http://git.libssh.org/users/aris/libssh.git/plain/doc/curve25519-sha256@libssh.org.txt?h=curve25519 | ||
| 42 | |||
| 43 | +1.9 transport: strict key exchange extension | ||
| 44 | + | ||
| 45 | +OpenSSH supports a number of transport-layer hardening measures under | ||
| 46 | +a "strict KEX" feature. This feature is signalled similarly to the | ||
| 47 | +RFC8308 ext-info feature: by including a additional algorithm in the | ||
| 48 | +initiial SSH2_MSG_KEXINIT kex_algorithms field. The client may append | ||
| 49 | +"kex-strict-c-v00@openssh.com" to its kex_algorithms and the server | ||
| 50 | +may append "kex-strict-s-v00@openssh.com". These pseudo-algorithms | ||
| 51 | +are only valid in the initial SSH2_MSG_KEXINIT and MUST be ignored | ||
| 52 | +if they are present in subsequent SSH2_MSG_KEXINIT packets. | ||
| 53 | + | ||
| 54 | +When an endpoint that supports this extension observes this algorithm | ||
| 55 | +name in a peer's KEXINIT packet, it MUST make the following changes to | ||
| 56 | +the the protocol: | ||
| 57 | + | ||
| 58 | +a) During initial KEX, terminate the connection if any unexpected or | ||
| 59 | + out-of-sequence packet is received. This includes terminating the | ||
| 60 | + connection if the first packet received is not SSH2_MSG_KEXINIT. | ||
| 61 | + Unexpected packets for the purpose of strict KEX include messages | ||
| 62 | + that are otherwise valid at any time during the connection such as | ||
| 63 | + SSH2_MSG_DEBUG and SSH2_MSG_IGNORE. | ||
| 64 | +b) After sending or receiving a SSH2_MSG_NEWKEYS message, reset the | ||
| 65 | + packet sequence number to zero. This behaviour persists for the | ||
| 66 | + duration of the connection (i.e. not just the first | ||
| 67 | + SSH2_MSG_NEWKEYS). | ||
| 68 | + | ||
| 69 | 2. Connection protocol changes | ||
| 70 | |||
| 71 | 2.1. connection: Channel write close extension "eow@openssh.com" | ||
| 72 | diff --git a/kex.c b/kex.c | ||
| 73 | index 0bcd27d..e7b2d4d 100644 | ||
| 74 | --- a/kex.c | ||
| 75 | +++ b/kex.c | ||
| 76 | @@ -63,7 +63,7 @@ | ||
| 77 | #include "digest.h" | ||
| 78 | |||
| 79 | /* prototype */ | ||
| 80 | -static int kex_choose_conf(struct ssh *); | ||
| 81 | +static int kex_choose_conf(struct ssh *, uint32_t seq); | ||
| 82 | static int kex_input_newkeys(int, u_int32_t, struct ssh *); | ||
| 83 | |||
| 84 | static const char * const proposal_names[PROPOSAL_MAX] = { | ||
| 85 | @@ -175,6 +175,18 @@ kex_names_valid(const char *names) | ||
| 86 | return 1; | ||
| 87 | } | ||
| 88 | |||
| 89 | +/* returns non-zero if proposal contains any algorithm from algs */ | ||
| 90 | +static int | ||
| 91 | +has_any_alg(const char *proposal, const char *algs) | ||
| 92 | +{ | ||
| 93 | + char *cp; | ||
| 94 | + | ||
| 95 | + if ((cp = match_list(proposal, algs, NULL)) == NULL) | ||
| 96 | + return 0; | ||
| 97 | + free(cp); | ||
| 98 | + return 1; | ||
| 99 | +} | ||
| 100 | + | ||
| 101 | /* | ||
| 102 | * Concatenate algorithm names, avoiding duplicates in the process. | ||
| 103 | * Caller must free returned string. | ||
| 104 | @@ -182,7 +194,7 @@ kex_names_valid(const char *names) | ||
| 105 | char * | ||
| 106 | kex_names_cat(const char *a, const char *b) | ||
| 107 | { | ||
| 108 | - char *ret = NULL, *tmp = NULL, *cp, *p, *m; | ||
| 109 | + char *ret = NULL, *tmp = NULL, *cp, *p; | ||
| 110 | size_t len; | ||
| 111 | |||
| 112 | if (a == NULL || *a == '\0') | ||
| 113 | @@ -199,10 +211,8 @@ kex_names_cat(const char *a, const char *b) | ||
| 114 | } | ||
| 115 | strlcpy(ret, a, len); | ||
| 116 | for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { | ||
| 117 | - if ((m = match_list(ret, p, NULL)) != NULL) { | ||
| 118 | - free(m); | ||
| 119 | + if (has_any_alg(ret, p)) | ||
| 120 | continue; /* Algorithm already present */ | ||
| 121 | - } | ||
| 122 | if (strlcat(ret, ",", len) >= len || | ||
| 123 | strlcat(ret, p, len) >= len) { | ||
| 124 | free(tmp); | ||
| 125 | @@ -410,7 +420,12 @@ kex_protocol_error(int type, u_int32_t seq, struct ssh *ssh) | ||
| 126 | { | ||
| 127 | int r; | ||
| 128 | |||
| 129 | - error("kex protocol error: type %d seq %u", type, seq); | ||
| 130 | + /* If in strict mode, any unexpected message is an error */ | ||
| 131 | + if ((ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict) { | ||
| 132 | + ssh_packet_disconnect(ssh, "strict KEX violation: " | ||
| 133 | + "unexpected packet type %u (seqnr %u)", type, seq); | ||
| 134 | + } | ||
| 135 | + error_f("type %u seq %u", type, seq); | ||
| 136 | if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 || | ||
| 137 | (r = sshpkt_put_u32(ssh, seq)) != 0 || | ||
| 138 | (r = sshpkt_send(ssh)) != 0) | ||
| 139 | @@ -485,6 +500,11 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh) | ||
| 140 | ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error); | ||
| 141 | if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0) | ||
| 142 | return r; | ||
| 143 | + if (ninfo >= 1024) { | ||
| 144 | + error("SSH2_MSG_EXT_INFO with too many entries, expected " | ||
| 145 | + "<=1024, received %u", ninfo); | ||
| 146 | + return dispatch_protocol_error(type, seq, ssh); | ||
| 147 | + } | ||
| 148 | for (i = 0; i < ninfo; i++) { | ||
| 149 | if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0) | ||
| 150 | return r; | ||
| 151 | @@ -600,7 +620,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh) | ||
| 152 | error_f("no kex"); | ||
| 153 | return SSH_ERR_INTERNAL_ERROR; | ||
| 154 | } | ||
| 155 | - ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL); | ||
| 156 | + ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_protocol_error); | ||
| 157 | ptr = sshpkt_ptr(ssh, &dlen); | ||
| 158 | if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) | ||
| 159 | return r; | ||
| 160 | @@ -636,7 +656,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh) | ||
| 161 | if (!(kex->flags & KEX_INIT_SENT)) | ||
| 162 | if ((r = kex_send_kexinit(ssh)) != 0) | ||
| 163 | return r; | ||
| 164 | - if ((r = kex_choose_conf(ssh)) != 0) | ||
| 165 | + if ((r = kex_choose_conf(ssh, seq)) != 0) | ||
| 166 | return r; | ||
| 167 | |||
| 168 | if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) | ||
| 169 | @@ -900,20 +920,14 @@ proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) | ||
| 170 | return (1); | ||
| 171 | } | ||
| 172 | |||
| 173 | -/* returns non-zero if proposal contains any algorithm from algs */ | ||
| 174 | static int | ||
| 175 | -has_any_alg(const char *proposal, const char *algs) | ||
| 176 | +kexalgs_contains(char **peer, const char *ext) | ||
| 177 | { | ||
| 178 | - char *cp; | ||
| 179 | - | ||
| 180 | - if ((cp = match_list(proposal, algs, NULL)) == NULL) | ||
| 181 | - return 0; | ||
| 182 | - free(cp); | ||
| 183 | - return 1; | ||
| 184 | + return has_any_alg(peer[PROPOSAL_KEX_ALGS], ext); | ||
| 185 | } | ||
| 186 | |||
| 187 | static int | ||
| 188 | -kex_choose_conf(struct ssh *ssh) | ||
| 189 | +kex_choose_conf(struct ssh *ssh, uint32_t seq) | ||
| 190 | { | ||
| 191 | struct kex *kex = ssh->kex; | ||
| 192 | struct newkeys *newkeys; | ||
| 193 | @@ -938,13 +952,23 @@ kex_choose_conf(struct ssh *ssh) | ||
| 194 | sprop=peer; | ||
| 195 | } | ||
| 196 | |||
| 197 | - /* Check whether client supports ext_info_c */ | ||
| 198 | - if (kex->server && (kex->flags & KEX_INITIAL)) { | ||
| 199 | - char *ext; | ||
| 200 | - | ||
| 201 | - ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL); | ||
| 202 | - kex->ext_info_c = (ext != NULL); | ||
| 203 | - free(ext); | ||
| 204 | + /* Check whether peer supports ext_info/kex_strict */ | ||
| 205 | + if ((kex->flags & KEX_INITIAL) != 0) { | ||
| 206 | + if (kex->server) { | ||
| 207 | + kex->ext_info_c = kexalgs_contains(peer, "ext-info-c"); | ||
| 208 | + kex->kex_strict = kexalgs_contains(peer, | ||
| 209 | + "kex-strict-c-v00@openssh.com"); | ||
| 210 | + } else { | ||
| 211 | + kex->kex_strict = kexalgs_contains(peer, | ||
| 212 | + "kex-strict-s-v00@openssh.com"); | ||
| 213 | + } | ||
| 214 | + if (kex->kex_strict) { | ||
| 215 | + debug3_f("will use strict KEX ordering"); | ||
| 216 | + if (seq != 0) | ||
| 217 | + ssh_packet_disconnect(ssh, | ||
| 218 | + "strict KEX violation: " | ||
| 219 | + "KEXINIT was not the first packet"); | ||
| 220 | + } | ||
| 221 | } | ||
| 222 | |||
| 223 | /* Check whether client supports rsa-sha2 algorithms */ | ||
| 224 | diff --git a/kex.h b/kex.h | ||
| 225 | index c353295..d97323e 100644 | ||
| 226 | --- a/kex.h | ||
| 227 | +++ b/kex.h | ||
| 228 | @@ -148,6 +148,7 @@ struct kex { | ||
| 229 | u_int kex_type; | ||
| 230 | char *server_sig_algs; | ||
| 231 | int ext_info_c; | ||
| 232 | + int kex_strict; | ||
| 233 | struct sshbuf *my; | ||
| 234 | struct sshbuf *peer; | ||
| 235 | struct sshbuf *client_version; | ||
| 236 | diff --git a/packet.c b/packet.c | ||
| 237 | index bde6c10..28f3729 100644 | ||
| 238 | --- a/packet.c | ||
| 239 | +++ b/packet.c | ||
| 240 | @@ -1205,8 +1205,13 @@ ssh_packet_send2_wrapped(struct ssh *ssh) | ||
| 241 | sshbuf_dump(state->output, stderr); | ||
| 242 | #endif | ||
| 243 | /* increment sequence number for outgoing packets */ | ||
| 244 | - if (++state->p_send.seqnr == 0) | ||
| 245 | + if (++state->p_send.seqnr == 0) { | ||
| 246 | + if ((ssh->kex->flags & KEX_INITIAL) != 0) { | ||
| 247 | + ssh_packet_disconnect(ssh, "outgoing sequence number " | ||
| 248 | + "wrapped during initial key exchange"); | ||
| 249 | + } | ||
| 250 | logit("outgoing seqnr wraps around"); | ||
| 251 | + } | ||
| 252 | if (++state->p_send.packets == 0) | ||
| 253 | if (!(ssh->compat & SSH_BUG_NOREKEY)) | ||
| 254 | return SSH_ERR_NEED_REKEY; | ||
| 255 | @@ -1214,6 +1219,11 @@ ssh_packet_send2_wrapped(struct ssh *ssh) | ||
| 256 | state->p_send.bytes += len; | ||
| 257 | sshbuf_reset(state->outgoing_packet); | ||
| 258 | |||
| 259 | + if (type == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) { | ||
| 260 | + debug_f("resetting send seqnr %u", state->p_send.seqnr); | ||
| 261 | + state->p_send.seqnr = 0; | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | if (type == SSH2_MSG_NEWKEYS) | ||
| 265 | r = ssh_set_newkeys(ssh, MODE_OUT); | ||
| 266 | else if (type == SSH2_MSG_USERAUTH_SUCCESS && state->server_side) | ||
| 267 | @@ -1342,8 +1352,7 @@ ssh_packet_read_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) | ||
| 268 | /* Stay in the loop until we have received a complete packet. */ | ||
| 269 | for (;;) { | ||
| 270 | /* Try to read a packet from the buffer. */ | ||
| 271 | - r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p); | ||
| 272 | - if (r != 0) | ||
| 273 | + if ((r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p)) != 0) | ||
| 274 | break; | ||
| 275 | /* If we got a packet, return it. */ | ||
| 276 | if (*typep != SSH_MSG_NONE) | ||
| 277 | @@ -1627,10 +1636,16 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) | ||
| 278 | if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0) | ||
| 279 | goto out; | ||
| 280 | } | ||
| 281 | + | ||
| 282 | if (seqnr_p != NULL) | ||
| 283 | *seqnr_p = state->p_read.seqnr; | ||
| 284 | - if (++state->p_read.seqnr == 0) | ||
| 285 | + if (++state->p_read.seqnr == 0) { | ||
| 286 | + if ((ssh->kex->flags & KEX_INITIAL) != 0) { | ||
| 287 | + ssh_packet_disconnect(ssh, "incoming sequence number " | ||
| 288 | + "wrapped during initial key exchange"); | ||
| 289 | + } | ||
| 290 | logit("incoming seqnr wraps around"); | ||
| 291 | + } | ||
| 292 | if (++state->p_read.packets == 0) | ||
| 293 | if (!(ssh->compat & SSH_BUG_NOREKEY)) | ||
| 294 | return SSH_ERR_NEED_REKEY; | ||
| 295 | @@ -1696,6 +1711,10 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) | ||
| 296 | #endif | ||
| 297 | /* reset for next packet */ | ||
| 298 | state->packlen = 0; | ||
| 299 | + if (*typep == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) { | ||
| 300 | + debug_f("resetting read seqnr %u", state->p_read.seqnr); | ||
| 301 | + state->p_read.seqnr = 0; | ||
| 302 | + } | ||
| 303 | |||
| 304 | if ((r = ssh_packet_check_rekey(ssh)) != 0) | ||
| 305 | return r; | ||
| 306 | @@ -1716,10 +1735,39 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) | ||
| 307 | r = ssh_packet_read_poll2(ssh, typep, seqnr_p); | ||
| 308 | if (r != 0) | ||
| 309 | return r; | ||
| 310 | - if (*typep) { | ||
| 311 | - state->keep_alive_timeouts = 0; | ||
| 312 | - DBG(debug("received packet type %d", *typep)); | ||
| 313 | + if (*typep == 0) { | ||
| 314 | + /* no message ready */ | ||
| 315 | + return 0; | ||
| 316 | + } | ||
| 317 | + state->keep_alive_timeouts = 0; | ||
| 318 | + DBG(debug("received packet type %d", *typep)); | ||
| 319 | + | ||
| 320 | + /* Always process disconnect messages */ | ||
| 321 | + if (*typep == SSH2_MSG_DISCONNECT) { | ||
| 322 | + if ((r = sshpkt_get_u32(ssh, &reason)) != 0 || | ||
| 323 | + (r = sshpkt_get_string(ssh, &msg, NULL)) != 0) | ||
| 324 | + return r; | ||
| 325 | + /* Ignore normal client exit notifications */ | ||
| 326 | + do_log2(ssh->state->server_side && | ||
| 327 | + reason == SSH2_DISCONNECT_BY_APPLICATION ? | ||
| 328 | + SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR, | ||
| 329 | + "Received disconnect from %s port %d:" | ||
| 330 | + "%u: %.400s", ssh_remote_ipaddr(ssh), | ||
| 331 | + ssh_remote_port(ssh), reason, msg); | ||
| 332 | + free(msg); | ||
| 333 | + return SSH_ERR_DISCONNECTED; | ||
| 334 | } | ||
| 335 | + | ||
| 336 | + /* | ||
| 337 | + * Do not implicitly handle any messages here during initial | ||
| 338 | + * KEX when in strict mode. They will be need to be allowed | ||
| 339 | + * explicitly by the KEX dispatch table or they will generate | ||
| 340 | + * protocol errors. | ||
| 341 | + */ | ||
| 342 | + if (ssh->kex != NULL && | ||
| 343 | + (ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict) | ||
| 344 | + return 0; | ||
| 345 | + /* Implicitly handle transport-level messages */ | ||
| 346 | switch (*typep) { | ||
| 347 | case SSH2_MSG_IGNORE: | ||
| 348 | debug3("Received SSH2_MSG_IGNORE"); | ||
| 349 | @@ -1734,19 +1782,6 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) | ||
| 350 | debug("Remote: %.900s", msg); | ||
| 351 | free(msg); | ||
| 352 | break; | ||
| 353 | - case SSH2_MSG_DISCONNECT: | ||
| 354 | - if ((r = sshpkt_get_u32(ssh, &reason)) != 0 || | ||
| 355 | - (r = sshpkt_get_string(ssh, &msg, NULL)) != 0) | ||
| 356 | - return r; | ||
| 357 | - /* Ignore normal client exit notifications */ | ||
| 358 | - do_log2(ssh->state->server_side && | ||
| 359 | - reason == SSH2_DISCONNECT_BY_APPLICATION ? | ||
| 360 | - SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR, | ||
| 361 | - "Received disconnect from %s port %d:" | ||
| 362 | - "%u: %.400s", ssh_remote_ipaddr(ssh), | ||
| 363 | - ssh_remote_port(ssh), reason, msg); | ||
| 364 | - free(msg); | ||
| 365 | - return SSH_ERR_DISCONNECTED; | ||
| 366 | case SSH2_MSG_UNIMPLEMENTED: | ||
| 367 | if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0) | ||
| 368 | return r; | ||
| 369 | @@ -2211,6 +2246,7 @@ kex_to_blob(struct sshbuf *m, struct kex *kex) | ||
| 370 | (r = sshbuf_put_u32(m, kex->hostkey_type)) != 0 || | ||
| 371 | (r = sshbuf_put_u32(m, kex->hostkey_nid)) != 0 || | ||
| 372 | (r = sshbuf_put_u32(m, kex->kex_type)) != 0 || | ||
| 373 | + (r = sshbuf_put_u32(m, kex->kex_strict)) != 0 || | ||
| 374 | (r = sshbuf_put_stringb(m, kex->my)) != 0 || | ||
| 375 | (r = sshbuf_put_stringb(m, kex->peer)) != 0 || | ||
| 376 | (r = sshbuf_put_stringb(m, kex->client_version)) != 0 || | ||
| 377 | @@ -2373,6 +2409,7 @@ kex_from_blob(struct sshbuf *m, struct kex **kexp) | ||
| 378 | (r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_type)) != 0 || | ||
| 379 | (r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_nid)) != 0 || | ||
| 380 | (r = sshbuf_get_u32(m, &kex->kex_type)) != 0 || | ||
| 381 | + (r = sshbuf_get_u32(m, &kex->kex_strict)) != 0 || | ||
| 382 | (r = sshbuf_get_stringb(m, kex->my)) != 0 || | ||
| 383 | (r = sshbuf_get_stringb(m, kex->peer)) != 0 || | ||
| 384 | (r = sshbuf_get_stringb(m, kex->client_version)) != 0 || | ||
| 385 | @@ -2701,6 +2738,7 @@ sshpkt_disconnect(struct ssh *ssh, const char *fmt,...) | ||
| 386 | vsnprintf(buf, sizeof(buf), fmt, args); | ||
| 387 | va_end(args); | ||
| 388 | |||
| 389 | + debug2_f("sending SSH2_MSG_DISCONNECT: %s", buf); | ||
| 390 | if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 || | ||
| 391 | (r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 || | ||
| 392 | (r = sshpkt_put_cstring(ssh, buf)) != 0 || | ||
| 393 | diff --git a/sshconnect2.c b/sshconnect2.c | ||
| 394 | index b25225e..83ae4a4 100644 | ||
| 395 | --- a/sshconnect2.c | ||
| 396 | +++ b/sshconnect2.c | ||
| 397 | @@ -241,7 +241,8 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, | ||
| 398 | fatal_fr(r, "kex_assemble_namelist"); | ||
| 399 | free(all_key); | ||
| 400 | |||
| 401 | - if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL) | ||
| 402 | + if ((s = kex_names_cat(options.kex_algorithms, | ||
| 403 | + "ext-info-c,kex-strict-c-v00@openssh.com")) == NULL) | ||
| 404 | fatal_f("kex_names_cat"); | ||
| 405 | myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(ssh, s); | ||
| 406 | myproposal[PROPOSAL_ENC_ALGS_CTOS] = | ||
| 407 | @@ -363,7 +364,6 @@ struct cauthmethod { | ||
| 408 | }; | ||
| 409 | |||
| 410 | static int input_userauth_service_accept(int, u_int32_t, struct ssh *); | ||
| 411 | -static int input_userauth_ext_info(int, u_int32_t, struct ssh *); | ||
| 412 | static int input_userauth_success(int, u_int32_t, struct ssh *); | ||
| 413 | static int input_userauth_failure(int, u_int32_t, struct ssh *); | ||
| 414 | static int input_userauth_banner(int, u_int32_t, struct ssh *); | ||
| 415 | @@ -477,7 +477,7 @@ ssh_userauth2(struct ssh *ssh, const char *local_user, | ||
| 416 | |||
| 417 | ssh->authctxt = &authctxt; | ||
| 418 | ssh_dispatch_init(ssh, &input_userauth_error); | ||
| 419 | - ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info); | ||
| 420 | + ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, kex_input_ext_info); | ||
| 421 | ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT, &input_userauth_service_accept); | ||
| 422 | ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt.success); /* loop until success */ | ||
| 423 | pubkey_cleanup(ssh); | ||
| 424 | @@ -529,13 +529,6 @@ input_userauth_service_accept(int type, u_int32_t seq, struct ssh *ssh) | ||
| 425 | return r; | ||
| 426 | } | ||
| 427 | |||
| 428 | -/* ARGSUSED */ | ||
| 429 | -static int | ||
| 430 | -input_userauth_ext_info(int type, u_int32_t seqnr, struct ssh *ssh) | ||
| 431 | -{ | ||
| 432 | - return kex_input_ext_info(type, seqnr, ssh); | ||
| 433 | -} | ||
| 434 | - | ||
| 435 | void | ||
| 436 | userauth(struct ssh *ssh, char *authlist) | ||
| 437 | { | ||
| 438 | @@ -617,6 +610,7 @@ input_userauth_success(int type, u_int32_t seq, struct ssh *ssh) | ||
| 439 | free(authctxt->methoddata); | ||
| 440 | authctxt->methoddata = NULL; | ||
| 441 | authctxt->success = 1; /* break out */ | ||
| 442 | + ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, dispatch_protocol_error); | ||
| 443 | return 0; | ||
| 444 | } | ||
| 445 | |||
| 446 | diff --git a/sshd.c b/sshd.c | ||
| 447 | index ef18ba4..652bdc3 100644 | ||
| 448 | --- a/sshd.c | ||
| 449 | +++ b/sshd.c | ||
| 450 | @@ -2354,11 +2354,13 @@ static void | ||
| 451 | do_ssh2_kex(struct ssh *ssh) | ||
| 452 | { | ||
| 453 | char *myproposal[PROPOSAL_MAX] = { KEX_SERVER }; | ||
| 454 | + char *s; | ||
| 455 | struct kex *kex; | ||
| 456 | int r; | ||
| 457 | |||
| 458 | - myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(ssh, | ||
| 459 | - options.kex_algorithms); | ||
| 460 | + if ((s = kex_names_cat(options.kex_algorithms, "kex-strict-s-v00@openssh.com")) == NULL) | ||
| 461 | + fatal_f("kex_names_cat"); | ||
| 462 | + myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(ssh, s); | ||
| 463 | myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(ssh, | ||
| 464 | options.ciphers); | ||
| 465 | myproposal[PROPOSAL_ENC_ALGS_STOC] = compat_cipher_proposal(ssh, | ||
| 466 | @@ -2411,6 +2413,7 @@ do_ssh2_kex(struct ssh *ssh) | ||
| 467 | (r = ssh_packet_write_wait(ssh)) != 0) | ||
| 468 | fatal_fr(r, "send test"); | ||
| 469 | #endif | ||
| 470 | + free(s); | ||
| 471 | debug("KEX done"); | ||
| 472 | } | ||
| 473 | |||
| 474 | -- | ||
| 475 | 2.25.1 | ||
| 476 | |||
diff --git a/meta/recipes-connectivity/openssh/openssh/fix-authorized-principals-command.patch b/meta/recipes-connectivity/openssh/openssh/fix-authorized-principals-command.patch new file mode 100644 index 0000000000..3790774f15 --- /dev/null +++ b/meta/recipes-connectivity/openssh/openssh/fix-authorized-principals-command.patch | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | From fcd78e31cdd45a7e69ccfe6d8a3b1037dc1de290 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: "djm@openbsd.org" <djm@openbsd.org> | ||
| 3 | Date: Wed, 24 May 2023 23:01:06 +0000 | ||
| 4 | Subject: [PATCH] upstream: fix AuthorizedPrincipalsCommand when | ||
| 5 | AuthorizedKeysCommand | ||
| 6 | Description: Fix the wrong code as the Subject suggests | ||
| 7 | I added that description to mention, that the file header change was | ||
| 8 | incompatible with the proposed code below and failed to apply, | ||
| 9 | therefore I dropped that chunk of the code. | ||
| 10 | Origin: backport, https://github.com/openssh/openssh-portable/commit/fcd78e31cdd45a7e69ccfe6d8a3b1037dc1de290 | ||
| 11 | Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=3574 | ||
| 12 | Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/openssh/+bug/2031942 | ||
| 13 | Last-Update: 2023-09-01 | ||
| 14 | |||
| 15 | Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/openssh/tree/debian/patches/fix-authorized-principals-command.patch?h=ubuntu/jammy-security | ||
| 16 | Upstream commit https://github.com/openssh/openssh-portable/commit/fcd78e31cdd45a7e69ccfe6d8a3b1037dc1de290] | ||
| 17 | Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> | ||
| 18 | --- | ||
| 19 | This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ | ||
| 20 | --- a/servconf.c | ||
| 21 | +++ b/servconf.c | ||
| 22 | @@ -2372,7 +2372,7 @@ process_server_config_line_depth(ServerO | ||
| 23 | fatal("%.200s line %d: %s must be an absolute path", | ||
| 24 | filename, linenum, keyword); | ||
| 25 | } | ||
| 26 | - if (*activep && options->authorized_keys_command == NULL) | ||
| 27 | + if (*activep && *charptr == NULL) | ||
| 28 | *charptr = xstrdup(str + len); | ||
| 29 | argv_consume(&ac); | ||
| 30 | break; | ||
diff --git a/meta/recipes-connectivity/openssh/openssh_8.9p1.bb b/meta/recipes-connectivity/openssh/openssh_8.9p1.bb index 32761b8bb8..7ad9bced1b 100644 --- a/meta/recipes-connectivity/openssh/openssh_8.9p1.bb +++ b/meta/recipes-connectivity/openssh/openssh_8.9p1.bb | |||
| @@ -32,6 +32,8 @@ SRC_URI = "http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-${PV}.tar | |||
| 32 | file://CVE-2023-38408-0002.patch \ | 32 | file://CVE-2023-38408-0002.patch \ |
| 33 | file://CVE-2023-38408-0003.patch \ | 33 | file://CVE-2023-38408-0003.patch \ |
| 34 | file://CVE-2023-38408-0004.patch \ | 34 | file://CVE-2023-38408-0004.patch \ |
| 35 | file://fix-authorized-principals-command.patch \ | ||
| 36 | file://CVE-2023-48795.patch \ | ||
| 35 | " | 37 | " |
| 36 | SRC_URI[sha256sum] = "fd497654b7ab1686dac672fb83dfb4ba4096e8b5ffcdaccd262380ae58bec5e7" | 38 | SRC_URI[sha256sum] = "fd497654b7ab1686dac672fb83dfb4ba4096e8b5ffcdaccd262380ae58bec5e7" |
| 37 | 39 | ||
