Fix GSS KEX causing ssh failures when connecting to WinSSHD

Resolves: RHEL-5321
This commit is contained in:
Dmitry Belyavskiy 2023-11-01 11:29:52 +01:00
parent 6242770aa2
commit 6c888396c9
2 changed files with 60 additions and 27 deletions

View File

@ -1509,7 +1509,7 @@ new file mode 100644
index 00000000..0b2f6a56 index 00000000..0b2f6a56
--- /dev/null --- /dev/null
+++ b/kexgssc.c +++ b/kexgssc.c
@@ -0,0 +1,595 @@ @@ -0,0 +1,618 @@
+/* +/*
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
+ * + *
@ -1571,7 +1571,7 @@ index 00000000..0b2f6a56
+ struct sshbuf *server_blob = NULL; + struct sshbuf *server_blob = NULL;
+ struct sshbuf *shared_secret = NULL; + struct sshbuf *shared_secret = NULL;
+ struct sshbuf *server_host_key_blob = NULL; + struct sshbuf *server_host_key_blob = NULL;
+ struct sshbuf *empty = sshbuf_new(); + struct sshbuf *empty = NULL;
+ u_char *msg; + u_char *msg;
+ int type = 0; + int type = 0;
+ int first = 1; + int first = 1;
@ -1610,8 +1610,10 @@ index 00000000..0b2f6a56
+ default: + default:
+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); + fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
+ } + }
+ if (r != 0) + if (r != 0) {
+ ssh_gssapi_delete_ctx(&ctxt);
+ return r; + return r;
+ }
+ +
+ token_ptr = GSS_C_NO_BUFFER; + token_ptr = GSS_C_NO_BUFFER;
+ +
@ -1674,11 +1676,16 @@ index 00000000..0b2f6a56
+ do { + do {
+ type = ssh_packet_read(ssh); + type = ssh_packet_read(ssh);
+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) { + if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
+ char *tmp = NULL;
+ size_t tmp_len = 0;
+
+ debug("Received KEXGSS_HOSTKEY"); + debug("Received KEXGSS_HOSTKEY");
+ if (server_host_key_blob) + if (server_host_key_blob)
+ fatal("Server host key received more than once"); + fatal("Server host key received more than once");
+ if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0) + if ((r = sshpkt_get_string(ssh, &tmp, &tmp_len)) != 0)
+ fatal("Failed to read server host key: %s", ssh_err(r)); + fatal("Failed to read server host key: %s", ssh_err(r));
+ if ((server_host_key_blob = sshbuf_from(tmp, tmp_len)) == NULL)
+ fatal("sshbuf_from failed");
+ } + }
+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY); + } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
+ +
@ -1779,6 +1786,11 @@ index 00000000..0b2f6a56
+ if (r != 0) + if (r != 0)
+ goto out; + goto out;
+ +
+ if ((empty = sshbuf_new()) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+
+ hashlen = sizeof(hash); + hashlen = sizeof(hash);
+ if ((r = kex_gen_hash( + if ((r = kex_gen_hash(
+ kex->hash_alg, + kex->hash_alg,
@ -1848,7 +1860,7 @@ index 00000000..0b2f6a56
+ size_t hashlen; + size_t hashlen;
+ const BIGNUM *pub_key, *dh_p, *dh_g; + const BIGNUM *pub_key, *dh_p, *dh_g;
+ int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX; + int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
+ struct sshbuf *empty = sshbuf_new(); + struct sshbuf *empty = NULL;
+ u_char c; + u_char c;
+ int r; + int r;
+ +
@ -1960,11 +1972,16 @@ index 00000000..0b2f6a56
+ do { + do {
+ type = ssh_packet_read(ssh); + type = ssh_packet_read(ssh);
+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) { + if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
+ char *tmp = NULL;
+ size_t tmp_len = 0;
+
+ debug("Received KEXGSS_HOSTKEY"); + debug("Received KEXGSS_HOSTKEY");
+ if (server_host_key_blob) + if (server_host_key_blob)
+ fatal("Server host key received more than once"); + fatal("Server host key received more than once");
+ if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0) + if ((r = sshpkt_get_string(ssh, &tmp, &tmp_len)) != 0)
+ fatal("sshpkt failed: %s", ssh_err(r)); + fatal("sshpkt failed: %s", ssh_err(r));
+ if ((server_host_key_blob = sshbuf_from(tmp, tmp_len)) == NULL)
+ fatal("sshbuf_from failed");
+ } + }
+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY); + } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
+ +
@ -2040,6 +2057,7 @@ index 00000000..0b2f6a56
+ (r = sshbuf_get_bignum2(buf, &dh_server_pub)) != 0) + (r = sshbuf_get_bignum2(buf, &dh_server_pub)) != 0)
+ goto out; + goto out;
+ sshbuf_free(buf); + sshbuf_free(buf);
+ buf = NULL;
+ +
+ if ((shared_secret = sshbuf_new()) == NULL) { + if ((shared_secret = sshbuf_new()) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL; + r = SSH_ERR_ALLOC_FAIL;
@ -2048,6 +2066,10 @@ index 00000000..0b2f6a56
+ +
+ if ((r = kex_dh_compute_key(kex, dh_server_pub, shared_secret)) != 0) + if ((r = kex_dh_compute_key(kex, dh_server_pub, shared_secret)) != 0)
+ goto out; + goto out;
+ if ((empty = sshbuf_new()) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ +
+ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); + DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g);
+ hashlen = sizeof(hash); + hashlen = sizeof(hash);
@ -2094,6 +2116,7 @@ index 00000000..0b2f6a56
+ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) + if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
+ r = kex_send_newkeys(ssh); + r = kex_send_newkeys(ssh);
+out: +out:
+ sshbuf_free(buf);
+ sshbuf_free(server_blob); + sshbuf_free(server_blob);
+ sshbuf_free(empty); + sshbuf_free(empty);
+ explicit_bzero(hash, sizeof(hash)); + explicit_bzero(hash, sizeof(hash));
@ -2110,7 +2133,7 @@ new file mode 100644
index 00000000..60bc02de index 00000000..60bc02de
--- /dev/null --- /dev/null
+++ b/kexgsss.c +++ b/kexgsss.c
@@ -0,0 +1,474 @@ @@ -0,0 +1,482 @@
+/* +/*
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
+ * + *
@ -2177,7 +2200,7 @@ index 00000000..60bc02de
+ */ + */
+ +
+ OM_uint32 ret_flags = 0; + OM_uint32 ret_flags = 0;
+ gss_buffer_desc gssbuf, recv_tok, msg_tok; + gss_buffer_desc gssbuf = {0, NULL}, recv_tok, msg_tok;
+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; + gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+ Gssctxt *ctxt = NULL; + Gssctxt *ctxt = NULL;
+ struct sshbuf *shared_secret = NULL; + struct sshbuf *shared_secret = NULL;
@ -2217,7 +2240,7 @@ index 00000000..60bc02de
+ type = ssh_packet_read(ssh); + type = ssh_packet_read(ssh);
+ switch(type) { + switch(type) {
+ case SSH2_MSG_KEXGSS_INIT: + case SSH2_MSG_KEXGSS_INIT:
+ if (client_pubkey != NULL) + if (gssbuf.value != NULL)
+ fatal("Received KEXGSS_INIT after initialising"); + fatal("Received KEXGSS_INIT after initialising");
+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, + if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
+ &recv_tok)) != 0 || + &recv_tok)) != 0 ||
@ -2248,6 +2271,31 @@ index 00000000..60bc02de
+ goto out; + goto out;
+ +
+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ + /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
+
+ /* Calculate the hash early so we can free the
+ * client_pubkey, which has reference to the parent
+ * buffer state->incoming_packet
+ */
+ hashlen = sizeof(hash);
+ if ((r = kex_gen_hash(
+ kex->hash_alg,
+ kex->client_version,
+ kex->server_version,
+ kex->peer,
+ kex->my,
+ empty,
+ client_pubkey,
+ server_pubkey,
+ shared_secret,
+ hash, &hashlen)) != 0)
+ goto out;
+
+ gssbuf.value = hash;
+ gssbuf.length = hashlen;
+
+ sshbuf_free(client_pubkey);
+ client_pubkey = NULL;
+
+ break; + break;
+ case SSH2_MSG_KEXGSS_CONTINUE: + case SSH2_MSG_KEXGSS_CONTINUE:
+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, + if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
@ -2269,7 +2317,7 @@ index 00000000..60bc02de
+ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) + if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
+ fatal("Zero length token output when incomplete"); + fatal("Zero length token output when incomplete");
+ +
+ if (client_pubkey == NULL) + if (gssbuf.value == NULL)
+ fatal("No client public key"); + fatal("No client public key");
+ +
+ if (maj_status & GSS_S_CONTINUE_NEEDED) { + if (maj_status & GSS_S_CONTINUE_NEEDED) {
@ -2298,23 +2346,6 @@ index 00000000..60bc02de
+ if (!(ret_flags & GSS_C_INTEG_FLAG)) + if (!(ret_flags & GSS_C_INTEG_FLAG))
+ fatal("Integrity flag wasn't set"); + fatal("Integrity flag wasn't set");
+ +
+ hashlen = sizeof(hash);
+ if ((r = kex_gen_hash(
+ kex->hash_alg,
+ kex->client_version,
+ kex->server_version,
+ kex->peer,
+ kex->my,
+ empty,
+ client_pubkey,
+ server_pubkey,
+ shared_secret,
+ hash, &hashlen)) != 0)
+ goto out;
+
+ gssbuf.value = hash;
+ gssbuf.length = hashlen;
+
+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt, &gssbuf, &msg_tok)))) + if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt, &gssbuf, &msg_tok))))
+ fatal("Couldn't get MIC"); + fatal("Couldn't get MIC");
+ +

View File

@ -826,6 +826,8 @@ getent passwd sshd >/dev/null || \
Resolves: RHEL-5279 Resolves: RHEL-5279
- Using DigestSign/DigestVerify functions for better FIPS compatibility - Using DigestSign/DigestVerify functions for better FIPS compatibility
Resolves: RHEL-5217 Resolves: RHEL-5217
- Fix GSS KEX causing ssh failures when connecting to WinSSHD
Resolves: RHEL-5321
* Thu Aug 24 2023 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-19 * Thu Aug 24 2023 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-19
- rebuilt - rebuilt